[geos-commits] r4040 - in trunk: include/geos/algorithm src/algorithm tests/xmltester tests/xmltester/tests/ticket

svn_geos at osgeo.org svn_geos at osgeo.org
Mon Jan 19 02:59:49 PST 2015


Author: strk
Date: 2015-01-19 02:59:48 -0800 (Mon, 19 Jan 2015)
New Revision: 4040

Added:
   trunk/tests/xmltester/tests/ticket/bug716.xml
Modified:
   trunk/include/geos/algorithm/RayCrossingCounter.h
   trunk/src/algorithm/CGAlgorithms.cpp
   trunk/src/algorithm/RayCrossingCounter.cpp
   trunk/tests/xmltester/Makefile.am
Log:
Improve robustness of intersection testing (#716)

RayCrossingCounter uses orientationIndex to handle floating point
precision errors the same way as LineIntersector.

Includes testcase for ticket #716 with CW and CCW polygons

Patch by Asmund Tokheim <tokheim at outlook.com>

Modified: trunk/include/geos/algorithm/RayCrossingCounter.h
===================================================================
--- trunk/include/geos/algorithm/RayCrossingCounter.h	2015-01-19 10:59:17 UTC (rev 4039)
+++ trunk/include/geos/algorithm/RayCrossingCounter.h	2015-01-19 10:59:48 UTC (rev 4040)
@@ -93,6 +93,22 @@
 	static int locatePointInRing(const geom::Coordinate& p,
 	         const std::vector<const geom::Coordinate*>& ring);
 
+	/** \brief
+	 * Returns the index of the direction of the point <code>q</code>
+	 * relative to a vector specified by <code>p1-p2</code>.
+	 *
+	 * @param p1 the origin point of the vector
+	 * @param p2 the final point of the vector
+	 * @param q the point to compute the direction to
+	 *
+	 * @return 1 if q is counter-clockwise (left) from p1-p2
+	 * @return -1 if q is clockwise (right) from p1-p2
+	 * @return 0 if q is collinear with p1-p2
+	 */
+	static int orientationIndex(const geom::Coordinate& p1,
+	         const geom::Coordinate& p2,
+	         const geom::Coordinate& q);
+
 	RayCrossingCounter(const geom::Coordinate& point)
 	:	point( point),
 		crossingCount( 0),

Modified: trunk/src/algorithm/CGAlgorithms.cpp
===================================================================
--- trunk/src/algorithm/CGAlgorithms.cpp	2015-01-19 10:59:17 UTC (rev 4039)
+++ trunk/src/algorithm/CGAlgorithms.cpp	2015-01-19 10:59:48 UTC (rev 4040)
@@ -42,14 +42,7 @@
 int
 CGAlgorithms::orientationIndex(const Coordinate& p1,const Coordinate& p2,const Coordinate& q)
 {
-	// travelling along p1->p2, turn counter clockwise to get to q return 1,
-	// travelling along p1->p2, turn clockwise to get to q return -1,
-	// p1, p2 and q are colinear return 0.
-	double dx1=p2.x-p1.x;
-	double dy1=p2.y-p1.y;
-	double dx2=q.x-p2.x;
-	double dy2=q.y-p2.y;
-	return RobustDeterminant::signOfDet2x2(dx1,dy1,dx2,dy2);
+	return RayCrossingCounter::orientationIndex(p1, p2, q);
 }
 
 /*public static*/

Modified: trunk/src/algorithm/RayCrossingCounter.cpp
===================================================================
--- trunk/src/algorithm/RayCrossingCounter.cpp	2015-01-19 10:59:17 UTC (rev 4039)
+++ trunk/src/algorithm/RayCrossingCounter.cpp	2015-01-19 10:59:48 UTC (rev 4040)
@@ -45,8 +45,8 @@
 
 	for (std::size_t i = 1, ni = ring.size(); i < ni; i++) 
 	{
-		const geom::Coordinate & p1 = ring[ i ];
-		const geom::Coordinate & p2 = ring[ i - 1 ];
+		const geom::Coordinate & p1 = ring[ i - 1 ];
+		const geom::Coordinate & p2 = ring[ i ];
 
 		rcc.countSegment(p1, p2);
 
@@ -64,8 +64,8 @@
 
 	for (std::size_t i = 1, ni = ring.size(); i < ni; i++) 
 	{
-		const geom::Coordinate & p1 = *ring[ i ];
-		const geom::Coordinate & p2 = *ring[ i - 1 ];
+		const geom::Coordinate & p1 = *ring[ i - 1 ];
+		const geom::Coordinate & p2 = *ring[ i ];
 
 		rcc.countSegment(p1, p2);
 
@@ -75,6 +75,20 @@
 	return rcc.getLocation();
 }
 
+/*public static*/
+int
+RayCrossingCounter::orientationIndex(const geom::Coordinate& p1,
+         const geom::Coordinate& p2, const geom::Coordinate& q)
+{
+	// travelling along p1->p2, turn counter clockwise to get to q return 1,
+	// travelling along p1->p2, turn clockwise to get to q return -1,
+	// p1, p2 and q are colinear return 0.
+	double dx1=p2.x-p1.x;
+	double dy1=p2.y-p1.y;
+	double dx2=q.x-p2.x;
+	double dy2=q.y-p2.y;
+	return RobustDeterminant::signOfDet2x2(dx1,dy1,dx2,dy2);
+}
 
 void 
 RayCrossingCounter::countSegment(const geom::Coordinate& p1,
@@ -124,30 +138,20 @@
 	if (((p1.y > point.y) && (p2.y <= point.y)) ||
 		((p2.y > point.y) && (p1.y <= point.y)) ) 
 	{
-		// translate the segment so that the test point lies
-		// on the origin
-		double x1 = p1.x - point.x;
-		double y1 = p1.y - point.y;
-		double x2 = p2.x - point.x;
-		double y2 = p2.y - point.y;
-
-		// The translated segment straddles the x-axis.
-		// Compute the sign of the ordinate of intersection
-		// with the x-axis. (y2 != y1, so denominator
-		// will never be 0.0)
-                        // MD - faster & more robust computation?
-                double xIntSign = RobustDeterminant::signOfDet2x2(x1, y1, x2, y2);
-		if (xIntSign == 0.0) 
+		// For an upward edge, orientationIndex will be positive when p1->p2
+		// crosses ray. Conversely, downward edges should have negative sign.
+		int sign = orientationIndex(p1, p2, point);
+		if (sign == 0)
 		{
 			isPointOnSegment = true;
 			return;
 		}
 
-		if (y2 < y1)
-			xIntSign = -xIntSign;
+		if (p2.y < p1.y)
+			sign = -sign;
 
 		// The segment crosses the ray if the sign is strictly positive.
-		if (xIntSign > 0.0) 
+		if (sign > 0)
 			crossingCount++;
 	}
 }

Modified: trunk/tests/xmltester/Makefile.am
===================================================================
--- trunk/tests/xmltester/Makefile.am	2015-01-19 10:59:17 UTC (rev 4039)
+++ trunk/tests/xmltester/Makefile.am	2015-01-19 10:59:48 UTC (rev 4040)
@@ -41,6 +41,7 @@
 	$(srcdir)/tests/ticket/bug599.xml \
 	$(srcdir)/tests/ticket/bug605.xml \
 	$(srcdir)/tests/ticket/bug615.xml \
+	$(srcdir)/tests/ticket/bug716.xml \
 	$(srcdir)/tests/general/TestBoundary.xml \
 	$(srcdir)/tests/general/TestBuffer.xml \
 	$(srcdir)/tests/general/TestBufferMitredJoin.xml \

Added: trunk/tests/xmltester/tests/ticket/bug716.xml
===================================================================
--- trunk/tests/xmltester/tests/ticket/bug716.xml	                        (rev 0)
+++ trunk/tests/xmltester/tests/ticket/bug716.xml	2015-01-19 10:59:48 UTC (rev 4040)
@@ -0,0 +1,75 @@
+<run>
+  <precisionModel type="FLOATING"/>
+  <desc>
+    Intersects operation of polygons with collinear lines. 
+    http://trac.osgeo.org/geos/ticket/716
+  </desc>
+<case>
+    <desc>
+      http://trac.osgeo.org/geos/ticket/716
+      a CW, b CW
+    </desc>
+  <a>
+    POLYGON((0.04745459120333707 7.998990511152711, 10.222919749090828 34.08521670606894, 10 10, 0.04745459120333707 7.998990511152711))
+  </a>
+  <b>
+    POLYGON((15 5, 0.010044793132693013 7.903085268568247, 10.260329547338191 34.181121949106455, 15 5))
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+<case>
+    <desc>
+      http://trac.osgeo.org/geos/ticket/716
+      a CCW, b CW
+    </desc>
+  <a>
+    POLYGON((0.04745459120333707 7.998990511152711, 10 10, 10.222919749090828 34.08521670606894, 0.04745459120333707 7.998990511152711))
+  </a>
+  <b>
+    POLYGON((15 5, 0.010044793132693013 7.903085268568247, 10.260329547338191 34.181121949106455, 15 5))
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+<case>
+    <desc>
+      http://trac.osgeo.org/geos/ticket/716
+      a CW, b CCW
+    </desc>
+  <a>
+    POLYGON((0.04745459120333707 7.998990511152711, 10.222919749090828 34.08521670606894, 10 10, 0.04745459120333707 7.998990511152711))
+  </a>
+  <b>
+    POLYGON((15 5, 10.260329547338191 34.181121949106455, 0.010044793132693013 7.903085268568247, 15 5))
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+<case>
+    <desc>
+      http://trac.osgeo.org/geos/ticket/716
+      a CCW, b CCW
+    </desc>
+  <a>
+    POLYGON((0.04745459120333707 7.998990511152711, 10 10, 10.222919749090828 34.08521670606894, 0.04745459120333707 7.998990511152711))
+  </a>
+  <b>
+    POLYGON((15 5, 10.260329547338191 34.181121949106455, 0.010044793132693013 7.903085268568247, 15 5))
+  </b>
+<test>
+  <op name="intersects" arg1="A" arg2="B">
+    true
+  </op>
+</test>
+</case>
+</run>



More information about the geos-commits mailing list