Convexity of a polygon C++? [duplicate] - c++

This question already has answers here:
How do I efficiently determine if a polygon is convex, non-convex or complex?
(10 answers)
How to check if polygon is convex? [duplicate]
(1 answer)
Closed 9 years ago.
How can i test if a polygon is convex or not only by knowing the points of the polygon
with their coordonates in c++?

For each side of polygon, calculate line equation (Ax+By+C=0) and check (put x and y into equation and get sign of it), that all points are from one side of it.
EDIT:
If travel convex polygon, you will always rotate into one direction (left or right) on every point.
Using cross product, you can simply deduce, onto which side (negative or positive) you will rotate next turn. If all cross products of three consecutive points will have equal sign, then your polygon is convex.

Find the convex hull using any of the common algorithms. A polygon is convex if and only if all its vertices belong to its convex hull.
This is O(n log n) but does not rely on the assumption that the points are given in the proper order around the edges of the polygon. If the assumption is true then the answer from hate-engine is optimal (i.e. linear time.)

the gift wrapping algorithm is an algorithm for computing the convex
hull of a given set of points.
Pseudocode from wiki:
jarvis(S)
pointOnHull = leftmost point in S
i = 0
repeat
P[i] = pointOnHull
endpoint = S[0] // initial endpoint for a candidate edge on the hull
for j from 1 to |S|-1
if (endpoint == pointOnHull) or
(S[j] is on left of line from P[i] to endpoint)
endpoint = S[j] // found greater left turn, update endpoint
i = i+1
pointOnHull = endpoint
until endpoint == P[0] // wrapped around to first hull point
If your points match detected points of above algorithm then the polygon is convex.

Related

Determine if point is in frustum

I'm trying to work out the best way to determine whether a point is inside a frustum. I have something working, but not sure whether it is too cumbersome, and perhaps there is a more elegant / efficient way I should be doing this.
Suppose I want to find out whether point 'x' is inside a frustrum:
Once I have the locations of the 8 points of the frustrum (4 near points, four far points), I am calculating the normal for each plane of the frustum based on a triangle made from three of the points. For example (as in the diagram above), for the right side, I am making two vectors from three of the points:
Vector U = FBR - NBR
Vector V = FTR - NBR
Then I am making the cross product between these two vectors, ensuring that the winding order is correct for the normal to be pointing inside the frustum, in this case V x U will give the correct normal.
Right_normal = V x U
Once I have the normal for each plane, I am then checking whether point x is in front of or behind the plane by drawing a vector from x to one of the plane's points:
Vector xNBR = x - NBR
Then I am doing the dot product between this vector and the normal and testing whether the answer is positive, confirming whether point x is the correct side of that plane of the frustrum:
if ( xNBR . Right_normal < 0 )
{
return false;
}
else continue testing x against other planes...
If x is positive for all planes, then it is inside the frustum.
So this seems to work, but I'm just wondering whether I'm doing this in a stupid way. I didn't even know what 'cross product' meant until yesterday, so it's all rather new to me and I might be doing something rather silly.
To adapt the approach you have taken, rather than change it totally, you can make use of the fact that 2 of the pairs of planes are parallel. Create only one normal for that pair of planes. You already have the test for the point being "in front" of one of the planes, but assuming you know the depth of the frustum, you can use the same distance to test the point against the other parallel face.
double distancePastFrontPlane = xNBR . Right_normal;
if (distancePastFrontPlane < 0 )
{
// point is in front of front plane
return false;
if(distancePastFrontPlane > depthFaceRtoFaceL)
{
// point is behind back plane
return false;
}
}
If you have multiple points to test against the same frustum you can benefit because you only calculate the frustum depth once (per pair of parallel planes).

CGAL Intersection Circle and Vertical Lines (not segments)

In CGAL I need to compute the exact intersection points between a set of lines and a set o circles. Starting from the circles (which can have irrational radius but rational squared_radius) I should compute the vertical line passing through the x_extremal_points of each circle (not segment but lines) and calculate the intersection point of each circle with each line.
I’m using CircularKernel and Circle_2 for the circles and Line_2 for the lines.
Here’s an example of how I compute the circles and the lines and how I check if they intersect.
int main()
{
Point_2 a = Point_2(250.5, 98.5);
Point_2 b = Point_2(156, 139);
//Radius is half distance ab
Circular_k::FT aRad = CGAL::squared_distance(a, b);
Circle_2 circle_a = Circle_2(a, aRad/4);
Circular_arc_point_2 a_left_point = CGAL::x_extremal_point(circle_a, false);
Circular_arc_point_2 a_right_point = CGAL::x_extremal_point(circle_a, true);
//for example use only left extremal point of circle a
CGAL::Bbox_2 a_left_point_bb = a_left_point.bbox();
Line_2 a_left_line = Line_2(Point_2(a_left_point_bb.xmin(), a_left_point_bb.ymin()),
Point_2(a_left_point_bb.xmin(), a_left_point_bb.ymax()));
if ( do_intersect(a_left_line, circle_a) ) {
std::cout << "intersect";
}
else {
std::cout << " do not intersect ";
}
return 0;
}
This flow rises this exception:
CGAL error: precondition violation!
Expression : y != 0
File : c:\dev\cgal-4.7\include\cgal\gmp\gmpq_type.h
Line : 371
Explanation:
Refer to the bug-reporting instructions at http://www.cgal.org/bug_report.html
I can’t figure out how I can calculate the intersection points.
Also, Is there a better way to compute the lines? I know abot the x_extremal_point function but it returns the Circular_arc_point point and I’m not able to construct a vertical line passing through them directly without using Bounding box.
In your code, you seem to compute the intersection of a circle with the vertical line that passes through the extremal point of the circle (I forget the bounding box). Well, then the (double) intersection is the extremal point itself...
More globally, you say in your text of introduction that you want to compute exact intersections. Then you should certainly not use bounding boxes, which by definition introduce some approximation.
If I understand your text correctly,
* for testing the intersection of your vertical lines with the other circles, you don't need to construct the lines, you only need to compare the abscissae of the extremal points of two circles, which you can do with the CGAL circular kernel.
* for computing the intersection of a vertical line that has non-rational coefficients (since its equation is of the form x= +-sqrt(r)) with another circle, then the CGAL circular kernel will not give you a pre-cooked solution. That kernel will help, but you must still compute a few things by hand.
If you don't want to bother, then you can also just take a standard CGAL kernel with Core::Expr as underlying number type. It can do "anything", but it will be slower.
For efficiency, you should look at the underlying 1D problem: projecting the lines and the circle on the X axis, you have a set of points and a set of intervals [Xc-R, Xc+R].
If the L points are sorted increasingly, you can locate the left bound of an interval in time Lg(L) by dichotomy, and scan the list of points until the right bound. This results in a O(Lg(L).C + I) behavior (C circle intervals), where I is the number of intersections reported.
I guess that with a merge-like process using an active list, if the interval bounds are also sorted you can lower to O(L + C + I).
The extension to 2D is elementary.

Detect extreme points of a convex polygon

How can i get the extreme points of a convex polygon looking from a determined point? I'm trying to make this by points angle, the smaller and bigger angles is the extreme points, but when observer is closer to points, this is not valid.
This is my code:
Vec2* bigger = &points[0]; // pointer to point with bigger angle
Vec2* smaller = &points[0]; // pointer to point with smaller angle
Vec2 observer = rayCenter;
// iterate through all points of polygon
for(unsigned u = 0 ; u < points.size() ; u++)
{
Vec2 distance = observer - points[u];
if(distance.angle() < (observer - *smaller).angle())
smaller = &points[u];
if(distance.angle() > (observer - *bigger).angle())
bigger = &points[u];
}
The result:
Where blue lines is the excluded points and yellow desirable points.
Is there a best way to resolve this?
Sorry for my english.
Polygon vertex A is extreme for the given location of the observer, iff all other points of the polygon lie on the same side of the observer-to-A line (or, possibly, lie on that line).
If the polygon is known to be convex, then the criterion is greatly simplified. There's no need to analyze all other points of the polygon. The extreme point can be easily recognized by analyzing the locations of its two immediate neighbors.
If A is our candidate point and P and N are its adjacent points in the polygon (previous and next), then A is an extreme point iff both P and N lie on the same side of observer-to-A line.
vec_of_A = A - observer; // observer-to-A vector
vec_of_P = P - observer;
vec_of_N = N - observer;
productP = vec_of_A.x * vec_of_P.y - vec_of_A.y * vec_of_P.x;
productN = vec_of_A.x * vec_of_N.y - vec_of_A.y * vec_of_N.x;
if (sign(productP) == sign(productN))
// A is an extreme point
else
// A is not an extreme point
Some extra decision making will be necessary if P and/or N lie exactly on the observer-to-A line (depends on what point you consider extreme in such cases).
Compute a new convex hull using the points from the existing convex hull plus the observer point. In the new convex hull, the points that are adjacent to the observer point are your "extreme" points.
Here is a matlab implementation. Below is a sample output where the blue point is the observer point and the green polygon is the convex hull of the red points. The implementation returns the points (0,0) and (2,0).
You shouldn't compare angles directly as there is a 360° wraparound.
Prefer to test "this point is more to the left" or "to the right" by computing the signed area of the triangle formed by the observer and two points.

How does the algorithm of merging two convex hulls by using their tangents work in practice?

I'm trying to implement in C++ the divide and conquer algorithm of finding the convex hull from a set of two dimensional points. For simplicity let's assume that all the points are described with integers.
The most important part of the algorithm is merging the two convex hulls that you have computed from previous recursive calls. This part involves finding the lower and upper tangents of the two convex hulls and then proceeding with the merging.
The merging is trivial, if you have found the four points that describe the tangents, then the points that aren't inside the polygon defined by these four points will be part of the new convex hull.
However, I have no idea how to find these four points.
Here is the pseudocode that most sources (this one is from http://www.cs.wustl.edu/~pless/506/l3.html) suggest for finding the lower tangent of convex hull HA and convex hull HB.
Finding the Lower Tangent
LowerTangent(HA ; HB ) :
(1) Let a be the rightmost point of HA .
(2) Let b be the leftmost point of HB .
(3) While ab is not a lower tangent for HA and HB do
(a) While ab is not a lower tangent to HA do a = a - 1 (move a clockwise).
(b) While ab is not a lower tangent to HB do b = b + 1 (move b counterCW).
(4) Return ab.
(1), (2)
The points are initially sorted by their x coordinate, so finding the rightmost point of HA and the leftmost point of HB can be done in O(1).
a = HA[HA.size-1]
b = HB[0]
Now I can't understand the next steps.
Having chosen this ab line segment, how can we check if ab is not a lower tangent so we can either enter the first while loop or not?
And then, how do we move the point a to a-1 by following a clockwise direction? The points are sorted by their x coordinate, and doing just a = a-1 will lead to wrong results.
Thanks!
Your reference only briefly states:
Lower tangency is a condition that can be tested locally by an
orientation test of the two vertices and neighboring vertices on the
hull. (This is a simple exercise.)
and doesn't appear to give any more details. I found this reference which goes into further details of how to find the lower tangency including some example code.
Also note that your should not be sorting the X-coordinates for this purpose. This algorithm relies on the points being in their normal consecutive order that defines the polygon. Sorting by X only helps you in finding the initial points.
Pseudo-code of the lower tangency algorithm from that reference is:
idx1 = (Rightmost point index of Poly1)
idx2 = (Leftmost point index of Poly2)
while (TRUE)
while (isLeft(Poly1[idx2], Poly2[idx1], Poly2[idx1+1]) <= 0)
++idx1;
end while
while (isLeft(Poly2[idx1], Poly1[idx2], Poly1[idx2-1]) >= 0)
--idx2;
done = FALSE;
end while
end while
// idx1/idx2 are now the two indices that form the lower tangent
The isLeft() code from the same reference is:
float isLeft (Point P0, Point P1, Point P2)
{
return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y);
}
If the two convex polygons are intersecting then it is incorrect to assume that there are only two tangents that connect the two polygons.
It depends upon how exactly the points are divided. If division ensures that the resultant convex hulls never intersect then it is fine to make such assumption. But if the division of points does not guarantee the convex hulls to be non intersecting then algorithm needs to be modified to find multiple tangents.

CGAL: Output from neighbour when the triangle has none

So I am wondering what happens in CGAL Delaunay triangulation when you call the neighbor function for a neighbor that doesn't exist. In the documentation (HERE) it says this:
The neighbor with index i is the neighbor which is opposite to the vertex with index i.
Face_handle f.neighbor ( int i) const //returns the neighbor i of f.
//Precondition: 0 ≤ i ≤ 2.
But not all triangles can have 3 neighbors. Edge and corner triangles will neighbor only 2. Given that it must now return a Face_handle, what would happen for the neighbors that don't exist? Maybe it will be NULL? How can i check this?
The reason i am looking to do this is because i would like to identify all the edge triangles in a Delaunay triangulation. Being able to check for triangles with 2 or less neighbors would be very useful.
Any ideas?
See the documentation.
CGAL introduces an infinite vertex, hence each "border edge" has an additional neighbour, which is an infinite triangle composed of the two vertices of your edge and the infinite vertex.