Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions capi/geos_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,12 @@ extern "C" {
return GEOSGeom_createCurvePolygon_r(handle, shell, holes, nholes);
}

Geometry*
GEOSGeom_homogenize(Geometry* g)
{
return GEOSGeom_homogenize_r(handle, g);
}

Geometry*
GEOSGeom_clone(const Geometry* g)
{
Expand Down
21 changes: 21 additions & 0 deletions capi/geos_c.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,11 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_createRectangle_r(
double xmin, double ymin,
double xmax, double ymax);

/** \see GEOSGeom_homogenize */
extern GEOSGeometry GEOS_DLL * GEOSGeom_homogenize_r(
GEOSContextHandle_t handle,
GEOSGeometry * g);

/** \see GEOSGeom_clone */
extern GEOSGeometry GEOS_DLL *GEOSGeom_clone_r(
GEOSContextHandle_t handle,
Expand Down Expand Up @@ -3107,6 +3112,22 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_createRectangle(
double xmin, double ymin,
double xmax, double ymax);

/**
* Returns the most specific representation of a geometry.
*
* If the input is a multi-element GeometryCollection whose elements all have
* the same type, then the input will be destroyed and a new collection
* of an appropriate type returned (MultiLineString, MultiPolygon, etc.) If the
* input is a single-element GeometryCollection, then the input will be
* destroyed and the single element returned. If the elements are not
* homogeneous, or if the input is not a collection, it will be returned
* unmodified. Nested collections are collapsed during processing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the current logic is all collection specific, should the function be named accordingly? ie "GEOSGeom_homogenizeCollection"?

There's an argument to be made that generic homogenization should also do things like turn a multilinestring containing a single linestring to a linestring, or turning a curve polygon which only consists of linestring rings into a non-curved polygon, or a compound curve with only straight segments to a linestring, etc...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the function should be GEOSGeom_simplifyStructure, and it should handle the curve->line cases you're describing.

*
* \since 3.15
*/
extern GEOSGeometry GEOS_DLL *GEOSGeom_homogenize(
GEOSGeometry* g);

/**
* Create a new copy of the input geometry.
* \param g The geometry to copy
Expand Down
12 changes: 12 additions & 0 deletions capi/geos_ts_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3860,6 +3860,18 @@ extern "C" {
});
}

Geometry*
GEOSGeom_homogenize_r(GEOSContextHandle_t extHandle, Geometry* g)
{
return execute(extHandle, [&]() -> Geometry* {
const int srid = g->getSRID();

auto g3 = geos::operation::cluster::GeometryFlattener::flatten(std::unique_ptr<Geometry>(g));
g3->setSRID(srid);
return g3.release();
});
}

Geometry*
GEOSGeom_clone_r(GEOSContextHandle_t extHandle, const Geometry* g)
{
Expand Down
2 changes: 1 addition & 1 deletion include/geos/geom/util/GeometryExtracter.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class GEOS_DLL GeometryExtracter {
*
* @param comps the container to extract into (will push_back to it)
*/
Extracter(TargetContainer& comps) : comps_(comps) {}
explicit Extracter(TargetContainer& comps) : comps_(comps) {}

TargetContainer& comps_;

Expand Down
96 changes: 96 additions & 0 deletions tests/unit/capi/GEOSGeom_homogenizeTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <tut/tut.hpp>
// geos
#include <geos_c.h>

#include "capi_test_utils.h"

namespace tut {
struct test_capigeosgeom_homogenize : public capitest::utility {

void testHomogenize(const std::string& wkt_in, const std::string& wkt_expected) {
GEOSGeometry* input = fromWKT(wkt_in.c_str());
result_ = GEOSGeom_homogenize(input);
expected_ = fromWKT(wkt_expected.c_str());

ensure_geometry_equals(result_, expected_);
}

void testHomogenizeUnchanged(const std::string& wkt) {
testHomogenize(wkt, wkt);
}
};

typedef test_group<test_capigeosgeom_homogenize> group;
typedef group::object object;

group test_capigeosgeom_homogenize_group("capi::GEOSGeom_homogenize");

template<>
template<>
void object::test<1>()
{
set_test_name("non-collection type");

testHomogenizeUnchanged("LINESTRING (0 0, 1 1)");
}

template<>
template<>
void object::test<2>()
{
set_test_name("non-homogeneous collection");

testHomogenizeUnchanged("GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1), POINT (2 2))");
}

template<>
template<>
void object::test<3>()
{
set_test_name("single-element collection");

testHomogenize("GEOMETRYCOLLECTION (POINT (0 2))", "POINT (0 2)");
testHomogenize("MULTIPOINT ((8 2))", "POINT (8 2)");
}

template<>
template<>
void object::test<4>()
{
set_test_name("homogeneous collection");

testHomogenize("GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1), LINESTRING (4 3, 2 7))",
"MULTILINESTRING ((0 0, 1 1), (4 3, 2 7))" );
}

template<>
template<>
void object::test<5>()
{
set_test_name("empty collection");

testHomogenizeUnchanged("GEOMETRYCOLLECTION EMPTY");
}

template<>
template<>
void object::test<6>()
{
set_test_name("nested homogeneous collection");

testHomogenize("GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1), GEOMETRYCOLLECTION(LINESTRING EMPTY, MULTILINESTRING ((1 1, 2 2), (2 2, 3 3))))",
"MULTILINESTRING ((0 0, 1 1), (1 1, 2 2), (2 2, 3 3), EMPTY)");
}

template<>
template<>
void object::test<7>()
{
set_test_name("nested non-homogeneous collection");

testHomogenize("GEOMETRYCOLLECTION (LINESTRING (0 0, 1 1), GEOMETRYCOLLECTION(COMPOUNDCURVE ((1 1, 2 2))))",
"MULTICURVE (LINESTRING (0 0, 1 1), COMPOUNDCURVE ((1 1, 2 2)))");
}

} // namespace tut

Loading