[geos-commits] r4017 - in trunk: . include/geos/geomgraph include/geos/operation/overlay src/geomgraph src/operation/overlay

svn_geos at osgeo.org svn_geos at osgeo.org
Tue Sep 23 00:55:54 PDT 2014


Author: strk
Date: 2014-09-23 00:55:54 -0700 (Tue, 23 Sep 2014)
New Revision: 4017

Modified:
   trunk/NEWS
   trunk/include/geos/geomgraph/GeometryGraph.h
   trunk/include/geos/geomgraph/GeometryGraph.inl
   trunk/include/geos/operation/overlay/OverlayOp.h
   trunk/src/geomgraph/GeometryGraph.cpp
   trunk/src/operation/overlay/OverlayOp.cpp
Log:
OverlayOp: restrict intersection computations to the target extent

Speeds up INTERSECTION and DIFFERENCE operations between geometries
with small bounding box overlap.

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/NEWS	2014-09-23 07:55:54 UTC (rev 4017)
@@ -7,6 +7,9 @@
   - GEOS_USE_ONLY_R_API macro support (#695)
   - PHP: WKBReader->read() & WKBWriter::write() methods (Benjamin Morel)
   ...
+- Improvements:
+  - Speed-up intersection and difference between geometries
+    with small bounding box overlap.
 
 Changes in 3.4.2
 2013-08-25

Modified: trunk/include/geos/geomgraph/GeometryGraph.h
===================================================================
--- trunk/include/geos/geomgraph/GeometryGraph.h	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/include/geos/geomgraph/GeometryGraph.h	2014-09-23 07:55:54 UTC (rev 4017)
@@ -48,6 +48,7 @@
 		class Geometry;
 		class GeometryCollection;
 		class Point;
+		class Envelope;
 	}
 	namespace algorithm {
 		class LineIntersector;
@@ -212,16 +213,21 @@
 	 */
 	index::SegmentIntersector* computeSelfNodes(
 			algorithm::LineIntersector *li,
-			bool computeRingSelfNodes);
+			bool computeRingSelfNodes,
+			const geom::Envelope *env=0)
+	{
+		return computeSelfNodes(*li, computeRingSelfNodes, env);
+	}
 
 	// Quick inline calling the function above, the above should probably
 	// be deprecated.
 	index::SegmentIntersector* computeSelfNodes(
 			algorithm::LineIntersector& li,
-			bool computeRingSelfNodes);
+			bool computeRingSelfNodes, const geom::Envelope *env=0);
 
 	index::SegmentIntersector* computeEdgeIntersections(GeometryGraph *g,
-		algorithm::LineIntersector *li, bool includeProper);
+		algorithm::LineIntersector *li, bool includeProper,
+		const geom::Envelope *env=0);
 
 	std::vector<Edge*> *getEdges();
 

Modified: trunk/include/geos/geomgraph/GeometryGraph.inl
===================================================================
--- trunk/include/geos/geomgraph/GeometryGraph.inl	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/include/geos/geomgraph/GeometryGraph.inl	2014-09-23 07:55:54 UTC (rev 4017)
@@ -26,14 +26,6 @@
 namespace geos {
 namespace geomgraph { // geos::geomgraph
 
-INLINE index::SegmentIntersector*
-GeometryGraph::computeSelfNodes(
-		algorithm::LineIntersector& li,
-		bool computeRingSelfNodes)
-{
-	return computeSelfNodes(&li, computeRingSelfNodes);
-}
-
 INLINE void
 GeometryGraph::getBoundaryNodes(std::vector<Node*>&bdyNodes)
 {

Modified: trunk/include/geos/operation/overlay/OverlayOp.h
===================================================================
--- trunk/include/geos/operation/overlay/OverlayOp.h	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/include/geos/operation/overlay/OverlayOp.h	2014-09-23 07:55:54 UTC (rev 4017)
@@ -38,6 +38,7 @@
 	namespace geom {
 		class Geometry;
 		class Coordinate;
+		class Envelope;
 		class GeometryFactory;
 		class Polygon;
 		class LineString;
@@ -240,7 +241,7 @@
 	 * but in the original arg Geometry it is actually
 	 * in the interior due to the Boundary Determination Rule)
 	 */
-	void copyPoints(int argIndex);
+	void copyPoints(int argIndex, const geom::Envelope *env=0);
 
 	/** \brief
 	 * Compute initial labelling for all DirectedEdges at each node.

Modified: trunk/src/geomgraph/GeometryGraph.cpp
===================================================================
--- trunk/src/geomgraph/GeometryGraph.cpp	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/src/geomgraph/GeometryGraph.cpp	2014-09-23 07:55:54 UTC (rev 4017)
@@ -37,6 +37,7 @@
 #include <geos/geom/CoordinateSequence.h>
 #include <geos/geom/Location.h>
 #include <geos/geom/Point.h>
+#include <geos/geom/Envelope.h>
 #include <geos/geom/LinearRing.h>
 #include <geos/geom/LineString.h>
 #include <geos/geom/Polygon.h>
@@ -165,6 +166,9 @@
 #endif
 		e->eiList.addSplitEdges(edgelist);
 	}
+#if GEOS_DEBUG
+	cerr<<"["<<this<<"] GeometryGraph::computeSplitEdges() completed "<<endl;
+#endif
 }
 
 void
@@ -343,24 +347,44 @@
 	insertPoint(argIndex,pt,Location::INTERIOR);
 }
 
+template <class T, class C>
+void collect_intersecting_edges(const Envelope *env, T start, T end, C &to)
+{
+  for (T i=start; i != end; ++i)
+  {
+    Edge *e = *i;
+    if ( e->getEnvelope()->intersects(env) ) to.push_back(e);
+  }
+}
+
 /*public*/
 SegmentIntersector*
-GeometryGraph::computeSelfNodes(LineIntersector *li, bool computeRingSelfNodes)
+GeometryGraph::computeSelfNodes(LineIntersector &li,
+  bool computeRingSelfNodes, const Envelope *env)
 {
-	SegmentIntersector *si=new SegmentIntersector(li,true,false);
+	SegmentIntersector *si=new SegmentIntersector(&li,true,false);
     	auto_ptr<EdgeSetIntersector> esi(createEdgeSetIntersector());
 
+	typedef vector<Edge*> EC;
+	EC *se = edges;
+	EC self_edges_copy;
+	if ( env ) { // TODO: ... and env does not cover self geom env
+		collect_intersecting_edges(env, se->begin(), se->end(), self_edges_copy);
+    cerr << "(computeSelfNodes) Self edges reduced from " << se->size() << " to " << self_edges_copy.size() << endl;
+		se = &self_edges_copy;
+	}
+
 	// optimized test for Polygons and Rings
 	if (! computeRingSelfNodes
 	    && ( dynamic_cast<const LinearRing*>(parentGeom)
 	    || dynamic_cast<const Polygon*>(parentGeom)
 	    || dynamic_cast<const MultiPolygon*>(parentGeom) ))
 	{
-		esi->computeIntersections(edges, si, false);
+		esi->computeIntersections(se, si, false);
 	}
 	else
 	{
-		esi->computeIntersections(edges, si, true);
+		esi->computeIntersections(se, si, true);
 	}
 
 #if GEOS_DEBUG
@@ -373,7 +397,7 @@
 
 SegmentIntersector*
 GeometryGraph::computeEdgeIntersections(GeometryGraph *g,
-	LineIntersector *li, bool includeProper)
+	LineIntersector *li, bool includeProper, const Envelope *env)
 {
 #if GEOS_DEBUG
 	cerr<<"GeometryGraph::computeEdgeIntersections call"<<endl;
@@ -382,7 +406,25 @@
 
 	si->setBoundaryNodes(getBoundaryNodes(), g->getBoundaryNodes());
 	auto_ptr<EdgeSetIntersector> esi(createEdgeSetIntersector());
-	esi->computeIntersections(edges, g->edges, si);
+
+	typedef vector<Edge*> EC;
+
+	EC self_edges_copy;
+	EC other_edges_copy;
+
+	EC *se = edges;
+	EC *oe = g->edges;
+	if ( env ) { // TODO: ... and env does not cover self geom env
+		collect_intersecting_edges(env, se->begin(), se->end(), self_edges_copy);
+    cerr << "Self edges reduced from " << se->size() << " to " << self_edges_copy.size() << endl;
+		se = &self_edges_copy;
+	}
+	if ( env ) { // TODO: ... and env does not cover other geom env
+		collect_intersecting_edges(env, oe->begin(), oe->end(), other_edges_copy);
+    cerr << "Other edges reduced from " << oe->size() << " to " << other_edges_copy.size() << endl;
+		oe = &other_edges_copy;
+	}
+	esi->computeIntersections(se, oe, si);
 #if GEOS_DEBUG
 	cerr<<"GeometryGraph::computeEdgeIntersections returns"<<endl;
 #endif

Modified: trunk/src/operation/overlay/OverlayOp.cpp
===================================================================
--- trunk/src/operation/overlay/OverlayOp.cpp	2014-09-22 14:13:11 UTC (rev 4016)
+++ trunk/src/operation/overlay/OverlayOp.cpp	2014-09-23 07:55:54 UTC (rev 4017)
@@ -232,20 +232,40 @@
 
 /*private*/
 void
-OverlayOp::copyPoints(int argIndex)
+OverlayOp::copyPoints(int argIndex, const Envelope *env)
 {
+#define GEOS_DEBUG_COPY_POINTS 1
+
+#ifdef GEOS_DEBUG_COPY_POINTS
+	int copied = 0;
+#endif
+
+	//env = 0; // WARNING: uncomment to disable env-optimization
+
+	// TODO: set env to null if it covers arg geometry envelope
+
 	NodeMap::container& nodeMap=arg[argIndex]->getNodeMap()->nodeMap;
 	for ( NodeMap::const_iterator it=nodeMap.begin(), itEnd=nodeMap.end();
 			it != itEnd; ++it )
 	{
 		Node* graphNode=it->second;
 		assert(graphNode);
+		const Coordinate &coord = graphNode->getCoordinate();
 
-		Node* newNode=graph.addNode(graphNode->getCoordinate());
+		if ( env && ! env->covers(coord) ) continue;
+
+#ifdef GEOS_DEBUG_COPY_POINTS
+		++copied;
+#endif
+		Node* newNode=graph.addNode(coord);
 		assert(newNode);
 
 		newNode->setLabel(argIndex, graphNode->getLabel().getLocation(argIndex));
 	}
+
+#ifdef GEOS_DEBUG_COPY_POINTS
+	cerr << "Copied " << copied << " nodes out of " << nodeMap.size() << " for geom " << argIndex << endl;
+#endif
 }
 
 /*private*/
@@ -648,17 +668,41 @@
 	//throw(TopologyException *)
 {
 
+	// Compute the target envelope
+	const Envelope *env = 0;
+	const Envelope *env0 = getArgGeometry(0)->getEnvelopeInternal();
+	const Envelope *env1 = getArgGeometry(1)->getEnvelopeInternal();
+	Envelope opEnv;
+	if ( resultPrecisionModel->isFloating() )
+	{
+		// Envelope-based optimization only works in floating precision
+		switch (opCode) {
+			case opINTERSECTION:
+				env0->intersection(*env1, opEnv);
+				env = &opEnv;
+				break;
+			case opDIFFERENCE:
+				opEnv = *env0;
+				env = &opEnv;
+				break;
+			default:
+				break;
+		}
+	}
+	//env = 0; // WARNING: uncomment to disable env-optimization
+
 	// copy points from input Geometries.
 	// This ensures that any Point geometries
 	// in the input are considered for inclusion in the result set
-	copyPoints(0);
-	copyPoints(1);
+	copyPoints(0, env);
+	copyPoints(1, env);
 
 	GEOS_CHECK_FOR_INTERRUPTS();
 
 	// node the input Geometries
-	delete arg[0]->computeSelfNodes(li,false);
-	delete arg[1]->computeSelfNodes(li,false);
+	delete arg[0]->computeSelfNodes(li, false, env);
+	GEOS_CHECK_FOR_INTERRUPTS();
+	delete arg[1]->computeSelfNodes(li, false, env);
 
 #if GEOS_DEBUG
 	cerr<<"OverlayOp::computeOverlay: computed SelfNodes"<<endl;
@@ -667,7 +711,7 @@
 	GEOS_CHECK_FOR_INTERRUPTS();
 
 	// compute intersections between edges of the two input geometries
-	delete arg[0]->computeEdgeIntersections(arg[1], &li,true);
+	delete arg[0]->computeEdgeIntersections(arg[1], &li, true, env);
 
 #if GEOS_DEBUG
 	cerr<<"OverlayOp::computeOverlay: computed EdgeIntersections"<<endl;
@@ -679,6 +723,7 @@
 
 	vector<Edge*> baseSplitEdges;
 	arg[0]->computeSplitEdges(&baseSplitEdges);
+	GEOS_CHECK_FOR_INTERRUPTS();
 	arg[1]->computeSplitEdges(&baseSplitEdges);
 
 	GEOS_CHECK_FOR_INTERRUPTS();



More information about the geos-commits mailing list