[geos-commits] [SCM] GEOS branch main updated. 1105298873b17260fcbcd7f82901ddcbfff8ff82

git at osgeo.org git at osgeo.org
Tue May 2 08:57:04 PDT 2023


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, main has been updated
       via  1105298873b17260fcbcd7f82901ddcbfff8ff82 (commit)
       via  8d67fd6be1b1c429f4b62376368e3c286b68cfc6 (commit)
       via  d054731ccdafdeae3a094051e47f760b64ecf72f (commit)
      from  8c647cb7c0a849cd05d121fd5cb3778d884c6d73 (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 1105298873b17260fcbcd7f82901ddcbfff8ff82
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Tue May 2 08:56:36 2023 -0700

    Add GEOSGeom_releaseCollection to CAPI (#882)
    
    Add GEOSGeom_releaseCollection to CAPI, references GH-848

diff --git a/NEWS.md b/NEWS.md
index cb386f976..c440567ea 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -21,6 +21,7 @@ xxxx-xx-xx
   - Voronoi: Add option to create diagram in order consistent with inputs (GH-781, Dan Baston)
   - Polygonal coverages: CoverageSimplifier (JTS-911, Martin Davis)
   - CAPI: GEOSCoverageIsValid, GEOSCoverageSimplifyVW (GH-867, Paul Ramsey)
+  - CAPI: GEOSGeom_releaseCollection (GH-848)
 
 - Fixes/Improvements:
   - WKTReader: Fix parsing of Z and M flags in WKTReader (#676 and GH-669, Dan Baston)
diff --git a/capi/geos_c.cpp b/capi/geos_c.cpp
index 5757a6f0b..43224e5c9 100644
--- a/capi/geos_c.cpp
+++ b/capi/geos_c.cpp
@@ -849,6 +849,12 @@ extern "C" {
         return GEOSGeom_createCollection_r(handle, type, geoms, ngeoms);
     }
 
+    Geometry**
+    GEOSGeom_releaseCollection(Geometry* collection, unsigned int * ngeoms)
+    {
+        return GEOSGeom_releaseCollection_r(handle, collection, ngeoms);
+    }
+
     Geometry*
     GEOSPolygonize(const Geometry* const* g, unsigned int ngeoms)
     {
diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index 6a25e4e4f..5b5e9af03 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -736,6 +736,12 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_createCollection_r(
     GEOSGeometry* *geoms,
     unsigned int ngeoms);
 
+/** \see GEOSGeom_releaseCollection */
+extern GEOSGeometry GEOS_DLL ** GEOSGeom_releaseCollection_r(
+    GEOSContextHandle_t handle,
+    GEOSGeometry * collection,
+    unsigned int * ngeoms);
+
 /** \see GEOSGeom_createEmptyCollection */
 extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCollection_r(
     GEOSContextHandle_t handle, int type);
@@ -2441,6 +2447,26 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_createCollection(
     GEOSGeometry** geoms,
     unsigned int ngeoms);
 
+/**
+* Release the sub-geometries of a collection for management.
+* by the caller. The input collection remains as an empty collection,
+* that the caller is responsible for destroying. The output geometries
+* are also the responsibility of the caller, as is the containing array,
+* which must be freed with GEOSFree().
+* \param collection The collection that will have its components released.
+* \param ngeoms A pointer to a variable that will be filled with the
+*        size of the output array.
+* \return A newly allocated array of GEOSGeometry pointers.
+* \note The caller is responsible for freeing the returned array
+*       with GEOSFree() and all the elements with GEOSGeom_destroy().
+*       If called with an empty collection, null will be returned
+*       and ngeoms set to zero.
+* \since 3.4
+*/
+extern GEOSGeometry GEOS_DLL ** GEOSGeom_releaseCollection(
+    GEOSGeometry * collection,
+    unsigned int * ngeoms);
+
 /**
 * Create an empty geometry collection.
 * \param type The geometry type, enumerated by \ref GEOSGeomTypes
diff --git a/capi/geos_ts_c.cpp b/capi/geos_ts_c.cpp
index 7c9333d1d..e30efc424 100644
--- a/capi/geos_ts_c.cpp
+++ b/capi/geos_ts_c.cpp
@@ -2024,6 +2024,38 @@ extern "C" {
         });
     }
 
+    Geometry**
+    GEOSGeom_releaseCollection_r(GEOSContextHandle_t extHandle, Geometry* collection, unsigned int * ngeoms)
+    {
+        return execute(extHandle, [&]() {
+            GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
+
+            if (ngeoms == nullptr) {
+                handle->ERROR_MESSAGE("Parameter ngeoms of GEOSGeom_releaseCollection_r must not be null");
+            }
+
+            GeometryCollection *col = dynamic_cast<GeometryCollection*>(collection);
+            if (!col) {
+                handle->ERROR_MESSAGE("Parameter collection of GEOSGeom_releaseCollection_r must not be a collection");
+            }
+
+            // Early exit on empty/null input
+            *ngeoms = static_cast<unsigned int>(col->getNumGeometries());
+            if (!col || *ngeoms == 0) {
+                return static_cast<Geometry**>(nullptr);
+            }
+
+            std::vector<std::unique_ptr<Geometry>> subgeoms = col->releaseGeometries();
+
+            Geometry** subgeomArray = static_cast<Geometry**>(malloc(sizeof(Geometry*) * subgeoms.size()));
+            for (std::size_t i = 0; i < subgeoms.size(); i++) {
+                subgeomArray[i] = subgeoms[i].release();
+            }
+
+            return subgeomArray;
+        });
+    }
+
     Geometry*
     GEOSPolygonize_r(GEOSContextHandle_t extHandle, const Geometry* const* g, unsigned int ngeoms)
     {
diff --git a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
index 7f8242588..11d640874 100644
--- a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
+++ b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
@@ -21,7 +21,11 @@ namespace tut {
 // Common data used in test cases.
 struct test_capigeosgeom_createcollection_data {
     GEOSContextHandle_t handle_;
-    GEOSGeom geom_; // collection result
+    GEOSWKTReader * reader_;
+    GEOSGeometry * geom_;
+    GEOSGeometry ** geoms_;
+    unsigned int ngeoms_;
+
     enum { geom_size = 3 };
 
     static void
@@ -37,16 +41,31 @@ struct test_capigeosgeom_createcollection_data {
         std::fprintf(stdout, "\n");
     }
 
+    GEOSGeometry*
+    read(const char* wkt)
+    {
+        return GEOSWKTReader_read_r(handle_, reader_, wkt);
+    }
+
     test_capigeosgeom_createcollection_data()
-        : handle_(initGEOS_r(notice, notice)), geom_(nullptr)
+        : handle_(initGEOS_r(notice, notice))
+        , reader_(GEOSWKTReader_create_r(handle_))
+        , geom_(nullptr)
+        , geoms_(nullptr)
+        , ngeoms_(0)
     {
     }
 
     ~test_capigeosgeom_createcollection_data()
     {
-        GEOSGeom_destroy(geom_);
-        geom_ = nullptr;
+        if (reader_) GEOSWKTReader_destroy_r(handle_, reader_);
+        if (geom_)   GEOSGeom_destroy_r(handle_, geom_);
+        if (geoms_)  GEOSFree_r(handle_, geoms_);
         finishGEOS_r(handle_);
+        handle_ = nullptr;
+        reader_ = nullptr;
+        geom_ = nullptr;
+        geoms_ = nullptr;
     }
 };
 
@@ -126,5 +145,63 @@ void object::test<4>
     ensure(geom_ == nullptr);
 }
 
+// Release empty collection
+template<>
+template<>
+void object::test<5>
+()
+{
+    const char *wkt = "MULTIPOLYGON EMPTY";
+    geom_ = read(wkt);
+    ensure(geom_ != nullptr);
+
+    geoms_ = GEOSGeom_releaseCollection_r(handle_, geom_, &ngeoms_);
+    ensure(geoms_ == nullptr);
+    ensure(ngeoms_ == 0);
+}
+
+
+// Release generic collection
+template<>
+template<>
+void object::test<6>
+()
+{
+    const char *wkt = "GEOMETRYCOLLECTION(POINT(0 0), POINT(1 1))";
+    geom_ = read(wkt);
+    ensure(geom_ != nullptr);
+
+    geoms_ = GEOSGeom_releaseCollection_r(handle_, geom_, &ngeoms_);
+    ensure(geoms_ != nullptr);
+    ensure(ngeoms_ == 2);
+
+    for (size_t i = 0 ; i < ngeoms_; i++) {
+        ensure(GEOSGeomTypeId_r(handle_, geoms_[i]) == GEOS_POINT);
+        GEOSGeom_destroy_r(handle_, geoms_[i]);
+    }
+
+}
+
+// Release typed collection
+template<>
+template<>
+void object::test<7>
+()
+{
+    const char *wkt = "MULTIPOINT(0 0, 1 1)";
+    geom_ = read(wkt);
+    ensure(geom_ != nullptr);
+
+    geoms_ = GEOSGeom_releaseCollection_r(handle_, geom_, &ngeoms_);
+    ensure(geoms_ != nullptr);
+    ensure(ngeoms_ == 2);
+
+    for (size_t i = 0 ; i < ngeoms_; i++) {
+        ensure(GEOSGeomTypeId_r(handle_, geoms_[i]) == GEOS_POINT);
+        GEOSGeom_destroy_r(handle_, geoms_[i]);
+    }
+
+}
+
 } // namespace tut
 

commit 8d67fd6be1b1c429f4b62376368e3c286b68cfc6
Author: Martin Davis <mtnclimb at gmail.com>
Date:   Sat Apr 29 21:29:03 2023 -0700

    Update NEWS

diff --git a/NEWS.md b/NEWS.md
index 9ea02451c..cb386f976 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -62,6 +62,9 @@ xxxx-xx-xx
   - LargestEmptyCircle: enhance boundary to allow any polygonal geometry (GH-859, Martin Davis)
   - Fix MaximumInscribedCircle and LargestEmptyCircle performance and memory issues (GH-883, Martin Davis)
 
+- Changes:
+  - Remove Orientation.isCCW exception to simplify logic and align with JTS (GH-878, Martin Davis)
+
 ## Changes in 3.11.0
 2022-07-01
 

commit d054731ccdafdeae3a094051e47f760b64ecf72f
Author: Casper van der Wel <caspervdw at gmail.com>
Date:   Sun Apr 30 00:50:56 2023 +0200

    Construction of XYZ points with NaN coordinates (#881)
    
    Coerce all-NaN points to empty at construction, constructing an empty point if its first coordinate is all-NaN

diff --git a/include/geos/geom/CoordinateSequence.h b/include/geos/geom/CoordinateSequence.h
index 34a725bd3..3070ec834 100644
--- a/include/geos/geom/CoordinateSequence.h
+++ b/include/geos/geom/CoordinateSequence.h
@@ -197,6 +197,20 @@ public:
         return m_vect.empty();
     }
 
+    /// Returns <code>true</code> if there is 1 coordinate and if it is null.
+    bool isNullPoint() const {
+        if (size() != 1) {
+            return false;
+        }
+        switch(getCoordinateType()) {
+            case CoordinateType::XY: return getAt<CoordinateXY>(0).isNull();
+            case CoordinateType::XYZ: return getAt<Coordinate>(0).isNull();
+            case CoordinateType::XYZM: return getAt<CoordinateXYZM>(0).isNull();
+            case CoordinateType::XYM: return getAt<CoordinateXYM>(0).isNull();
+            default: return false;
+        }
+    }
+
     /** \brief
     * Tests whether an a {@link CoordinateSequence} forms a ring,
     * by checking length and closure. Self-intersection is not checked.
diff --git a/src/geom/GeometryFactory.cpp b/src/geom/GeometryFactory.cpp
index 5b933b010..d30ee4906 100644
--- a/src/geom/GeometryFactory.cpp
+++ b/src/geom/GeometryFactory.cpp
@@ -224,16 +224,19 @@ GeometryFactory::createPoint(std::size_t coordinateDimension) const
 std::unique_ptr<Point>
 GeometryFactory::createPoint(std::unique_ptr<CoordinateSequence>&& coords) const
 {
-    return std::unique_ptr<Point>(new Point(
-                                      coords ? std::move(*coords) : CoordinateSequence(),
-                                      this));
+    if (!coords) {
+        return createPoint();
+    } else if ((*coords).isNullPoint()) {
+        return createPoint((*coords).getDimension());
+    }
+    return std::unique_ptr<Point>(new Point(std::move(*coords), this));
 }
 
 std::unique_ptr<Point>
 GeometryFactory::createPoint(const CoordinateXY& coordinate) const
 {
     if(coordinate.isNull()) {
-        return createPoint();
+        return createPoint(2);
     }
     else {
         return std::unique_ptr<Point>(new Point(coordinate, this));
@@ -245,7 +248,7 @@ std::unique_ptr<Point>
 GeometryFactory::createPoint(const Coordinate& coordinate) const
 {
     if(coordinate.isNull()) {
-        return createPoint();
+        return createPoint(3);
     }
     else {
         return std::unique_ptr<Point>(new Point(coordinate, this));
@@ -256,7 +259,7 @@ std::unique_ptr<Point>
 GeometryFactory::createPoint(const CoordinateXYM& coordinate) const
 {
     if(coordinate.isNull()) {
-        return createPoint();
+        return createPoint(4);  // can't do XYM!
     }
     else {
         return std::unique_ptr<Point>(new Point(coordinate, this));
@@ -267,7 +270,7 @@ std::unique_ptr<Point>
 GeometryFactory::createPoint(const CoordinateXYZM& coordinate) const
 {
     if(coordinate.isNull()) {
-        return createPoint();
+        return createPoint(4);
     }
     else {
         return std::unique_ptr<Point>(new Point(coordinate, this));
@@ -278,6 +281,9 @@ GeometryFactory::createPoint(const CoordinateXYZM& coordinate) const
 std::unique_ptr<Point>
 GeometryFactory::createPoint(const CoordinateSequence& fromCoords) const
 {
+    if (fromCoords.isNullPoint()) {
+        return createPoint(fromCoords.getDimension());
+    }
     CoordinateSequence newCoords(fromCoords);
     return std::unique_ptr<Point>(new Point(std::move(newCoords), this));
 
diff --git a/src/geom/Point.cpp b/src/geom/Point.cpp
index 86cf54ccc..b5c77570c 100644
--- a/src/geom/Point.cpp
+++ b/src/geom/Point.cpp
@@ -105,16 +105,7 @@ Point::getNumPoints() const
 bool
 Point::isEmpty() const
 {
-    if (coordinates.isEmpty()) {
-        return true;
-    }
-
-    const CoordinateXY& c = coordinates.getAt<CoordinateXY>(0);
-    if (std::isnan(c.x) && std::isnan(c.y)) {
-        return true;
-    }
-
-    return false;
+    return coordinates.isEmpty();
 }
 
 bool
diff --git a/src/io/WKTWriter.cpp b/src/io/WKTWriter.cpp
index 39740894f..7f1552240 100644
--- a/src/io/WKTWriter.cpp
+++ b/src/io/WKTWriter.cpp
@@ -281,7 +281,7 @@ WKTWriter::appendPointTaggedText(const Point& point, OrdinateSet outputOrdinates
     appendOrdinateText(outputOrdinates, writer);
 
     const CoordinateXY* coord = point.getCoordinate();
-    if (coord == nullptr || (std::isnan(coord->x) && std::isnan(coord->y))) {
+    if (coord == nullptr) {
         writer.write("EMPTY");
     } else {
         appendSequenceText(*point.getCoordinatesRO(), outputOrdinates, p_level, false, writer);

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

Summary of changes:
 NEWS.md                                           |  4 ++
 capi/geos_c.cpp                                   |  6 ++
 capi/geos_c.h.in                                  | 26 +++++++
 capi/geos_ts_c.cpp                                | 32 +++++++++
 include/geos/geom/CoordinateSequence.h            | 14 ++++
 src/geom/GeometryFactory.cpp                      | 20 ++++--
 src/geom/Point.cpp                                | 11 +--
 src/io/WKTWriter.cpp                              |  2 +-
 tests/unit/capi/GEOSGeom_createCollectionTest.cpp | 85 +++++++++++++++++++++--
 9 files changed, 178 insertions(+), 22 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list