[geos-commits] r3321 - in trunk: . include/geos/operation/predicate src/operation/predicate

svn_geos at osgeo.org svn_geos at osgeo.org
Thu Apr 28 12:39:02 EDT 2011


Author: strk
Date: 2011-04-28 09:39:02 -0700 (Thu, 28 Apr 2011)
New Revision: 3321

Modified:
   trunk/.gitignore
   trunk/NEWS
   trunk/include/geos/operation/predicate/RectangleIntersects.h
   trunk/include/geos/operation/predicate/SegmentIntersectionTester.h
   trunk/src/operation/predicate/RectangleIntersects.cpp
   trunk/src/operation/predicate/SegmentIntersectionTester.cpp
Log:
Improve performance of RectangleIntersects (of one order of magnitude).

Modified: trunk/.gitignore
===================================================================
--- trunk/.gitignore	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/.gitignore	2011-04-28 16:39:02 UTC (rev 3321)
@@ -22,6 +22,7 @@
 tests/bigtest/bug234
 tests/geostest/geostest
 tests/perf/operation/buffer/IteratedBufferStressTest
+tests/perf/operation/predicate/RectangleIntersectsPerfTest
 include/geos/platform.h
 include/geos/stamp-h2
 include/geos/version.h

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/NEWS	2011-04-28 16:39:02 UTC (rev 3321)
@@ -31,7 +31,7 @@
     ownership of vector elements
   - Empty LinearRings are closed by definition
   - Fixed Geometry.distance() and DistanceOp to return 0.0 for empty inputs
-- Bug fixes:
+- Bug fixes / improvements
   - Invalid compound geometries reported as valid (#333)
   - Return up to 15 digits of precision from GEOSisValidReason_t (#329)
   - CAPI: do not leak contexts when using the non-reentrant interface
@@ -42,6 +42,8 @@
     (via safeOctant)
   - Fixed buffer OffsetCurveSetBuilder to handle "flat" rings correctly
   - Added illegal state check in LineSegment::pointAlongOffset() 
+  - Improved performance of RectangleIntersects by always using
+    segment-scanning and refining SegmentIntersectionTester
 
 Changes in 3.2.0 
 2009-12-14

Modified: trunk/include/geos/operation/predicate/RectangleIntersects.h
===================================================================
--- trunk/include/geos/operation/predicate/RectangleIntersects.h	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/include/geos/operation/predicate/RectangleIntersects.h	2011-04-28 16:39:02 UTC (rev 3321)
@@ -1,9 +1,9 @@
 /**********************************************************************
- * $Id$
  *
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: operation/predicate/RectangleIntersects.java rev 1.4 (JTS-1.10)
+ * Last port: operation/predicate/RectangleIntersects.java r378 (JTS-1.12)
  *
  **********************************************************************/
 
@@ -37,12 +37,16 @@
 namespace predicate { // geos::operation::predicate
 
 /** \brief
- * Optimized implementation of spatial predicate "intersects"
- * for cases where the first Geometry is a rectangle.
+ * Optimized implementation of the "intersects" spatial predicate
+ * for cases where one Geometry is a rectangle.
+ *
+ * This class works for all input geometries, including
+ * {@link GeometryCollection}s.
  * 
  * As a further optimization,
- * this class can be used directly to test many geometries against a single
- * rectangle.
+ * this class can be used to test
+ * many geometries against a single
+ * rectangle in a slightly more efficient way.
  *
  */
 class GEOS_DLL RectangleIntersects {
@@ -60,15 +64,6 @@
 public:
 
 	/** \brief
-	 * Crossover size at which brute-force intersection scanning
-	 * is slower than indexed intersection detection.
-	 *
-	 * Must be determined empirically.  Should err on the
-	 * safe side by making value smaller rather than larger.
-	 */
-	static const std::size_t MAXIMUM_SCAN_SEGMENT_COUNT;
-
-	/** \brief
 	 * Create a new intersects computer for a rectangle.
 	 *
 	 * @param newRect a rectangular geometry
@@ -81,6 +76,13 @@
 
 	bool intersects(const geom::Geometry& geom);
 
+	/** \brief
+	 * Tests whether a rectangle intersects a given geometry.
+	 *
+	 * @param rectangle a rectangular Polygon
+	 * @param b a Geometry of any type
+	 * @return true if the geometries intersect
+	 */
 	static bool intersects(const geom::Polygon &rectangle,
 			const geom::Geometry &b)
 	{

Modified: trunk/include/geos/operation/predicate/SegmentIntersectionTester.h
===================================================================
--- trunk/include/geos/operation/predicate/SegmentIntersectionTester.h	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/include/geos/operation/predicate/SegmentIntersectionTester.h	2011-04-28 16:39:02 UTC (rev 3321)
@@ -1,9 +1,9 @@
 /**********************************************************************
- * $Id$
  *
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: operation/predicate/SegmentIntersectionTester.java rev. 1.3 (JTS-1.10)
+ * Last port: operation/predicate/SegmentIntersectionTester.java r378 (JTS-1.12)
  *
  **********************************************************************/
 
@@ -23,6 +23,7 @@
 #include <geos/export.h>
 
 #include <geos/algorithm/LineIntersector.h> // for composition
+#include <geos/geom/Coordinate.h> // for composition
 
 // Forward declarations
 namespace geos {
@@ -38,9 +39,10 @@
 
 /** \brief
  * Tests if any line segments in two sets of CoordinateSequences intersect.
- * Optimized for use when at least one input is of small size.
  *
- * Short-circuited to return as soon an intersection is found.
+ * The algorithm is optimized for use when the first input has smaller extent
+ * than the set of test lines.
+ * The code is short-circuited to return as soon an intersection is found.
  *
  */
 class GEOS_DLL SegmentIntersectionTester {
@@ -55,17 +57,40 @@
 
 	bool hasIntersectionVar;
 
+  geom::Coordinate pt10;
+  geom::Coordinate pt11;
+  geom::Coordinate pt00;
+  geom::Coordinate pt01;
+
+
 public:
 
 	SegmentIntersectionTester(): hasIntersectionVar(false) {}
 
-	bool hasIntersectionWithLineStrings(const geom::CoordinateSequence &seq,
+	bool hasIntersectionWithLineStrings(const geom::LineString &line,
 		const std::vector<const geom::LineString *>& lines);
 
-	bool hasIntersection(const geom::CoordinateSequence &seq0,
-		const geom::CoordinateSequence &seq1);
+	bool hasIntersection(const geom::LineString &line,
+		const geom::LineString &testLine);
 
+	/**
+	 * Tests the segments of a LineString against the segs in
+	 * another LineString for intersection.
+	 * Uses the envelope of the query LineString
+	 * to filter before testing segments directly.
+	 * This is optimized for the case when the query
+	 * LineString is a rectangle.
+	 *
+	 * Testing shows this is somewhat faster than not checking the envelope.
+	 *
+	 * @param line
+	 * @param testLine
+	 * @return
+	 */
+	bool hasIntersectionWithEnvelopeFilter(const geom::LineString &line,
+		const geom::LineString &testLine);
 
+
 };
 
 } // namespace geos::operation::predicate

Modified: trunk/src/operation/predicate/RectangleIntersects.cpp
===================================================================
--- trunk/src/operation/predicate/RectangleIntersects.cpp	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/src/operation/predicate/RectangleIntersects.cpp	2011-04-28 16:39:02 UTC (rev 3321)
@@ -1,9 +1,9 @@
 /**********************************************************************
- * $Id$
  *
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: operation/predicate/RectangleIntersects.java rev 1.4 (JTS-1.10)
+ * Last port: operation/predicate/RectangleIntersects.java r378 (JTS-1.12)
  *
  **********************************************************************/
 
@@ -39,9 +39,6 @@
 namespace operation { // geos.operation
 namespace predicate { // geos.operation.predicate
 
-const size_t RectangleIntersects::MAXIMUM_SCAN_SEGMENT_COUNT = 200;
-
-
 //----------------------------------------------------------------
 // EnvelopeIntersectsVisitor
 //----------------------------------------------------------------
@@ -70,10 +67,8 @@
 	{
 		const geom::Envelope &elementEnv = *(element.getEnvelopeInternal());
 
-		// disjoint
-		if ( ! rectEnv.intersects(elementEnv) ) {
-			return;
-		}
+		// skip if envelopes do not intersect
+		if ( ! rectEnv.intersects(elementEnv) ) return;
 
 		// fully contained - must intersect
 		if ( rectEnv.contains(elementEnv) ) {
@@ -148,6 +143,7 @@
 
 		const geom::Polygon *poly;
 
+		// if test geometry is not polygonal this check is not needed
 		if ( 0 == (poly=dynamic_cast<const geom::Polygon *>(&geom)) ) {
 			return;
 		}
@@ -201,10 +197,11 @@
 {
 private:
 
-	const geom::Polygon& rectangle;
+	//const geom::Polygon& rectangle;
 	const geom::Envelope& rectEnv;
+	const geom::LineString& rectLine;
 	bool intersectsVar;
-	const geom::CoordinateSequence &rectSeq;
+	//const geom::CoordinateSequence &rectSeq;
 
 	void computeSegmentIntersection(const geom::Geometry &geom)
 	{
@@ -215,7 +212,7 @@
 		geom::LineString::ConstVect lines;
 		LinearComponentExtracter::getLines(geom, lines);
 		SegmentIntersectionTester si;
-		if ( si.hasIntersectionWithLineStrings(rectSeq, lines) )
+		if ( si.hasIntersectionWithLineStrings(rectLine, lines) )
 		{
 			intersectsVar = true;
 			return;
@@ -231,20 +228,10 @@
 	void visit(const geom::Geometry &geom)
 	{
 		const geom::Envelope &elementEnv = *(geom.getEnvelopeInternal());
-		if (! rectEnv.intersects(elementEnv) ) {
-			return;
-		}
 
-		// check if general relate algorithm should be used,
-		// since it's faster for large inputs
-		if (geom.getNumPoints() > RectangleIntersects::MAXIMUM_SCAN_SEGMENT_COUNT)
-		{
-      std::auto_ptr<geom::IntersectionMatrix> im ( rectangle.relate(geom) );
-			intersectsVar = im->isIntersects();
-			return;
-		}
+		// check for envelope intersection
+		if (! rectEnv.intersects(elementEnv) ) return;
 
-		// if small enough, test for segment intersection directly
 		computeSegmentIntersection(geom);
 	}
 
@@ -254,10 +241,11 @@
 
 	LineIntersectsVisitor(const geom::Polygon &rect)
 		:
-		rectangle(rect),
+		//rectangle(rect),
 		rectEnv(*(rect.getEnvelopeInternal())),
-		intersectsVar(false),
-		rectSeq(*(rect.getExteriorRing()->getCoordinatesRO()))
+		rectLine(*(rect.getExteriorRing())),
+		intersectsVar(false)
+		//rectSeq(*(rect.getExteriorRing()->getCoordinatesRO()))
 		{}
 
 	/**
@@ -266,7 +254,7 @@
 	 * @return <code>true</code> if a segment intersection exists
 	 * <code>false</code> if no segment intersection exists
 	 */
-	bool intersects() { return intersectsVar; }
+	bool intersects() const { return intersectsVar; }
 
 };
 

Modified: trunk/src/operation/predicate/SegmentIntersectionTester.cpp
===================================================================
--- trunk/src/operation/predicate/SegmentIntersectionTester.cpp	2011-04-28 16:38:43 UTC (rev 3320)
+++ trunk/src/operation/predicate/SegmentIntersectionTester.cpp	2011-04-28 16:39:02 UTC (rev 3321)
@@ -1,9 +1,9 @@
 /**********************************************************************
- * $Id$
  *
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: operation/predicate/SegmentIntersectionTester.java rev. 1.3 (JTS-1.10)
+ * Last port: operation/predicate/SegmentIntersectionTester.java r378 (JTS-1.12)
  *
  **********************************************************************/
 
@@ -30,13 +30,14 @@
 
 bool
 SegmentIntersectionTester::hasIntersectionWithLineStrings(
-	const CoordinateSequence &seq,
+	const LineString &line,
 	const LineString::ConstVect& lines)
 {
+  hasIntersectionVar = false;
 	for (size_t i=0, n=lines.size(); i<n; ++i )
 	{
-		const LineString *line = lines[i];
-		hasIntersection(seq, *(line->getCoordinatesRO()));
+		const LineString *testLine = lines[i];
+		hasIntersection(line, *testLine);
 		if (hasIntersectionVar) break;
 	}
 	return hasIntersectionVar;
@@ -44,30 +45,68 @@
 
 bool
 SegmentIntersectionTester::hasIntersection(
-	const CoordinateSequence &seq0, const CoordinateSequence &seq1)
+	const LineString &line, const LineString &testLine)
 {
+  typedef std::size_t size_type;
 
-    for (std::size_t i = 1, ni = seq0.getSize(); i < ni; ++i)
+	const CoordinateSequence &seq0 = *(line.getCoordinatesRO());
+  size_type seq0size = seq0.getSize();
+
+  const CoordinateSequence &seq1 = *(testLine.getCoordinatesRO());
+  size_type seq1size = seq1.getSize();
+
+  for (size_type i = 1; i<seq0size && !hasIntersectionVar; ++i)
 	{
-		const Coordinate& pt00 = seq0.getAt(i - 1);
-		const Coordinate& pt01 = seq0.getAt(i);
+    seq0.getAt(i - 1, pt00);
+    seq0.getAt(i, pt01);
+
+    for (size_type j = 1; j < seq1size && !hasIntersectionVar; ++j)
+		{
+      seq1.getAt(j-1, pt10);
+      seq1.getAt(j, pt11); 
 		
-        for (std::size_t j = 1, nj = seq1.getSize(); j < nj; ++j)
+			li.computeIntersection(pt00, pt01, pt10, pt11);
+			if (li.hasIntersection()) hasIntersectionVar = true;
+		}
+	}
+
+	return hasIntersectionVar;
+}
+
+bool
+SegmentIntersectionTester::hasIntersectionWithEnvelopeFilter(
+	const LineString &line, const LineString &testLine)
+{
+  typedef std::size_t size_type;
+
+	const CoordinateSequence &seq0 = *(line.getCoordinatesRO());
+  size_type seq0size = seq0.getSize();
+
+  const CoordinateSequence &seq1 = *(testLine.getCoordinatesRO());
+  size_type seq1size = seq1.getSize();
+
+  const Envelope* lineEnv = line.getEnvelopeInternal();
+
+  typedef std::size_t size_type;
+
+  for (size_type i = 1; i<seq1size && !hasIntersectionVar; ++i)
+	{
+    seq1.getAt(i-1, pt10);
+    seq1.getAt(i, pt11); 
+
+    // skip test if segment does not intersect query envelope
+    if (! lineEnv->intersects(Envelope(pt10, pt11))) continue;
+
+    for (size_type j = 1; j < seq0size && !hasIntersectionVar; ++j)
 		{
-			const Coordinate& pt10 = seq1.getAt(j-1);
-			const Coordinate& pt11 = seq1.getAt(j); 
-
-			li.algorithm::LineIntersector::computeIntersection(pt00, pt01, pt10, pt11);
-			if (li.hasIntersection())
-			{
-				hasIntersectionVar = true;
-				goto out_of_loop;
-			}
+      seq0.getAt(j - 1, pt00);
+      seq0.getAt(j, pt01);
+		
+			li.computeIntersection(pt00, pt01, pt10, pt11);
+			if (li.hasIntersection()) hasIntersectionVar = true;
 		}
 	}
 
-	out_of_loop:
-
 	return hasIntersectionVar;
 }
 



More information about the geos-commits mailing list