[Git][debian-gis-team/geos][upstream] New upstream version 3.10.2

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Sun Jan 16 07:52:26 GMT 2022



Bas Couwenberg pushed to branch upstream at Debian GIS Project / geos


Commits:
d4949261 by Bas Couwenberg at 2022-01-16T07:16:22+01:00
New upstream version 3.10.2
- - - - -


26 changed files:

- CMakeLists.txt
- NEWS
- README.md
- Version.txt
- include/geos/geom/CoordinateSequence.h
- include/geos/index/SpatialIndex.h
- include/geos/index/strtree/TemplateSTRtree.h
- include/geos/precision/CommonBitsRemover.h
- include/geos/triangulate/polygon/PolygonEarClipper.h
- include/geos/triangulate/polygon/PolygonHoleJoiner.h
- src/algorithm/construct/MaximumInscribedCircle.cpp
- − src/dirlist.mk
- src/geomgraph/Node.cpp
- src/index/chain/MonotoneChainBuilder.cpp
- src/io/GeoJSONWriter.cpp
- src/operation/polygonize/BuildArea.cpp
- src/operation/union/CascadedPolygonUnion.cpp
- src/triangulate/polygon/PolygonEarClipper.cpp
- tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp
- tests/unit/capi/GEOSPreparedGeometryTest.cpp
- tests/unit/capi/GEOSSTRtreeTest.cpp
- + tests/unit/geom/Geometry/differenceTest.cpp
- tests/unit/index/chain/MonotoneChainBuilderTest.cpp
- tests/unit/io/GeoJSONWriterTest.cpp
- tests/unit/triangulate/polygon/PolygonTriangulatorTest.cpp
- tests/xmltester/tests/general/TestUnaryUnion.xml


Changes:

=====================================
CMakeLists.txt
=====================================
@@ -368,6 +368,11 @@ install(DIRECTORY
   "${CMAKE_CURRENT_BINARY_DIR}/include/geos"
   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
   FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY
+  "${CMAKE_CURRENT_LIST_DIR}/include/geos"
+  "${CMAKE_CURRENT_BINARY_DIR}/include/geos"
+  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+  FILES_MATCHING PATTERN "*.hpp")
 if(NOT DISABLE_GEOS_INLINE)
   install(DIRECTORY
     "${CMAKE_CURRENT_LIST_DIR}/include/geos"


=====================================
NEWS
=====================================
@@ -1,3 +1,21 @@
+
+Changes in 3.10.2
+2022-01-15
+
+- Fixes/Improvements:
+  - Fix crash in MonotoneChain with empty CoordinateSequence (GH-539, Sandro Santilli)
+  - Fix crash in GeoJSONWriter in case of empty points (TRAC-1139, Paul Ramsey)
+  - Improve BuildArea performance (TRAC-1122, Sandro Santilli)
+  - Fix unaryUnion to avoid segfault with empty polygon (GH-501, Mike Taves)
+  - Fix memory leak on exception in prepared geometry (GH-506, Dan Baston)
+  - Iterator invalidation in rare cases (GH-508, Momtchil Momtchev)
+  - Infinite loop on collapsed input to MaximumInscribedCircle (Paul Ramsey)
+  - Write LinearRing to GeoJSON as LineString (TRAC-1140, Paul Ramsey)
+  - Fix PolygonEarClipper to handle collapsed corners (GH-526, Martin Davis)
+  - Fix GEOSSTRtree_remove for empty tree (GH-544, Dan Baston)
+  - Fix crash on query of STRtree with removed items (GH-545, Dan Baston)
+
+
 Changes in 3.10.1
 2021-11-2
 


=====================================
README.md
=====================================
@@ -1,16 +1,16 @@
 GEOS -- Geometry Engine, Open Source
 ====================================
 
-GEOS is a C++11 library for performing operations on two-dimensional vector
+GEOS is a C++ library for performing operations on two-dimensional vector
 geometries. It is primarily a port of the [JTS Topology
 Suite](https://github.com/locationtech/jts) Java library.  It provides many of
 the algorithms used by [PostGIS](http://www.postgis.net/), the
 [Shapely](https://pypi.org/project/Shapely/) package for Python, the
 [sf](https://github.com/r-spatial/sf) package for R, and others.
 
-More information is available the [project homepage](https://trac.osgeo.org/geos).
+More information is available the [project homepage](https://libgeos.org).
 
-The official Git repository is at [OSGEO Gitea](https://git.osgeo.org/gitea/geos).
+The official Git repository is at [GitHub](https://github.com/libgeos/geos).
 
 ## Build status
 


=====================================
Version.txt
=====================================
@@ -2,7 +2,7 @@
 # GEOS Versions
 GEOS_VERSION_MAJOR=3
 GEOS_VERSION_MINOR=10
-GEOS_VERSION_PATCH=1
+GEOS_VERSION_PATCH=2
 
 # OPTIONS: "", "dev", "rc1" etc.
 GEOS_PATCH_WORD=


=====================================
include/geos/geom/CoordinateSequence.h
=====================================
@@ -159,10 +159,9 @@ public:
     static CoordinateSequence* atLeastNCoordinatesOrNothing(std::size_t n,
             CoordinateSequence* c);
 
-    /// Return position of a Coordinate, or -1 if not found
-    ///
-    /// FIXME: return std::size_t, using numeric_limits<std::size_t>::max
-    /// as 'not found' value.
+    /// Return position of a Coordinate
+    //
+    /// or numeric_limits<std::size_t>::max() if not found
     ///
     static std::size_t indexOf(const Coordinate* coordinate,
                           const CoordinateSequence* cl);


=====================================
include/geos/index/SpatialIndex.h
=====================================
@@ -71,9 +71,7 @@ public:
      * intersect the query envelope.
      *
      * @param searchEnv the envelope to query for
-     * @return a list of the items found by the query in a newly allocated vector
      */
-    //virtual std::vector<void*>* query(const geom::Envelope *searchEnv)=0;
     virtual void query(const geom::Envelope* searchEnv, std::vector<void*>&) = 0;
 
     /** \brief


=====================================
include/geos/index/strtree/TemplateSTRtree.h
=====================================
@@ -306,6 +306,8 @@ public:
     /// @{
 
     bool remove(const BoundsType& itemEnv, const ItemType& item) {
+        build();
+
         if (root == nullptr) {
             return false;
         }
@@ -359,12 +361,12 @@ public:
 
         // begin and end define a range of nodes needing parents
         auto begin = nodes.begin();
-        auto end = nodes.end();
+        auto number = static_cast<size_t>(std::distance(begin, nodes.end()));
 
-        while (std::distance(begin, end) > 1) {
-            createParentNodes(begin, end);
-            begin = end; // parents just added become children in the next round
-            end = nodes.end();
+        while (number > 1) {
+            createParentNodes(begin, number);
+            std::advance(begin, static_cast<long>(number)); // parents just added become children in the next round
+            number = static_cast<size_t>(std::distance(begin, nodes.end()));
         }
 
         assert(finalSize == nodes.size());
@@ -421,22 +423,24 @@ protected:
         return nodesInTree;
     }
 
-    void createParentNodes(const NodeListIterator& begin, const NodeListIterator& end) {
+    void createParentNodes(const NodeListIterator& begin, size_t number) {
         // Arrange child nodes in two dimensions.
         // First, divide them into vertical slices of a given size (left-to-right)
         // Then create nodes within those slices (bottom-to-top)
-        auto numChildren = static_cast<std::size_t>(std::distance(begin, end));
-        auto numSlices = sliceCount(numChildren);
-        std::size_t nodesPerSlice = sliceCapacity(numChildren, numSlices);
+        auto numSlices = sliceCount(number);
+        std::size_t nodesPerSlice = sliceCapacity(number, numSlices);
 
         // We could sort all of the nodes here, but we don't actually need them to be
         // completely sorted. They need to be sorted enough for each node to end up
         // in the right vertical slice, but their relative position within the slice
         // doesn't matter. So we do a partial sort for each slice below instead.
+        auto end = begin + static_cast<long>(number);
         sortNodesX(begin, end);
 
         auto startOfSlice = begin;
         for (decltype(numSlices) j = 0; j < numSlices; j++) {
+            // end iterator is being invalidated at each iteration
+            end = begin + static_cast<long>(number);
             auto nodesRemaining = static_cast<size_t>(std::distance(startOfSlice, end));
             auto nodesInSlice = std::min(nodesRemaining, nodesPerSlice);
             auto endOfSlice = std::next(startOfSlice, static_cast<long>(nodesInSlice));
@@ -544,9 +548,11 @@ protected:
 
         for (auto *child = node.beginChildren(); child < node.endChildren(); ++child) {
             if (child->boundsIntersect(queryEnv)) {
-                if (child->isLeaf() && !child->isDeleted()) {
-                    if (!visitLeaf(visitor, *child)) {
-                        return;
+                if (child->isLeaf()) {
+                    if (!child->isDeleted()) {
+                        if (!visitLeaf(visitor, *child)) {
+                            return;
+                        }
                     }
                 } else {
                     query(queryEnv, *child, visitor);


=====================================
include/geos/precision/CommonBitsRemover.h
=====================================
@@ -75,7 +75,6 @@ public:
      *
      * @param geom the Geometry from which to remove the common
      *             coordinate bits
-     * @return the shifted Geometry
      */
     void removeCommonBits(geom::Geometry* geom);
 


=====================================
include/geos/triangulate/polygon/PolygonEarClipper.h
=====================================
@@ -164,7 +164,12 @@ private:
 
     bool isFlat(const std::array<Coordinate, 3>& pts) const;
 
-    bool hasRepeatedPoint(const std::array<Coordinate, 3>& pts) const;
+    /**
+    * Detects if a corner has repeated points (AAB or ABB), or is collapsed (ABA).
+    * @param pts the corner points
+    * @return true if the corner is flat or collapsed
+    */
+    bool isCornerInvalid(const std::array<Coordinate, 3>& pts) const;
 
 
 public:


=====================================
include/geos/triangulate/polygon/PolygonHoleJoiner.h
=====================================
@@ -51,11 +51,15 @@ namespace polygon {
 
 
 /**
- * Transforms a polygon with holes into a single self-touching ring
+ * Transforms a polygon with holes into a single self-touching (invalid) ring
  * by connecting holes to the exterior shell or to another hole.
  * The holes are added from the lowest upwards.
  * As the resulting shell develops, a hole might be added to what was
  * originally another hole.
+ *
+ * There is no attempt to optimize the quality of the join lines.
+ * In particular, a hole which already touches at a vertex may be
+ * joined at a different vertex.
  */
 class GEOS_DLL PolygonHoleJoiner {
 


=====================================
src/algorithm/construct/MaximumInscribedCircle.cpp
=====================================
@@ -121,6 +121,10 @@ MaximumInscribedCircle::createInitialGrid(const Envelope* env, std::priority_que
     double cellSize = std::min(width, height);
     double hSize = cellSize / 2.0;
 
+    // Collapsed geometries just end up using the centroid
+    // as the answer and skip all the other machinery
+    if (cellSize == 0) return;
+
     // compute initial grid of cells to cover area
     for (double x = minX; x < maxX; x += cellSize) {
         for (double y = minY; y < maxY; y += cellSize) {


=====================================
src/dirlist.mk deleted
=====================================
@@ -1,48 +0,0 @@
-#
-# List of directories use by makefile.vc to clean .obj files
-#
-
-GEOS_DIRLIST =  \
-	algorithm \
-	algorithm\distance \
-	algorithm\locate \
-	examples \
-	geom \
-	geom\util \
-	geom\prep \
-	geomgraph \
-	geomgraph\index \
-	headers \
-	headers\geos \
-	index \
-	index\bintree \
-	index\chain \
-	index\intervalrtree \
-	index\quadtree \
-	index\strtree \
-	index\sweepline \
-	io \
-	linearref \
-	noding \
-	noding\snapround \
-	operation \
-	operation\buffer \
-	operation\distance \
-	operation\intersection \
-	operation\linemerge \
-	operation\overlay \
-	operation\overlay\snap \
-	operation\overlay\validate \
-	operation\polygonize \
-	operation\predicate \
-	operation\relate \
-	operation\sharedpaths \
-	operation\union \
-	operation\valid \
-	planargraph \
-	planargraph\algorithm \
-	precision \
-	simplify \
-	triangulate \
-	triangulate\quadedge \
-	util


=====================================
src/geomgraph/Node.cpp
=====================================
@@ -29,6 +29,7 @@
 #include <geos/util.h>
 
 #include <cmath>
+#include <memory>
 #include <string>
 #include <sstream>
 #include <vector>
@@ -132,8 +133,9 @@ Node::isIncidentEdgeInResult() const
 }
 
 void
-Node::add(EdgeEnd* e)
+Node::add(EdgeEnd* p_e)
 {
+    std::unique_ptr<EdgeEnd> e(p_e);
     assert(e);
 #if GEOS_DEBUG
     std::cerr << "[" << this << "] Node::add(" << e->print() << ")" << std::endl;
@@ -152,10 +154,10 @@ Node::add(EdgeEnd* e)
     assert(edges);
     //if (edges==NULL) return;
 
-    edges->insert(e);
-    e->setNode(this);
+    edges->insert(e.release());
+    p_e->setNode(this);
 #if COMPUTE_Z
-    addZ(e->getCoordinate().z);
+    addZ(p_e->getCoordinate().z);
 #endif
     testInvariant();
 }


=====================================
src/index/chain/MonotoneChainBuilder.cpp
=====================================
@@ -64,6 +64,7 @@ public:
 
 private:
     void finishChain() {
+        if ( m_i == 0 ) return;
         m_ends.push_back(m_i - 1);
     }
 


=====================================
src/io/GeoJSONWriter.cpp
=====================================
@@ -180,6 +180,10 @@ void GeoJSONWriter::encodeGeometry(const geom::Geometry* geometry, geos_nlohmann
         auto line = static_cast<const geom::LineString*>(geometry);
         encodeLineString(line, j);
     }
+    else if (type == GEOS_LINEARRING) {
+        auto line = static_cast<const geom::LineString*>(geometry);
+        encodeLineString(line, j);
+    }
     else if (type == GEOS_POLYGON) {
         auto poly = static_cast<const geom::Polygon*>(geometry);
         encodePolygon(poly, j);
@@ -205,7 +209,12 @@ void GeoJSONWriter::encodeGeometry(const geom::Geometry* geometry, geos_nlohmann
 void GeoJSONWriter::encodePoint(const geom::Point* point, geos_nlohmann::ordered_json& j)
 {
     j["type"] = "Point";
-    j["coordinates"] = convertCoordinate(point->getCoordinate());
+    if (!point->isEmpty()) {
+        j["coordinates"] = convertCoordinate(point->getCoordinate());
+    }
+    else {
+        j["coordinates"] = j.array();
+    }
 }
 
 void GeoJSONWriter::encodeLineString(const geom::LineString* line, geos_nlohmann::ordered_json& j)


=====================================
src/operation/polygonize/BuildArea.cpp
=====================================
@@ -66,6 +66,74 @@ struct Face {
     }
 };
 
+static bool ringsEqualAnyDirection(const LinearRing* r1, const LinearRing* r2)
+{
+
+    const CoordinateSequence *cs1 = r1->getCoordinatesRO();
+    const CoordinateSequence *cs2 = r2->getCoordinatesRO();
+
+    /* Check same number of points */
+    size_t npoints = cs1->size();
+    if ( npoints != cs2->size() )
+    {
+        return false;
+    }
+
+    if ( npoints == 0 ) return true; /* if empty, they are equal */
+
+    /* Check same envelope (probably better avoid, as it'd need to
+     * compute the envelope doing an additional scan for each) */
+    if ( ! r1->getEnvelopeInternal()->equals(r2->getEnvelopeInternal()) )
+    {
+        return false;
+    }
+
+    /* Pretend the rings had one less point, as the last one will be
+     * equal to the first one anyway */
+    --npoints;
+
+    const Coordinate& firstPoint = cs1->getAt(0);
+    size_t offset = CoordinateSequence::indexOf(&firstPoint, cs2);
+    if ( offset == std::numeric_limits<std::size_t>::max() ) return false;
+
+    bool equal = true;
+
+    /* Check equals forward (skip first point, we checked it alread) */
+    for (size_t i=1; i<npoints; ++i)
+    {
+        size_t j = ( i + offset ) % npoints;
+        const Coordinate& c1 = cs1->getAt(i);
+        const Coordinate& c2 = cs2->getAt(j);
+        if ( ! c1.equals(c2) ) {
+            equal = false;
+            break;
+        }
+    }
+
+    if ( equal ) return true;
+
+    /* Check equals backward (skip first point, we checked it already) */
+    equal = true;
+    for (size_t i=1; i<npoints; ++i)
+    {
+        size_t j;
+        if ( i <= offset ) {
+            j = offset - i;
+        } else {
+            j = npoints - ( i - offset );
+        }
+
+        const Coordinate& c1 = cs1->getAt(i);
+        const Coordinate& c2 = cs2->getAt(j);
+        if ( ! c1.equals(c2) ) {
+            equal = false;
+            break;
+        }
+    }
+
+    return equal;
+}
+
 static std::unique_ptr<Face> newFace(const geom::Polygon* p) {
     auto f = std::unique_ptr<Face>(new Face());
     f->poly = p;
@@ -100,13 +168,8 @@ static void findFaceHoles(std::vector<std::unique_ptr<Face>>& faces) {
                 if( f2->parent ) {
                     continue; /* hole already assigned */
                 }
-                const auto f2er = f2->poly->getExteriorRing();
-                /* TODO: can be optimized as the ring would have the
-                *       same vertices, possibly in different order.
-                *       maybe comparing number of points could already be
-                *       useful.
-                */
-                if( f2er->equals(hole) ) {
+                const auto shell = f2->poly->getExteriorRing();
+                if( ringsEqualAnyDirection(shell, hole) ) {
                     f2->parent = f.get();
                     break;
                 }


=====================================
src/operation/union/CascadedPolygonUnion.cpp
=====================================
@@ -102,7 +102,10 @@ std::unique_ptr<geom::Geometry>
 CascadedPolygonUnion::binaryUnion(const std::vector<const geom::Geometry*> & geoms,
                                   std::size_t start, std::size_t end)
 {
-    if(end - start <= 1) {
+    if(end - start == 0) {
+        return nullptr;
+    }
+    else if(end - start == 1) {
         return unionSafe(geoms[start], nullptr);
     }
     else if(end - start == 2) {


=====================================
src/triangulate/polygon/PolygonEarClipper.cpp
=====================================
@@ -100,8 +100,8 @@ PolygonEarClipper::compute(TriList& triList)
         * after enough ears are removed)
         */
         if (! isConvex(corner)) {
-            // remove the corner if it is flat or a repeated point
-            bool isCornerRemoved = hasRepeatedPoint(corner)
+            // remove the corner if it is invalid or flat (if required)
+            bool isCornerRemoved = isCornerInvalid(corner)
                 || (isFlatCornersSkipped && isFlat(corner));
             if (isCornerRemoved) {
                 removeCorner();
@@ -337,9 +337,9 @@ PolygonEarClipper::isFlat(const std::array<Coordinate, 3>& pts) const
 
 /* private static */
 bool
-PolygonEarClipper::hasRepeatedPoint(const std::array<Coordinate, 3>& pts) const
+PolygonEarClipper::isCornerInvalid(const std::array<Coordinate, 3>& pts) const
 {
-    return pts[1].equals2D(pts[0]) || pts[1].equals2D(pts[2]);
+    return pts[1].equals2D(pts[0]) || pts[1].equals2D(pts[2]) || pts[0].equals2D(pts[2]);
 }
 
 


=====================================
tests/unit/algorithm/construct/MaximumInscribedCircleTest.cpp
=====================================
@@ -174,6 +174,18 @@ void object::test<6>
 }
 
 
+// //
+// // Invalid polygon collapsed to a line
+// //
+template<>
+template<>
+void object::test<7>
+()
+{
+     checkCircle("POLYGON((1 2, 1 2, 1 2, 1 2, 3 2, 1 2))",
+       0.01, 2, 2, 0 );
+}
+
 
 
 } // namespace tut


=====================================
tests/unit/capi/GEOSPreparedGeometryTest.cpp
=====================================
@@ -405,5 +405,23 @@ void object::test<13>
     ensure_equals(ret, 0);
 }
 
+// Verify no memory leak on exception (https://github.com/libgeos/geos/issues/505)
+template<>
+template<>
+void object::test<14>
+()
+{
+    geom1_ = GEOSGeomFromWKT("LINESTRING(0 0, 1 NaN)");
+    geom2_ = GEOSGeomFromWKT("POINT(0 0)");
+    prepGeom1_ = GEOSPrepare(geom1_);
+
+    ensure(nullptr != prepGeom1_);
+    ensure(nullptr != geom2_);
+
+    int ret = GEOSPreparedTouches(prepGeom1_, geom2_);
+    ensure_equals(ret, 2);
+}
+
+
 } // namespace tut
 


=====================================
tests/unit/capi/GEOSSTRtreeTest.cpp
=====================================
@@ -382,6 +382,40 @@ void object::test<11>()
     GEOSSTRtree_destroy(tree);
 }
 
+template<>
+template<>
+void object::test<12>()
+{
+    GEOSSTRtree* tree = GEOSSTRtree_create(10);
+
+    GEOSGeometry* g1 = GEOSGeomFromWKT("LINESTRING (0 0, 10 10)");
+    GEOSGeometry* g2 = GEOSGeomFromWKT("LINESTRING (20 20, 30 30)");
+    GEOSGeometry* g3 = GEOSGeomFromWKT("LINESTRING (20 20, 30 30)");
+
+    GEOSSTRtree_insert(tree, g1, g1);
+    GEOSSTRtree_insert(tree, g2, g2);
+    GEOSSTRtree_insert(tree, g3, g3);
+
+    GEOSGeometry* p = GEOSGeomFromWKT("POINT (5 5)");
+
+    ensure_equals(GEOSSTRtree_remove(tree, p, g1), 1);
+
+    std::vector<GEOSGeometry*> hits;
+    GEOSSTRtree_query(tree, p, [](void* item, void* userdata) {
+        auto h = static_cast<std::vector<GEOSGeometry*>*>(userdata);
+        h->push_back(static_cast<GEOSGeometry*>(item));
+    }, &hits);
+
+    ensure(hits.empty());
+
+    GEOSGeom_destroy(g1);
+    GEOSGeom_destroy(g2);
+    GEOSGeom_destroy(g3);
+    GEOSGeom_destroy(p);
+
+    GEOSSTRtree_destroy(tree);
+}
+
 
 } // namespace tut
 


=====================================
tests/unit/geom/Geometry/differenceTest.cpp
=====================================
@@ -0,0 +1,60 @@
+//
+// Test Suite for geos::geom::Geometry::difference() method.
+
+#include <tut/tut.hpp>
+#include <utility.h>
+// geos
+#include <geos/io/WKTReader.h>
+#include <geos/io/WKTWriter.h>
+#include <geos/geom/PrecisionModel.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/Geometry.h>
+#include <geos/geom/Point.h>
+#include <geos/geom/LineString.h>
+#include <geos/util.h>
+
+namespace tut {
+// dummy data, not used
+struct test_geometry_difference_data {
+    geos::io::WKTReader wktreader;
+    geos::io::WKTWriter wktwriter;
+
+    test_geometry_difference_data()
+        :
+        wktreader()
+    {}
+};
+
+typedef test_group<test_geometry_difference_data> group;
+typedef group::object object;
+
+group test_geometry_difference_group("geos::geom::Geometry::difference");
+
+//
+// Test Cases
+
+
+// This issue exercised a bug in MonotoneChainBuilder
+// https://github.com/libgeos/geos/issues/290
+template<>
+template<>
+void object::test<1>
+()
+{
+    std::string wkt1("POLYGON((0 0, 0 2, 2 2, 2 0, 0 0))");
+    std::unique_ptr<geos::geom::Geometry> g1(wktreader.read(wkt1));
+
+    std::string wkt2("POLYGON((0.1 0.1, 4.0 0.1, 4.0 1.9, 0.1 1.9, 0.1 0.1))");
+    std::unique_ptr<geos::geom::Geometry> g2(wktreader.read(wkt2));
+
+    auto result = g2->difference(g1.get());
+    result->normalize();
+
+    std::string wktExpected("POLYGON ((2 0.1, 2 1.9, 4 1.9, 4 0.1, 2 0.1))");
+    std::unique_ptr<geos::geom::Geometry> expected(wktreader.read(wktExpected));
+
+    ensure_equals_geometry(expected.get(), result.get());
+}
+
+
+} // namespace tut


=====================================
tests/unit/index/chain/MonotoneChainBuilderTest.cpp
=====================================
@@ -4,14 +4,11 @@
 #include <tut/tut.hpp>
 #include <utility.h>
 // geos
-#include <geos/io/WKTReader.h>
-#include <geos/io/WKTWriter.h>
-#include <geos/geom/PrecisionModel.h>
-#include <geos/geom/GeometryFactory.h>
-#include <geos/geom/Geometry.h>
-#include <geos/geom/Point.h>
-#include <geos/geom/LineString.h>
-#include <geos/util.h>
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/CoordinateArraySequence.h>
+#include <geos/index/chain/MonotoneChain.h>
+#include <geos/index/chain/MonotoneChainBuilder.h>
+
 
 namespace tut {
 // dummy data, not used
@@ -33,28 +30,19 @@ group test_monotonechain_group("geos::index::chain::MonotoneChainBuilder");
 //
 // Test Cases
 
-
 // This issue exercised a bug in MonotoneChainBuilder
-// https://github.com/libgeos/geos/issues/290
+// https://github.com/libgeos/geos/issues/539
 template<>
 template<>
 void object::test<1>
 ()
 {
-    std::string wkt1("POLYGON((0 0, 0 2, 2 2, 2 0, 0 0))");
-    std::unique_ptr<geos::geom::Geometry> g1(wktreader.read(wkt1));
-
-    std::string wkt2("POLYGON((0.1 0.1, 4.0 0.1, 4.0 1.9, 0.1 1.9, 0.1 0.1))");
-    std::unique_ptr<geos::geom::Geometry> g2(wktreader.read(wkt2));
+    std::vector<geos::index::chain::MonotoneChain> chain;
+    geos::geom::CoordinateArraySequence pts;
 
-    auto result = g2->difference(g1.get());
-    result->normalize();
+    geos::index::chain::MonotoneChainBuilder::getChains(&pts, 0, chain);
 
-    std::string wktExpected("POLYGON ((2 0.1, 2 1.9, 4 1.9, 4 0.1, 2 0.1))");
-    std::unique_ptr<geos::geom::Geometry> expected(wktreader.read(wktExpected));
-
-    ensure_equals_geometry(expected.get(), result.get());
+    ensure_equals(chain.size(), 0u);
 }
 
-
 } // namespace tut


=====================================
tests/unit/io/GeoJSONWriterTest.cpp
=====================================
@@ -252,4 +252,60 @@ void object::test<14>
     ensure_equals(result, "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-117.0,33.0]},\"properties\":{\"id\":1.0,\"name\":\"One\"}},{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-127.0,53.0]},\"properties\":{\"id\":2.0,\"name\":\"Two\"}}]}");
 }
 
+// Write an empty point
+template<>
+template<>
+void object::test<15>
+()
+{
+    GeomPtr geom(wktreader.read("POINT EMPTY"));
+    std::string result = geojsonwriter.write(geom.get());
+    ensure_equals(result, "{\"type\":\"Point\",\"coordinates\":[]}");
+}
+
+// Write an empty linestring
+template<>
+template<>
+void object::test<16>
+()
+{
+    GeomPtr geom(wktreader.read("LINESTRING EMPTY"));
+    std::string result = geojsonwriter.write(geom.get());
+    ensure_equals(result, "{\"type\":\"LineString\",\"coordinates\":[]}");
+}
+
+// Write an empty polygon
+template<>
+template<>
+void object::test<17>
+()
+{
+    GeomPtr geom(wktreader.read("POLYGON EMPTY"));
+    std::string result = geojsonwriter.write(geom.get());
+    ensure_equals(result, "{\"type\":\"Polygon\",\"coordinates\":[[]]}");
+}
+
+// Write an empty polygon
+template<>
+template<>
+void object::test<18>
+()
+{
+    GeomPtr geom(wktreader.read("GEOMETRYCOLLECTION EMPTY"));
+    std::string result = geojsonwriter.write(geom.get());
+    ensure_equals(result, "{\"type\":\"GeometryCollection\",\"geometries\":[]}");
+}
+
+// Write a linear ring (as a linestring)
+template<>
+template<>
+void object::test<19>
+()
+{
+    GeomPtr geom(wktreader.read("LINEARRING (0 0, 1 1, 1 0, 0 0)"));
+    std::string result = geojsonwriter.write(geom.get());
+    ensure_equals(result, "{\"type\":\"LineString\",\"coordinates\":[[0.0,0.0],[1.0,1.0],[1.0,0.0],[0.0,0.0]]}");
+}
+
+
 }


=====================================
tests/unit/triangulate/polygon/PolygonTriangulatorTest.cpp
=====================================
@@ -181,6 +181,19 @@ void object::test<11>()
         );
 }
 
+
+// testCollapsedCorner
+template<>
+template<>
+void object::test<12>()
+{
+    checkTri(
+        "POLYGON ((186 90, 71 17, 74 10, 65 0, 0 121, 186 90), (73 34, 67 41, 71 17, 73 34))"
+        );
+}
+
+
+
 } // namespace tut
 
 


=====================================
tests/xmltester/tests/general/TestUnaryUnion.xml
=====================================
@@ -156,6 +156,68 @@
   </test>
 </case>
 
+<case>
+  <desc>P - empty point</desc>
+  <a>POINT EMPTY</a>
+  <test>
+    <op name="union" arg1="A">POINT EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>mP - empty multi point</desc>
+  <a>MULTIPOINT EMPTY</a>
+  <test>
+    <op name="union" arg1="A">MULTIPOINT EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>L - empty line</desc>
+  <a>LINESTRING EMPTY</a>
+  <test>
+    <op name="union" arg1="A">LINESTRING EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>mL - empty multi line</desc>
+  <a>MULTILINESTRING EMPTY</a>
+  <test>
+    <op name="union" arg1="A">MULTILINESTRING EMPTY</op>
+  </test>
+</case>
 
+<case>
+  <desc>L - empty linear ring</desc>
+  <a>LINEARRING EMPTY</a>
+  <test>
+    <op name="union" arg1="A">LINEARRING EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>P - empty polygon</desc>
+  <a>POLYGON EMPTY</a>
+  <test>
+    <op name="union" arg1="A">POLYGON EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>mP - empty multi polygon</desc>
+  <a>MULTIPOLYGON EMPTY</a>
+  <test>
+    <op name="union" arg1="A">MULTIPOLYGON EMPTY</op>
+  </test>
+</case>
+
+<case>
+  <desc>GC - empty geometry collection</desc>
+  <a>GEOMETRYCOLLECTION EMPTY</a>
+  <test>
+    <op name="union" arg1="A">GEOMETRYCOLLECTION EMPTY</op>
+  </test>
+</case>
 
 </run>



View it on GitLab: https://salsa.debian.org/debian-gis-team/geos/-/commit/d49492612fd028a5229ed0f51b10dc79bd29e963

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/geos/-/commit/d49492612fd028a5229ed0f51b10dc79bd29e963
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20220116/108e81a6/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list