[geos-commits] [SCM] GEOS branch master updated. 87ce4c1a06460d82fa97fb1c7736434015928ac5

git at osgeo.org git at osgeo.org
Mon Aug 24 12:40:11 PDT 2020


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".

The branch, master has been updated
       via  87ce4c1a06460d82fa97fb1c7736434015928ac5 (commit)
      from  80f78fb880a911262d4021aca4cf2b47715a40d9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 87ce4c1a06460d82fa97fb1c7736434015928ac5
Author: Sandro Santilli <strk at kbt.io>
Date:   Fri Aug 21 12:05:45 2020 +0200

    Expose "precise" overlay CAPI functions
    
    Provide "Prec" suffixed functions for all overlay ops, having
    them call OverlayNGSnapIfNeeded when passed a gridSize=0 and
    precision-mediated OverlayNG otherwise.
    
    Enable existing GEOSUnion test
    Add GEOSUnionPrec and GEOSIntersectionPrec tests
    
    Includes NEWS entry

diff --git a/NEWS b/NEWS
index 8aa7dd0..34d6548 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,8 @@ Changes in 3.9.0
 2020-xx-xx
 
 - New things:
-  -  MaximumInscribedCircle and LargestEmptyCircle (JTS-530, Paul Ramsey)
+  - MaximumInscribedCircle and LargestEmptyCircle (JTS-530, Paul Ramsey)
+  - CAPI: Fixed precision overlay operations (Sandro Santilli, Paul Ramsey)
 
 - Improvements:
   - Stack allocate segments in OverlapUnion (Paul Ramsey)
diff --git a/capi/geos_c.cpp b/capi/geos_c.cpp
index 363d8bf..d5d79a4 100644
--- a/capi/geos_c.cpp
+++ b/capi/geos_c.cpp
@@ -416,6 +416,12 @@ extern "C" {
     }
 
     Geometry*
+    GEOSIntersectionPrec(const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return GEOSIntersectionPrec_r(handle, g1, g2, gridSize);
+    }
+
+    Geometry*
     GEOSBuffer(const Geometry* g, double width, int quadrantsegments)
     {
         return GEOSBuffer_r(handle, g, width, quadrantsegments);
@@ -494,6 +500,12 @@ extern "C" {
     }
 
     Geometry*
+    GEOSDifferencePrec(const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return GEOSDifferencePrec_r(handle, g1, g2, gridSize);
+    }
+
+    Geometry*
     GEOSBoundary(const Geometry* g)
     {
         return GEOSBoundary_r(handle, g);
@@ -506,18 +518,36 @@ extern "C" {
     }
 
     Geometry*
+    GEOSSymDifferencePrec(const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return GEOSSymDifferencePrec_r(handle, g1, g2, gridSize);
+    }
+
+    Geometry*
     GEOSUnion(const Geometry* g1, const Geometry* g2)
     {
         return GEOSUnion_r(handle, g1, g2);
     }
 
     Geometry*
+    GEOSUnionPrec(const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return GEOSUnionPrec_r(handle, g1, g2, gridSize);
+    }
+
+    Geometry*
     GEOSUnaryUnion(const Geometry* g)
     {
         return GEOSUnaryUnion_r(handle, g);
     }
 
     Geometry*
+    GEOSUnaryUnionPrec(const Geometry* g, double gridSize)
+    {
+        return GEOSUnaryUnionPrec_r(handle, g, gridSize);
+    }
+
+    Geometry*
     GEOSCoverageUnion(const Geometry* g)
     {
         return GEOSCoverageUnion_r(handle, g);
diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index ccccbc1..6fdf5f1 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -550,6 +550,10 @@ extern GEOSGeometry GEOS_DLL *GEOSEnvelope_r(GEOSContextHandle_t handle,
 extern GEOSGeometry GEOS_DLL *GEOSIntersection_r(GEOSContextHandle_t handle,
                                                  const GEOSGeometry* g1,
                                                  const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSIntersectionPrec_r(GEOSContextHandle_t handle,
+                                                 const GEOSGeometry* g1,
+                                                 const GEOSGeometry* g2,
+                                                 double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSConvexHull_r(GEOSContextHandle_t handle,
                                                const GEOSGeometry* g);
 
@@ -583,16 +587,31 @@ extern int GEOS_DLL GEOSMinimumClearance_r(GEOSContextHandle_t handle,
 extern GEOSGeometry GEOS_DLL *GEOSDifference_r(GEOSContextHandle_t handle,
                                                const GEOSGeometry* g1,
                                                const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSDifferencePrec_r(GEOSContextHandle_t handle,
+                                                   const GEOSGeometry* g1,
+                                                   const GEOSGeometry* g2,
+                                                   double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSSymDifference_r(GEOSContextHandle_t handle,
                                                   const GEOSGeometry* g1,
                                                   const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSSymDifferencePrec_r(GEOSContextHandle_t handle,
+                                                      const GEOSGeometry* g1,
+                                                      const GEOSGeometry* g2,
+                                                      double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSBoundary_r(GEOSContextHandle_t handle,
                                              const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSUnion_r(GEOSContextHandle_t handle,
                                           const GEOSGeometry* g1,
                                           const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSUnionPrec_r(GEOSContextHandle_t handle,
+                                              const GEOSGeometry* g1,
+                                              const GEOSGeometry* g2,
+                                              double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSUnaryUnion_r(GEOSContextHandle_t handle,
                                           const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSUnaryUnionPrec_r(GEOSContextHandle_t handle,
+                                          const GEOSGeometry* g,
+                                          double gridSize);
 /* GEOSCoverageUnion is an optimized union algorithm for polygonal inputs that are correctly
  * noded and do not overlap. It will not generate an error (return NULL) for inputs that
  * do not satisfy this constraint. */
@@ -1593,6 +1612,7 @@ extern void GEOS_DLL GEOSGeom_destroy(GEOSGeometry* g);
 
 extern GEOSGeometry GEOS_DLL *GEOSEnvelope(const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSIntersection(const GEOSGeometry* g1, const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSIntersectionPrec(const GEOSGeometry* g1, const GEOSGeometry* g2, double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSConvexHull(const GEOSGeometry* g);
 
 /* Returns the minimum rotated rectangular POLYGON which encloses the input geometry. The rectangle
@@ -1669,10 +1689,14 @@ extern int GEOS_DLL GEOSMinimumClearance(const GEOSGeometry* g, double* d);
 extern GEOSGeometry GEOS_DLL *GEOSMinimumClearanceLine(const GEOSGeometry* g);
 
 extern GEOSGeometry GEOS_DLL *GEOSDifference(const GEOSGeometry* g1, const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSDifferencePrec(const GEOSGeometry* g1, const GEOSGeometry* g2, double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSSymDifference(const GEOSGeometry* g1, const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSSymDifferencePrec(const GEOSGeometry* g1, const GEOSGeometry* g2, double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSBoundary(const GEOSGeometry* g);
 extern GEOSGeometry GEOS_DLL *GEOSUnion(const GEOSGeometry* g1, const GEOSGeometry* g2);
+extern GEOSGeometry GEOS_DLL *GEOSUnionPrec(const GEOSGeometry* g1, const GEOSGeometry* g2, double gridSize);
 extern GEOSGeometry GEOS_DLL *GEOSUnaryUnion(const GEOSGeometry* g);
+extern GEOSGeometry GEOS_DLL *GEOSUnaryUnionPrec(const GEOSGeometry* g, double gridSize);
 
 /* GEOSCoverageUnion is an optimized union algorithm for polygonal inputs that are correctly
  * noded and do not overlap. It will not generate an error (return NULL) for inputs that
diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 519da23..361d634 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -63,6 +63,8 @@
 #include <geos/operation/distance/IndexedFacetDistance.h>
 #include <geos/operation/linemerge/LineMerger.h>
 #include <geos/operation/overlay/OverlayOp.h>
+#include <geos/operation/overlayng/OverlayNG.h>
+#include <geos/operation/overlayng/OverlayNGSnapIfNeeded.h>
 #include <geos/operation/overlay/snap/GeometrySnapper.h>
 #include <geos/operation/intersection/Rectangle.h>
 #include <geos/operation/intersection/RectangleIntersection.h>
@@ -146,7 +148,10 @@ using geos::io::WKTWriter;
 using geos::io::WKBReader;
 using geos::io::WKBWriter;
 
+using geos::geom::PrecisionModel;
 using geos::operation::overlay::OverlayOp;
+using geos::operation::overlayng::OverlayNG;
+using geos::operation::overlayng::OverlayNGSnapIfNeeded;
 using geos::operation::overlay::overlayOp;
 using geos::operation::geounion::CascadedPolygonUnion;
 using geos::operation::distance::IndexedFacetDistance;
@@ -1041,6 +1046,28 @@ extern "C" {
     }
 
     Geometry*
+    GEOSIntersectionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return execute(extHandle, [&]() {
+            using geos::geom::PrecisionModel;
+
+            std::unique_ptr<PrecisionModel> pm;
+            if(gridSize != 0) {
+                pm.reset(new PrecisionModel(1.0 / gridSize));
+            }
+            else {
+                pm.reset(new PrecisionModel());
+            }
+            auto g3 = gridSize != 0 ?
+              OverlayNG::overlay(g1, g2, OverlayNG::INTERSECTION, pm.get())
+              :
+              OverlayNGSnapIfNeeded::Overlay(g1, g2, OverlayNG::INTERSECTION);
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSBuffer_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadrantsegments)
     {
         return execute(extHandle, [&]() {
@@ -1227,6 +1254,27 @@ extern "C" {
     }
 
     Geometry*
+    GEOSDifferencePrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return execute(extHandle, [&]() {
+
+            std::unique_ptr<PrecisionModel> pm;
+            if(gridSize != 0) {
+                pm.reset(new PrecisionModel(1.0 / gridSize));
+            }
+            else {
+                pm.reset(new PrecisionModel());
+            }
+            auto g3 = gridSize != 0 ?
+                OverlayNG::overlay(g1, g2, OverlayNG::DIFFERENCE, pm.get())
+                :
+                OverlayNGSnapIfNeeded::Overlay(g1, g2, OverlayNG::DIFFERENCE);
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSBoundary_r(GEOSContextHandle_t extHandle, const Geometry* g1)
     {
         return execute(extHandle, [&]() {
@@ -1247,6 +1295,27 @@ extern "C" {
     }
 
     Geometry*
+    GEOSSymDifferencePrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return execute(extHandle, [&]() {
+
+            std::unique_ptr<PrecisionModel> pm;
+            if(gridSize != 0) {
+                pm.reset(new PrecisionModel(1.0 / gridSize));
+            }
+            else {
+                pm.reset(new PrecisionModel());
+            }
+            auto g3 = gridSize != 0 ?
+              OverlayNG::overlay(g1, g2, OverlayNG::SYMDIFFERENCE, pm.get())
+              :
+              OverlayNGSnapIfNeeded::Overlay(g1, g2, OverlayNG::SYMDIFFERENCE);
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSUnion_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2)
     {
         return execute(extHandle, [&]() {
@@ -1257,6 +1326,27 @@ extern "C" {
     }
 
     Geometry*
+    GEOSUnionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, const Geometry* g2, double gridSize)
+    {
+        return execute(extHandle, [&]() {
+
+            std::unique_ptr<PrecisionModel> pm;
+            if(gridSize != 0) {
+                pm.reset(new PrecisionModel(1.0 / gridSize));
+            }
+            else {
+                pm.reset(new PrecisionModel());
+            }
+            auto g3 = gridSize != 0 ?
+              OverlayNG::overlay(g1, g2, OverlayNG::UNION, pm.get())
+              :
+              OverlayNGSnapIfNeeded::Overlay(g1, g2, OverlayNG::UNION);
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSCoverageUnion_r(GEOSContextHandle_t extHandle, const Geometry* g)
     {
         return execute(extHandle, [&]() {
@@ -1277,6 +1367,27 @@ extern "C" {
     }
 
     Geometry*
+    GEOSUnaryUnionPrec_r(GEOSContextHandle_t extHandle, const Geometry* g1, double gridSize)
+    {
+        return execute(extHandle, [&]() {
+
+            std::unique_ptr<PrecisionModel> pm;
+            if(gridSize != 0) {
+                pm.reset(new PrecisionModel(1.0 / gridSize));
+            }
+            else {
+                pm.reset(new PrecisionModel());
+            }
+            auto g3 = gridSize != 0 ?
+              OverlayNG::geomunion(g1, pm.get())
+              :
+              OverlayNGSnapIfNeeded::Union(g1);
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSNode_r(GEOSContextHandle_t extHandle, const Geometry* g)
     {
         return execute(extHandle, [&]() {
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index 44b2ad2..deb5d10 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -85,6 +85,7 @@ geos_unit_SOURCES = \
 	capi/GEOSInterpolateTest.cpp \
 	capi/GEOSInterruptTest.cpp \
 	capi/GEOSIntersectionTest.cpp \
+	capi/GEOSIntersectionPrecTest.cpp \
 	capi/GEOSIntersectsTest.cpp \
 	capi/GEOSisClosedTest.cpp \
 	capi/GEOSisValidDetailTest.cpp \
@@ -110,6 +111,8 @@ geos_unit_SOURCES = \
 	capi/GEOSSimplifyTest.cpp \
 	capi/GEOSSnapTest.cpp \
 	capi/GEOSSTRtreeTest.cpp \
+	capi/GEOSUnionTest.cpp \
+	capi/GEOSUnionPrecTest.cpp \
 	capi/GEOSUnaryUnionTest.cpp \
 	capi/GEOSUserDataTest.cpp \
 	capi/GEOSVoronoiDiagramTest.cpp \
diff --git a/tests/unit/capi/GEOSIntersectionPrecTest.cpp b/tests/unit/capi/GEOSIntersectionPrecTest.cpp
new file mode 100644
index 0000000..7c733bb
--- /dev/null
+++ b/tests/unit/capi/GEOSIntersectionPrecTest.cpp
@@ -0,0 +1,215 @@
+//
+// Test Suite for C-API GEOSintersection
+
+#include <tut/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_capigeosintersectionprec_data {
+    GEOSWKTWriter* wktw_;
+    GEOSGeometry* geom1_;
+    GEOSGeometry* geom2_;
+    GEOSGeometry* geom3_;
+    GEOSGeometry* expected_;
+
+    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_capigeosintersectionprec_data()
+        : geom1_(nullptr), geom2_(nullptr), geom3_(nullptr)
+    {
+        initGEOS(notice, notice);
+        wktw_ = GEOSWKTWriter_create();
+        GEOSWKTWriter_setTrim(wktw_, 1);
+        GEOSWKTWriter_setOutputDimension(wktw_, 3);
+        geom1_ = nullptr;
+        geom2_ = nullptr;
+        geom3_ = nullptr;
+        expected_ = nullptr;
+    }
+
+    std::string
+    toWKT(GEOSGeometry* g)
+    {
+        char* wkt = GEOSWKTWriter_write(wktw_, g);
+        std::string ret(wkt);
+        GEOSFree(wkt);
+        return ret;
+    }
+
+    int
+    same(GEOSGeometry* g1, GEOSGeometry* g2, double tolerance)
+    {
+        GEOSNormalize(g1);
+        GEOSNormalize(g2);
+        return GEOSEqualsExact(g1, g2, tolerance);
+    }
+
+    ~test_capigeosintersectionprec_data()
+    {
+        GEOSWKTWriter_destroy(wktw_);
+        GEOSGeom_destroy(geom1_);
+        GEOSGeom_destroy(geom2_);
+        GEOSGeom_destroy(geom3_);
+        if (expected_) GEOSGeom_destroy(expected_);
+        geom1_ = nullptr;
+        geom2_ = nullptr;
+        geom3_ = nullptr;
+        expected_ = nullptr;
+        finishGEOS();
+    }
+
+};
+
+typedef test_group<test_capigeosintersectionprec_data> group;
+typedef group::object object;
+
+group test_capigeosintersectionprec_group("capi::GEOSIntersectionPrec");
+
+//
+// Test Cases
+//
+
+template<>
+template<>
+void object::test<1>
+()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON EMPTY");
+    geom2_ = GEOSGeomFromWKT("POLYGON EMPTY");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+    ensure(nullptr != geom3_);
+    ensure_equals(toWKT(geom3_), std::string("POLYGON EMPTY"));
+}
+
+template<>
+template<>
+void object::test<2>
+()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON((1 1,1 5,5 5,5 1,1 1))");
+    geom2_ = GEOSGeomFromWKT("POINT(2 2)");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+    ensure(nullptr != geom3_);
+    ensure_equals(toWKT(geom3_), std::string("POINT (2 2)"));
+}
+
+template<>
+template<>
+void object::test<3>
+()
+{
+    geom1_ = GEOSGeomFromWKT("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))");
+    geom2_ = GEOSGeomFromWKT("POLYGON((-1 1,-1 2,2 2,2 1,-1 1))");
+    expected_ = GEOSGeomFromWKT("POLYGON ((0 1, 0 2, 2 2, 2 1, 0 1))");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+
+    ensure(nullptr != geom3_);
+    ensure(same(geom3_, expected_, 0.1));
+}
+
+/* See http://trac.osgeo.org/geos/ticket/719 */
+template<>
+template<>
+void object::test<4>
+()
+{
+    geom1_ = GEOSGeomFromWKT("MULTIPOLYGON(((0 0,5 10,10 0,0 0),(1 1,1 2,2 2,2 1,1 1),(100 100,100 102,102 102,102 100,100 100)))");
+    geom2_ = GEOSGeomFromWKT("POLYGON((0 1,0 2,10 2,10 1,0 1))");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+    GEOSNormalize(geom3_);
+
+    ensure(nullptr != geom3_);
+
+    expected_ = GEOSGeomFromWKT("GEOMETRYCOLLECTION (LINESTRING (1 2, 2 2), LINESTRING (2 1, 1 1), POLYGON ((0.5 1, 1 2, 1 1, 0.5 1)), POLYGON ((9 2, 9.5 1, 2 1, 2 2, 9 2)))");
+    GEOSNormalize(expected_);
+    ensure(GEOSEqualsExact(expected_, geom3_, 0.00001));
+}
+
+template<>
+template<>
+void object::test<5>
+()
+{
+    geom1_ = GEOSGeomFromWKT("LINESTRING(0 0, 10 0)");
+    geom2_ = GEOSGeomFromWKT("LINESTRING(0 1, 10 1)");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+    ensure(nullptr != geom3_);
+    ensure_equals(toWKT(geom3_), std::string("LINESTRING EMPTY"));
+}
+
+template<>
+template<>
+void object::test<6>
+()
+{
+    geom1_ = GEOSGeomFromWKT("LINESTRING(0 0, 10 0)");
+    geom2_ = GEOSGeomFromWKT("LINESTRING(0 1, 10 1)");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 10);
+    ensure(nullptr != geom3_);
+    ensure_equals(toWKT(geom3_), std::string("LINESTRING (0 0, 10 0)"));
+}
+
+template<>
+template<>
+void object::test<7>
+()
+{
+    geom1_ = GEOSGeomFromWKT("LINESTRING(0 0, 10 0)");
+    geom2_ = GEOSGeomFromWKT("LINESTRING(0 1, 10 0)");
+
+    ensure(nullptr != geom1_);
+    ensure(nullptr != geom2_);
+
+    geom3_ = GEOSIntersectionPrec(geom1_, geom2_, 0);
+    ensure(nullptr != geom3_);
+    ensure_equals(toWKT(geom3_), std::string("POINT (10 0)"));
+}
+
+} // namespace tut
+
diff --git a/tests/unit/capi/GEOSUnionPrecTest.cpp b/tests/unit/capi/GEOSUnionPrecTest.cpp
new file mode 100644
index 0000000..b5c2ab9
--- /dev/null
+++ b/tests/unit/capi/GEOSUnionPrecTest.cpp
@@ -0,0 +1,47 @@
+#include <tut/tut.hpp>
+// geos
+#include <geos_c.h>
+
+#include "capi_test_utils.h"
+
+namespace tut {
+//
+// Test Group
+//
+
+struct test_geosunionprec_data : public capitest::test_handlers {};
+
+typedef test_group<test_geosunionprec_data> group;
+typedef group::object object;
+
+group test_geosunionprec("capi::GEOSUnionPrec");
+
+template<>
+template<>
+void object::test<1>()
+{
+    GEOSGeometry* a = GEOSGeomFromWKT("POINT (1.9 8.2)");
+    GEOSGeometry* b = GEOSGeomFromWKT("POINT (4.1 9.8)");
+
+    ensure(a);
+    ensure(b);
+
+    GEOSSetSRID(a, 4326);
+
+    GEOSGeometry* result = GEOSUnionPrec(a, b, 2);
+    GEOSGeometry* expected = GEOSGeomFromWKT("MULTIPOINT (2 8, 4 10)");
+
+    ensure(result);
+    ensure(expected);
+
+    ensure_equals(GEOSEqualsExact(result, expected, 0), 1);
+    ensure_equals(GEOSGetSRID(a), GEOSGetSRID(result));
+
+    GEOSGeom_destroy(a);
+    GEOSGeom_destroy(b);
+    GEOSGeom_destroy(result);
+    GEOSGeom_destroy(expected);
+}
+
+} // namespace tut
+

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                               |   3 +-
 capi/geos_c.cpp                                    |  30 ++++++
 capi/geos_c.h.in                                   |  24 +++++
 capi/geos_ts_c.cpp                                 | 111 +++++++++++++++++++++
 tests/unit/Makefile.am                             |   3 +
 ...ectionTest.cpp => GEOSIntersectionPrecTest.cpp} |  66 ++++++++++--
 .../{GEOSUnionTest.cpp => GEOSUnionPrecTest.cpp}   |  14 +--
 7 files changed, 234 insertions(+), 17 deletions(-)
 copy tests/unit/capi/{GEOSIntersectionTest.cpp => GEOSIntersectionPrecTest.cpp} (68%)
 copy tests/unit/capi/{GEOSUnionTest.cpp => GEOSUnionPrecTest.cpp} (57%)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list