[geos-commits] r4092 - in trunk: . capi php php/test tests/unit tests/unit/capi

svn_geos at osgeo.org svn_geos at osgeo.org
Fri Oct 2 09:47:34 PDT 2015


Author: strk
Date: 2015-10-02 09:47:34 -0700 (Fri, 02 Oct 2015)
New Revision: 4092

Added:
   trunk/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp
Modified:
   trunk/NEWS
   trunk/capi/geos_c.cpp
   trunk/capi/geos_c.h.in
   trunk/capi/geos_ts_c.cpp
   trunk/php/geos.c
   trunk/php/test/test.php
   trunk/tests/unit/Makefile.am
Log:
Add GEOSGeom_setPrecision function to C-API (#713)

Include unit tests and PHP bindings

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/NEWS	2015-10-02 16:47:34 UTC (rev 4092)
@@ -2,7 +2,9 @@
 2015-MM-DD
 
 - New things:
+  - CAPI: GEOSGeom_setPrecision (#713) - PHP: Geometry->setPrecision
 - Improvements:
+  - ...
 - C++ API changes:
   - Automatic memory management for GeometryFactory objects
 

Modified: trunk/capi/geos_c.cpp
===================================================================
--- trunk/capi/geos_c.cpp	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/capi/geos_c.cpp	2015-10-02 16:47:34 UTC (rev 4092)
@@ -838,6 +838,12 @@
     return GEOSGeom_clone_r( handle, g );
 }
 
+GEOSGeometry *
+GEOSGeom_setPrecision(const GEOSGeometry *g, double gridSize, int flags)
+{
+	return GEOSGeom_setPrecision_r(handle, g, gridSize, flags);
+}
+
 int
 GEOSGeom_getDimensions(const Geometry *g)
 {

Modified: trunk/capi/geos_c.h.in
===================================================================
--- trunk/capi/geos_c.h.in	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/capi/geos_c.h.in	2015-10-02 16:47:34 UTC (rev 4092)
@@ -941,6 +941,34 @@
 extern int GEOS_DLL GEOSNormalize_r(GEOSContextHandle_t handle,
                                     GEOSGeometry* g);
 
+/** This option causes #GEOSGeom_setPrecision_r()
+  * to not attempt at preserving the topology */
+#define GEOS_PREC_NO_TOPO         (1<<0)
+
+/** This option causes #GEOSGeom_setPrecision_r()
+  * to retain collapsed elements */
+#define GEOS_PREC_KEEP_COLLAPSED  (1<<1)
+
+/**
+ * Set the geometry's precision, optionally rounding all its
+ * coordinates to the precision grid (if it changes).
+ *
+ * Note that operations will always be performed in the precision
+ * of the geometry with higher precision (smaller "gridSize").
+ * That same precision will be attached to the operation outputs.
+ *
+ * @param gridSize size of the precision grid, or 0 for FLOATING
+ *                 precision.
+ * @param flags The bitwise OR of one of more of the
+ *              @ref GEOS_PREC_NO_TOPO "precision options"
+ * @retuns NULL on exception or a new GEOSGeometry object
+ *
+ */
+extern GEOSGeometry GEOS_DLL *GEOSGeom_setPrecision_r(
+                                       GEOSContextHandle_t handle,
+                                       const GEOSGeometry *g,
+                                       double gridSize, int flags);
+
 /* Return -1 on exception */
 extern int GEOS_DLL GEOSGetNumInteriorRings_r(GEOSContextHandle_t handle,
                                               const GEOSGeometry* g);
@@ -1687,6 +1715,10 @@
 /* Return -1 on exception */
 extern int GEOS_DLL GEOSNormalize(GEOSGeometry* g);
 
+/* Return NULL on exception */
+extern GEOSGeometry GEOS_DLL *GEOSGeom_setPrecision(
+	const GEOSGeometry *g, double gridSize, int flags);
+
 /* Return -1 on exception */
 extern int GEOS_DLL GEOSGetNumInteriorRings(const GEOSGeometry* g);
 

Modified: trunk/capi/geos_ts_c.cpp
===================================================================
--- trunk/capi/geos_ts_c.cpp	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/capi/geos_ts_c.cpp	2015-10-02 16:47:34 UTC (rev 4092)
@@ -61,6 +61,7 @@
 #include <geos/operation/sharedpaths/SharedPathsOp.h>
 #include <geos/operation/union/CascadedPolygonUnion.h>
 #include <geos/operation/valid/IsValidOp.h>
+#include <geos/precision/GeometryPrecisionReducer.h>
 #include <geos/linearref/LengthIndexedLine.h>
 #include <geos/triangulate/DelaunayTriangulationBuilder.h>
 #include <geos/triangulate/VoronoiDiagramBuilder.h>
@@ -132,6 +133,7 @@
 using geos::operation::geounion::CascadedPolygonUnion;
 using geos::operation::buffer::BufferParameters;
 using geos::operation::buffer::BufferBuilder;
+using geos::precision::GeometryPrecisionReducer;
 using geos::util::IllegalArgumentException;
 using geos::algorithm::distance::DiscreteHausdorffDistance;
 
@@ -4226,6 +4228,63 @@
     return NULL;
 }
 
+GEOSGeometry *
+GEOSGeom_setPrecision_r(GEOSContextHandle_t extHandle, const GEOSGeometry *g,
+                                          double gridSize, int flags)
+{
+    using namespace geos::geom;
+
+    assert(0 != g);
+
+    if ( 0 == extHandle )
+    {
+        return NULL;
+    }
+
+    GEOSContextHandleInternal_t *handle = 0;
+    handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+    if ( 0 == handle->initialized )
+    {
+        return NULL;
+    }
+
+    try
+    {
+        const PrecisionModel *pm = g->getPrecisionModel();
+        double cursize = pm->isFloating() ? 0 : 1.0/pm->getScale();
+        std::auto_ptr<PrecisionModel> newpm;
+        if ( gridSize ) newpm.reset( new PrecisionModel(1.0/gridSize) );
+        else newpm.reset( new PrecisionModel() );
+        GeometryFactory::unique_ptr gf =
+            GeometryFactory::create( newpm.get(), g->getSRID() );
+        Geometry *ret;
+        if ( gridSize && cursize != gridSize )
+        {
+          // We need to snap the geometry
+          GeometryPrecisionReducer reducer( *gf );
+          reducer.setPointwise( flags & GEOS_PREC_NO_TOPO );
+          reducer.setRemoveCollapsedComponents( ! (flags & GEOS_PREC_KEEP_COLLAPSED) );
+          ret = reducer.reduce( *g ).release();
+        }
+        else
+        {
+          // No need or willing to snap, just change the factory
+          ret = gf->createGeometry(g);
+        }
+        return ret;
+    }
+    catch (const std::exception &e)
+    {
+        handle->ERROR_MESSAGE("%s", e.what());
+    }
+    catch (...)
+    {
+        handle->ERROR_MESSAGE("Unknown exception thrown");
+    }
+
+    return NULL;
+}
+
 int
 GEOSGeom_getDimensions_r(GEOSContextHandle_t extHandle, const Geometry *g)
 {

Modified: trunk/php/geos.c
===================================================================
--- trunk/php/geos.c	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/php/geos.c	2015-10-02 16:47:34 UTC (rev 4092)
@@ -204,6 +204,7 @@
 PHP_METHOD(Geometry, relateBoundaryNodeRule); 
 PHP_METHOD(Geometry, simplify); /* also does topology-preserving */
 PHP_METHOD(Geometry, normalize);
+PHP_METHOD(Geometry, setPrecision);
 PHP_METHOD(Geometry, extractUniquePoints); 
 PHP_METHOD(Geometry, disjoint);
 PHP_METHOD(Geometry, touches);
@@ -270,6 +271,7 @@
     PHP_ME(Geometry, relateBoundaryNodeRule, NULL, 0)
     PHP_ME(Geometry, simplify, NULL, 0)
     PHP_ME(Geometry, normalize, NULL, 0)
+    PHP_ME(Geometry, setPrecision, NULL, 0)
     PHP_ME(Geometry, extractUniquePoints, NULL, 0)
     PHP_ME(Geometry, disjoint, NULL, 0)
     PHP_ME(Geometry, touches, NULL, 0)
@@ -1042,6 +1044,32 @@
 }
 
 /**
+ * GEOSGeometry GEOSGeometry::setPrecision(gridsize, [flags])
+ */
+PHP_METHOD(Geometry, setPrecision)
+{
+    GEOSGeometry *this;
+    double gridSize;
+    long int flags = 0;
+    GEOSGeometry *ret;
+
+    this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
+
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l",
+            &gridSize, &flags) == FAILURE) {
+        RETURN_NULL();
+    }
+
+    ret = GEOSGeom_setPrecision(this, gridSize, flags);
+
+    if ( ! ret ) RETURN_NULL(); /* should get an exception first */
+
+    /* return_value is a zval */
+    object_init_ex(return_value, Geometry_ce_ptr);
+    setRelay(return_value, ret);
+}
+
+/**
  * GEOSGeometry GEOSGeometry::normalize()
  */
 PHP_METHOD(Geometry, normalize)
@@ -2885,6 +2913,11 @@
         GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE,
         CONST_CS|CONST_PERSISTENT);
 
+    REGISTER_LONG_CONSTANT("GEOS_PREC_NO_TOPO", GEOS_PREC_NO_TOPO,
+        CONST_CS|CONST_PERSISTENT);
+    REGISTER_LONG_CONSTANT("GEOS_PREC_KEEP_COLLAPSED", GEOS_PREC_NO_TOPO,
+        CONST_CS|CONST_PERSISTENT);
+
     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MOD2", GEOSRELATE_BNR_MOD2,
         CONST_CS|CONST_PERSISTENT);
     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_OGC", GEOSRELATE_BNR_OGC,

Modified: trunk/php/test/test.php
===================================================================
--- trunk/php/test/test.php	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/php/test/test.php	2015-10-02 16:47:34 UTC (rev 4092)
@@ -1356,6 +1356,45 @@
             , $writer->write($gs));
     }
 
+    public function testGeometry_setPrecision()
+    {
+        $reader = new GEOSWKTReader();
+        $writer = new GEOSWKTWriter();
+        $writer->setRoundingPrecision(0);
+
+        $g = $reader->read('LINESTRING(0 0, 3 4, 5 10, 10 0, 10 9, 5 11, 0 9)');
+        $g = $g->setPrecision(2);
+        $this->assertEquals(
+            'LINESTRING (0 0, 4 4, 6 10, 10 0, 10 10, 6 12, 0 10)'
+            , $writer->write($g));
+
+        $g = $g->setPrecision(0);
+        $this->assertEquals(
+            'LINESTRING (0 0, 4 4, 6 10, 10 0, 10 10, 6 12, 0 10)'
+            , $writer->write($g));
+
+        $g = $g->setPrecision(8);
+        $this->assertEquals(
+            'LINESTRING (0 0, 8 8, 8 0, 8 8, 8 16, 0 8)'
+            , $writer->write($g));
+
+        $g = $g->setPrecision(10);
+        $this->assertEquals(
+            'LINESTRING (0 0, 10 10, 10 0, 10 10, 10 20, 0 10)'
+            , $writer->write($g));
+
+        $g = $g->setPrecision(20);
+        $this->assertEquals(
+            'LINESTRING (0 0, 20 20, 20 0, 20 20, 0 20)'
+            , $writer->write($g));
+
+        $g = $reader->read('POLYGON((0 0, 2 0, 2 2, 0 2, 0 0))');
+        $g = $g->setPrecision(20);
+        $this->assertEquals(
+            'POLYGON EMPTY'
+            , $writer->write($g));
+    }
+
     public function testGeometry_extractUniquePoints()
     {
         $reader = new GEOSWKTReader();

Modified: trunk/tests/unit/Makefile.am
===================================================================
--- trunk/tests/unit/Makefile.am	2015-10-02 09:59:33 UTC (rev 4091)
+++ trunk/tests/unit/Makefile.am	2015-10-02 16:47:34 UTC (rev 4092)
@@ -121,6 +121,7 @@
 	capi/GEOSVoronoiDiagramTest.cpp \
 	capi/GEOSGeomFromWKBTest.cpp \
 	capi/GEOSGeomToWKTTest.cpp \
+	capi/GEOSGeom_setPrecisionTest.cpp \
 	capi/GEOSGetCentroidTest.cpp \
 	capi/GEOSContainsTest.cpp \
 	capi/GEOSConvexHullTest.cpp \

Added: trunk/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp
===================================================================
--- trunk/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp	                        (rev 0)
+++ trunk/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp	2015-10-02 16:47:34 UTC (rev 4092)
@@ -0,0 +1,178 @@
+// 
+// Test Suite for C-API GEOSGeom_setPrecision_r
+
+#include <tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+namespace tut
+{
+    //
+    // Test Group
+    //
+
+    // Common data used in test cases.
+    struct test_capigeosgeomsetprecision_data
+    {
+        GEOSWKTWriter* wktw_;
+        GEOSGeometry* geom1_;
+        GEOSGeometry* geom2_;
+        GEOSGeometry* geom3_;
+
+        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");
+        }
+
+        GEOSGeometry *fromWKT(const char *wkt)
+        {
+          GEOSGeometry *g = GEOSGeomFromWKT(wkt);
+          ensure(g);
+          return g;
+        }
+        std::string toWKT(GEOSGeometry* g)
+        {
+          char* wkt = GEOSWKTWriter_write(wktw_, g);
+          std::string ret (wkt);
+          GEOSFree(wkt);
+          return ret;
+        }
+
+        test_capigeosgeomsetprecision_data()
+                : geom1_(0), geom2_(0), geom3_(0)
+        {
+            initGEOS(notice, notice);
+            wktw_ = GEOSWKTWriter_create();
+            GEOSWKTWriter_setTrim(wktw_, 1);
+            GEOSWKTWriter_setRoundingPrecision(wktw_, 10);
+            //GEOSWKTWriter_setOutputDimension(wktw_, 3);
+        }       
+
+        ~test_capigeosgeomsetprecision_data()
+        {
+            GEOSGeom_destroy(geom1_);
+            GEOSGeom_destroy(geom2_);
+            if( geom3_ )
+                GEOSGeom_destroy(geom3_);
+            GEOSWKTWriter_destroy(wktw_);
+
+            geom1_ = 0;
+            geom2_ = 0;
+            geom3_ = 0;
+            finishGEOS();
+        }
+
+    };
+
+    typedef test_group<test_capigeosgeomsetprecision_data> group;
+    typedef group::object object;
+
+    group test_capigeosgeomsetprecision_group("capi::GEOSGeom_setPrecision");
+
+    //
+    // Test Cases
+    //
+
+    template<>
+    template<>
+    void object::test<1>()
+    {
+        geom1_ = fromWKT("POLYGON EMPTY");
+        ensure(geom1_);
+        geom3_ = GEOSGeom_setPrecision(geom1_, 2.0, 0);
+        ensure(geom3_);
+        ensure_equals(toWKT(geom3_), std::string("POLYGON EMPTY"));
+    }
+
+    template<>
+    template<>
+    void object::test<2>()
+    {
+        geom1_ = fromWKT("LINESTRING(-3 6, 9 1)");
+        ensure(geom1_);
+        geom3_ = GEOSGeom_setPrecision(geom1_, 2.0, 0);
+        ensure(geom3_);
+        ensure_equals(toWKT(geom3_), std::string("LINESTRING (-2 6, 10 2)"));
+    }
+
+    // See effects of precision reduction on intersection operation
+    template<>
+    template<>
+    void object::test<3>()
+    {
+        geom1_ = fromWKT("LINESTRING(2 10, 4 30)");
+        ensure(geom1_);
+        geom2_ = fromWKT("LINESTRING(4 10, 2 30)");
+        ensure(geom2_);
+        geom3_ = GEOSIntersection(geom1_, geom2_);
+        ensure(geom3_);
+        ensure_equals(toWKT(geom3_), std::string("POINT (3 20)"));
+
+        GEOSGeometry* g;
+
+        // Both inputs with precision grid of 2.0
+        g = GEOSGeom_setPrecision(geom1_, 2.0, 0); ensure(g);
+        GEOSGeom_destroy(geom1_); geom1_ = g;
+        g = GEOSGeom_setPrecision(geom2_, 2.0, 0); ensure(g);
+        GEOSGeom_destroy(geom2_); geom2_ = g;
+        GEOSGeom_destroy(geom3_);
+        geom3_ = GEOSIntersection(geom1_, geom2_);
+        ensure(geom3_);
+        ensure_equals(toWKT(geom3_), std::string("POINT (4 20)"));
+
+        // One input with precision grid of 0.5, the other of 2.0
+        g = GEOSGeom_setPrecision(geom1_, 0.5, 0); ensure(g);
+        GEOSGeom_destroy(geom1_); geom1_ = g;
+        GEOSGeom_destroy(geom3_);
+        geom3_ = GEOSIntersection(geom1_, geom2_);
+        ensure(geom3_);
+        ensure_equals(toWKT(geom3_), std::string("POINT (3 20)"));
+    }
+
+    // Retain (or not) topology
+    template<>
+    template<>
+    void object::test<4>()
+    {
+        geom1_ = fromWKT("POLYGON((10 10,20 10,16 15,20 20, 10 20, 14 15, 10 10))");
+        ensure(geom1_);
+        geom2_ = GEOSGeom_setPrecision(geom1_, 5.0, 0);
+        ensure_equals(toWKT(geom2_), std::string(
+          "MULTIPOLYGON (((10 10, 15 15, 20 10, 10 10)), ((15 15, 10 20, 20 20, 15 15)))"
+        ));
+        geom3_ = GEOSGeom_setPrecision(geom1_, 5.0, GEOS_PREC_NO_TOPO);
+        ensure_equals(toWKT(geom3_), std::string(
+          "POLYGON ((10 10, 20 10, 15 15, 20 20, 10 20, 15 15, 10 10))"
+        ));
+    }
+
+    // Retain (or not) collapsed elements
+    template<>
+    template<>
+    void object::test<5>()
+    {
+        geom1_ = fromWKT("LINESTRING(1 0, 2 0)");
+        ensure(geom1_);
+        geom2_ = GEOSGeom_setPrecision(geom1_, 5.0, 0);
+        ensure_equals(toWKT(geom2_), std::string(
+          "LINESTRING EMPTY"
+        ));
+        geom3_ = GEOSGeom_setPrecision(geom1_, 5.0, GEOS_PREC_KEEP_COLLAPSED);
+        ensure_equals(toWKT(geom3_), std::string(
+          "LINESTRING (0 0, 0 0)"
+        ));
+    }
+ 
+} // namespace tut
+



More information about the geos-commits mailing list