[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