This is an early draft of the full articlepublished in Graphics Gems IV, the citation is:
Haines, Eric, "Point in Polygon Strategies," Graphics Gems IV, ed. Paul Heckbert, Academic Press, p. 24-46, 1994.
(The full article is better, but I cannot find the final text on my machine.)The associated code for this articleis available online.
Testing whether a point is inside a polygon is a basic operation in computergraphics. Graphics Gems presents an algorithm for testing points againstconvex polygons (Badouel 1990). This Gem provides algorithms which are from1.6 to 9 or more times faster for convex polygons. It also presentsalgorithms for testing non-convex polygons and discusses the advantages anddrawbacks of each. Faster, more memory intensive algorithms are alsopresented, along with an O(log n) algorithm for convex polygons. Code isincluded for the algorithms discussed.
If the entire area enclosed by the polygon is to be considered inside, thenthe winding number is used for testing. This value is the number oftimes the polygon goes around the point. For example, a point in the centerpentagonal area formed by a star has a winding number of two, since theoutline goes around it twice. If the point is outside, the polygon does notwind around it and so the winding number is zero. Winding numbers also have asign, which corresponds to the direction the edges wrap around the point.
Complex polygons can be formed using either polygon definition. A complexpolygon is one that has separate outlines (which can overlap). For example,the letter "R" can be defined by two polygons, one consisting of the exterioroutline, the other the inside hole in the letter. Most point in polygonalgorithms can be easily extended to test multiple outline polygons by simplyrunning each polygon outline through separately and keeping track of the totalparity.
While the above method is simple and quick, another projection may be usefulwhen the polygon vertices are not guaranteed to lay on a single plane. Whilesuch polygons could be considered ill defined, they do crop up. For example,if a spline surface is tessellated into quadrilaterals instead of triangles,then the quadrilaterals are likely to be ill defined in this way. If acomponent is simply dropped, cracking can occur between such polygons whenthey are cast upon different planes.
One solution is to tessellate such polygons into triangles, but this may beimpractical for a variety of reasons. Another approach is to cast allpolygons tested onto a plane perpendicular to the testing ray's direction. Apolygon might have no area on this plane, but the ray would miss this polygonanyway. Casting a polygon onto an arbitrary plane means having to perform amatrix transformation, but this solution does provide a way around potentialcracking problems.
In ray tracing, Worley (Worley 1993a) points out that the polygon's 3D bounding boxcan be treated like a 2D bounding box by throwing away one coordinate, as doneabove for polygons. By analysis of the operations involved, it can be shownto be generally more profitable to first intersect the polygon's plane thentest whether the point is inside the 2D bounding box rather than first testingthe 3D bounding box. Other bounding box variants can be found in Woo (Woo 1992).
One way to think about this algorithm is to consider the test point to be atthe origin and to check the edges against this point. If the Y components ofa polygon edge differ in sign, then the edge can cross the test ray. In thiscase, if both X components are positive, the edge and ray must intersect and acrossing is recorded. Else, if the X signs differ, then the X intersectionof the edge and the ray is computed and if positive a crossing is recorded.
MacMartin (MacMartin 1992) pointed out that for polygons with a large number of edgesthere are generally runs of edges which have Y components with the same sign.For example, a polygon representing Brazil might have a thousand edges, butonly a few of these will straddle any given latitude line and there are longruns of contiguous edges on one side of the line. So a faster strategy is toloop through just the Y components as fast as possible; when they differ thenretrieve and check the X components. Compared to the basic crossings test theMacMartin test was up to 1.8 times faster for polygons up to 100 sides, withperformance particularly enhanced for polygons with many edges.
Other optimizations can be done for this test. Preprocessing the edge listinto separate X and Y component lists, with the first vertex added to the end,makes for particularly tight loops in the testing algorithm. This is not donein the code provided so as to avoid any preprocessing or additional memorycosts.
[Addenda: Joseph Samosky and Mark Haigh-Hutchinson submitted (unpublished)articles to Graphics Gems V.One idea these submissions inspired is a somewhat faster crossings test.By turning the division for testing the X axis crossinginto a tricky multiplication test this part of the test became faster,which had the additional effect of making the test for "both to left orboth to right" a bit slower for triangles than simply computing theintersection each time. The main increase is in triangle testing speed,which was about 15% faster; all other polygon complexities were pretty muchthe same as before. On machines where division is very expensive (not thecase on the HP 9000 series on which I tested) this test should be muchfaster overall than the old code. Your mileage may (in fact, will) vary,depending on the machine and the test data, but in general I believe thiscode is both shorter and faster. Related work by Samosky is in:Samosky, Joseph, "SectionView: A system for interactively specifying andvisualizing sections through three-dimensional medical image data",M.S. Thesis, Department of Electrical Engineering and Computer Science,Massachusetts Institute of Technology, 1993. The routine online is called the CrossingsMultiplyTest.]
When the number of sides is small, the barycentric test is comparable to theMacMartin test in speed, with the additional bonus of having the barycentriccoordinates computed. As the number of sides approached 100, the MacMartintest becomes 3 to 6 times faster than the barycentric method.
A faster triangle fan tester proposed by Green (Green 1993) is to store a set ofhalf-plane equations for each triangle and test each in turn. If the point isoutside any of the three edges, it is outside the triangle. The half-planetest is an old idea, but storing the half-planes instead of deriving them onthe fly from the vertices gives this scheme its speed at the cost of someadditional storage space. For triangles this scheme is the fastest of all ofthe algorithms discussed so far, being almost twice as fast as the MacMartincrossings test. It is also very simple to code and so lends itself toassembly language translation.
Both the half-plane and barycentric triangle testers can be sped up further bysorting the order of the edge tests. Worley and Haines (Worley 1993b) note that thehalf-plane triangle test is more efficient if the longer edges are testedfirst. Larger edges tend to cut off more exterior area of the polygon'sbounding box, and so can result in earlier exit from testing a given triangle.Sorting in this way makes the test up to 1.6 times faster, rising quickly withthe number of edges in the polygon. However, polygons with a large number ofedges tend to bog down the sorted edge triangle algorithm, with the MacMartintest being from 1.6 to 2.2 times faster for 100 edge polygons.
For the general test a better ordering for each triangle's edges is to sort bythe area of the polygon's bounding box outside the edge, since we are tryingto maximize the amount of area discarded by each edge test. This orderingprovides up to another 10% savings in testing time. Unfortunately, for theconvex test below, this ordering actually loses about 10% for regular polygonsdue to a subtle quirk. As such, this ordering is not presented in thestatistics section or the code.
The triangle fan tests can exit as soon as any triangle is found to containthe point. This algorithm can be enhanced by both sorting the edges of eachtriangle by length and also sorting the testing order of triangles by theirareas. Larger triangles are more likely to enclose a point and so end testingearlier. Using both of these sorting strategies makes convex testing 1.2times faster for squares and 2.5 times faster for regular 100 sided polygons.
Another strategy is to test the point against each exterior edge in turn. Ifthe point is outside any edge, then the point must be outside the entireconvex polygon. This algorithm uses less additional storage than the trianglefan and is very simple to code.
The order of edges tested affects the speed of the algorithm; testing edgeswhich cut off the most area of the bounding box earliest on is the bestordering. Finding this optimal ordering is non-trivial, but doing the edgesin order is often the worst strategy, since each neighboring edge usually cutsoff little more area than the previous. Randomizing the order of the edgesmakes this algorithm up to 10% faster overall for regular polygons. However,even then the triangle fan algorithm with sorting is up to 1.35 times fasterfor 100 edge regular polygons.
The exterior edge strategy looks for an early exit due to the point beingoutside the polygon, while the triangle fan convex test looks for one due tothe point being inside. For example, for 100 edge polygons if all pointstested are inside the polygon the triangle fan is 1.7 times faster; if allare outside the exterior test is more than 11 times faster (but only 3 timesfaster if the edges are not randomized). So when the polygon/bounding box areais low the exterior edge strategy might be best.
A method with O(log n) performance is discussed by Preparata and Shamos(Preparata 1985). The polygon is preprocessed by adding a central point to it and isthen divided into wedges. The angles from an anchor edge to each wedge'sedges are computed and saved, along with half-plane equations for each wedge'spolygon edge. When a point is tested, the angle from the anchor edge iscomputed and a binary search is used to determine the wedge it is in, then thecorresponding polygon edge is tested against it (Figure 4). This algorithm isslower for polygons with few edges because the startup cost is high, but thebinary search makes for a much faster test when the number of edges is high.
Problems occur in triangle fan algorithms when the code assumes that a pointthat lies on a triangle edge is inside that triangle. Points on the edgesbetween test triangles will be classified as being inside two triangles, andso will be classified as being outside the polygon. This problem does nothappen with the convex test. However, another problem is common to thisfamily of algorithms. If a point is on the edge between two polygons, it willbe classified as being inside both.
The code presented for these algorithms does not fully address either of theseproblems. In reality, a random point tested against a polygon using eitheralgorithm has an infinitesimal chance of landing exactly on any edge. Forrendering purposes this problem can be ignored, with the result being onemis-shaded pixel once in a great while.
The crossings test does not have these problems when the 2D polygons are inthe same plane. By the nature of the test, all points are consistentlycategorized as being to one side of any given edge or vertex. This means thatwhen a point is somewhere inside a mesh of polygons the point will always bein only one polygon. Points exactly on the unshared edge of a polygon will beclassified as arbitrarily inside or outside the polygon by this method,however. Again, this problem is rarely encountered in rendering and so canusually be ignored.
When a point is to be classified, the proper bin is retrieved and if the pointis outside the X bounds, it must be outside the polygon. Else, the list istraversed and the edges tested against the point. Essentially, a modifiedcrossings test is done, with additional speed coming from the sorted order andfrom the storage of the "fully crosses" condition (Figure 5).
To test a point against this structure is extremely quick in most cases. Fora reasonable polygon many of the cells are either inside or outside, sotesting consists of a simple look-up. If the cell contains edges, then a linesegment is formed from the test point to the cell corner and is tested againstall edges in the list (Antonio 1992). Since the state of the corner is known,the state of the test point can be found from the number of intersections(Figure 6).
Care must be taken when a polygon edge exactly (or even nearly exactly)crosses a grid corner, as this corner is then unclassifiable. Rather thancoping with the topological and numerical problems involved, one simplesolution is to just start generating the grid from scratch again, givingslightly different dimensions to the bounding box. When testing the linesegment against the edges in a list, exact intersections of an edge endpointmust be counted only once.
One additional speed up is possible. Each grid cell has four sides. If noedges cross a side, then that side will be fully inside or outside thepolygon. A perfectly horizontal or vertical test line segment can then begenerated and the faster crossings test can be used against the edges in thecell. The only test case where this made a significant difference was witha 20x20 grid imposed on a 1000 edge polygon, where the grid cell side testwas 1.3 times faster.
The performance of all the algorithms is practically linear; as such, theratios of times for the 1000 edge polygons are representative of performancefor polygons with a large number of edges.
General Algorithms, Random Polygons:
number of edges per polygon 3 4 10 100 1000 MacMartin 2.9 3.2 5.9 50.6 485 Crossings 3.1 3.4 6.8 60.0 624 Triangle Fan+edge sort 1.1 1.8 6.5 77.6 787 Triangle Fan 1.2 2.1 7.3 85.4 865 Barycentric 2.1 3.8 13.8 160.7 1665 Angle Summation 56.2 70.4 153.6 1403.8 14693 Grid (100x100) 1.5 1.5 1.6 2.1 9.8 Grid (20x20) 1.7 1.7 1.9 5.7 42.2 Bins (100) 1.8 1.9 2.7 15.1 117 Bins (20) 2.1 2.2 3.7 26.3 278General Algorithms, Regular Polygons:
number of edges per polygon 3 4 10 100 1000 MacMartin 2.7 2.8 4.0 23.7 225 Crossings 2.8 3.1 5.3 42.3 444 Triangle Fan+edge sort 1.3 1.9 5.2 53.1 546 Triangle Fan 1.3 2.2 7.5 86.7 894 Barycentric 2.1 3.9 13.0 143.5 1482 Angle Summation 52.9 68.1 158.8 1489.3 15762 Grid (100x100) 1.5 1.5 1.5 1.5 1.5 Grid (20x20) 1.6 1.6 1.6 1.7 2.5 Bins (100) 2.1 2.2 2.6 4.6 3.8 Bins (20) 2.4 2.5 3.4 9.3 55.0Convex Algorithms, Regular Polygons:
number of edges per polygon 3 4 10 100 1000 Inclusion 4.82 5.01 6.21 7.12 8.3 Sorted Triangle Fan 1.11 1.41 3.75 29.36 289.6 Unsorted Triangle Fan 1.25 2.04 6.30 69.18 734.7 Unsorted Barycentric* 1.79 2.80 6.94 65.62 668.7 Random Exterior Edges 1.11 1.61 3.82 33.44 333.6 Ordered Exterior Edges 1.28 1.70 4.15 41.07 408.9 Convex MacMartin 2.44 2.48 3.18 17.31 159.8* The "unsorted barycentric" code is a slightly optimized version of Badouel'scode in Graphics Gems (Badoeul 1990).
Of the algorithms with efficiency structures, the trapezoid algorithm issomewhere in between the edge based algorithms and the gridding algorithm inspeed. Gridding gives almost constant time performance for most normalpolygons, though like the other crossings test it performs a bit slower whenentirely random polygons are tested. Interestingly, even for polygons withjust a few edges the gridding algorithm outperforms most of the other tests.
Testing times can be noticeably decreased by using an algorithm optimized forconvex testing when possible. For example, the convex sorted triangle fantest is up to 2 times faster than its general case counterpart. For convexpolygons with many edges the inclusion test is extremely efficient because ofits O(log n) behavior. There is a zone from around 8 to 25 or so edges wherethe convex MacMartin test is slightly faster than the others, though notsignificantly so.
In summary, the basic crossings test is generally useful, but we can do better.Testing triangles using the sorted half-plane algorithm was more than twiceas fast; on the other end of the spectrum, the MacMartin optimization madetesting nearly twice as fast for polygons with many edges.
Code for this article is on the web.
from:http://erich.realtimerendering.com/ptinpoly/