If you’ve been struggling with the problem of determining whether a point lies inside or outside a polygon, perhaps in google maps, read on. This post is specific to Android and Node.js but the algorithm can easily be implemented in any other language/platform as the algorithm itself is a piece of cake once understood.
To further elaborate the problem, take a look at the diagram below:
Here we have an irregular polygon (yellow region) and points a, b, c and d. We have to programmatically determine whether these points lie inside the polygon or outside. At first glance this might sound trivial, and yes it is, but the solution provided in Google Maps api is not good enough for most of the cases.
Solution provided in Google Maps api
Google Maps api considers a super-rectangle that contains all the bounding points of the given polygon and then determines if the point lies inside this rectangle or not. This would work great if the polygon is close to a rectangle or square in shape but not for anything else (definitely not for our Yellow polygon above). Although their method is not as simple as it sounds. It considers the earth’s curvature and the fact that earth is a skewed sphere. Great! But the precision that’s lost during patching a super-rectangle over our innocent irregular polygon would leave you in tears. Diagram below shows the super-rectangle in gray.
Now you do see the problem, right? Point ‘b’ and ‘c’ will be considered inside the polygon while they are not.
Ray Casting Algorithm
It’s a concept in computational geometry that let’s you determine if a point lies inside a bounded region by casting infinitely long ray from the given point to see how many edges of the given polygon this ray intersects. If the number of intersections is 0 or an even number, the point lies outside the polygon otherwise inside.
Following illustration shows how Ray casting solves the problem we discussed above.
It shows that rays from point ‘b’ and ‘c’ are having 0 or even number of intersections, no matter in which direction you draw a line starting from it, concluding that they lie outside the polygon.
My Implementations of RayCast
In the above github repository, RaycastHelper.java contains the implementation of RayCast Algorithm. You have to provide LatLngs or points as vertices of the polygon in correct clockwise or anticlockwise sequence. The solution also assumes that the LatLngs or points you provide form a closed polygon. It exposes following 2 static methods:
boolean isLatLngInside(ArrayList latLngs, LatLng latLng)
This method is optimised for geo-locations. Ray-casting algorithm works for a linear surface and earth is spherical. So, before going for ray-casting, this method normalises the provided latlngs for a 2-D plain by settling the irregularity in longitudes near International Date Line (… -178, -179, 179, 178 …).
boolean isPointInside(ArrayList points, Point point)
This can be used for any X-Y plane. Point is class provided in the above repo to represent a point in an x-y plane.
npm install raycast
This npm package provides the same two methods described in the Android section above. The package also provides two helper classes LatLng and Point to deal with the corresponding methods.
In Depth Explanation. TL;DR
The logical line of thought behind the algorithm is that if I draw a ray (infinitely long line) from a point it would either never enter a given polygon or will finally exit it at some point of time. If the point is outside the polygon, a ray from it will either “never enter” OR “will have one or more enter-exit pairs.” Ray from a point inside the polygon will also finally exit and as it starts from within the polygon in the first place, it will have an extra exit count.
In other words, take the number of intersections and consider that the last intersection (if any) is always for an EXIT. If you draw the ENTER-EXIT sequence backwards, for an odd count the first in the sequence will always be an EXIT, proving that it’s a case of point lying inside the polygon. And for an even count the first in the sequence will always be an ENTER, proving that it’s a case of point being outside the polygon.
In the illustration we discussed above, following are the ENTER-EXIT sequences for the 4 points
intersections count: 1
Sequence: — EXIT —
conclusion: Point A is inside the polygon
intersections count: 0
conclusion: Point B is out the polygon
intersections count: 2
Sequence: — ENTER — EXIT —
conclusion: Point C is outside the polygon
intersections count: 3
Sequence: — EXIT — ENTER — EXIT —
conclusion: Point D is inside the polygon
If you find this algorithm useful and interesting, it goes very well with another computational geometry concept called Voronoi. You might want to take a look at my blogpost on Voronoi and this npm package.