[geos-commits] [SCM] GEOS branch master updated. 17ab55a55aeed3e5a0a83b05428463bf1646471f

git at osgeo.org git at osgeo.org
Wed Feb 3 13:48:30 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  17ab55a55aeed3e5a0a83b05428463bf1646471f (commit)
       via  ba888c27909a9e1255a27ec8dc659ca2e48a8a84 (commit)
       via  e507ccfb95139b2b610e3cc017ef390ee76ed671 (commit)
       via  580dcbaef1f27d794636e2e3c8c2b1e0ff565306 (commit)
       via  3c3b17edc880787526a3c81f09f559254b1b9825 (commit)
      from  230ee8b46c80a37861da72ddca9c9940b3354239 (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 17ab55a55aeed3e5a0a83b05428463bf1646471f
Merge: ba888c2 3c3b17e
Author: Daniel Baston <dbaston at gmail.com>
Date:   Wed Feb 3 16:48:21 2021 -0500

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


commit ba888c27909a9e1255a27ec8dc659ca2e48a8a84
Merge: 230ee8b e507ccf
Author: Daniel Baston <dbaston at gmail.com>
Date:   Wed Feb 3 16:48:16 2021 -0500

    Merge branch 'geom-release'


commit e507ccfb95139b2b610e3cc017ef390ee76ed671
Author: Daniel Baston <dbaston at gmail.com>
Date:   Wed Feb 3 14:36:28 2021 -0500

    Add methods to release objects owned by some Geometry types
    
    This can allow for more efficient implementation implementation of some
    operations such as GeometryCombiner. Objects that release their
    components are left in an undefined state. This approach is taken
    because it is analogous to the state of moved-from objects, and because
    reverting the objects to a defined state can be expensive. For example,
    an empty Polygon must own an empty LinearRing, which must own an empty
    CoordinateSequence.

diff --git a/include/geos/geom/Envelope.h b/include/geos/geom/Envelope.h
index dd891ac..b61ab57 100644
--- a/include/geos/geom/Envelope.h
+++ b/include/geos/geom/Envelope.h
@@ -520,6 +520,8 @@ private:
 /// Checks if two Envelopes are equal (2D only check)
 GEOS_DLL bool operator==(const Envelope& a, const Envelope& b);
 
+GEOS_DLL bool operator!=(const Envelope& a, const Envelope& b);
+
 } // namespace geos::geom
 } // namespace geos
 
diff --git a/include/geos/geom/Envelope.inl b/include/geos/geom/Envelope.inl
index 07ff498..a1b5ec3 100644
--- a/include/geos/geom/Envelope.inl
+++ b/include/geos/geom/Envelope.inl
@@ -344,6 +344,11 @@ Envelope::distanceSquaredToCoordinate(const Coordinate & c, const Coordinate & p
     return dx*dx + dy*dy;
 }
 
+INLINE
+bool operator!=(const Envelope& a, const Envelope& b) {
+    return !(a == b);
+}
+
 } // namespace geos::geom
 } // namespace geos
 
diff --git a/include/geos/geom/GeometryCollection.h b/include/geos/geom/GeometryCollection.h
index 434e95f..aeb8245 100644
--- a/include/geos/geom/GeometryCollection.h
+++ b/include/geos/geom/GeometryCollection.h
@@ -163,6 +163,15 @@ public:
     const Geometry* getGeometryN(std::size_t n) const override;
 
     /**
+     * \brief
+     * Take ownership of the sub-geometries managed by this GeometryCollection.
+     * After releasing the sub-geometries, the collection should be considered
+     * in a moved-from state and should not be accessed.
+     * @return vector of sub-geometries
+     */
+    std::vector<std::unique_ptr<Geometry>> releaseGeometries();
+
+    /**
      * Creates a GeometryCollection with
      * every component reversed.
      * The order of the components in the collection are not reversed.
diff --git a/include/geos/geom/LineString.h b/include/geos/geom/LineString.h
index d9e3616..5b0d3d0 100644
--- a/include/geos/geom/LineString.h
+++ b/include/geos/geom/LineString.h
@@ -92,6 +92,15 @@ public:
 
     virtual const Coordinate& getCoordinateN(std::size_t n) const;
 
+    /**
+     * \brief
+     * Take ownership of the CoordinateSequence managed by this geometry.
+     * After releasing the coordinates, the geometry should be considered
+     * in a moved-from state and should not be accessed.
+     * @return this Geometry's CoordinateSequence.
+     */
+    std::unique_ptr<CoordinateSequence> releaseCoordinates();
+
     /// Returns line dimension (1)
     Dimension::DimensionType getDimension() const override;
 
diff --git a/include/geos/geom/Polygon.h b/include/geos/geom/Polygon.h
index 4b85e25..20b8e32 100644
--- a/include/geos/geom/Polygon.h
+++ b/include/geos/geom/Polygon.h
@@ -110,12 +110,32 @@ public:
     /// Returns the exterior ring (shell)
     const LinearRing* getExteriorRing() const;
 
+    /**
+     * \brief
+     * Take ownership of this Polygon's exterior ring.
+     * After releasing the exterior ring, the Polygon should be
+     * considered in a moved-from state and should not be accessed,
+     * except to release the interior rings (if desired.)
+     * @return exterior ring
+     */
+    std::unique_ptr<LinearRing> releaseExteriorRing();
+
     /// Returns number of interior rings (hole)
     std::size_t getNumInteriorRing() const;
 
     /// Get nth interior ring (hole)
     const LinearRing* getInteriorRingN(std::size_t n) const;
 
+    /**
+     * \brief
+     * Take ownership of this Polygon's interior rings.
+     * After releasing the rings, the Polygon should be
+     * considered in a moved-from state and should not be accessed,
+     * except to release the exterior ring (if desired.)
+     * @return vector of rings (may be empty)
+     */
+    std::vector<std::unique_ptr<LinearRing>> releaseInteriorRings();
+
     std::string getGeometryType() const override;
     GeometryTypeId getGeometryTypeId() const override;
     bool equalsExact(const Geometry* other, double tolerance = 0) const override;
diff --git a/src/geom/GeometryCollection.cpp b/src/geom/GeometryCollection.cpp
index 6742f76..0671c2a 100644
--- a/src/geom/GeometryCollection.cpp
+++ b/src/geom/GeometryCollection.cpp
@@ -175,6 +175,14 @@ GeometryCollection::getGeometryN(std::size_t n) const
     return geometries[n].get();
 }
 
+std::vector<std::unique_ptr<Geometry>>
+GeometryCollection::releaseGeometries()
+{
+    auto ret = std::move(geometries);
+    geometryChanged();
+    return ret;
+}
+
 size_t
 GeometryCollection::getNumPoints() const
 {
diff --git a/src/geom/LineString.cpp b/src/geom/LineString.cpp
index 6ac932e..1c5727f 100644
--- a/src/geom/LineString.cpp
+++ b/src/geom/LineString.cpp
@@ -122,6 +122,14 @@ LineString::getCoordinatesRO() const
     return points.get();
 }
 
+std::unique_ptr<CoordinateSequence>
+LineString::releaseCoordinates()
+{
+    auto ret = std::move(points);
+    geometryChanged();
+    return ret;
+}
+
 const Coordinate&
 LineString::getCoordinateN(std::size_t n) const
 {
diff --git a/src/geom/Polygon.cpp b/src/geom/Polygon.cpp
index 708563a..0d78f6b 100644
--- a/src/geom/Polygon.cpp
+++ b/src/geom/Polygon.cpp
@@ -191,6 +191,13 @@ Polygon::getExteriorRing() const
     return shell.get();
 }
 
+std::unique_ptr<LinearRing>
+Polygon::releaseExteriorRing()
+{
+    envelope.reset();
+    return std::move(shell);
+}
+
 size_t
 Polygon::getNumInteriorRing() const
 {
@@ -203,6 +210,12 @@ Polygon::getInteriorRingN(std::size_t n) const
     return holes[n].get();
 }
 
+std::vector<std::unique_ptr<LinearRing>>
+Polygon::releaseInteriorRings()
+{
+    return std::move(holes);
+}
+
 std::string
 Polygon::getGeometryType() const
 {
@@ -313,6 +326,7 @@ Polygon::convexHull() const
     return getExteriorRing()->convexHull();
 }
 
+
 void
 Polygon::normalize()
 {
diff --git a/tests/unit/geom/GeometryCollectionTest.cpp b/tests/unit/geom/GeometryCollectionTest.cpp
index 3ca8da0..934af2d 100644
--- a/tests/unit/geom/GeometryCollectionTest.cpp
+++ b/tests/unit/geom/GeometryCollectionTest.cpp
@@ -143,4 +143,15 @@ void object::test<6>
     ensure(!gc->isDimensionStrict(geos::geom::Dimension::A));
 }
 
+template<>
+template<>
+void object::test<7>()
+{
+    auto gc = geos::io::WKTReader().read<geos::geom::GeometryCollection>("GEOMETRYCOLLECTION (POINT (1 1), LINESTRING (1 1, 2 2))");
+    ensure_equals(*gc->getEnvelopeInternal(), geos::geom::Envelope(1, 2, 1, 2));
+
+    auto components = gc->releaseGeometries();
+    ensure_equals(components.size(), 2u);
+}
+
 } // namespace tut
diff --git a/tests/unit/geom/LineStringTest.cpp b/tests/unit/geom/LineStringTest.cpp
index 1d4d214..f97eedb 100644
--- a/tests/unit/geom/LineStringTest.cpp
+++ b/tests/unit/geom/LineStringTest.cpp
@@ -527,5 +527,19 @@ void object::test<29>
     ensure(c != nullptr);
 }
 
+// releaseCoordinates
+template<>
+template<>
+void object::test<30>()
+{
+    auto ls = reader_.read<geos::geom::LineString>("LINESTRING (0 0, 10 10)");
+    auto env = ls->getEnvelopeInternal();
+    ensure_equals(*env, geos::geom::Envelope(0,10, 0, 10));
+
+    auto cs = ls->releaseCoordinates();
+    ensure_equals(cs->getSize(), 2u);
+}
+
+
 } // namespace tut
 
diff --git a/tests/unit/geom/PolygonTest.cpp b/tests/unit/geom/PolygonTest.cpp
index 970aee2..458119c 100644
--- a/tests/unit/geom/PolygonTest.cpp
+++ b/tests/unit/geom/PolygonTest.cpp
@@ -34,6 +34,10 @@ struct test_polygon_data {
     typedef std::unique_ptr<geos::geom::Polygon> PolygonAutoPtr;
     typedef geos::geom::GeometryFactory GeometryFactory;
 
+    using Geometry = geos::geom::Geometry;
+    using Envelope = geos::geom::Envelope;
+    using Polygon = geos::geom::Polygon;
+
     geos::geom::PrecisionModel pm_;
     GeometryFactory::Ptr factory_;
     geos::io::WKTReader reader_;
@@ -632,4 +636,19 @@ void object::test<43>
         poly->compareTo(poly3.get()) != 0);
 }
 
+template<>
+template<>
+void object::test<44>()
+{
+    auto poly = reader_.read<Polygon>("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 3, 3 3, 3 2, 2 2))");
+    auto env = poly->getEnvelopeInternal();
+    ensure_equals(*env, Envelope(0,10, 0, 10));
+
+    auto shell = poly->releaseExteriorRing();
+    ensure_equals(*shell->getEnvelopeInternal(), Envelope(0, 10, 0, 10));
+
+    auto holes = poly->releaseInteriorRings();
+    ensure_equals(holes.size(), 1u);
+}
+
 } // namespace tut

commit 580dcbaef1f27d794636e2e3c8c2b1e0ff565306
Author: Daniel Baston <dbaston at gmail.com>
Date:   Wed Feb 3 14:18:29 2021 -0500

    Add typed variant of WKTReader::read

diff --git a/include/geos/io/WKTReader.h b/include/geos/io/WKTReader.h
index ff222d4..0184a15 100644
--- a/include/geos/io/WKTReader.h
+++ b/include/geos/io/WKTReader.h
@@ -25,6 +25,7 @@
 #include <geos/geom/GeometryFactory.h>
 #include <geos/geom/CoordinateSequence.h>
 #include <geos/geom/Geometry.h>
+#include <geos/io/ParseException.h>
 #include <string>
 
 // Forward declarations
@@ -81,6 +82,17 @@ public:
     ~WKTReader();
 
     /// Parse a WKT string returning a Geometry
+    template<typename T>
+    std::unique_ptr<T> read(const std::string& wkt) const {
+        auto g = read(wkt);
+        auto gt = dynamic_cast<const T*>(g.get());
+        if (!gt) {
+            // Can improve this message once there's a good way to get a string repr of T
+            throw io::ParseException("Unexpected WKT type");
+        }
+        return std::unique_ptr<T>(static_cast<T*>(g.release()));
+    }
+
     std::unique_ptr<geom::Geometry> read(const std::string& wellKnownText) const;
 
 //	Geometry* read(Reader& reader);	//Not implemented yet
diff --git a/tests/unit/io/WKTReaderTest.cpp b/tests/unit/io/WKTReaderTest.cpp
index ddc44c1..179eeb8 100644
--- a/tests/unit/io/WKTReaderTest.cpp
+++ b/tests/unit/io/WKTReaderTest.cpp
@@ -9,7 +9,10 @@
 #include <geos/geom/PrecisionModel.h>
 #include <geos/geom/GeometryFactory.h>
 #include <geos/geom/Geometry.h>
+#include <geos/geom/LineString.h>
+#include <geos/geom/Point.h>
 #include <geos/geom/CoordinateSequence.h>
+#include <geos/util/GEOSException.h>
 #include <geos/util/IllegalArgumentException.h>
 // std
 #include <sstream>
@@ -254,4 +257,31 @@ void object::test<10>
     ensure("dimension(POLYGON ((0 0, 1 0, 1 1 1, 0 1, 0 0)) == 2", geom->getCoordinateDimension() == 2);
 }
 
+template<>
+template<>
+void object::test<11>
+()
+{
+    // Correct type
+    auto ls = wktreader.read<geos::geom::LineString>("LINESTRING (5 8, 5 7)");
+    ensure(ls != nullptr);
+
+    // Exception thrown on incorrect type
+    try {
+        auto poly = wktreader.read<geos::geom::LineString>("POINT (2 8)");
+        fail();
+    } catch (geos::util::GEOSException & e) {
+        ensure_equals(std::string(e.what()), "ParseException: Unexpected WKT type");
+    }
+
+    // Malformed
+    try {
+        auto ps = wktreader.read<geos::geom::Point>("POINT (2, 8)");
+        fail();
+    } catch (geos::util::GEOSException & e) {
+        ensure_equals(std::string(e.what()), "ParseException: Expected number but encountered ','");
+    }
+
+}
+
 } // namespace tut

commit 3c3b17edc880787526a3c81f09f559254b1b9825
Author: Brendan C. Ward <bcward at astutespruce.com>
Date:   Tue Feb 2 09:29:44 2021 -0800

    Expand XML densify tests, reduce boilerplate in C API densify tests

diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
index 73ef2d7..006a368 100644
--- a/tests/unit/capi/GEOSDensifyTest.cpp
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -1,5 +1,5 @@
 //
-// Test Suite for C-API GEOSBuffer and GEOSBufferWithStyle
+// Test Suite for C-API GEOSDensify
 
 #include <tut/tut.hpp>
 // geos
@@ -7,38 +7,34 @@
 
 #include "capi_test_utils.h"
 
-
 namespace tut {
 //
 // Test Group
 //
 
-// Common data used in test cases.
-struct test_capigeosdensify_data : public capitest::utility {
-    GEOSGeometry* geom1_;
-    GEOSGeometry* geom2_;
-    GEOSWKTWriter* w_;
-    char* wkt_;
-
-    test_capigeosdensify_data()
-        : geom1_(nullptr), geom2_(nullptr), w_(nullptr)
+struct test_capigeosdensify_data : public capitest::utility
+{
+    void testDensify(const std::string &wkt_input,
+                            const std::string &wkt_output,
+                            double tolerance)
     {
-        initGEOS(notice, notice);
-        w_ = GEOSWKTWriter_create();
-        GEOSWKTWriter_setTrim(w_, 1);
-    }
+        int srid = 3857;
 
-    ~test_capigeosdensify_data()
-    {
-        GEOSGeom_destroy(geom1_);
-        GEOSGeom_destroy(geom2_);
-        GEOSWKTWriter_destroy(w_);
-        geom1_ = nullptr;
-        geom2_ = nullptr;
-        wkt_ = nullptr;
-        finishGEOS();
-    }
+        GEOSGeometry *input = GEOSGeomFromWKT(wkt_input.c_str());
+        GEOSSetSRID(input, srid);
+
+        GEOSGeometry *expected = GEOSGeomFromWKT(wkt_output.c_str());
+
+        GEOSGeometry *result = GEOSDensify(input, tolerance);
+        ensure("result not NULL", result != nullptr);
+
+        ensure_geometry_equals(result, expected);
+        ensure_equals("result SRID == expected SRID", GEOSGetSRID(result), srid);
 
+        GEOSGeom_destroy(input);
+        GEOSGeom_destroy(expected);
+        GEOSGeom_destroy(result);
+    }
 };
 
 typedef test_group<test_capigeosdensify_data> group;
@@ -50,165 +46,122 @@ group test_capigeosdensify_group("capi::GEOSDensify");
 // Test Cases
 //
 
-// Densify with a tolerance slightly larger than length of all edges.
+// Densify with a tolerance greater than or equal to length of all edges.
 // Result should match inputs.
-template<>
-template<>
+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.0);
-
-    ensure("result not null", geom2_ != nullptr);
-    ensure_geometry_equals(geom2_, geom1_);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))",
+        "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))",
+        10.0
+    );
 }
 
-
 // Densify with a tolerance that evenly subdivides all outer and inner edges.
-template<>
-template<>
+template <>
+template <>
 void object::test<2>()
 {
-    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_, 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 4, 1 7, 4 7, 7 7, 7 4, 7 1, 4 1, 1 1))");
-
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 1 7, 7 7, 7 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))",
+        5.0
+    );
 }
 
 // Densify a LINESTRING
-template<>
-template<>
+template <>
+template <>
 void object::test<3>()
 {
-    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )");
-    ensure(geom1_ != nullptr);
-    GEOSSetSRID(geom1_, 3857);
-
-    geom2_ = GEOSDensify(geom1_, 3);
-
-    ensure("result not null", geom2_ != nullptr);
-    ensure_geometry_equals(
-        geom2_,
-        "LINESTRING (0 0, 0 3, 0 6)");
-
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "LINESTRING (0 0, 0 6 )",
+        "LINESTRING (0 0, 0 3, 0 6)",
+        3.0
+    );
 }
 
 // Ensure that tolerance results in the right number of subdivisions
 // ceil(6 / 2.9999999) = 3 new segments; 2 new vertices
-template<>
-template<>
+template <>
+template <>
 void object::test<4>()
 {
-    geom1_ = GEOSGeomFromWKT("LINESTRING (0 0, 0 6 )");
-    ensure(geom1_ != nullptr);
-    GEOSSetSRID(geom1_, 3857);
-
-    geom2_ = GEOSDensify(geom1_, 2.9999999);
-
-    ensure("result not null", geom2_ != nullptr);
-    ensure_geometry_equals(
-        geom2_,
-        "LINESTRING (0 0, 0 2, 0 4, 0 6)");
-
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "LINESTRING (0 0, 0 6 )",
+        "LINESTRING (0 0, 0 2, 0 4, 0 6)",
+        2.9999999
+    );
 }
 
-
 // Densify a LINEARRING
-template<>
-template<>
+template <>
+template <>
 void object::test<5>()
 {
-    geom1_ = GEOSGeomFromWKT("LINEARRING (0 0, 0 6, 6 6, 0 0)");
-    ensure(geom1_ != nullptr);
-    GEOSSetSRID(geom1_, 3857);
-
-    geom2_ = GEOSDensify(geom1_, 3.0);
-
-    ensure("result not null", geom2_ != nullptr);
-    ensure_geometry_equals(
-        geom2_,
-        "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);
+    testDensify(
+        "LINEARRING (0 0, 0 6, 6 6, 0 0)",
+        "LINEARRING (0 0, 0 3, 0 6, 3 6, 6 6, 4 4, 2 2, 0 0)",
+        3.0
+    );
 }
 
 // Densify a POINT
 // Results should match inputs
-template<>
-template<>
+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_geometry_equals(geom2_, geom1_);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "POINT (0 0)",
+        "POINT (0 0)",
+        3.0
+    );
 }
 
 // Densify a MULTIPOINT
 // Results should match inputs
-template<>
-template<>
+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_geometry_equals(geom2_, geom1_);
-    ensure_equals("result SRID == expected SRID", GEOSGetSRID(geom2_), 3857);
+    testDensify(
+        "MULTIPOINT ((0 0), (10 10))",
+        "MULTIPOINT ((0 0), (10 10))",
+        3.0
+    );
 }
 
 // Densify an empty polygon
 // Results should match inputs
-template<>
-template<>
+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_geometry_equals(geom2_, geom1_);
+    testDensify(
+        "POLYGON EMPTY",
+        "POLYGON EMPTY",
+        3.0
+    );
 }
 
 // Densify with an invalid tolerances should fail
 // Note: this raises "IllegalArgumentException: Tolerance must be positive:
-template<>
-template<>
+template <>
+template <>
 void object::test<9>()
 {
-    geom1_ = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
-    ensure(geom1_ != nullptr);
+    GEOSGeometry *input = GEOSGeomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
 
-    geom2_ = GEOSDensify(geom1_, 0.0);
-    ensure(geom2_ == nullptr);
+    GEOSGeometry *result = GEOSDensify(input, 0.0);
+    ensure("result expected to be NULL", result == nullptr);
 
-    geom2_ = GEOSDensify(geom1_, -1.0);
-    ensure(geom2_ == nullptr);
+    result = GEOSDensify(input, -1.0);
+    ensure("result expected to be NULL", result == nullptr);
+
+    GEOSGeom_destroy(input);
 }
 
 } // namespace tut
-
diff --git a/tests/xmltester/XMLTester.cpp b/tests/xmltester/XMLTester.cpp
index 7aeb905..e549c81 100644
--- a/tests/xmltester/XMLTester.cpp
+++ b/tests/xmltester/XMLTester.cpp
@@ -1305,7 +1305,6 @@ XMLTester::parseTest(const tinyxml2::XMLNode* node)
 
             actual_result = printGeom(gRealRes.get());
             expected_result = printGeom(gRes.get());
-
         }
 
 
diff --git a/tests/xmltester/tests/general/TestDensify.xml b/tests/xmltester/tests/general/TestDensify.xml
index 5a68370..68f14b4 100644
--- a/tests/xmltester/tests/general/TestDensify.xml
+++ b/tests/xmltester/tests/general/TestDensify.xml
@@ -1,65 +1,316 @@
 <run>
   <precisionModel type="FLOATING" />
 
-<case>
-  <desc>P - single point</desc>
-  <a>    POINT (10 10) </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>  POINT (10 10)	</op></test>
-</case>
-
-<case>
-  <desc>mP - multi point</desc>
-  <a>    MULTIPOINT ((10 10), (20 10)) </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>  MULTIPOINT ((10 10), (20 10))	</op></test>
-</case>
-
-<case>
-  <desc>L - single segment</desc>
-  <a>    LINESTRING(10 10, 100 10)  </a>
-<test><op name="densify" arg1='A'  arg2='10.0'>
+  <case>
+    <desc>P - single point</desc>
+    <a>
+POINT (10 10)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+POINT (10 10)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>P - empty point</desc>
+    <a>
+POINT EMPTY
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+POINT EMPTY
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>mP - multi point</desc>
+    <a>
+MULTIPOINT ((10 10), (20 10))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+MULTIPOINT ((10 10), (20 10))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - empty line</desc>
+    <a>
+LINESTRING EMPTY
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+LINESTRING EMPTY
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - single segment with length equal to densify tolerance</desc>
+    <a>
+LINESTRING(10 10, 20 10)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+LINESTRING(10 10, 20 10)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - single segment with length less than densify tolerance</desc>
+    <a>
+LINESTRING(10 10, 15 10)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+LINESTRING(10 10, 15 10)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - single segment with length greater than densify tolerance</desc>
+    <a>LINESTRING(10 10, 100 10)</a>
+    <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))
-	</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 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)),
-  ((80 110, 80 70, 120 70, 120 110, 80 110)))  </a>
-<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>
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - single segment with non-integer tolerance, result is evenly subdivided</desc>
+    <a>LINESTRING (0 0, 0 6 )</a>
+    <test>
+      <op name="densify" arg1='A' arg2='2.999999'>
+LINESTRING (0 0, 0 2, 0 4, 0 6)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - empty linear ring</desc>
+    <a>LINEARRING EMPTY</a>
+    <test>
+      <op name="densify" arg1='A' arg2='6'>
+LINEARRING EMPTY
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - linear ring with segment lengths equal to densify tolerance</desc>
+    <a>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='6'>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - linear ring with segment lengths equal to densify tolerance</desc>
+    <a>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='6'>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - linear ring with segment lengths greater than densify tolerance</desc>
+    <a>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='3'>
+LINEARRING (0 0, 0 3, 0 6, 3 6, 6 6, 6 3, 6 0, 3 0, 0 0)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>L - linear ring with non-integer tolerance, result is evenly subdivided</desc>
+    <a>
+LINEARRING (0 0, 0 6, 6 6, 6 0, 0 0)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='2.999999'>
+LINEARRING (0 0, 0 2, 0 4, 0 6, 2 6, 4 6, 6 6, 6 4, 6 2, 6 0, 4 0, 2 0, 0 0)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>mL - multiple lines with segment lengths equal to densify tolerance</desc>
+    <a>
+MULTILINESTRING ((0 0, 10 0), (20 0, 20 10))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+MULTILINESTRING ((0 0, 10 0), (20 0, 20 10))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>mL - multiple lines with segment lengths greater than densify tolerance</desc>
+    <a>
+MULTILINESTRING ((0 0, 10 0), (20 0, 20 10))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='5.0'>
+MULTILINESTRING ((0 0, 5 0, 10 0), (20 0, 20 5, 20 10))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>mL - multiple lines with non-integer tolerance, result is evenly subdivided</desc>
+    <a>
+MULTILINESTRING ((0 0, 10 0), (20 0, 20 10))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='2.999999'>
+MULTILINESTRING ((20 0, 20 2.5, 20 5, 20 7.5, 20 10), (0 0, 2.5 0, 5 0, 7.5 0, 10 0))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>A - simple polygon with segment lengths equal to densify tolerance</desc>
+    <a>
+POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>A - simple polygon with segment lengths greater than densify tolerance</desc>
+    <a>
+POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='5.0'>
+POLYGON ((0 0, 0 5, 0 10, 5 10, 10 10, 10 5, 10 0, 5 0, 0 0))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>A - polygon with hole with segment lengths equal to densify tolerance</desc>
+    <a>
+POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2))
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2))
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>A - polygon with hole with segment lengths greater than densify tolerance</desc>
+    <a>
+POLYGON (
+  (0 0, 0 10, 10 10, 10 0, 0 0),
+  (2 2, 2 8, 8 8, 8 2, 2 2)
+)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='5.0'>
+POLYGON (
+  (0 0, 0 5, 0 10, 5 10, 10 10, 10 5, 10 0, 5 0, 0 0),
+  (2 2, 2 5, 2 8, 5 8, 8 8, 8 5, 8 2, 5 2, 2 2)
+)
+      </op>
+    </test>
+  </case>
+
+  <case>
+    <desc>A - polygon with hole with non-integer tolerance, result is evenly subdivided</desc>
+    <a>
+POLYGON (
+  (0 0, 0 10, 10 10, 10 0, 0 0),
+  (2 2, 2 8, 8 8, 8 2, 2 2)
+)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='2.999999'>
+POLYGON (
+  (0 0, 0 2.5, 0 5, 0 7.5, 0 10, 2.5 10, 5 10, 7.5 10, 10 10, 10 7.5, 10 5, 10 2.5, 10 0, 7.5 0, 5 0, 2.5 0, 0 0),
+  (2 2, 4 2, 6 2, 8 2, 8 4, 8 6, 8 8, 6 8, 4 8, 2 8, 2 6, 2 4, 2 2)
+)
+      </op>
+    </test>
+  </case>
 
+  <case>
+    <desc>mA - multipolygon with segment lengths equal to densify tolerance</desc>
+    <a>
+MULTIPOLYGON (
+  ((0 0, 0 10, 10 10, 10 0, 0 0)),
+  ((20 20, 20 30, 30 30, 30 20, 20 20))
+)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='10.0'>
+MULTIPOLYGON (
+  ((0 0, 0 10, 10 10, 10 0, 0 0)),
+  ((20 20, 20 30, 30 30, 30 20, 20 20))
+)
+      </op>
+    </test>
+  </case>
 
+  <case>
+    <desc>mA - multipolygon with segment lengths greater than densify tolerance</desc>
+    <a>
+MULTIPOLYGON (
+  ((0 0, 0 10, 10 10, 10 0, 0 0)),
+  ((20 20, 20 30, 30 30, 30 20, 20 20))
+)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='5.0'>
+MULTIPOLYGON (
+  ((20 20, 20 25, 20 30, 25 30, 30 30, 30 25, 30 20, 25 20, 20 20)),
+  ((0 0, 0 5, 0 10, 5 10, 10 10, 10 5, 10 0, 5 0, 0 0))
+)
+      </op>
+    </test>
+  </case>
 
+  <case>
+    <desc>mA - multipolygon with segment with non-integer tolerance, result is evenly subdivided</desc>
+    <a>
+MULTIPOLYGON (
+  ((20 20, 20 30, 30 30, 30 20, 20 20)),
+  ((0 0, 0 10, 10 10, 10 0, 0 0))
+)
+    </a>
+    <test>
+      <op name="densify" arg1='A' arg2='2.999999'>
+MULTIPOLYGON (
+  ((20 20, 20 22.5, 20 25, 20 27.5, 20 30, 22.5 30, 25 30, 27.5 30, 30 30, 30 27.5, 30 25, 30 22.5, 30 20, 27.5 20, 25 20, 22.5 20, 20 20)),
+  ((0 0, 0 2.5, 0 5, 0 7.5, 0 10, 2.5 10, 5 10, 7.5 10, 10 10, 10 7.5, 10 5, 10 2.5, 10 0, 7.5 0, 5 0, 2.5 0, 0 0))
+)
+      </op>
+    </test>
+  </case>
 
 </run>

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

Summary of changes:
 include/geos/geom/Envelope.h                  |   2 +
 include/geos/geom/Envelope.inl                |   5 +
 include/geos/geom/GeometryCollection.h        |   9 +
 include/geos/geom/LineString.h                |   9 +
 include/geos/geom/Polygon.h                   |  20 ++
 include/geos/io/WKTReader.h                   |  12 +
 src/geom/GeometryCollection.cpp               |   8 +
 src/geom/LineString.cpp                       |   8 +
 src/geom/Polygon.cpp                          |  14 +
 tests/unit/capi/GEOSDensifyTest.cpp           | 221 ++++++----------
 tests/unit/geom/GeometryCollectionTest.cpp    |  11 +
 tests/unit/geom/LineStringTest.cpp            |  14 +
 tests/unit/geom/PolygonTest.cpp               |  19 ++
 tests/unit/io/WKTReaderTest.cpp               |  30 +++
 tests/xmltester/XMLTester.cpp                 |   1 -
 tests/xmltester/tests/general/TestDensify.xml | 363 ++++++++++++++++++++++----
 16 files changed, 555 insertions(+), 191 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list