[geos-commits] [SCM] GEOS branch main updated. 2289bad7aac673a1bffcbbdd96944fcc57405a9c

git at osgeo.org git at osgeo.org
Fri Oct 30 07:21:53 PDT 2026


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  2289bad7aac673a1bffcbbdd96944fcc57405a9c (commit)
       via  1ff45c6ba7c956c8f38fb5a139db626bb7d4c8dc (commit)
      from  4b364c0312ab3b396377afc3bba0a7fd70cf2f51 (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 2289bad7aac673a1bffcbbdd96944fcc57405a9c
Author: Alejandro Pacheco <ale at alepacheco.dev>
Date:   Thu Oct 29 07:16:51 2026 +0100

    Check element types of MultiPoint, MultiLineString and MultiPolygon
    
    The constructors taking a vector of Geometry now throw
    IllegalArgumentException for an element of another type, as the
    MultiCurve and MultiSurface constructors already do. This also covers
    GEOSGeom_createCollection.
    
    buildGeometry(from, toofar) chose its result type by sort index and
    dimension, so it put several CircularStrings or CompoundCurves into a
    MultiLineString and several collections of one type into a Multi*
    geometry. It now calls buildGeometry(const std::vector<const Geometry*>&),
    whose semantics its documentation already refers to. As a result,
    GEOSUnaryUnion of CircularStrings alone no longer fails with "Noder does
    not support curved paths".

diff --git a/include/geos/geom/GeometryFactory.h b/include/geos/geom/GeometryFactory.h
index 73fcb5995..22d663468 100644
--- a/include/geos/geom/GeometryFactory.h
+++ b/include/geos/geom/GeometryFactory.h
@@ -434,54 +434,7 @@ public:
     std::unique_ptr<Geometry>
     buildGeometry(T from, T toofar) const
     {
-        bool isHeterogeneous = false;
-        std::size_t count = 0;
-        int geomClass = -1;
-        for(T i = from; i != toofar; ++i) {
-            ++count;
-            const Geometry* g = *i;
-            if(geomClass < 0) {
-                geomClass = g->getSortIndex();
-            }
-            else if(geomClass != g->getSortIndex()) {
-                isHeterogeneous = true;
-            }
-        }
-
-        // for the empty geometry, return an empty GeometryCollection
-        if(count == 0) {
-            return std::unique_ptr<Geometry>(createGeometryCollection());
-        }
-
-        // for the single geometry, return a clone
-        if(count == 1) {
-            return (*from)->clone();
-        }
-
-        // Now we know it is a collection
-
-        // FIXME:
-        // Until we tweak all the createMulti* interfaces
-        // to support taking iterators we'll have to build
-        // a custom vector here.
-        std::vector<std::unique_ptr<Geometry>> fromGeoms;
-        for(T i = from; i != toofar; ++i) {
-            fromGeoms.push_back((*i)->clone());
-        }
-
-        // for an heterogeneous ...
-        if(isHeterogeneous) {
-            return createGeometryCollection(std::move(fromGeoms));
-        }
-
-        // At this point we know the collection is not hetereogenous.
-        switch((*from)->getDimension()) {
-            case Dimension::A: return createMultiPolygon(std::move(fromGeoms));
-            case Dimension::L: return createMultiLineString(std::move(fromGeoms));
-            case Dimension::P: return createMultiPoint(std::move(fromGeoms));
-            default:
-                throw geos::util::IllegalArgumentException(std::string("Invalid geometry type."));
-        }
+        return buildGeometry(std::vector<const Geometry*>(from, toofar));
     }
 
     /** \brief
diff --git a/src/geom/MultiLineString.cpp b/src/geom/MultiLineString.cpp
index c58615076..f4116f0b2 100644
--- a/src/geom/MultiLineString.cpp
+++ b/src/geom/MultiLineString.cpp
@@ -45,7 +45,14 @@ MultiLineString::MultiLineString(std::vector<std::unique_ptr<LineString>> && new
 MultiLineString::MultiLineString(std::vector<std::unique_ptr<Geometry>> && newLines,
                                  const GeometryFactory& factory)
         : GeometryCollection(std::move(newLines), factory)
-{}
+{
+    for (const auto& geom : geometries) {
+        const auto typeId = geom->getGeometryTypeId();
+        if (typeId != GEOS_LINESTRING && typeId != GEOS_LINEARRING) {
+            throw util::IllegalArgumentException("All elements of MultiLineString must be a LineString");
+        }
+    }
+}
 
 MultiLineString::MultiLineString(std::vector<std::unique_ptr<Curve>> && newLines,
                                  const GeometryFactory& factory)
diff --git a/src/geom/MultiPoint.cpp b/src/geom/MultiPoint.cpp
index aa615bf1a..8513e1bf1 100644
--- a/src/geom/MultiPoint.cpp
+++ b/src/geom/MultiPoint.cpp
@@ -22,6 +22,7 @@
 #include <geos/geom/MultiPoint.h>
 #include <geos/geom/GeometryFactory.h>
 #include <geos/geom/Dimension.h>
+#include <geos/util/IllegalArgumentException.h>
 
 #include <vector>
 
@@ -40,7 +41,11 @@ MultiPoint::MultiPoint(std::vector<std::unique_ptr<Geometry>> && newPoints, cons
         :
         GeometryCollection(std::move(newPoints), factory)
 {
-
+    for (const auto& geom : geometries) {
+        if (geom->getGeometryTypeId() != GEOS_POINT) {
+            throw util::IllegalArgumentException("All elements of MultiPoint must be a Point");
+        }
+    }
 }
 
 Dimension::DimensionType
diff --git a/src/geom/MultiPolygon.cpp b/src/geom/MultiPolygon.cpp
index ae5c253fc..8f7c82b68 100644
--- a/src/geom/MultiPolygon.cpp
+++ b/src/geom/MultiPolygon.cpp
@@ -25,6 +25,7 @@
 #include <geos/geom/MultiSurface.h>
 #include <geos/geom/GeometryFactory.h>
 #include <geos/geom/Dimension.h>
+#include <geos/util/IllegalArgumentException.h>
 
 #include <cassert>
 #include <string>
@@ -42,7 +43,13 @@ MultiPolygon::MultiPolygon(std::vector<std::unique_ptr<Polygon>> && newPolys, co
 
 MultiPolygon::MultiPolygon(std::vector<std::unique_ptr<Geometry>> && newPolys, const GeometryFactory& factory)
         : GeometryCollection(std::move(newPolys), factory)
-{}
+{
+    for (const auto& geom : geometries) {
+        if (geom->getGeometryTypeId() != GEOS_POLYGON) {
+            throw util::IllegalArgumentException("All elements of MultiPolygon must be a Polygon");
+        }
+    }
+}
 
 MultiPolygon::~MultiPolygon() {}
 
diff --git a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
index c52bce50a..56f40ef39 100644
--- a/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
+++ b/tests/unit/capi/GEOSGeom_createCollectionTest.cpp
@@ -202,5 +202,46 @@ void object::test<9>
 }
 
 
-} // namespace tut
+// Error on an element of another type, ownership is still transferred
+template<>
+template<>
+void object::test<10>
+()
+{
+    GEOSGeometry* points[2];
+    points[0] = fromWKT("POINT (0 0)");
+    points[1] = fromWKT("LINESTRING (0 0, 1 1)");
+    geom1_ = GEOSGeom_createCollection(GEOS_MULTIPOINT, points, 2);
+    ensure(geom1_ == nullptr);
 
+    GEOSGeometry* lines[2];
+    lines[0] = fromWKT("LINESTRING (0 0, 1 1)");
+    lines[1] = fromWKT("MULTILINESTRING ((2 2, 3 3))");
+    geom1_ = GEOSGeom_createCollection(GEOS_MULTILINESTRING, lines, 2);
+    ensure(geom1_ == nullptr);
+
+    GEOSGeometry* polygons[2];
+    polygons[0] = fromWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))");
+    polygons[1] = fromWKT("POINT (5 5)");
+    geom1_ = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, polygons, 2);
+    ensure(geom1_ == nullptr);
+}
+
+// A LinearRing is accepted as an element of a MultiLineString
+template<>
+template<>
+void object::test<11>
+()
+{
+    GEOSGeometry* lines[2];
+    lines[0] = fromWKT("LINEARRING (0 0, 1 0, 1 1, 0 0)");
+    lines[1] = fromWKT("LINESTRING (2 2, 3 3)");
+    geom1_ = GEOSGeom_createCollection(GEOS_MULTILINESTRING, lines, 2);
+    ensure(geom1_ != nullptr);
+
+    ensure_equals(GEOSGeomTypeId(geom1_), GEOS_MULTILINESTRING);
+    ensure_equals(GEOSGetNumGeometries(geom1_), 2);
+    ensure_equals(GEOSGeomTypeId(GEOSGetGeometryN(geom1_, 0)), GEOS_LINEARRING);
+}
+
+} // namespace tut
diff --git a/tests/unit/capi/GEOSUnaryUnionTest.cpp b/tests/unit/capi/GEOSUnaryUnionTest.cpp
index af484b8ef..802078ba9 100644
--- a/tests/unit/capi/GEOSUnaryUnionTest.cpp
+++ b/tests/unit/capi/GEOSUnaryUnionTest.cpp
@@ -333,6 +333,21 @@ void object::test<17>()
     ensure_geometry_equals(result_, input_, 1e-8);
 }
 
+template<>
+template<>
+void object::test<18>()
+{
+    set_test_name("CircularString-only dim=1 inputs");
+
+    input_ = fromWKT("MULTICURVE (CIRCULARSTRING (0 0, 1 1, 2 0), CIRCULARSTRING (2 0, 3 -1, 4 0))");
+
+    result_ = GEOSUnaryUnion(input_);
+    ensure(result_);
+
+    expected_ = fromWKT("CIRCULARSTRING (0 0, 1 1, 2 0, 3 -1, 4 0)");
+    ensure_geometry_equals(result_, expected_, 1e-8);
+}
+
 } // namespace tut
 
 
diff --git a/tests/unit/geom/GeometryFactoryTest.cpp b/tests/unit/geom/GeometryFactoryTest.cpp
index 30a27a924..3d950d03c 100644
--- a/tests/unit/geom/GeometryFactoryTest.cpp
+++ b/tests/unit/geom/GeometryFactoryTest.cpp
@@ -3,6 +3,7 @@
 
 // tut
 #include <tut/tut.hpp>
+#include <tut/tut_macros.hpp>
 #include <utility.h>
 // geos
 #include <geos/geom/GeometryFactory.h>
@@ -1622,4 +1623,87 @@ void object::test<44>()
     }
 }
 
+template<>
+template<>
+void object::test<45>()
+{
+    set_test_name("createMultiPoint, createMultiLineString, createMultiPolygon reject elements of another type");
+
+    using geos::geom::Geometry;
+    using geos::util::IllegalArgumentException;
+
+    auto elements = [this](const std::string& wkt1, const std::string& wkt2) {
+        std::vector<std::unique_ptr<Geometry>> geoms;
+        geoms.push_back(reader_.read(wkt1));
+        geoms.push_back(reader_.read(wkt2));
+        return geoms;
+    };
+
+    ensure_THROW(factory_->createMultiPoint(elements("POINT (0 0)", "MULTIPOINT ((1 1))")), IllegalArgumentException);
+    ensure_THROW(factory_->createMultiPoint(elements("POINT (0 0)", "LINESTRING (0 0, 1 1)")), IllegalArgumentException);
+
+    ensure_THROW(factory_->createMultiLineString(elements("LINESTRING (0 0, 1 1)", "MULTILINESTRING ((2 2, 3 3))")), IllegalArgumentException);
+    ensure_THROW(factory_->createMultiLineString(elements("LINESTRING (0 0, 1 1)", "CIRCULARSTRING (0 0, 1 1, 2 0)")), IllegalArgumentException);
+    ensure_THROW(factory_->createMultiLineString(elements("LINESTRING (0 0, 1 1)", "POINT (0 0)")), IllegalArgumentException);
+
+    ensure_THROW(factory_->createMultiPolygon(elements("POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON (((2 2, 3 2, 3 3, 2 2)))")), IllegalArgumentException);
+    ensure_THROW(factory_->createMultiPolygon(elements("POLYGON ((0 0, 1 0, 1 1, 0 0))", "CURVEPOLYGON ((2 2, 3 2, 3 3, 2 2))")), IllegalArgumentException);
+    ensure_THROW(factory_->createMultiPolygon(elements("POLYGON ((0 0, 1 0, 1 1, 0 0))", "LINESTRING (0 0, 1 1)")), IllegalArgumentException);
+
+    // createMultiPolygon(const std::vector<const Geometry*>&) clones into the checked constructor
+    auto poly = reader_.read("POLYGON ((0 0, 1 0, 1 1, 0 0))");
+    auto mpoly = reader_.read("MULTIPOLYGON (((2 2, 3 2, 3 3, 2 2)))");
+    std::vector<const Geometry*> borrowed{ poly.get(), mpoly.get() };
+    ensure_THROW(factory_->createMultiPolygon(borrowed), IllegalArgumentException);
+
+    // A LinearRing is a LineString
+    auto mls = factory_->createMultiLineString(elements("LINESTRING (0 0, 1 1)", "LINEARRING (2 2, 3 2, 3 3, 2 2)"));
+    ensure_equals(mls->getNumGeometries(), 2u);
+}
+
+template<>
+template<>
+void object::test<46>()
+{
+    set_test_name("buildGeometry(from, toofar) and buildGeometry(const std::vector<const Geometry*>&) give the same type");
+
+    using geos::geom::Geometry;
+    using geos::geom::GeometryTypeId;
+
+    struct Case {
+        std::string wkt1;
+        std::string wkt2;
+        GeometryTypeId type;
+    };
+
+    const std::vector<Case> cases = {
+        { "POINT (1 1)", "POINT (2 2)", geos::geom::GEOS_MULTIPOINT },
+        { "LINESTRING (0 0, 1 1)", "LINESTRING (2 2, 3 3)", geos::geom::GEOS_MULTILINESTRING },
+        { "LINESTRING (0 0, 1 1)", "LINEARRING (2 2, 3 2, 3 3, 2 2)", geos::geom::GEOS_MULTILINESTRING },
+        { "POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((2 2, 3 2, 3 3, 2 2))", geos::geom::GEOS_MULTIPOLYGON },
+        { "CIRCULARSTRING (0 0, 1 1, 2 0)", "CIRCULARSTRING (2 0, 3 1, 4 0)", geos::geom::GEOS_MULTICURVE },
+        { "COMPOUNDCURVE ((0 0, 1 1))", "COMPOUNDCURVE ((2 2, 3 3))", geos::geom::GEOS_MULTICURVE },
+        { "LINESTRING (0 0, 1 1)", "CIRCULARSTRING (2 0, 3 1, 4 0)", geos::geom::GEOS_MULTICURVE },
+        { "CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0))", "CURVEPOLYGON ((2 2, 3 2, 3 3, 2 2))", geos::geom::GEOS_MULTISURFACE },
+        { "POLYGON ((0 0, 1 0, 1 1, 0 0))", "CURVEPOLYGON ((2 2, 3 2, 3 3, 2 2))", geos::geom::GEOS_MULTISURFACE },
+        { "MULTIPOINT ((0 0))", "MULTIPOINT ((2 2), (3 3))", geos::geom::GEOS_GEOMETRYCOLLECTION },
+        { "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)))", "MULTIPOLYGON (((2 2, 3 2, 3 3, 2 2)))", geos::geom::GEOS_GEOMETRYCOLLECTION },
+        { "POINT (1 1)", "LINESTRING (2 2, 3 3)", geos::geom::GEOS_GEOMETRYCOLLECTION },
+    };
+
+    for (const auto& c : cases) {
+        auto g1 = reader_.read(c.wkt1);
+        auto g2 = reader_.read(c.wkt2);
+        std::vector<const Geometry*> geoms{ g1.get(), g2.get() };
+
+        auto fromVector = factory_->buildGeometry(geoms);
+        ensure_equals(c.wkt2, fromVector->getGeometryTypeId(), c.type);
+        ensure_equals(c.wkt2, fromVector->getNumGeometries(), 2u);
+
+        auto fromIterators = factory_->buildGeometry(geoms.begin(), geoms.end());
+        ensure_equals(c.wkt2, fromIterators->getGeometryTypeId(), c.type);
+        ensure_equals(c.wkt2, fromIterators->getNumGeometries(), 2u);
+    }
+}
+
 } // namespace tut

commit 1ff45c6ba7c956c8f38fb5a139db626bb7d4c8dc
Author: Alejandro Pacheco <ale at alepacheco.dev>
Date:   Thu Oct 29 07:16:51 2026 +0100

    GeometryFactory::buildGeometry: return GeometryCollection when an element is a collection
    
    Since 4e50c4d3c, commonType compares the dimension of the elements
    rather than their type, so a collection among elements of one
    dimension gave a MultiPoint, MultiLineString or MultiPolygon holding
    that collection. Return a GeometryCollection for these, as the
    documentation of buildGeometry says and as 3.14 did.

diff --git a/src/geom/GeometryFactory.cpp b/src/geom/GeometryFactory.cpp
index 1454dc86a..541b90649 100644
--- a/src/geom/GeometryFactory.cpp
+++ b/src/geom/GeometryFactory.cpp
@@ -903,7 +903,9 @@ GeometryTypeId commonType(const T& geoms) {
     for (std::size_t i = 1; i < geoms.size(); i++) {
         curvedType |= geoms[i]->hasCurvedTypes();
 
-        if (geoms[i]->getDimension() != dim) {
+        // A collection can only be an element of a GeometryCollection,
+        // even when its dimension matches the other elements.
+        if (geoms[i]->isCollection() || geoms[i]->getDimension() != dim) {
             return GEOS_GEOMETRYCOLLECTION;
         }
     }
diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp
index 43e87d569..2f1145132 100644
--- a/tests/unit/capi/GEOSDensifyTest.cpp
+++ b/tests/unit/capi/GEOSDensifyTest.cpp
@@ -227,4 +227,20 @@ void object::test<14>()
     );
 }
 
+template<>
+template<>
+void object::test<15>()
+{
+    set_test_name("MultiPolygon with rings collapsed to lines gives a GeometryCollection");
+
+    input_ = fromWKT("MULTIPOLYGON (((0 0, 1 1, 0 0)), ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+
+    result_ = GEOSDensify(input_, 100);
+    ensure(result_);
+
+    // Not a MultiLineString with a MultiLineString element
+    ensure_equals(GEOSGeomTypeId(result_), GEOS_GEOMETRYCOLLECTION);
+    ensure_equals(toWKT(result_), "GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1, 0 0), MULTILINESTRING ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+}
+
 } // namespace tut
diff --git a/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp b/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp
index 2c70f84d3..4f1f1609c 100644
--- a/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp
+++ b/tests/unit/capi/GEOSGeom_setPrecisionTest.cpp
@@ -339,5 +339,20 @@ void object::test<24>()
     ensure_geometry_equals_identical(result_, input_);
 }
 
-} // namespace tut
+template<>
+template<>
+void object::test<25>()
+{
+    set_test_name("MultiPolygon with rings collapsed to lines gives a GeometryCollection");
 
+    input_ = fromWKT("MULTIPOLYGON (((0 0, 1 1, 0 0)), ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+
+    result_ = GEOSGeom_setPrecision(input_, 1.0, GEOS_PREC_NO_TOPO);
+    ensure(result_);
+
+    // Not a MultiLineString with a MultiLineString element
+    ensure_equals(GEOSGeomTypeId(result_), GEOS_GEOMETRYCOLLECTION);
+    ensure_equals(toWKT(result_), "GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1, 0 0), MULTILINESTRING ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+}
+
+} // namespace tut
diff --git a/tests/unit/capi/GEOSSnapTest.cpp b/tests/unit/capi/GEOSSnapTest.cpp
index 7fedee2e6..f56f0d5d6 100644
--- a/tests/unit/capi/GEOSSnapTest.cpp
+++ b/tests/unit/capi/GEOSSnapTest.cpp
@@ -220,5 +220,20 @@ void object::test<11>()
     ensure("curved geometry not supported", result_ == nullptr);
 }
 
-} // namespace tut
+template<>
+template<>
+void object::test<12>()
+{
+    set_test_name("MultiPolygon with rings collapsed to lines gives a GeometryCollection");
 
+    input_ = fromWKT("MULTIPOLYGON (((0 0, 1 1, 0 0)), ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+
+    result_ = GEOSSnap(input_, input_, 0);
+    ensure(result_);
+
+    // Not a MultiLineString with a MultiLineString element
+    ensure_equals(GEOSGeomTypeId(result_), GEOS_GEOMETRYCOLLECTION);
+    ensure_equals(toWKT(result_), "GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1, 0 0), MULTILINESTRING ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+}
+
+} // namespace tut
diff --git a/tests/unit/capi/GEOSTopologyPreserveSimplifyTest.cpp b/tests/unit/capi/GEOSTopologyPreserveSimplifyTest.cpp
index a6ada22d1..11517b2e9 100644
--- a/tests/unit/capi/GEOSTopologyPreserveSimplifyTest.cpp
+++ b/tests/unit/capi/GEOSTopologyPreserveSimplifyTest.cpp
@@ -74,5 +74,20 @@ void object::test<4>()
     ensure_geometry_equals_identical(result_, expected_);
 }
 
-} // namespace tut
+template<>
+template<>
+void object::test<5>()
+{
+    set_test_name("MultiPolygon with rings collapsed to lines gives a GeometryCollection");
 
+    input_ = fromWKT("MULTIPOLYGON (((0 0, 1 1, 0 0)), ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+
+    result_ = GEOSTopologyPreserveSimplify(input_, 0);
+    ensure(result_);
+
+    // Not a MultiLineString with a MultiLineString element
+    ensure_equals(GEOSGeomTypeId(result_), GEOS_GEOMETRYCOLLECTION);
+    ensure_equals(toWKT(result_), "GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1, 0 0), MULTILINESTRING ((10 10, 11 11, 10 10), (0 0, 30 0, 30 30, 0 30, 0 0)))");
+}
+
+} // namespace tut
diff --git a/tests/unit/geom/GeometryFactoryTest.cpp b/tests/unit/geom/GeometryFactoryTest.cpp
index 3b10c2015..30a27a924 100644
--- a/tests/unit/geom/GeometryFactoryTest.cpp
+++ b/tests/unit/geom/GeometryFactoryTest.cpp
@@ -22,6 +22,8 @@
 #include <geos/util/IllegalArgumentException.h>
 #include <geos/util.h>
 // std
+#include <string>
+#include <utility>
 #include <vector>
 #include <cstring> // std::size_t
 
@@ -1575,5 +1577,49 @@ void object::test<43>()
         ensure_equals(g->getNumGeometries(), 2u);
     }
 }
-    
+
+template<>
+template<>
+void object::test<44>()
+{
+    set_test_name("buildGeometry returns a GeometryCollection when an element is a collection");
+
+    using geos::geom::Geometry;
+
+    const std::vector<std::pair<std::string, std::string>> cases = {
+        { "POINT (1 1)", "MULTIPOINT ((2 2), (3 3))" },
+        { "LINESTRING (0 0, 1 1)", "MULTILINESTRING ((2 2, 3 3), (4 4, 5 5))" },
+        { "POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON (((2 2, 3 2, 3 3, 2 2)))" },
+        { "LINESTRING (0 0, 1 1)", "GEOMETRYCOLLECTION (LINESTRING (2 2, 3 3))" },
+        { "CIRCULARSTRING (0 0, 1 1, 2 0)", "MULTICURVE ((2 2, 3 3))" },
+        { "POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTISURFACE (((2 2, 3 2, 3 3, 2 2)))" },
+    };
+
+    for (const auto& c : cases) {
+        auto single = reader_.read(c.first);
+        auto multi = reader_.read(c.second);
+
+        for (bool multiFirst : { false, true }) {
+            const Geometry* a = multiFirst ? multi.get() : single.get();
+            const Geometry* b = multiFirst ? single.get() : multi.get();
+
+            std::vector<std::unique_ptr<Geometry>> owned;
+            owned.push_back(a->clone());
+            owned.push_back(b->clone());
+            auto fromOwned = factory_->buildGeometry(std::move(owned));
+            ensure_equals(c.second, fromOwned->getGeometryTypeId(), geos::geom::GEOS_GEOMETRYCOLLECTION);
+            ensure_equals(c.second, fromOwned->getNumGeometries(), 2u);
+
+            std::vector<const Geometry*> borrowed{ a, b };
+            auto fromBorrowed = factory_->buildGeometry(borrowed);
+            ensure_equals(c.second, fromBorrowed->getGeometryTypeId(), geos::geom::GEOS_GEOMETRYCOLLECTION);
+            ensure_equals(c.second, fromBorrowed->getNumGeometries(), 2u);
+
+            auto fromIterators = factory_->buildGeometry(borrowed.begin(), borrowed.end());
+            ensure_equals(c.second, fromIterators->getGeometryTypeId(), geos::geom::GEOS_GEOMETRYCOLLECTION);
+            ensure_equals(c.second, fromIterators->getNumGeometries(), 2u);
+        }
+    }
+}
+
 } // namespace tut

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

Summary of changes:
 include/geos/geom/GeometryFactory.h                |  49 +-------
 src/geom/GeometryFactory.cpp                       |   4 +-
 src/geom/MultiLineString.cpp                       |   9 +-
 src/geom/MultiPoint.cpp                            |   7 +-
 src/geom/MultiPolygon.cpp                          |   9 +-
 tests/unit/capi/GEOSDensifyTest.cpp                |  16 +++
 tests/unit/capi/GEOSGeom_createCollectionTest.cpp  |  43 ++++++-
 tests/unit/capi/GEOSGeom_setPrecisionTest.cpp      |  17 ++-
 tests/unit/capi/GEOSSnapTest.cpp                   |  17 ++-
 .../unit/capi/GEOSTopologyPreserveSimplifyTest.cpp |  17 ++-
 tests/unit/capi/GEOSUnaryUnionTest.cpp             |  15 +++
 tests/unit/geom/GeometryFactoryTest.cpp            | 132 ++++++++++++++++++++-
 12 files changed, 278 insertions(+), 57 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list