Get Polygon Intersection Line with CGAL - c++

How can I easily retrieve the intersection line (from the first to the last intersection point) of two intersecting polygons with CGAL. See the image for clarification, the green line is what I want.
Currently I use the following algorithm, where I get the intersection polygon and then find the points which are on both polygon boundaries, these should be the intersection points. Here it is in code:
Polygon_2 P,Q;
Pwh_list_2 intR;
Pwh_list_2::const_iterator it;
CGAL::intersection(P, Q, std::back_inserter(intR));
//Loop through intersection polygons
for (it = intR.begin(); it != intR.end(); ++it) {
boost::numeric::ublas::vector<double> firstIntersectPoint(3), lastIntersectPoint(3);
Polygon_2 Overlap = it->outer_boundary();
typename CGAL::Polygon_2<Kernel>::Vertex_iterator vit;
int pointNr = 1;
//Loop through points of intersection polygon to find first and last intersection point.
for (vit = Overlap.vertices_begin(); vit != Overlap.vertices_end(); ++vit) {
CGAL::Bounded_side bsideThis = P.bounded_side(*vit);
CGAL::Bounded_side bsideArg = Q.bounded_side(*vit);
if (bsideThis == CGAL::ON_BOUNDARY && bsideArg == CGAL::ON_BOUNDARY && pointNr == 1) {
firstIntersectPoint <<= 0, CGAL::to_double(vit->x()), CGAL::to_double(vit->y());
pointNr = 2;
}
else if (bsideThis == CGAL::ON_BOUNDARY && bsideArg == CGAL::ON_BOUNDARY && pointNr == 2) {
lastIntersectPoint <<= 0, CGAL::to_double(vit->x()), CGAL::to_double(vit->y());
pointNr = 2;
}
}
//RESULT
std::cout << firstIntersectPoint << std::endl;
std::cout << lastIntersectPoint << std::endl;
}
Although this works I don't think it is the correct way to go. Can somebody give me an indication whether this is the correct way to do this or give my pointers how to do it better.

Insert the segments of the two polygons into a 2D Arrangement. Then find the vertices with degree 4. Notice that in the general case there might be more than 2; there might be none, and there might be 1.
std::list<X_monotone_curve_2> segments;
for (const auto& pgn : polygons) {
for (auto it = pgn.curves_begin(); it != pgn.curves_end(); ++it)
segments.push_back(*it);
}
Arrangement_2 arr;
insert(arr, segments.begin(), segments.end());
for (auto it = arr.begin_vertices(); it != arr.end_vertices(); ++it) {
if (4 == it->degree())
...
}
You can avoid the construction of the 'segments' list and instead directly insert the segments of the polygons into the arrangement using an iterator adapter. (This is pure generic programming and nothing to do with CGAL.)

Related

2D Delaunay, Divide and Conquer - Rare bug

I have been working on a two dimensional Divide and Conquer algorithm written in c++, a language I am rather new to. I used this page to base my algorithm on. The Y-axis is inverted in my example images.
I create a grid with a chosen width and height. The program then selects a random coordinate within each cell, these are the points for the Delaunay Triangulation.
The algorithm works as follows
Sort the coordinates in ascending order on the x-axis (similar x values; sort on y)
Divide into subgroups, until each group contains no more than 3 coordinates. Connect each coordinate with a line (I call them 'Edges'). This is in a binary tree structure. The Leaves contain a vector of these edges.
Recursively merge the leaves upwards
# Select the starting edge: select the coordinates, L and R, with the lowest y value from the left and right subgroup. If the edge L-R does not intersect with any edges of either group: select that edge. Else, select the next coordinate. (If the L-R edge intersects with an edge from the left subgroup select the next left coordinate. Ditto with the right group)
Based on the starting edge ('base' in my code) select the next candidate from both groups, left_C and right_C (the following is the left subgroup selection process, the right subgroup is the same but only mirrored):
Select the neighboring coordinates: all coordinates that have a direct connection to the base edge
Sort the neighbors by increasing clockwise angles.
# The candidate selection process: Select first (i = 0) coordinate as the candidate C, the second (i + 1) as the next candidate nC.
Check if the angle between the L-R and C is bigger than 180° or pi. If so: no candidate is selected, else move on to the next condition.
& Check if, the nC is within the circumcircle defined by triangle L-R-C (distance between circumcircle center and nC < radius circumcircle). delete the edge defined by L-C. nC becomes the new candidate C, the candidate with the next highest angle becomes nC, repeat check.
return candidate at the position i
If neither left nor right groups return a candidate, then the merge is complete.
Else if only one group returns a candidate, obviously that is the to-be-used candidate
Else both subgroups return a candidate, then select the candidate where the circumcircle defined by it and the base edge does not contain the other.
A triangle is created using the selected candidate and the base edge: an edge is created between the candidate and base-coordinate from the other subgroup ( eg. candidate of the left-subgroup: R-left_C ). This becomes the base edge for the next iteration.
iterate until the merge is complete (neither subgroup offers a candidate)
And so the tree is merged recursively.
So TL;DR.
The issue that I am having is two steps of the D&C algorithm coming into conflict. the two are the selection of the starting base edge (see step #) and the selection of the candidate coordinates (see step # and &)
The bug (read: feature) occurs with this orientation of the subgroups:
Animated Gif
It skips one of the coordinates of the right group in the first merger. This is because the algorithm specifies that you take the lowest y values of both groups that do not intersect with any other edges as the base edge. Then all the right group candidates, which are attached to the base edge, are selected with their counter-clockwise angle, the left with the clockwise angles. This skips one coordinate. leading to the following result.
I have no idea how to solve this.
Here is my code:
triangulate():
Node* Branch::triangulate() {
if (l != nullptr && r == nullptr) {
return l;
}
else {
// recursive merge
Node* left = l->triangulate();
Node* right = r->triangulate();
vector<Edge> left_edges = left->getEdges();
vector<Edge> right_edges = right->getEdges();
Edge base = selectBase(left_edges, right_edges);
bool merge = true;
vector<Edge> mergedEdges;
vector<Edge> newEdges;
newEdges.push_back(base);
while (merge) {
Coordinate left_candidate = selectCandidateFromSubgroup(left_edges, base, true);
Coordinate right_candidate = selectCandidateFromSubgroup(right_edges, base, false);
Coordinate null(DBL_MIN, DBL_MIN);
if (left_candidate == null && right_candidate == null) {
merge = false;
}
else {
Edge new_base;
if (right_candidate == null) {
new_base = Edge(left_candidate, *base.p2());
}
else if (left_candidate == null) {
new_base = Edge(*base.p1(), right_candidate);
}
else {
double left_a, left_b, left_c,
base_a, base_b, base_c;
functionFromEdge(base, base_a, base_b, base_c);
Edge left_edge(left_candidate, *base.p2());
functionFromEdge(left_edge, left_a, left_b, left_c);
perpendicularBisector(base, base_a, base_b, base_c);
perpendicularBisector(left_edge, left_a, left_b, left_c);
Coordinate left_circumcircle_center = intersection(left_a, left_b, left_c,
base_a, base_b, base_c);
new_base = (Coordinate::distance(left_circumcircle_center, left_candidate)
< Coordinate::distance(left_circumcircle_center, right_candidate))
? left_edge : Edge(*base.p1(), right_candidate);
}
newEdges.push_back(new_base);
base = new_base;
}
}
mergedEdges.reserve(newEdges.size() + left_edges.size() + right_edges.size());
for (Edge e : left_edges) {
mergedEdges.push_back(e);
}
for (Edge e : right_edges) {
mergedEdges.push_back(e);
}
for (Edge e : newEdges) {
mergedEdges.push_back(e);
}
return new Leaf(mergedEdges,i);
}
}
selectBase():
vector<Coordinate> left_points = extractCoordinates(left);
vector<Coordinate> right_points = extractCoordinates(right);
Edge* out = nullptr;
bool found = false;
int i = 0;
int j = 0;
while (!found) {
Coordinate l = left_points.at(i), r = right_points.at(j);
Edge base(l, r);
out = &base;
for (Edge e : left) {
if (out!= nullptr && e.intersects(base)) {
//cout << e << " intersects with " << *out << " i++" << endl;
i++;
out = nullptr;
}
if (out != nullptr && left_points.size() ==2 && (*e.p1() == *base.p1() || *e.p2() == *base.p1())) {
Coordinate other = (*e.p1() == *base.p1()) ? *e.p2() : *e.p1();
if (Angle::calcClockAngle(l, r, other, true).rad() > M_PI) {
out = nullptr; i++;
}
}
}
for (Edge e : right) {
if (out != nullptr && e.intersects(base)) {
//cout << e << " intersects with " << *out << " j++" << endl;
j++;
out = nullptr;
}
if (out != nullptr && right_points.size() == 2 && (*e.p1() == *base.p2() || *e.p2() == *base.p2())) {
Coordinate other = (*e.p1() == *base.p2()) ? *e.p2() : *e.p1();
if (Angle::calcClockAngle(r, l, other, false).rad() > M_PI) {
out = nullptr; j++;
}
}
}
if (out != nullptr) found = true;
}
return Edge(left_points.at(i), right_points.at(j));
}
In the above function I tried to make a check that checks if there is a skipped point, by checking in subgroups of size 2 if there is an angle larger than pi.
It worked for smaller groups. But the issue still occurs.
selectCandidateFromSubgroup:
Coordinate selectCandidateFromSubgroup(vector<Edge>& es, Edge& base, bool left) {
// select neighboring edges from base
Coordinate* shared_point = (left)? base.p1() : base.p2();
Coordinate* other_point = (left)? base.p2() : base.p1();
vector<Coordinate> candidates;
for (Edge e : es) {
if (*shared_point == *e.p2() || *shared_point == *e.p1()) {
Coordinate c = (*shared_point == *e.p2()) ? *e.p1() : *e.p2();
candidates.push_back(c);
}
}
if (candidates.size() != 0) {
algorithm::quicksort(candidates, 0, candidates.size() -1,
[&shared_point,&other_point,&left](Coordinate a, Coordinate b) {
double angle = Angle::calcClockAngle(*shared_point, *other_point, a, left).getDegrees();
double angle2 = Angle::calcClockAngle(*shared_point, *other_point, b, left).getDegrees();
return (angle < angle2 || (angle == angle2 && a.y() < b.y()));
});
double base_a, base_b, base_c;
functionFromEdge(base, base_a, base_b, base_c);
perpendicularBisector(base, base_a, base_b, base_c);
Coordinate* candidate=nullptr;
Coordinate* next_candidate = nullptr;
int i = 0;
bool checking_candidates = true;
while (checking_candidates) {
candidate = &candidates.at(i);
double angle = Angle::calcClockAngle(*shared_point,
*other_point,
*candidate,
left).rad();
if (angle < M_PI) {
Edge candidate_edge;
int cei = 0;
int j = 0;
for (Edge e : es) {
if ((*e.p1() == *shared_point && *e.p2() == *candidate) || (*e.p2() == *shared_point && *e.p1() == *candidate)) {
candidate_edge = e;
cei = j;
break;
}
j++;
}
if (i + 1 == candidates.size()) return *candidate;
next_candidate= &candidates.at(i+1);
double candidate_edge_a, candidate_edge_b, candidate_edge_c;
functionFromEdge(candidate_edge, candidate_edge_a,
candidate_edge_b, candidate_edge_c);
perpendicularBisector(candidate_edge, candidate_edge_a,
candidate_edge_b, candidate_edge_c);
Coordinate circumcicle_center = intersection(base_a, base_b, base_c,
candidate_edge_a, candidate_edge_b, candidate_edge_c);
double radius = Coordinate::distance(circumcicle_center, *shared_point);
double distance_center_nCandidate = Coordinate::distance(circumcicle_center, *next_candidate);
if (radius < distance_center_nCandidate) {
return *candidate;
}
else {
i++;
es.erase(es.begin() + cei);
}
}
else {
return Coordinate(DBL_MIN, DBL_MIN);
}
}
}
return Coordinate(DBL_MIN, DBL_MIN);
}
extractCoordinates(vector) extracts and sorts all coordiates on the y axis ascendingly.
functionFromEdge(Edge,double a,double b,double c) takes an edge and makes a functional representation of the lines like 'ax+by=c', which is used by
perpendicularBisector(Edge, double a, double b, double c) converts the a, b, and c values to represent the function of the perpendicular bisector of the Edge so that the algorithm can calulate the
intersection(double a1, double b1, double c1, double a2, double b2, double c2) of two functions.
the calcClockAngle(Coordinate a, Coordinate b, Coordinate c, bool clockwise) calulates the angle in a bewteen the vectors |AB| and |AC|, depending on the clockwise boolean, it calculates the cloclwise or counter clockwise angle.
If I forgot something please let me know.
Sorry for the long question. but I am seriously at a loss here.
I get results like this:

Iterating over list of list of object

I want to iterate over a list of list of Object,
list<list<Point>> gnuPoints;
this is a static list which accepts list from various classes like circle and polygon all of which classes pushes multiple objects i.e Point(x,y) to the list
while (angle != 360)
{
double x = m_radius*cos(angle);
double y = m_radius*sin(angle);
angle += 30;
circlePoint.push_back(Point(x, y));
}
similarly goes with Polygon and line shapes
polygonPoint.push_back(Point(x,y));
linePoint.Push_back(point(x,y));
then these lists are pushed in gnuPoint(list< list< Point> >).
gnuPoints.push_back(circlePoints);
gnuPoints.push_back(polygonPoints);
gnuPoints.push_back(linePoints);
now i want to write all these x,y values of different shapes in a file,
To iterate over it i cant find any particular solution after this code.
for (list<list<Point>>::iterator it = Point::gnuPoints.begin();
it != Point::gnuPoints.end();
it++)
{
//My assumption is that another For loop would come but could not apply
as I don't know what is available at the first index of gnuPoints list.
}
for (list<list<Point>>::iterator it = Point::gnuPoints.begin();
it != Point::gnuPoints.end();
it++)
{
for (list<Point>::iterator innerIt = it->begin(); innerIt != it->end(); ++innerIt)
}
If you are already on a compiler that supports c++11, this could be simply written as:
for (const auto& container : Point::gnuPoints)
{
for (const auto& item : container)
{
}
}

Logic for creating graph c++

I am working on a project where I am given a list of edges with a weight of either A or B. I need eventually determine if it is possible to create a spanning tree with 'x' number of A edges.
Right now I am trying to make a list of all the edges that are used in creating the minimally spanning tree and am doing that by making a list of the vertices that I have used. If two of the vertices have been used then that edges is discarded. The problem I am having is that once I get to the end my graph, I am often left with two halves of graphs that are not connected because the edge that would connect the two halves have already been used. Any thoughts on how I can fix this problem, or is the overall approach wrong?
struct Edge{
int start;
int end;
char letter;
bool used;
};
void PrimWhite(...)
{
vector<int> usedVertices;
int count,maxNum,begin,end;
int totalVertexs = 0;
maxNum = whiteEdge.size();
Edge temp;
Edge *point = &temp;
Edge *usedorNah;
for (count = 0;count < maxNum; count++)
{
temp = whiteEdge[count];
usedorNah = &whiteEdge[count];
begin = point->start;
end = point->end;
if ( (find(usedVertices.begin(), usedVertices.end(), begin) == usedVertices.end()) && (find(usedVertices.begin(), usedVertices.end(), end) == usedVertices.end()))
{
usedVertices.push_back(begin);
usedVertices.push_back(end);
totalVertexs = totalVertexs + 2;
usedorNah->used = true;
}
else if ((find(usedVertices.begin(), usedVertices.end(), begin) == usedVertices.end()) && (find(usedVertices.begin(), usedVertices.end(), end) != usedVertices.end()))
{
usedVertices.push_back(begin);
totalVertexs++;
usedorNah->used = true;
}
else if ((find(usedVertices.begin(), usedVertices.end(), begin) != usedVertices.end()) && (find(usedVertices.begin(), usedVertices.end(), end) == usedVertices.end()) )
{
usedVertices.push_back(end);
totalVertexs++;
usedorNah->used = true;
}
Just use the criterion that Kruskal's algorithm uses: Add an edge to the graph if it does not form a loop. To check this, you have to check if the two incident nodes are connected to the same connected component. This can be done efficiently with the Union-Find data structure. I.e. whenever you add an edge, unite the components of both vertices. Before adding an edge, check if the two components are the same.

CGAL Polyhedron_3 flip_edge function breaks surface

I am using a Polyhedron_3 as a surface. I distort the surface and to ensure quality I want to flip edges to avoid bad triangles.
So far my code looks like :
std::vector<std::pair<PlaneMeshAPI::Polyhedron::Halfedge_handle, double> > vEdgeToFlip;
for (PlaneMeshAPI::Polyhedron::Edge_iterator e = P.edges_begin(); e != P.edges_end(); ++e)
{
// Edge_iterator so that we consider only one of the 2 possible halfedges
bool bFlippable = true;
if (e->is_border_edge()) bFlippable = false;
if (bFlippable && e->facet()->marked() == -1) bFlippable = false;
if (bFlippable && e->facet()->marked() != e->opposite()->facet()->marked()) bFlippable = false;
// Marked() returns an int, I want to flip edges between two triangles of the same component
if (bFlippable)
{
PlaneMeshAPI::Polyhedron::Facet_iterator f1, f2;
PlaneMeshAPI::Polyhedron::Halfedge_handle heh = e;
double lowestBef = lowestAngle(e->facet(), e->opposite()->facet()); // returns the lowest angle of the two adjacent triangles
vEdgeToFlip.push_back(std::make_pair(e, lowestBef));
}
}
for (int i = 0; i < vEdgeToFlip.size(); ++i)
{
PlaneMeshAPI::Polyhedron::Halfedge_handle e = vEdgeToFlip[i].first;
e = P.flip_edge(e);
double lowestNow = lowestAngle(e->facet(), e->opposite()->facet());
if (lowestNow < vEdgeToFlip[i].second)
P.flip_edge(e);
}
The code is running fine but when I run P.is_valid(true) I have this error message:
halfedge 7504
previous pointer integrity corrupted.
summe border halfedges (2*nb) = 0
end of CGAL::HalfedgeDS_const_decorator<HDS>::is_valid(): structure is NOT VALID
.
counting halfedges failed.
end of CGAL::Polyhedron_3<...>::is_valid(): structure is NOT VALID.
The documentation on flip_edgeis quite scarce. I don't know if I need to flip both halfedges, if it breaks something in the iterator (so that once I flipped one, all the others can't be flipped).
We finally found why the edge flips caused the surface to break. Before you flip the facet e = P.flip_edge(e);, you have to make sure it doesn't create a singularity :
// Do not flip if this would create two triangle with the same vertices
if (e->next()->opposite()->next()->opposite() == e->opposite()->next()->next()) continue;
if (e->opposite()->next()->opposite()->next()->opposite() == e->next()->next()) continue;
// Do not flip if it would create an edge linking a vertex with itself
if (e->next()->vertex() == e->opposite()->next()->vertex()) continue;

C++ Mark for contiguous sections in a 3D array of objects

If we have a 3x3x3 array of objects, which contain two members: a boolean, and an integer; can anyone suggest an efficient way of marking this array in to contiguous chunks, based on the boolean value.
For example, if we picture it as a Rubix cube, and a middle slice was missing (everything on 1,x,x == false), could we mark the two outer slices as separate groups, by way of a unique group identifier on the int member.
The same needs to apply if the "slice" goes through 90 degrees, leaving an L shape and a strip.
Could it be done with very large 3D arrays using recursion? Could it be threaded.
I've hit the ground typing a few times so far but have ended up in a few dead ends and stack overflows.
Very grateful for any help, thanks.
It could be done that way:
struct A {int m_i; bool m_b;};
enum {ELimit = 3};
int neighbour_offsets_positive[3] = {1, ELimit, ELimit*ELimit};
A cube[ELimit][ELimit][ELimit];
A * first = &cube[0][0][0];
A * last = &cube[ELimit-1][ELimit-1][ELimit-1];
// Init 'cube'.
for(A * it = first; it <= last; ++it)
it->m_i = 0, it->m_b = true;
// Slice.
for(int i = 0; i != ELimit; ++i)
for(int j = 0; j != ELimit; ++j)
cube[1][i][j].m_b = false;
// Assign unique ids to coherent parts.
int id = 0;
for(A * it = first; it <= last; ++it)
{
if (it->m_b == false)
continue;
if (it->m_i == 0)
it->m_i = ++id;
for (int k = 0; k != 3; ++k)
{
A * neighbour = it + neighbour_offsets_positive[k];
if (neighbour <= last)
if (neighbour->m_b == true)
neighbour->m_i = it->m_i;
}
}
If I understand the term "contiguous chunk" correctly, i.e the maximal set of all those array elements for which there is a path from each vertex to all other vertices and they all share the same boolean value, then this is a problem of finding connected components in a graph which can be done with a simple DFS. Imagine that each array element is a vertex, and two vertices are connected if and only if 1) they share the same boolean value 2) they differ only by one coordinate and that difference is 1 by absolute value (i.e. they are adjacent)