[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