How Reliable Are Practical Point in Polygon Strategies?

Stefan Schirra

News:

Sep 11, 2008 Polygon data updated. "Random" orthogonal polygons have been added and all real-world polygons are counterclockwise oriented now.
Sep 11, 2008 Documentation updated.
Sep 10, 2008 The crossing number code from Real-Time Rendering (2nd ed.) has been added to the set of strategies

These are companion pages to "How Reliable Are Practical Point in Polygon Strategies?" (preliminary version), presented at ESA 2008. We study reliabilty, i.e., correctness and numerical robustness, of a number of strategies for testing whether a given point is contained in a given simple closed polygon. We experimentally compare several implementations, most of them publicy available on the world wide web. The selected code includes strategies from Eric Haines beautiful article on Point in Polygon Strategies published in Graphics Gems IV.

Point-in-Polygon Tests

Our test set includes point-in-polygon code called crossings, halfplane, barycentric, and spackman belong to the methods discussed in Point in Polygon Strategies. The associated code is available online. This C-code was used as is, besides that we changed function declarations and definitions from K&R-style to ANSI style for use within C++. weiler is another method discussed in an article published in Graphics Gems IV. Haines' code includes C-code for weiler as well. We refer to Point in Polygon Strategies for a discussion of these methods. PNPOLY is another implementation of a crossing number algorithm by W.R. Franklin, see PNPOLY-Point Inclusion in Polygon Test. Corresponding C-code (only a few lines of code!) is available on this page as well. csg is an implementation of a method discussed in "Practical Point-in-Polygon Tests Using CSG Representations of Polygons" by R. Walker and J. Snoeyink. The code is not publicy available and hence not included on this page. Thanks to Robert Walker for making his code available to us. Finally CGAL is template code from the Computational Geometry Algorithms Library CGAL instantiated with CGAL's simple Cartesian kernel using double precision arithmetic. RTRL is the crossing number algorithm presented in Real-Time Rendering (2nd ed.) on page 585. The authors of the book refer to Haines' code there, although that code is different. We "adapted" the code from the book.

For convenience our experiments make use of CGAL and LEDA (note that there is a LEDA free editon of LEDA available again which suffices for our purpose). LEDA is used for correctness checking and visualisation of experimental results. Thus, strictly speaking, you need both libraries in order to rerun the experiments.

Polygon Data

Our polygon test data used in the reported experiments include real-world polygons as well as "random" polygons. The random polygons are generated by a CGAL generator using the 2-opt heuristic for a random point set. You may also create random polygons with RPG which provides additional heuristics for generating random polygons besides 2-opt. Thanks to Martin Held for making RPG availbale to us. The test polygons now also include some "random" orthogonal polygons, i.e. polygons with axis-parallel edges. Thanks to Ana Paula Tomas for making the inflate-cut code availbale to us. All polygons were scaled to the unit square.



Query Point Data

We used a number of generators to produce "difficult" query point set instances, namely query points (almost) on the edges of a polygon, query points on the "diagonals" of a polygon used by the triangle-fan based algorithms barycentric, halfplane, and spackman, points on horizontals and verticals through the vertices of a polygon, query points on the supporting lines of the edges of a polygon, and query points near the vertices of a polygon:


template < class InputIterator, class OutputIterator >
OutputIterator p_o_s ( InputIterator first, InputIterator beyond, OutputIterator res, int per_edge)
computes per_edge query points on each edge of the polygon defined by the point range [first, beyond) and reports these points via res. Points on the edges are generated using CGAL::points_on_segment_2. If we use double precision floating-point arithmetic to compute the points, they are not necessarily exactly on the edges. For each edge both the start point and the target point are among the generated query points.

template < class InputIterator, class OutputIterator >
OutputIterator p_o_d ( InputIterator first, InputIterator beyond, OutputIterator res, int per_diagonal)
computes per_diagonal query points on each line segment that connects the first point of the polygon with another point on the polygon and reports these points via res. Points on these "diagonals" are generated using CGAL::points_on_segment_2. If we use double precision floating-point arithmetic to compute the points, they are not necessarily exactly on the edges. For each edge both the start point and the target point are among the generated query points.

template < class InputIterator, class OutputIterator >
OutputIterator p_c_v ( InputIterator first, InputIterator beyond, OutputIterator res, int per_crossline)
computes per_crossline query points on both the horizontal and the vertical line through each vertex, more precisely, on the intersection of these lines with the unit square, and reports these points via res. Points on these horizontal and vertical segments are generated using CGAL::points_on_segment_2.

template < class InputIterator, class OutputIterator >
OutputIterator p_o_l ( InputIterator first, InputIterator beyond, OutputIterator res, int per_egde)
computes per_egde query points on the intersection segment of the lines supporting the polygon edges with the unit square and reports these points via res. Points on these horizontal and vertical segments are generated using CGAL::points_on_segment_2. If we use double precision floating-point arithmetic to compute the points, they are not necessarily exactly on the lines.



Testbed Code

We use Literate Programming using LEDA's tools based on noweb. The following preliminary(!) Lweb and noweb files provide our testbed code (including query point generators, but not the point-in-polygon code itself) and documentation.
As said above, we use both CGAL and LEDA and you need noweb to extract the test file like this:

notangle -L -R'main' ReliabilityExperiments.lw > pip.C



This page is always under construction!