[geos-commits] r3593 - in trunk: capi include/geos/noding src/noding tests/unit tests/unit/capi

svn_geos at osgeo.org svn_geos at osgeo.org
Thu Apr 5 09:40:17 EDT 2012


Author: strk
Date: 2012-04-05 06:40:16 -0700 (Thu, 05 Apr 2012)
New Revision: 3593

Added:
   trunk/include/geos/noding/GeometryNoder.h
   trunk/src/noding/GeometryNoder.cpp
   trunk/tests/unit/capi/GEOSNodeTest.cpp
Modified:
   trunk/capi/geos_c.cpp
   trunk/capi/geos_c.h.in
   trunk/capi/geos_ts_c.cpp
   trunk/include/geos/noding/Makefile.am
   trunk/src/noding/IteratedNoder.cpp
   trunk/src/noding/Makefile.am
   trunk/tests/unit/Makefile.am
Log:
Add GEOSNode C-API interface (#496)

Includes a new GeometryNoder C++ class and regression testing.

Modified: trunk/capi/geos_c.cpp
===================================================================
--- trunk/capi/geos_c.cpp	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/capi/geos_c.cpp	2012-04-05 13:40:16 UTC (rev 3593)
@@ -437,6 +437,12 @@
 }
 
 Geometry *
+GEOSNode(const Geometry *g)
+{
+    return GEOSNode_r( handle, g );
+}
+
+Geometry *
 GEOSUnionCascaded(const Geometry *g1)
 {
 	return GEOSUnionCascaded_r( handle, g1 );

Modified: trunk/capi/geos_c.h.in
===================================================================
--- trunk/capi/geos_c.h.in	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/capi/geos_c.h.in	2012-04-05 13:40:16 UTC (rev 3593)
@@ -573,6 +573,7 @@
 extern GEOSGeometry GEOS_DLL *GEOSBoundary(const GEOSGeometry* g1);
 extern GEOSGeometry GEOS_DLL *GEOSUnion(const GEOSGeometry* g1, const GEOSGeometry* g2);
 extern GEOSGeometry GEOS_DLL *GEOSUnaryUnion(const GEOSGeometry* g1);
+extern GEOSGeometry GEOS_DLL *GEOSNode(const GEOSGeometry* g);
 
 /* @deprecated in 3.3.0: use GEOSUnaryUnion instead */
 extern GEOSGeometry GEOS_DLL *GEOSUnionCascaded(const GEOSGeometry* g1);
@@ -605,6 +606,8 @@
                                                    const GEOSGeometry* g1);
 extern GEOSGeometry GEOS_DLL *GEOSGetCentroid_r(GEOSContextHandle_t handle,
                                                 const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSNode_r(GEOSContextHandle_t handle,
+                                         const GEOSGeometry* g);
 
 /*
  * all arguments remain ownership of the caller

Modified: trunk/capi/geos_ts_c.cpp
===================================================================
--- trunk/capi/geos_ts_c.cpp	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/capi/geos_ts_c.cpp	2012-04-05 13:40:16 UTC (rev 3593)
@@ -45,6 +45,7 @@
 #include <geos/algorithm/BoundaryNodeRule.h>
 #include <geos/simplify/DouglasPeuckerSimplifier.h>
 #include <geos/simplify/TopologyPreservingSimplifier.h>
+#include <geos/noding/GeometryNoder.h>
 #include <geos/operation/valid/IsValidOp.h>
 #include <geos/operation/polygonize/Polygonizer.h>
 #include <geos/operation/linemerge/LineMerger.h>
@@ -2018,6 +2019,45 @@
 }
 
 Geometry *
+GEOSNode_r(GEOSContextHandle_t extHandle, const Geometry *g)
+{
+    if ( 0 == extHandle )
+    {
+        return NULL;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return NULL;
+    }
+
+    try
+    {
+        std::auto_ptr<Geometry> g3 = geos::noding::GeometryNoder::node(*g);
+        return g3.release();
+    }
+    catch (const std::exception &e)
+    {
+#if VERBOSE_EXCEPTIONS
+        std::ostringstream s; 
+        s << "Exception on GEOSUnaryUnion with following inputs:" << std::endl;
+        s << "A: "<<g1->toString() << std::endl;
+        s << "B: "<<g2->toString() << std::endl;
+        handle->NOTICE_MESSAGE("%s", s.str().c_str());
+#endif // VERBOSE_EXCEPTIONS
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+    
+    return NULL;
+}
+
+Geometry *
 GEOSUnionCascaded_r(GEOSContextHandle_t extHandle, const Geometry *g1)
 {
     if ( 0 == extHandle )

Added: trunk/include/geos/noding/GeometryNoder.h
===================================================================
--- trunk/include/geos/noding/GeometryNoder.h	                        (rev 0)
+++ trunk/include/geos/noding/GeometryNoder.h	2012-04-05 13:40:16 UTC (rev 3593)
@@ -0,0 +1,69 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2012  Sandro Santilli <strk at keybit.net>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation. 
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * NOTE: this is not in JTS. JTS has a snapround/GeometryNoder though
+ *
+ **********************************************************************/
+
+#ifndef GEOS_NODING_GEOMETRYNODER_H
+#define GEOS_NODING_GEOMETRYNODER_H
+
+#include <noding/SegmentString.h> // for NonConstVect
+
+#include <memory> // for auto_ptr
+
+// Forward declarations
+namespace geos {
+	namespace geom {
+    class Geometry;
+  }
+	namespace noding {
+		class Noder;
+	}
+}
+
+namespace geos {
+namespace noding { // geos.noding
+
+class GeometryNoder
+{
+public:
+
+  static std::auto_ptr<geom::Geometry> node(const geom::Geometry& geom);
+
+  GeometryNoder(const geom::Geometry& g);
+
+  std::auto_ptr<geom::Geometry> getNoded();
+
+private:
+
+  const geom::Geometry& argGeom;
+
+  SegmentString::NonConstVect lineList;
+
+  static void extractSegmentStrings(const geom::Geometry& g,
+                                    SegmentString::NonConstVect& to);
+
+  Noder& getNoder();
+
+  std::auto_ptr<Noder> noder;
+
+  std::auto_ptr<geom::Geometry> toGeometry(SegmentString::NonConstVect& noded);
+
+};
+
+} // namespace geos.noding
+} // namespace geos
+
+#endif // GEOS_NODING_NODER_H

Modified: trunk/include/geos/noding/Makefile.am
===================================================================
--- trunk/include/geos/noding/Makefile.am	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/include/geos/noding/Makefile.am	2012-04-05 13:40:16 UTC (rev 3593)
@@ -11,6 +11,7 @@
     BasicSegmentString.h \
     FastNodingValidator.h \
     FastSegmentSetIntersectionFinder.h \
+    GeometryNoder.h \
     IntersectionAdder.h \
     IntersectionFinderAdder.h \
     IteratedNoder.h \

Added: trunk/src/noding/GeometryNoder.cpp
===================================================================
--- trunk/src/noding/GeometryNoder.cpp	                        (rev 0)
+++ trunk/src/noding/GeometryNoder.cpp	2012-04-05 13:40:16 UTC (rev 3593)
@@ -0,0 +1,182 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.osgeo.org
+ *
+ * Copyright (C) 2012  Sandro Santilli <strk at keybit.net>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation. 
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * NOTE: this is not in JTS. JTS has a snapround/GeometryNoder though
+ *
+ **********************************************************************/
+
+#include <noding/GeometryNoder.h>
+#include <noding/SegmentString.h>
+#include <noding/NodedSegmentString.h>
+#include <noding/OrientedCoordinateArray.h>
+#include <noding/Noder.h>
+#include <geom/Geometry.h>
+#include <geom/PrecisionModel.h>
+#include <geom/CoordinateSequence.h>
+#include <geom/GeometryFactory.h>
+#include <geom/LineString.h>
+
+#include <noding/IteratedNoder.h>
+
+#include <algorithm/LineIntersector.h>
+#include <noding/IntersectionAdder.h>
+#include <noding/MCIndexNoder.h>
+
+#include <noding/snapround/SimpleSnapRounder.h>
+#include <noding/snapround/MCIndexSnapRounder.h>
+
+#include <memory> // for auto_ptr
+#include <iostream> 
+
+namespace geos {
+namespace noding { // geos.noding
+
+namespace {
+
+/**
+ * Add every linear element in a geometry into SegmentString vector
+ */
+class SegmentStringExtractor: public geom::GeometryComponentFilter {
+public:
+  SegmentStringExtractor(SegmentString::NonConstVect& to)
+    : _to(to)
+  {}
+
+  void filter_ro(const geom::Geometry * g) {
+    const geom::LineString *ls = dynamic_cast<const geom::LineString *>(g);
+    if ( ls ) {
+      geom::CoordinateSequence* coord = ls->getCoordinates(); 
+      // coord ownership transferred to SegmentString
+      SegmentString *ss = new NodedSegmentString(coord, 0);
+      _to.push_back(ss);
+    }
+  }
+private:
+  SegmentString::NonConstVect& _to;
+};
+
+}
+
+
+/* public static */
+std::auto_ptr<geom::Geometry>
+GeometryNoder::node(const geom::Geometry& geom)
+{
+  GeometryNoder noder(geom);
+  return noder.getNoded();
+}
+
+/* public */
+GeometryNoder::GeometryNoder(const geom::Geometry& g)
+  :
+  argGeom(g)
+{
+}
+
+/* private */
+std::auto_ptr<geom::Geometry>
+GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges)
+{
+  const geom::GeometryFactory *geomFact = argGeom.getFactory();
+
+  std::set< OrientedCoordinateArray > ocas;
+
+  // Create a geometry out of the noded substrings.
+  std::vector< geom::Geometry* >* lines = new std::vector< geom::Geometry * >();
+  lines->reserve(nodedEdges.size());
+  for ( unsigned int i = 0, n = nodedEdges.size(); i < n; ++i )
+  {
+    SegmentString* ss = nodedEdges [i];
+
+    const geom::CoordinateSequence* coords = ss->getCoordinates();
+
+    // Check if an equivalent edge is known 
+    OrientedCoordinateArray oca1( *coords );
+    if ( ocas.insert(oca1).second ) {
+      geom::Geometry* tmp = geomFact->createLineString( coords->clone() );
+      lines->push_back( tmp );
+    }
+  }
+
+  std::auto_ptr<geom::Geometry> noded ( geomFact->createMultiLineString( lines ) );
+
+  return noded;
+}
+
+/* public */
+std::auto_ptr<geom::Geometry> 
+GeometryNoder::getNoded()
+{
+  SegmentString::NonConstVect lineList;
+  extractSegmentStrings(argGeom, lineList);
+
+  Noder& noder = getNoder();
+
+  noder.computeNodes( &lineList );
+  SegmentString::NonConstVect* nodedEdges = noder.getNodedSubstrings();
+
+  std::auto_ptr<geom::Geometry> noded = toGeometry(*nodedEdges);
+
+  for ( unsigned int i = 0, n = nodedEdges->size(); i < n; ++i )
+    delete ( *nodedEdges )[i];
+  delete nodedEdges;
+
+  for (size_t i=0, n=lineList.size(); i<n; ++i)
+    delete lineList[i];
+  lineList.clear();
+
+  return noded;
+}
+
+/* private static */
+void
+GeometryNoder::extractSegmentStrings(const geom::Geometry& g,
+                                     SegmentString::NonConstVect& to)
+{
+  SegmentStringExtractor ex(to);
+	g.apply_ro(&ex);
+}
+
+/* private */
+Noder&
+GeometryNoder::getNoder()
+{
+  if ( ! noder.get() )
+  {
+    const geom::PrecisionModel *pm = argGeom.getFactory()->getPrecisionModel();
+#if 0
+    using algorithm::LineIntersector;
+		LineIntersector li;
+		IntersectionAdder intersectionAdder(li);
+    noder.reset( new MCIndexNoder(&intersectionAdder) );
+#else
+
+    IteratedNoder* in = new IteratedNoder(pm);
+    //in->setMaximumIterations(0);
+    noder.reset( in );
+
+    //using snapround::SimpleSnapRounder;
+    //noder.reset( new SimpleSnapRounder(*pm) );
+
+    //using snapround::MCIndexSnapRounder;
+    //noder.reset( new MCIndexSnapRounder(*pm) );
+#endif
+  }
+  return *noder;
+  
+
+}
+
+} // namespace geos.noding
+} // namespace geos

Modified: trunk/src/noding/IteratedNoder.cpp
===================================================================
--- trunk/src/noding/IteratedNoder.cpp	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/src/noding/IteratedNoder.cpp	2012-04-05 13:40:16 UTC (rev 3593)
@@ -88,7 +88,7 @@
 		{
 			stringstream s;
 			s<<"Iterated noding failed to converge after "<<
-                                    nodingIterationCount<<" iterations";
+                                    nodingIterationCount << " iterations";
 			throw util::TopologyException(s.str());
 		}
 		lastNodesCreated = nodesCreated;

Modified: trunk/src/noding/Makefile.am
===================================================================
--- trunk/src/noding/Makefile.am	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/src/noding/Makefile.am	2012-04-05 13:40:16 UTC (rev 3593)
@@ -11,6 +11,7 @@
 	BasicSegmentString.cpp \
 	FastNodingValidator.cpp \
 	FastSegmentSetIntersectionFinder.cpp \
+	GeometryNoder.cpp \
 	IntersectionAdder.cpp \
 	IntersectionFinderAdder.cpp \
 	IteratedNoder.cpp \

Modified: trunk/tests/unit/Makefile.am
===================================================================
--- trunk/tests/unit/Makefile.am	2012-04-05 12:05:34 UTC (rev 3592)
+++ trunk/tests/unit/Makefile.am	2012-04-05 13:40:16 UTC (rev 3593)
@@ -116,6 +116,7 @@
 	capi/GEOSGeom_extractUniquePointsTest.cpp \
 	capi/GEOSOrientationIndex.cpp \
 	capi/GEOSLineString_PointTest.cpp \
+	capi/GEOSNodeTest.cpp \
 	capi/GEOSSnapTest.cpp \
 	capi/GEOSSharedPathsTest.cpp \
 	capi/GEOSRelateBoundaryNodeRuleTest.cpp \

Added: trunk/tests/unit/capi/GEOSNodeTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSNodeTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSNodeTest.cpp	2012-04-05 13:40:16 UTC (rev 3593)
@@ -0,0 +1,120 @@
+// 
+// Test Suite for C-API GEOSNode
+
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeosnode_data
+    {
+        GEOSGeometry* geom1_;
+        GEOSGeometry* geom2_;
+        GEOSWKTWriter* w_;
+
+        static void notice(const char *fmt, ...)
+        {
+            std::fprintf( stdout, "NOTICE: ");
+
+            va_list ap;
+            va_start(ap, fmt);
+            std::vfprintf(stdout, fmt, ap);
+            va_end(ap);
+        
+            std::fprintf(stdout, "\n");
+        }
+
+        test_capigeosnode_data()
+            : geom1_(0), geom2_(0), w_(0)
+        {
+            initGEOS(notice, notice);
+            w_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(w_, 1);
+        }       
+
+        ~test_capigeosnode_data()
+        {
+            GEOSGeom_destroy(geom1_);
+            GEOSGeom_destroy(geom2_);
+            GEOSWKTWriter_destroy(w_);
+            geom1_ = 0;
+            geom2_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeosnode_data> group;
+    typedef group::object object;
+
+    group test_capigeosnode_group("capi::GEOSNode");
+
+    //
+    // Test Cases
+    //
+
+    /// Self-intersecting line
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        geom1_ = GEOSGeomFromWKT("LINESTRING(0 0, 10 10, 10 0, 0 10)");
+        geom2_ = GEOSNode(geom1_);
+
+        char* wkt_c = GEOSWKTWriter_write(w_, geom2_);
+        std::string out(wkt_c); 
+        free(wkt_c);
+
+        ensure_equals(out,
+          "MULTILINESTRING ((0 0, 5 5), (5 5, 10 10, 10 0, 5 5), (5 5, 0 10))"
+        );
+    }
+
+    /// Overlapping lines
+    template<>
+    template<>
+    void object::test<2>()
+    {
+        geom1_ = GEOSGeomFromWKT("MULTILINESTRING((0 0, 2 0, 4 0),(5 0, 3 0, 1 0))");
+        geom2_ = GEOSNode(geom1_);
+
+        char* wkt_c = GEOSWKTWriter_write(w_, geom2_);
+        std::string out(wkt_c); 
+        free(wkt_c);
+
+        ensure_equals(out,
+          "MULTILINESTRING ((0 0, 1 0), (1 0, 2 0), (2 0, 3 0), (3 0, 4 0), (5 0, 4 0))"
+        );
+    }
+
+    /// Equal lines
+    template<>
+    template<>
+    void object::test<3>()
+    {
+        geom1_ = GEOSGeomFromWKT("MULTILINESTRING((0 0, 2 0, 4 0),(0 0, 2 0, 4 0))");
+        geom2_ = GEOSNode(geom1_);
+
+        char* wkt_c = GEOSWKTWriter_write(w_, geom2_);
+        std::string out(wkt_c); 
+        free(wkt_c);
+
+        ensure_equals(out,
+          "MULTILINESTRING ((0 0, 2 0), (2 0, 4 0))"
+        );
+    }
+    
+
+} // namespace tut
+



More information about the geos-commits mailing list