[geos-commits] [SCM] GEOS branch master updated. fff6a78b4567339a5beab9ab30c3abb15c05fb60

git at osgeo.org git at osgeo.org
Mon Feb 1 08:14:56 PST 2021


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  fff6a78b4567339a5beab9ab30c3abb15c05fb60 (commit)
       via  e5dad0d7b856ea13f5160e20e61836f52c81a39a (commit)
       via  9429ff3732080c6391cf01e78698fb214c5bc91a (commit)
       via  64ccc7ce96108e720f4f59931b047dcec7807866 (commit)
       via  51c6e77ac0ac42f33a41f3eaeef3514c059115dc (commit)
       via  7960e9ff4abafc222bf848f55f8b771acac56a9c (commit)
      from  bb9d66b073cc86faec10954ee79a208433dd51ae (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 fff6a78b4567339a5beab9ab30c3abb15c05fb60
Merge: bb9d66b e5dad0d
Author: Daniel Baston <dbaston at gmail.com>
Date:   Mon Feb 1 11:14:37 2021 -0500

    Merge remote-tracking branch 'brendan-ward/add_densify_c_api'


commit e5dad0d7b856ea13f5160e20e61836f52c81a39a
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Fri Jan 29 19:50:44 2021 -0800

    Ensure densify results in segments <= tolerance

diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index c6f1516..f5d79ec 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -2020,8 +2020,8 @@ extern GEOSGeometry GEOS_DLL *GEOSBufferWithStyle(
 /**
 * Densifies a geometry using a given distance tolerance.
 * Additional vertices will be added to every line segment
-* that is greater than or equal to this tolerance; these
-* vertices will evenly subdivide that segment.
+* that is greater this tolerance; these vertices will
+* evenly subdivide that segment.
 * Only linear components of input geometry are densified.
 * \param g The geometry to densify
 * \param tolerance the distance tolerance to densify
diff --git a/src/geom/util/Densifier.cpp b/src/geom/util/Densifier.cpp
index 9cab359..3f5a7cb 100644
--- a/src/geom/util/Densifier.cpp
+++ b/src/geom/util/Densifier.cpp
@@ -18,6 +18,8 @@
  *
  **********************************************************************/
 
+#include <math.h>
+
 #include <geos/geom/util/Densifier.h>
 #include <geos/geom/CoordinateSequenceFactory.h>
 #include <geos/geom/CoordinateList.h>
@@ -113,7 +115,8 @@ Densifier::densifyPoints(const Coordinate::Vect pts, double distanceTolerance, c
         seg.p1 = *(it + 1);
         coordList.insert(coordList.end(), seg.p0, false);
         double len = seg.getLength();
-        int densifiedSegCount = (int)(len / distanceTolerance) + 1;
+
+        int densifiedSegCount = (int)(ceil(len / distanceTolerance));
         if(densifiedSegCount > 1) {
             double densifiedSegLen = len / densifiedSegCount;
             for(int j = 1; j < densifiedSegCount; j++) {
@@ -124,6 +127,10 @@ Densifier::densifyPoints(const Coordinate::Vect pts, double distanceTolerance, c
                 coordList.insert(coordList.end(), p, false);
             }
         }
+        else {
+            // no densification required; insert the last coordinate and continue
+            coordList.insert(coordList.end(), seg.p1, false);
+        }
     }
     coordList.insert(coordList.end(), pts[pts.size() - 1], false);
     return coordList.toCoordinateArray();
diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
index b379f16..73ef2d7 100644
--- a/tests/unit/capi/GEOSDensifyTest.cpp
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -60,7 +60,7 @@ void object::test<1>()
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSDensify(geom1_, 10.00000000001);
+    geom2_ = GEOSDensify(geom1_, 10.0);
 
     ensure("result not null", geom2_ != nullptr);
     ensure_geometry_equals(geom2_, geom1_);
@@ -68,61 +68,65 @@ void object::test<1>()
 }
 
 
-// Densify with a tolerance equal to length of all outer edges.
-// Outer edges are densified; interior ring edges are not.
+// Densify with a tolerance that evenly subdivides all outer and inner edges.
 template<>
 template<>
 void object::test<2>()
 {
-    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
+    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 1, 1 1))");
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSDensify(geom1_, 10.0);
+    geom2_ = GEOSDensify(geom1_, 5.0);
 
     ensure("result not null", geom2_ != nullptr);
     ensure_geometry_equals(
         geom2_,
-        "POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
+        "POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
 
     ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
-// Densify with a tolerance that evenly subdivides all outer and inner edges.
+// Densify a LINESTRING
 template<>
 template<>
 void object::test<3>()
 {
-    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 1, 1 1))");
+    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )");
     ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSDensify(geom1_, 5.00000000001);
+    geom2_ = GEOSDensify(geom1_, 3);
 
     ensure("result not null", geom2_ != nullptr);
     ensure_geometry_equals(
         geom2_,
-        "POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
+        "LINESTRING (0 0, 0 3, 0 6)");
+
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
-// Densify a LINESTRING
+// Ensure that tolerance results in the right number of subdivisions
+// ceil(6 / 2.9999999) = 3 new segments; 2 new vertices
 template<>
 template<>
 void object::test<4>()
 {
-    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 6 6)");
+    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )");
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSDensify(geom1_, 3.0);
+    geom2_ = GEOSDensify(geom1_, 2.9999999);
 
     ensure("result not null", geom2_ != nullptr);
     ensure_geometry_equals(
         geom2_,
-        "LINESTRING (0 0, 2 2, 4 4, 6 6)");
+        "LINESTRING (0 0, 0 2, 0 4, 0 6)");
 
     ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
+
 // Densify a LINEARRING
 template<>
 template<>
@@ -137,7 +141,7 @@ void object::test<5>()
     ensure("result not null", geom2_ != nullptr);
     ensure_geometry_equals(
         geom2_,
-        "LINEARRING (0 0, 0 2, 0 4, 0 6, 2 6, 4 6, 6 6, 4 4, 2 2, 0 0)");
+        "LINEARRING (0 0, 0 3, 0 6, 3 6, 6 6, 4 4, 2 2, 0 0)");
     ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
@@ -206,6 +210,5 @@ void object::test<9>()
     ensure(geom2_ == nullptr);
 }
 
-
 } // namespace tut
 
diff --git a/tests/xmltester/tests/general/TestDensify.xml b/tests/xmltester/tests/general/TestDensify.xml
index 3a8fdfc..5a68370 100644
--- a/tests/xmltester/tests/general/TestDensify.xml
+++ b/tests/xmltester/tests/general/TestDensify.xml
@@ -16,39 +16,47 @@
 <case>
   <desc>L - single segment</desc>
   <a>    LINESTRING(10 10, 100 10)  </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>    
-	LINESTRING (10 10, 19 10, 28 10, 37 10, 46 10, 55 10, 64 10, 73 10, 82 10, 91 10, 100 10)   
+<test><op name="densify" arg1='A'  arg2='10.0'>
+	LINESTRING (10 10, 20 10, 30 10, 40 10, 50 10, 60 10, 70 10, 80 10, 90 10, 100 10)
 	</op></test>
 </case>
 
 <case>
   <desc>mL - multiple lines</desc>
   <a>    MULTILINESTRING ((10 10, 30 30, 50 10, 70 30), (10 50, 40 50, 70 50))  </a>
-<test><op name="densify" arg1='A'  arg2='8.0'>    
-	MULTILINESTRING ((10 10, 15 15, 20 20, 25 25, 30 30, 35 25, 40 20, 45 15, 50 10, 55 15, 60 20, 65 25, 70 30), 
-  (10 50, 17.5 50, 25 50, 32.5 50, 40 50, 47.5 50, 55 50, 62.5 50, 70 50))   
+<test><op name="densify" arg1='A'  arg2='8.0'>
+	MULTILINESTRING ((10 10, 15 15, 20 20, 25 25, 30 30, 35 25, 40 20, 45 15, 50 10, 55 15, 60 20, 65 25, 70 30),
+  (10 50, 17.5 50, 25 50, 32.5 50, 40 50, 47.5 50, 55 50, 62.5 50, 70 50))
 	</op></test>
 </case>
 
+<case>
+  <desc>A - simple polygon</desc>
+  <a>    POLYGON ((0 0, 0 20, 20 20, 20 0, 0 0))  </a>
+<test><op name="densify" arg1='A'  arg2='10.0'>
+  POLYGON ((0 0, 0 10, 0 20, 10 20, 20 20, 20 10, 20 0, 10 0, 0 0))
+  	</op></test>
+</case>
 
 <case>
   <desc>A - polygon with hole</desc>
   <a>    POLYGON ((0 0, 0 70, 70 70, 70 0, 0 0), (10 10, 10 60, 60 60, 10 10))  </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>    
-POLYGON ((0 0, 0 8.75, 0 17.5, 0 26.25, 0 35, 0 43.75, 0 52.5, 0 61.25, 0 70, 8.75 70, 17.5 70, 26.25 70, 35 70, 43.75 70, 52.5 70, 61.25 70, 70 70, 70 61.25, 70 52.5, 70 43.75, 70 35, 70 26.25, 70 17.5, 70 8.75, 70 0, 61.25 0, 52.5 0, 43.75 0, 35 0, 26.25 0, 17.5 0, 8.75 0, 0 0), 
-  (10 10, 16.25 16.25, 22.5 22.5, 28.75 28.75, 35 35, 41.25 41.25, 47.5 47.5, 53.75 53.75, 60 60, 51.66666666666667 60, 43.333333333333336 60, 35 60, 26.666666666666668 60, 18.333333333333336 60, 10 60, 10 51.66666666666667, 10 43.333333333333336, 10 35, 10 26.666666666666668, 10 18.333333333333336, 10 10))
+<test><op name="densify" arg1='A'  arg2='10.0'>
+  POLYGON ((0 0, 0 10, 0 20, 0 30, 0 40, 0 50, 0 60, 0 70, 10 70, 20 70, 30 70, 40 70, 50 70, 60 70, 70 70, 70 60, 70 50, 70 40, 70 30, 70 20, 70 10, 70 0, 60 0, 50 0, 40 0, 30 0, 20 0, 10 0, 0 0),
+  (10 10, 16.25 16.25, 22.5 22.5, 28.75 28.75, 35 35, 41.25 41.25, 47.5 47.5, 53.75 53.75, 60 60, 50 60, 40 60, 30 60, 20 60, 10 60, 10 50, 10 40, 10 30, 10 20, 10 10))
   	</op></test>
 </case>
 
 <case>
   <desc>mA - multipolygon</desc>
-  <a>    MULTIPOLYGON (((0 0, 0 70, 70 70, 70 0, 0 0), 
-  (10 10, 10 60, 60 60, 10 10)), 
+  <a>    MULTIPOLYGON (((0 0, 0 70, 70 70, 70 0, 0 0),
+  (10 10, 10 60, 60 60, 10 10)),
   ((80 110, 80 70, 120 70, 120 110, 80 110)))  </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>    
-MULTIPOLYGON (((80 110, 88 110, 96 110, 104 110, 112 110, 120 110, 120 102, 120 94, 120 86, 120 78, 120 70, 112 70, 104 70, 96 70, 88 70, 80 70, 80 78, 80 86, 80 94, 80 102, 80 110)), 
-  ((0 0, 0 8.75, 0 17.5, 0 26.25, 0 35, 0 43.75, 0 52.5, 0 61.25, 0 70, 8.75 70, 17.5 70, 26.25 70, 35 70, 43.75 70, 52.5 70, 61.25 70, 70 70, 70 61.25, 70 52.5, 70 43.75, 70 35, 70 26.25, 70 17.5, 70 8.75, 70 0, 61.25 0, 52.5 0, 43.75 0, 35 0, 26.25 0, 17.5 0, 8.75 0, 0 0), 
-    (10 10, 16.25 16.25, 22.5 22.5, 28.75 28.75, 35 35, 41.25 41.25, 47.5 47.5, 53.75 53.75, 60 60, 51.66666666666667 60, 43.333333333333336 60, 35 60, 26.666666666666668 60, 18.333333333333336 60, 10 60, 10 51.66666666666667, 10 43.333333333333336, 10 35, 10 26.666666666666668, 10 18.333333333333336, 10 10)))      	</op></test>
+<test><op name="densify" arg1='A'  arg2='10.0'>
+  MULTIPOLYGON (((80 70, 80 80, 80 90, 80 100, 80 110, 90 110, 100 110, 110 110, 120 110, 120 100, 120 90, 120 80, 120 70, 110 70, 100 70, 90 70, 80 70)),
+    ((0 0, 0 10, 0 20, 0 30, 0 40, 0 50, 0 60, 0 70, 10 70, 20 70, 30 70, 40 70, 50 70, 60 70, 70 70, 70 60, 70 50, 70 40, 70 30, 70 20, 70 10, 70 0, 60 0, 50 0, 40 0, 30 0, 20 0, 10 0, 0 0),
+    (10 10, 16.25 16.25, 22.5 22.5, 28.75 28.75, 35 35, 41.25 41.25, 47.5 47.5, 53.75 53.75, 60 60, 50 60, 40 60, 30 60, 20 60, 10 60, 10 50, 10 40, 10 30, 10 20, 10 10)))
+  </op></test>
 </case>
 
 

commit 9429ff3732080c6391cf01e78698fb214c5bc91a
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Thu Jan 28 18:39:30 2021 -0800

    Move empty check to Densifier; reduce test boilerplate

diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 9e78d9b..34d0d97 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -1117,10 +1117,6 @@ extern "C" {
         using geos::geom::util::Densifier;
 
         return execute(extHandle, [&]() {
-            if (g->isEmpty()) {
-                return g->clone().release();
-            }
-
             Densifier densifier(g);
             densifier.setDistanceTolerance(tolerance);
             auto g3 = densifier.getResultGeometry();
diff --git a/src/geom/util/Densifier.cpp b/src/geom/util/Densifier.cpp
index e0c5387..9cab359 100644
--- a/src/geom/util/Densifier.cpp
+++ b/src/geom/util/Densifier.cpp
@@ -157,6 +157,10 @@ Densifier::setDistanceTolerance(double tol)
 Geometry::Ptr
 Densifier::getResultGeometry() const
 {
+    if (inputGeom->isEmpty()) {
+        return inputGeom->clone();
+    }
+
     DensifyTransformer dt(distanceTolerance);
     return dt.transform(inputGeom);
 }
diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
index 11ad056..b379f16 100644
--- a/tests/unit/capi/GEOSDensifyTest.cpp
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -4,11 +4,9 @@
 #include <tut/tut.hpp>
 // geos
 #include <geos_c.h>
-// std
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
+
+#include "capi_test_utils.h"
+
 
 namespace tut {
 //
@@ -16,28 +14,14 @@ namespace tut {
 //
 
 // Common data used in test cases.
-struct test_capigeosdensify_data {
+struct test_capigeosdensify_data : public capitest::utility {
     GEOSGeometry* geom1_;
     GEOSGeometry* geom2_;
-    GEOSGeometry* geom3_;
     GEOSWKTWriter* w_;
     char* wkt_;
 
-    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_capigeosdensify_data()
-        : geom1_(nullptr), geom2_(nullptr), geom3_(nullptr), w_(nullptr)
+        : geom1_(nullptr), geom2_(nullptr), w_(nullptr)
     {
         initGEOS(notice, notice);
         w_ = GEOSWKTWriter_create();
@@ -48,11 +32,9 @@ struct test_capigeosdensify_data {
     {
         GEOSGeom_destroy(geom1_);
         GEOSGeom_destroy(geom2_);
-        GEOSGeom_destroy(geom3_);
         GEOSWKTWriter_destroy(w_);
         geom1_ = nullptr;
         geom2_ = nullptr;
-        geom3_ = nullptr;
         wkt_ = nullptr;
         finishGEOS();
     }
@@ -81,8 +63,8 @@ void object::test<1>()
     geom2_ = GEOSDensify(geom1_, 10.00000000001);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+    ensure_geometry_equals(geom2_, geom1_);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 
@@ -96,15 +78,14 @@ void object::test<2>()
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSGeomFromWKT("POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
-    ensure(geom2_ != nullptr);
-    GEOSSetSRID(geom2_, 3857);
+    geom2_ = GEOSDensify(geom1_, 10.0);
 
-    geom3_ = GEOSDensify(geom1_, 10.0);
+    ensure("result not null", geom2_ != nullptr);
+    ensure_geometry_equals(
+        geom2_,
+        "POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
 
-    ensure("result not null", geom3_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 // Densify with a tolerance that evenly subdivides all outer and inner edges.
@@ -115,13 +96,12 @@ void object::test<3>()
     geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 1, 1 1))");
     ensure(geom1_ != nullptr);
 
-    geom2_ = GEOSGeomFromWKT("POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
-    ensure(geom2_ != nullptr);
+    geom2_ = GEOSDensify(geom1_, 5.00000000001);
 
-    geom3_ = GEOSDensify(geom1_, 5.00000000001);
-
-    ensure("result not null", geom3_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
+    ensure("result not null", geom2_ != nullptr);
+    ensure_geometry_equals(
+        geom2_,
+        "POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
 }
 
 // Densify a LINESTRING
@@ -133,15 +113,14 @@ void object::test<4>()
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSGeomFromWKT("LINESTRING (0 0, 2 2, 4 4, 6 6)");
-    ensure(geom2_ != nullptr);
-    GEOSSetSRID(geom2_, 3857);
-
-    geom3_ = GEOSDensify(geom1_, 3.0);
+    geom2_ = GEOSDensify(geom1_, 3.0);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+    ensure_geometry_equals(
+        geom2_,
+        "LINESTRING (0 0, 2 2, 4 4, 6 6)");
+
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 // Densify a LINEARRING
@@ -153,15 +132,13 @@ void object::test<5>()
     ensure(geom1_ != nullptr);
     GEOSSetSRID(geom1_, 3857);
 
-    geom2_ = GEOSGeomFromWKT("LINEARRING (0 0, 0 2, 0 4, 0 6, 2 6, 4 6, 6 6, 4 4, 2 2, 0 0)");
-    ensure(geom2_ != nullptr);
-    GEOSSetSRID(geom2_, 3857);
-
-    geom3_ = GEOSDensify(geom1_, 3.0);
+    geom2_ = GEOSDensify(geom1_, 3.0);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+    ensure_geometry_equals(
+        geom2_,
+        "LINEARRING (0 0, 0 2, 0 4, 0 6, 2 6, 4 6, 6 6, 4 4, 2 2, 0 0)");
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 // Densify a POINT
@@ -177,8 +154,8 @@ void object::test<6>()
     geom2_ = GEOSDensify(geom1_, 3.0);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+    ensure_geometry_equals(geom2_, geom1_);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 // Densify a MULTIPOINT
@@ -194,8 +171,8 @@ void object::test<7>()
     geom2_ = GEOSDensify(geom1_, 3.0);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+    ensure_geometry_equals(geom2_, geom1_);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
 }
 
 // Densify an empty polygon
@@ -210,7 +187,7 @@ void object::test<8>()
     geom2_ = GEOSDensify(geom1_, 3.0);
 
     ensure("result not null", geom2_ != nullptr);
-    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
+    ensure_geometry_equals(geom2_, geom1_);
 }
 
 // Densify with an invalid tolerances should fail

commit 64ccc7ce96108e720f4f59931b047dcec7807866
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Thu Jan 28 12:09:07 2021 -0800

    Remove guard for null geometry and associated test

diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 7f7207e..9e78d9b 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -1116,10 +1116,6 @@ extern "C" {
     {
         using geos::geom::util::Densifier;
 
-        if (g == nullptr) {
-            return nullptr;
-        }
-
         return execute(extHandle, [&]() {
             if (g->isEmpty()) {
                 return g->clone().release();
diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
index f0a7fcf..11ad056 100644
--- a/tests/unit/capi/GEOSDensifyTest.cpp
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -213,21 +213,11 @@ void object::test<8>()
     ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
 }
 
-// Densify a null geometry
-// Result should be null
-template<>
-template<>
-void object::test<9>()
-{
-    geom2_ = GEOSDensify(nullptr, 3.0);
-    ensure("result is null", geom2_ == nullptr);
-}
-
 // Densify with an invalid tolerances should fail
 // Note: this raises "IllegalArgumentException: Tolerance must be positive:
 template<>
 template<>
-void object::test<10>()
+void object::test<9>()
 {
     geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
     ensure(geom1_ != nullptr);

commit 51c6e77ac0ac42f33a41f3eaeef3514c059115dc
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Thu Jan 28 11:52:42 2021 -0800

    Fix geometry variable name

diff --git a/capi/geos_c.cpp b/capi/geos_c.cpp
index 82faa3f..c6c23a4 100644
--- a/capi/geos_c.cpp
+++ b/capi/geos_c.cpp
@@ -428,9 +428,9 @@ extern "C" {
     }
 
     Geometry*
-    GEOSDensify(const Geometry* g1, double tolerance)
+    GEOSDensify(const Geometry* g, double tolerance)
     {
-        return GEOSDensify_r(handle, g1, tolerance);
+        return GEOSDensify_r(handle, g, tolerance);
     }
 
 
diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index e276a51..c6f1516 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -2029,7 +2029,7 @@ extern GEOSGeometry GEOS_DLL *GEOSBufferWithStyle(
 * Caller is responsible for freeing with GEOSGeom_destroy().
 */
 extern GEOSGeometry GEOS_DLL *GEOSDensify(
-    const GEOSGeometry* g1,
+    const GEOSGeometry* g,
     double tolerance);
 
 /**
diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 24398ea..7f7207e 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -1112,23 +1112,23 @@ extern "C" {
     }
 
     Geometry*
-    GEOSDensify_r(GEOSContextHandle_t extHandle, const Geometry* g1, double tolerance)
+    GEOSDensify_r(GEOSContextHandle_t extHandle, const Geometry* g, double tolerance)
     {
         using geos::geom::util::Densifier;
 
-        if (g1 == nullptr) {
+        if (g == nullptr) {
             return nullptr;
         }
 
         return execute(extHandle, [&]() {
-            if (g1->isEmpty()) {
-                return g1->clone().release();
+            if (g->isEmpty()) {
+                return g->clone().release();
             }
 
-            Densifier densifier(g1);
+            Densifier densifier(g);
             densifier.setDistanceTolerance(tolerance);
             auto g3 = densifier.getResultGeometry();
-            g3->setSRID(g1->getSRID());
+            g3->setSRID(g->getSRID());
             return g3.release();
         });
     }

commit 7960e9ff4abafc222bf848f55f8b771acac56a9c
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Thu Jan 28 11:35:58 2021 -0800

    Add GEOSDensify to CAPI

diff --git a/NEWS b/NEWS
index 8b1da7a..6c9c555 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Changes in 3.10.0
     library (#868, Paul Ramsey)
   - geosop CLI for GEOS (Martin Davis)
   - Full doxygen of the C-API (Paul Ramsey)
+  - CAPI: GEOSDensify (Brendan Ward)
 
 - Improvements:
   - Preserve ordering of lines in overlay results (Martin Davis)
diff --git a/capi/geos_c.cpp b/capi/geos_c.cpp
index 34b1c75..82faa3f 100644
--- a/capi/geos_c.cpp
+++ b/capi/geos_c.cpp
@@ -428,6 +428,13 @@ extern "C" {
     }
 
     Geometry*
+    GEOSDensify(const Geometry* g1, double tolerance)
+    {
+        return GEOSDensify_r(handle, g1, tolerance);
+    }
+
+
+    Geometry*
     GEOSSingleSidedBuffer(const Geometry* g, double width, int quadsegs,
                           int joinStyle, double mitreLimit, int leftSide)
     {
diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index 863a177..e276a51 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -582,6 +582,12 @@ extern GEOSGeometry GEOS_DLL *GEOSBufferWithStyle_r(
     double width, int quadsegs, int endCapStyle,
 	int joinStyle, double mitreLimit);
 
+/** \see GEOSDensify */
+extern GEOSGeometry GEOS_DLL *GEOSDensify_r(
+    GEOSContextHandle_t handle,
+	const GEOSGeometry* g,
+    double tolerance);
+
 /** \see GEOSOffsetCurve */
 extern GEOSGeometry GEOS_DLL *GEOSOffsetCurve_r(
     GEOSContextHandle_t handle,
@@ -2012,6 +2018,21 @@ extern GEOSGeometry GEOS_DLL *GEOSBufferWithStyle(
     double mitreLimit);
 
 /**
+* Densifies a geometry using a given distance tolerance.
+* Additional vertices will be added to every line segment
+* that is greater than or equal to this tolerance; these
+* vertices will evenly subdivide that segment.
+* Only linear components of input geometry are densified.
+* \param g The geometry to densify
+* \param tolerance the distance tolerance to densify
+* \return The densified geometry, or NULL on exception.
+* Caller is responsible for freeing with GEOSGeom_destroy().
+*/
+extern GEOSGeometry GEOS_DLL *GEOSDensify(
+    const GEOSGeometry* g1,
+    double tolerance);
+
+/**
 * Generates offset curve for linear geometry.
 * Only LineStrings accepted as input.
 * \param g The linear geometry to offset from
diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 052c60f..24398ea 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -37,6 +37,7 @@
 #include <geos/geom/Coordinate.h>
 #include <geos/geom/IntersectionMatrix.h>
 #include <geos/geom/Envelope.h>
+#include <geos/geom/util/Densifier.h>
 #include <geos/index/strtree/SimpleSTRtree.h>
 #include <geos/index/strtree/GeometryItemDistance.h>
 #include <geos/index/ItemVisitor.h>
@@ -1111,6 +1112,28 @@ extern "C" {
     }
 
     Geometry*
+    GEOSDensify_r(GEOSContextHandle_t extHandle, const Geometry* g1, double tolerance)
+    {
+        using geos::geom::util::Densifier;
+
+        if (g1 == nullptr) {
+            return nullptr;
+        }
+
+        return execute(extHandle, [&]() {
+            if (g1->isEmpty()) {
+                return g1->clone().release();
+            }
+
+            Densifier densifier(g1);
+            densifier.setDistanceTolerance(tolerance);
+            auto g3 = densifier.getResultGeometry();
+            g3->setSRID(g1->getSRID());
+            return g3.release();
+        });
+    }
+
+    Geometry*
     GEOSOffsetCurve_r(GEOSContextHandle_t extHandle, const Geometry* g1, double width, int quadsegs, int joinStyle,
                       double mitreLimit)
     {
diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
new file mode 100644
index 0000000..f0a7fcf
--- /dev/null
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -0,0 +1,244 @@
+//
+// Test Suite for C-API GEOSBuffer and GEOSBufferWithStyle
+
+#include <tut/tut.hpp>
+// geos
+#include <geos_c.h>
+// std
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+namespace tut {
+//
+// Test Group
+//
+
+// Common data used in test cases.
+struct test_capigeosdensify_data {
+    GEOSGeometry* geom1_;
+    GEOSGeometry* geom2_;
+    GEOSGeometry* geom3_;
+    GEOSWKTWriter* w_;
+    char* wkt_;
+
+    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_capigeosdensify_data()
+        : geom1_(nullptr), geom2_(nullptr), geom3_(nullptr), w_(nullptr)
+    {
+        initGEOS(notice, notice);
+        w_ = GEOSWKTWriter_create();
+        GEOSWKTWriter_setTrim(w_, 1);
+    }
+
+    ~test_capigeosdensify_data()
+    {
+        GEOSGeom_destroy(geom1_);
+        GEOSGeom_destroy(geom2_);
+        GEOSGeom_destroy(geom3_);
+        GEOSWKTWriter_destroy(w_);
+        geom1_ = nullptr;
+        geom2_ = nullptr;
+        geom3_ = nullptr;
+        wkt_ = nullptr;
+        finishGEOS();
+    }
+
+};
+
+typedef test_group<test_capigeosdensify_data> group;
+typedef group::object object;
+
+group test_capigeosdensify_group("capi::GEOSDensify");
+
+//
+// Test Cases
+//
+
+// Densify with a tolerance slightly larger than length of all edges.
+// Result should match inputs.
+template<>
+template<>
+void object::test<1>()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSDensify(geom1_, 10.00000000001);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+}
+
+
+// Densify with a tolerance equal to length of all outer edges.
+// Outer edges are densified; interior ring edges are not.
+template<>
+template<>
+void object::test<2>()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSGeomFromWKT("POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))");
+    ensure(geom2_ != nullptr);
+    GEOSSetSRID(geom2_, 3857);
+
+    geom3_ = GEOSDensify(geom1_, 10.0);
+
+    ensure("result not null", geom3_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+}
+
+// Densify with a tolerance that evenly subdivides all outer and inner edges.
+template<>
+template<>
+void object::test<3>()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 1, 1 1))");
+    ensure(geom1_ != nullptr);
+
+    geom2_ = GEOSGeomFromWKT("POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0), (1 1, 1 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
+    ensure(geom2_ != nullptr);
+
+    geom3_ = GEOSDensify(geom1_, 5.00000000001);
+
+    ensure("result not null", geom3_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
+}
+
+// Densify a LINESTRING
+template<>
+template<>
+void object::test<4>()
+{
+    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 6 6)");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSGeomFromWKT("LINESTRING (0 0, 2 2, 4 4, 6 6)");
+    ensure(geom2_ != nullptr);
+    GEOSSetSRID(geom2_, 3857);
+
+    geom3_ = GEOSDensify(geom1_, 3.0);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+}
+
+// Densify a LINEARRING
+template<>
+template<>
+void object::test<5>()
+{
+    geom1_ = GEOSGeomFromWKT("LINEARRING (0 0, 0 6, 6 6, 0 0)");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSGeomFromWKT("LINEARRING (0 0, 0 2, 0 4, 0 6, 2 6, 4 6, 6 6, 4 4, 2 2, 0 0)");
+    ensure(geom2_ != nullptr);
+    GEOSSetSRID(geom2_, 3857);
+
+    geom3_ = GEOSDensify(geom1_, 3.0);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom3_, geom2_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom3_), GEOSGetSRID(geom2_));
+}
+
+// Densify a POINT
+// Results should match inputs
+template<>
+template<>
+void object::test<6>()
+{
+    geom1_ = GEOSGeomFromWKT("POINT (0 0)");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSDensify(geom1_, 3.0);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+}
+
+// Densify a MULTIPOINT
+// Results should match inputs
+template<>
+template<>
+void object::test<7>()
+{
+    geom1_ = GEOSGeomFromWKT("MULTIPOINT ((0 0), (10 10))");
+    ensure(geom1_ != nullptr);
+    GEOSSetSRID(geom1_, 3857);
+
+    geom2_ = GEOSDensify(geom1_, 3.0);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
+    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), GEOSGetSRID(geom1_));
+}
+
+// Densify an empty polygon
+// Results should match inputs
+template<>
+template<>
+void object::test<8>()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON EMPTY");
+    ensure(geom1_ != nullptr);
+
+    geom2_ = GEOSDensify(geom1_, 3.0);
+
+    ensure("result not null", geom2_ != nullptr);
+    ensure_equals("result == expected", GEOSEqualsExact(geom2_, geom1_, 0), 1);
+}
+
+// Densify a null geometry
+// Result should be null
+template<>
+template<>
+void object::test<9>()
+{
+    geom2_ = GEOSDensify(nullptr, 3.0);
+    ensure("result is null", geom2_ == nullptr);
+}
+
+// Densify with an invalid tolerances should fail
+// Note: this raises "IllegalArgumentException: Tolerance must be positive:
+template<>
+template<>
+void object::test<10>()
+{
+    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
+    ensure(geom1_ != nullptr);
+
+    geom2_ = GEOSDensify(geom1_, 0.0);
+    ensure(geom2_ == nullptr);
+
+    geom2_ = GEOSDensify(geom1_, -1.0);
+    ensure(geom2_ == nullptr);
+}
+
+
+} // namespace tut
+

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

Summary of changes:
 NEWS                                          |   1 +
 capi/geos_c.cpp                               |   7 +
 capi/geos_c.h.in                              |  21 +++
 capi/geos_ts_c.cpp                            |  15 ++
 src/geom/util/Densifier.cpp                   |  13 +-
 tests/unit/capi/GEOSDensifyTest.cpp           | 214 ++++++++++++++++++++++++++
 tests/xmltester/tests/general/TestDensify.xml |  36 +++--
 7 files changed, 292 insertions(+), 15 deletions(-)
 create mode 100644 tests/unit/capi/GEOSDensifyTest.cpp


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list