The smart polygon or how to detect line segments intersection
geo polygon line segment intersection swift algorithm mercator Estimated reading time: 6 minutesAs mobile developers, we should always think not only about the correctness of the logic but also about usability (UX) and about different ways, that can reduce the number of errors when we receive user input (kind of Poka-yoke ポカヨケ).
In this post, I would like to describe the process of how we can improve the polygon selection for the area on the map (by removing polygon side interactions).
I already wrote about some techniques related to the map that was used on my current project (like this post about area coverage or this one about area calculation).
Current post can be used as an improvement for area coverage - the first step of the process described there.
The Problem
If the user defines the polygon on the map, then, it’s the user’s responsibility to correctly determine the polygon and every point of it. But, the standard way of creating a polygon - is just to combine all points one-by-one into some structure, without checking if the new point intersects the already created side of the polygon or no.
Such behavior works fine, if the user precise enough, but, in some cases, this can cause a problem - the polygon gets an unexpected shape.
As always - one image much better than thousend word:
The Solution
Note - nothing new in this article is discovered - I just want to summarise my experience in solving this problem.
As a solution we can restrict the selection of points for polygon, that, in combination with any of the existing points in the polygon, can create a line (polyline) intersection with our polygon. In other words - we should check all possible lines (combination of any 2 points) in polygon for a possible intersection.
This means, that we should:
- Determine all possible lines combination from polygon
- Check whenever any combination of 2 lines segments (from step1) can intersect
Obviously - not the most efficient method - complexity of this is about O(nˆ2). While our polygon not very big and complex, we can use it. In another case, we may want to improve the process.
Determine all possible lines combination from polygon
At the first look, this part is not very complicated - all that needs to be done is to iterate through all points and create all combinations of them (all possible segments). Thus for a line, we need 2 points, we should create 2 iterations.
This naive approach can look like a simple for-each loop where input is a points: [CLLocationCoordinate2D]
Then - just to check whenever 2 segments are intersected.
The result at first looks fine:
But, as soon, as user pick a bit tricky polygon, we can get this:
The problem here - is because we check all segments for the existing polygon within the new segment, except the last segment - between the new point and first point.
This means, that we should modify the loop, we should create 2 segments using a new point - for last and for the first point in the polygon point’s list and then check intersection with all segments present in the polygon.
Within the previous approach segment p1-p5 was not included in the check
The code could looks like this:
We check all segments for intersection and exclude points, that already a corners for polygon
Check if 2 lines segments intersect
Looking for a solution, I found a very interesting comment from Gavin. He mentions, that there is a book by Andre LeMothe’s “Tricks of the Windows Game Programming Gurus” with an algorithm, that solve this problem. The code that he puts there works fine, but I would like to know how it works before actually use.
Here is the code:
To simplify usage with map
How it works. In the mentioned above book, there is a very good explanation in chapter 13 “Intersection the Line segments”.
Here are a few images, that explain everything better than any words:
The difference between lines (infinite) and line segments (finite)
Intersecting and non-intersection segments
To solve the problem used parametric representation of each line segment: U
- the position vector of any point on line segment S1
and V
same on segment S2
:
By using Cramer’s rule the author solved this task. I won’t copy the whole steps, just the final result (used in a code sample above):
Exactly these formulas used in the code above.
Slightly improved code, adjusted for use with coordinates:
The result of such cheking is in the next demo:
left - after; right - before
Resources
- Andre LeMothe’s “Tricks of the Windows Game Programming Gurus”
- Collinearity
- Cramer’s rule
- Poka-yoke
- The Dot Product
- Dot product
- MKPolygon+GSPolygonIntersections
- SO UIBezierPath intersect
- SO - detecting intersection from sprite kit SKShapeNode drawings
- SO comment from Gavin
- Sylvester matrix
- SO - Detect self-intersection of a polygon with n sides?
- SO - How do you detect where two line segments intersect? [closed]
Share on: