[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