Skip to content

Commit

Permalink
Add GEOSGeom_releaseCollection to CAPI (libgeos#882)
Browse files Browse the repository at this point in the history
Add GEOSGeom_releaseCollection to CAPI, references libgeosGH-848
  • Loading branch information
pramsey authored May 2, 2023
1 parent 8d67fd6 commit 1105298
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 4 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions capi/geos_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
26 changes: 26 additions & 0 deletions capi/geos_c.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions capi/geos_ts_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
85 changes: 81 additions & 4 deletions tests/unit/capi/GEOSGeom_createCollectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
};

Expand Down Expand Up @@ -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

0 comments on commit 1105298

Please sign in to comment.