How do I determine if two convex polygons intersect? - geometry

Suppose there are a number of convex polygons on a plane, perhaps a map. These polygons can bump up against each other and share an edge, but cannot overlap.
To test if two polygons P and Q overlap, first I can test each edge in P to see if it intersects with any of the edges in Q. If an intersection is found, I declare that P and Q intersect. If none intersect, I then have to test for the case that P is completely contained by Q, and vice versa. Next, there's the case that P==Q. Finally, there's the case that share a few edges, but not all of them. (These last two cases can probably be thought of as the same general case, but that might not be important.)
I have an algorithm that detects where two line segments intersect. If the two segments are co-linear, they are not considered to intersect for my purposes.
Have I properly enumerated the cases? Any suggestions for testing for these cases?
Note that I'm not looking to find the new convex polygon that is the intersection, I just want to know if an intersection exists. There are many well documented algorithms for finding the intersection, but I don't need to go through all the effort.

You could use this collision algorithm:
To be able to decide whether two convex polygons are intersecting (touching each other) we can use the Separating Axis Theorem. Essentially:
If two convex polygons are not intersecting, there exists a line that passes between them.
Such a line only exists if one of the sides of one of the polygons forms such a line.
The first statement is easy. Since the polygons are both convex, you'll be able to draw a line with one polygon on one side and the other polygon on the other side unless they are intersecting. The second is slightly less intuitive. Look at figure 1. Unless the closest sided of the polygons are parallel to each other, the point where they get closest to each other is the point where a corner of one polygon gets closest to a side of the other polygon. This side will then form a separating axis between the polygons. If the sides are parallel, they both are separating axes.
So how does this concretely help us decide whether polygon A and B intersect? Well, we just go over each side of each polygon and check whether it forms a separating axis. To do this we'll be using some basic vector math to squash all the points of both polygons onto a line that is perpendicular to the potential separating line (see figure 2). Now the whole problem is conveniently 1-dimensional. We can determine a region in which the points for each polygon lie, and this line is a separating axis if these regions do not overlap.
If, after checking each line from both polygons, no separating axis was found, it has been proven that the polygons intersect and something has to be done about it.

There are several ways to detect intersection and / or containment between convex polygons. It all depends on how efficient you want the algorithm to be. Consider two convex polygons R and B with r and b vertices, respectively:
Sweep line based algorithm. As you mentioned you can perform a sweep line procedure and keep the intervals resulting from the intersection of the polygons with the sweeping line. If at any time the intervals overlap, then the polygons intersect. The complexity is O((r + b) log (r + b)) time.
Rotating Callipers based algorithm. See here and here for more details. The complexity is O(r + b) time.
The most efficient methods can be found here and here. These algorithms take O(log r + log b) time.

if the polygons are always convex, first calculate the angle of a line drawn from center to center of the polygons. you can then eliminate needing to test edge segments in the half of the polygon(s) 180 degrees away from the other polygon(s).
to eliminate the edges, Start with the polygon on the left. take the line segment from the center of the polygon that is perpendicular to the line segment from the previous bullet, and touches both sides of the polygon. call this line segment p, with vertexes p1 and p2. Then, for all vertexes if the x coordinate is less than p1.x and p2.x That vertex can go in the "safe bucket".
if it doesn't, you have to check to make sure it is on the "safe" side of the line (just check the y coordinates too)
-if a line segment in the polygon has all vertexes in the "safe bucket" you can ignore it.
-reverse the polarity so you are "right oriented" for the second polygon.

GJK collision detection should work.

Since altCognito already gave you a solution, I'll only point out an excellent book on computational geometry that might interest you.

Your test cases should work, since you're checking the case where the polygons don't intersect at all (completely outside or completely inside), as well as where there is any form of partial intersection (edges intersect always if there is overlap).
For testing, I would just make sure to test every potential combination. The one missing above from what I see is a single edge shared, but one poly contained in the other. I would also add tests for some more complex poly shapes, from tri -> many sided, just as a precaution.
Also, if you had a U shaped poly that completely surrounded the poly, but didn't overlap, I believe your case would handle that, but I would add that as a check, as well.

Here's an idea:
Find the center point of each polygon
Find the two points of each polygon closest to the center point of the other. They will be adjacent points in convex polygons. These define the nearest edge of each polygon, let's call the points {A, B} and {Y, Z}
Find the intersection of lines AB and YZ. If the line segments cross (the intersection on AB lies between A and B), your polygons intersect. If AB and XY are parallel ignore this condition, the next step will trap the problem.
There is one more case you need to check for, which is when the polygons intersect heavily enough that AB and XY are completely past each other and don't actually intersect.
To trap this case, calculate the perpendicular distances of AB and XY to each polygons center points. If either center point is closer to the opposite polygon's line segment your polygon overlap heavily.

Related

What's the translation that brings one 2D polygon completely inside another?

Given two 2D polygons, how do I calculate the shortest translation that brings the first inside the second?
Assume there is a solution (i.e. the first does in fact fit inside the second)
Prefer a simple algorithm over completeness of solution. For example if the algorithm is simplified by making assumptions about the shapes having a certain number of sides, being concave, etc. then make those assumptions.
I can imagine a brute force solution, where I first calculate which are the offending vertices that lie outside the initial polygon. I'd then iterate through these external vertices and find the closest edge to each. Then I'm stuck. Each distance from an external vertex to an edge creates a constraint (a "need to move"). I then need to solve this system of constraints to find the movement that fulfills them all without creating any new violations.
I'm not sure if this can be a general solution, but here is at least a point to start with:
We want to move the green polygon into the red polygon. We use several translations. Each translation is defined by a start point and an end point.
Step 1: Start point is the mid-point between the left-most vertex and the right-most vertex in green polygon. End point, same criterion with the red polygon:
Step 2: Start point is the mid-point between the top-most vertex and the low-most vertex. End point, same criterion with the red polygon:
Notice that setps 1 & 2 are kind of centering. This method with mid points is similar to use the bounding boxes. Other way would be using circumcircles, but they are hard to get.
Step 3: Find the vertex in red polygon closest to an edge in the green polygon. You will need to iterate over all of them. Find the line perpendicular to that edge:
Well, this is not perfect. Depending on the given polygons it's better to proceed the other way: closest vertex in green to edges in red. Choose the smallest distance.
Finally, move the green polygon along that line:
If this method doesn't work (I'm sure there are cases where it fails), then you can also move the inner polygon along a line (a red edge or a perpendicular) that solves the issue. And continue moving until no issues are found.

How to test if a line intersects a convex polygon?

Assume you are given the equation of a line (in 2d), and the equations of lines that form a convex polygon (the polygon could be unbounded). How do I determine if the line intersects the polygon?
Furthermore, are there computational geometry libraries where such tasks are pre-defined? I ask because I'm interested not just in the 2D version but n-dimensional geometry.
For the 2D case, I think the problem simplifies a bit.
The line partitions the space into two regions.
If the polygon is present in only one of those regions, then the line does not intersect it.
If the polygon is present in both regions, then the line does intersect it.
So:
Take any perpendicular to the line, making the intersection with the
line the origin.
Project each vertex of the polytope onto the perpendicular.
If those projections occur with both signs, then the polygon
intersects the line.
[Update following elexhobby's comment.]
Forgot to include the handling of the unbounded case.
I meant to add that one could create a "virtual vertex" to represent the open area. What we really need is the "direction" of the open area. We can take this as the mean of the vectors for the bounding edges of the open area.
We then treat the dot product of that direction with the normal and add that to the set of vertex projections.
In geometry, typically see wikipedia a polygon is bounded.
What you are describing is usually called a polytope or a polyhedron see wikipedia
There are a few geometry libraries available, two that come to mind are boost (polygon) and CGAL. Generally, there is a distinct split between computational methods that deal with 2d,3d, and N-d - for obvious reasons.
For your problem, I would use a somewhat Binary Space Partitioning Tree approach. I would take the first line of your "poly" and trim the query line against it, creating a ray. The ray would start at the intersection of the two lines, and proceed in direction of the interior of the half-space generated by the first line of the "poly". Now I would repeat the procedure with the ray and the second line of the "poly". (this could generate a segment instead of ray) If at some point the ray (or now segment) origin lies on the outer side of a poly line currently considered and does not intersect it, then the answer is no - the line does not intersect your "poly". Otherwise it intersects. Take special care with various parallel edge cases. Fairly straight forward and works for multi-dimensional cases.
I am not fully sure, but I guess you can address this by use of duality. First normalize your line equations as a.x+b.y=1, and consider the set of points (a,b).
These must form a convex polygon, and my guess is that the new line may not correspond to a point inside the polygon. This is readily checked by verifying that the new point is on the same side of all the edges. (If you don't know the order of the lines, first construct the convex hull.)
Let's start from finite polygons.
To intersect polygon a line must intersect one of its edges. Intersection between line and an edge is possible only if two points lie on different sides from the line.
That can be easily checked with sign(cross_product(Ep-Lp,Ld)) for two points of the edge. Ep - edge point, Lp - some point on the line, Ld - direction vector of the line, cross_product(A,B)=Ax*By-Ay*Bx.
To deal with infinite polygons we may introduce "infinite points". If we have a half infinite edge with point E1 and direction Ed, its "second point" is something like E1+infinity*Ed, where infinity is "big enough number".
For "infinite points" the check will be slightly different:
cross_product(Ep-Lp,Ld)=
=cross_product(E1+infinity*Ed-Lp,Ld)=
=cross_product(E1-Lp+infinity*Ed,Ld)=
=cross_product(E1-Lp,Ld)+cross_product(infinity*Ed,Ld)=
=cross_product(E1-Lp,Ld)+infinity*cross_product(Ed,Ld)
If cross_product(Ed,Ld) is zero (the line is parallel to the edge), the sign will be determined by the first component. Otherwise the second component will dominate and determine the sign.

How to determine whether an edge of a nonzero-fill polygon is an outside edge?

Let's assume I have a polygon and I have computed all of its self-intersections. How do I determine whether a specific edge is inside or outside according to the nonzero fill rule? By "outside edge" I mean an edge which lies between a filled region and a non-filled region.
Example:
On the left is an example polygon, filled according to the nonzero fill rule. On the right is the same polygon with its outside edges highlighted in red. I'm looking for an algorithm that, given the edges of the polygon and their intersections with each other, can mark each of the edges as either outside or inside.
Preferably, the solution should generalize to paths that are composed of e.g. Bezier curves.
[EDIT] two more examples to consider:
I've noticed that the "outside edge" that is enclosed within the shape must cross an even number of intersections before they get to the outside. The "non-outside edges" that are enclosed must cross an odd number of intersections.
You might try an algorithm like this
isOutside = true
edge = find first outside edge*
edge.IsOutside = isOutside
while (not got back to start) {
edge = next
if (gone over intersection)
isOutside = !isOutside
edge.IsOutside = isOutside
}
For example:
*I think that you can always find an outside edge by trying each line in turn: try extending it infinitely - if it does not cross another line then it should be on the outside. This seems intuitively true but I wonder if there are some pathological cases where you cannot find a start line using this rule. Using this method of finding the first line will not work with curves.
I think, you problem can be solved in two steps.
A triangulation of a source polygon with algorithm that supports self-intersecting polygons. Good start is Seidel algorithm. The section 5.2 of the linked PDF document describes self-intersecting polygons.
A merge triangles into the single polygon with algorithm that supports holes, i.e. Weiler-Atherton algorithm. This algorithm can be used for both the clipping and the merging, so you need it's "merging" case. Maybe you can simplify the algorithm, cause triangles form first step are not intersecting.
I realized this can be determined in a fairly simple way, using a slight modification of the standard routine that computes the winding number. It is conceptually similar to evaluating the winding both immediately to the left and immediately to the right of the target edge. Here is the algorithm for arbitrary curves, not just line segments:
Pick a point on the target segment. Ensure the Y derivative at that point is nonzero.
Subdivide the target segment at the Y roots of its derivative. In the next point, ignore the portion of the segment that contains the point you picked in step 1.
Determine the winding number at the point picked in 1. This can be done by casting a ray in the +X direction and seeing what intersects it, and in what direction. Intersections at points where Y component of derivative is positive are counted as +1. While doing this, ignore the Y-monotonic portion that contains the point you picked in step 1.
If the winding number is 0, we are done - this is definitely an outside edge. If it is nonzero and different than -1, 0 or 1, we are done - this is definitely an inside edge.
Inspect the derivative at the point picked in step 1. If intersection of the ray with that point would be counted as -1 and the winding number obtained in step 3 is +1, this is an outside edge; similarly for +1/-1 case. Otherwise this is an inside edge.
In essence, we are checking whether intersection of the ray with the target segment changes the winding number between zero and non-zero.
I'd suggest what I feel is a simpler implementation of your solution that has worked for me:
1. Pick ANY point on the target segment. (I arbitrarily pick the midpoint.)
2. Construct a ray from that point normal to the segment. (I use a left normal ray for a CW polygon and a right normal ray for a CCW polygon.)
3. Count the intersections of the ray with the polygon, ignoring the target segment itself. Here you can chose a NonZero winding rule [decrement for polygon segments crossing to the left (CCW) and increment for a crossing to the right (CW); where an inside edge yields a zero count] or an EvenOdd rule [count all crossings where an inside edge yields an odd count]. For line segments, crossing direction is determined with a simple left-or-right test for its start and end points. For arcs and curves it can be done with tangents at the intersection, an exercise for the reader.
My purpose for this analysis is to divide a self-intersecting polygon into an equivalent set of not self-intersecting polygons. To that end, it's useful to likewise analyze the ray in the opposite direction and sense if the original polygon would be filled there or not. This results in an inside/outside determination for BOTH sides of the segment, yielding four possible states. I suspect an OUTSIDE-OUTSIDE state might be valid only for a non-closed polygon, but for this analysis it might be desirable to temporarily close it. Segments with the same state can be collected into non-intersecting polygons by tracing their shared intersections. In some cases, such as with a pure fill, you might even decide to eliminate INSIDE-INSIDE polygons as redundant since they fill an already-filled space.
And thanks for your original solution!!

polygon vertices - clockwise or counterclockwise

I came across this link http://www.mathopenref.com/coordpolygonarea2.html
It explains how to calculate the area of a polygon and helps to identify whether the polygon vertices we entered is clockwise or counter clockwise.
If area value is +ve, it is clockwise, if it is -nv then it is in counterclockwise.
My requirement is to identify only whether it is clockwise or counterclockwise. Is this rule will work correctly (though there are limitations as mentioned in the link). I have only regular polygons (not complicated, no self intersections) but the vertices are more.
I am not interested in the area value accuracy, just to know the ring rotation.
Any other thought on this.
For convex polygons:
Select two edges with a common vertex.
Lets say, edge1 is between vertex A and B. Edge2 is between vertex B and C.
Define to vectors: vect1: A----->B
vect2: B----->C
Cross product vect1 and vect2.
If the result is positive, the sequence A-->B-->C is Counter-clockwise.
If the result is negative, the sequence A-->B-->C is clockwise.
If you have only convex polygons (and all regular polygons are convex), and if your points are all organized consistently--either all counterclockwise or all clockwise--then you can determine which by just computing the (signed) area of one triangle determined by any three consecutive points. This is essentially computing the cross product of the two vectors along the two edges.

How to determine a diagonal is in or out of a concave polygon?

The diagonal (a diagonal is a segment connecting nonadjacent vertices) of a concave (non-convex) polygon can be completely in or out of the polygon(or can intersect with the edges of polygon). How to determine whether it is completely in the polygon?(a method without point-in-polygon test).
If the diagonal has at least one intersection with the edges, it is partially in and partially out of the polygon, however, If the diagonal has no intersection with them, there are only two states: it is compeletely in or completely out of the polygon.
To determine whether it is in or out of the polygon:
Suppose polygon's vertices are sorted counterclockwise. Consider one of the endpoints of the diagonal which lies on the vertex named P[i] (the other endpoint is p[j]). Then, Make three vectors whose first points are p[i] :
V1 : p[i+1] - p[i]
V2 : p[i-1] - p[i]
V3 : p[j] - p[i]
The diagonal is completely in the polygon if and only if V3 is between V1 and V2 when we move around counterclockwise from V1 to V2.
How to determine whether V3 is between V1 and V2 when we go from V1 to V2 counterclockwise? go to here.
I've written a program using this method and it works effectively .
How to determine whether it is completely in the polygon?
If you want to determine whether a diagonal never leaves the polygon's boundary, just determine whether or not it intersects any lines between two adjacent vertices.
If it does, it's partially in and partially out of the polygon.
If not, it's either completely in or completely out of the polygon. From there, the simplest method is to use the point-in-polygon on any point on the diagonal, but if you don't want to do that, use the winding algorithm.
I believe John's answer misses an important case: when the diagonal is completely outside the polygon from the get-go. Imagine making the diagonal "bridge" the two towers of his "u" shaped polygon.
I had to solve this several years ago, so please forgive if my recollection is a bit spotty.
The way I solved this was to perform line intersection tests of the diagonal against every edge in the polygon. You then have two possible cases: you either had at least one intersection, or you had no intersections. If you get any intersections, the diagonal is not inside the polygon.
If you don't get any intersections, you need to determine whether the diagonal is completely inside or completely outside the polygon. Let's say the diagonal is joining p[i] to p[j], that i < j and you have a polygon with clockwise winding. You can work out if the diagonal is outside the polygon by looking at the edge joining p[i] to p[i+1]. Work out the 2D angle of this edge (using, say, the x-axis as the baseline.) Rotate your diagonal so that the p[i]-p[i+1] edge is its baseline and compute its 2D angle.
Once you've done this, the 2D angle of the diagonal will be positive if the diagonal is outside the polygon, or negative if it's inside the polygon.
I understand this question was answered many years ago, but I have a new approach which is easy to implement.
As suggested in previous answers, you should first compute for all edges of the polygon if any of them intersect with the diagonal line segment. The code to compute intersection and determine if one even exists is described here.
If all edges (excluding those that share vertices with diagonal) do not have an intersection with diagonal then you know that the diagonal is either completely inside or completely outside of the polygon meaning that the midpoint of the diagonal is also completely inside or completely outside respectively. The midpoint is the average of the diagonal's two endpoints.
We now have transformed the problem to computing whether the diagonal is inside or outside the polygon to whether the midpoint is inside or outside the polygon. Working with a single point is easier than with a line.
The way to determine if a point is within a polygon is described here and can be summarized by counting the amount of intersection of horizontal ray starting at the point and seeing how many polygon edges this ray intersects. If the ray intersects an odd amount of times then the point is inside the polygon and otherwise outside the polygon.
The reason why this implementation is easy to implement is while you iterate through all the edges to check for intersection with diagonal you can now also count if the diagonal's midpoint's ray intersects with the current edge being processed. If your for loop returns with no intersection between diagonal and edges then you can see the even/odd count to determine if diagonal is inside or outside.
With regard to checking for intersections between line segments (which is the first step you would likely have to do), I found the explanations on SoftSurfer to be helpful. You would have to check for an intersection between the diagonal and any of the edges of the polygon. If you are using MATLAB, you should be able to find an efficient way to check intersections for all the edges simultaneously using matrix and vector operations (I've dealt with computing intersection points in this way for ray-triangle intersections).
John's answer is spot on:
If you want to determine whether a diagonal never leaves the polygon's boundary, just determine whether or not it intersects any lines between two adjacent vertices. If so, it's left the polygon.
A efficient way to do this check is to run the Bentley-Ottman sweepline algorithm on the data. It's easy to implement but hard to make numerical stable. If you have less than ... say ... 20 edges in your polygons a brute force search will most likely be faster.

Resources