Skip to content

Commit 3962961

Browse files
authored
C API: Add functions to create curved types (#1108)
1 parent 5dc668b commit 3962961

7 files changed

+437
-0
lines changed

capi/geos_c.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,24 @@ extern "C" {
12041204
return GEOSGeom_createPolygon_r(handle, shell, holes, nholes);
12051205
}
12061206

1207+
Geometry*
1208+
GEOSGeom_createCircularString(CoordinateSequence* cs)
1209+
{
1210+
return GEOSGeom_createCircularString_r(handle, cs);
1211+
}
1212+
1213+
Geometry*
1214+
GEOSGeom_createCompoundCurve(Geometry** curves, unsigned int ngeoms)
1215+
{
1216+
return GEOSGeom_createCompoundCurve_r(handle, curves, ngeoms);
1217+
}
1218+
1219+
Geometry*
1220+
GEOSGeom_createCurvePolygon(Geometry* shell, Geometry** holes, unsigned int nholes)
1221+
{
1222+
return GEOSGeom_createCurvePolygon_r(handle, shell, holes, nholes);
1223+
}
1224+
12071225
Geometry*
12081226
GEOSGeom_clone(const Geometry* g)
12091227
{
@@ -1728,6 +1746,24 @@ extern "C" {
17281746
return GEOSGeom_createEmptyPolygon_r(handle);
17291747
}
17301748

1749+
geos::geom::Geometry*
1750+
GEOSGeom_createEmptyCircularString()
1751+
{
1752+
return GEOSGeom_createEmptyCircularString_r(handle);
1753+
}
1754+
1755+
geos::geom::Geometry*
1756+
GEOSGeom_createEmptyCompoundCurve()
1757+
{
1758+
return GEOSGeom_createEmptyCompoundCurve_r(handle);
1759+
}
1760+
1761+
geos::geom::Geometry*
1762+
GEOSGeom_createEmptyCurvePolygon()
1763+
{
1764+
return GEOSGeom_createEmptyCurvePolygon_r(handle);
1765+
}
1766+
17311767
geos::geom::Geometry*
17321768
GEOSGeom_createRectangle(double xmin, double ymin, double xmax,
17331769
double ymax)

capi/geos_c.h.in

+92
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,36 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_clone_r(
763763
GEOSContextHandle_t handle,
764764
const GEOSGeometry* g);
765765

766+
/** \see GEOSGeom_createCircularString */
767+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCircularString_r(
768+
GEOSContextHandle_t handle,
769+
GEOSCoordSequence* s);
770+
771+
/** \see GEOSGeom_createEmptyCircularString */
772+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCircularString_r(
773+
GEOSContextHandle_t handle);
774+
775+
/** \see GEOSGeom_createCompoundCurve */
776+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCompoundCurve_r(
777+
GEOSContextHandle_t handle,
778+
GEOSGeometry** curves,
779+
unsigned int ncurves);
780+
781+
/** \see GEOSGeom_createEmptyCompoundCurve */
782+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCompoundCurve_r(
783+
GEOSContextHandle_t handle);
784+
785+
/** \see GEOSGeom_createCurvePolygon */
786+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCurvePolygon_r(
787+
GEOSContextHandle_t handle,
788+
GEOSGeometry* shell,
789+
GEOSGeometry** holes,
790+
unsigned int nholes);
791+
792+
/** \see GEOSGeom_createEmptyCurvePolygon */
793+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCurvePolygon_r(
794+
GEOSContextHandle_t handle);
795+
766796
/* ========= Memory management ========= */
767797

768798
/** \see GEOSGeom_destroy */
@@ -2458,6 +2488,68 @@ extern GEOSGeometry GEOS_DLL *GEOSGeom_createPolygon(
24582488
GEOSGeometry** holes,
24592489
unsigned int nholes);
24602490

2491+
/**
2492+
* Creates a CircularString geometry.
2493+
* \param s Input coordinate sequence, ownership passes to the geometry
2494+
* \return A newly allocated CircularString geometry. NULL on exception.
2495+
* Caller is responsible for freeing with GEOSGeom_destroy().
2496+
* \since 3.13
2497+
*/
2498+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCircularString(GEOSCoordSequence* s);
2499+
2500+
/**
2501+
* Creates an empty CircularString geometry.
2502+
* \return A newly allocated CircularString geometry. NULL on exception.
2503+
* Caller is responsible for freeing with GEOSGeom_destroy().
2504+
* \since 3.13
2505+
*/
2506+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCircularString();
2507+
2508+
/**
2509+
* Creates a CompoundCurve geometry.
2510+
* \param curves A list of geometries that will form the CompoundCurve
2511+
* \param ncurves The number of geometries in the curves list
2512+
* \return A newly allocated CompoundCurve geometry. NULL on exception.
2513+
* Caller is responsible for freeing with GEOSGeom_destroy().
2514+
* \since 3.13
2515+
*/
2516+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCompoundCurve(GEOSGeometry** curves,
2517+
unsigned int ncurves);
2518+
2519+
/**
2520+
* Creates an empty CompoundCurve geometry.
2521+
* \return A newly allocated CompoundCurve geometry. NULL on exception.
2522+
* Caller is responsible for freeing with GEOSGeom_destroy().
2523+
* \since 3.13
2524+
*/
2525+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCompoundCurve();
2526+
2527+
/**
2528+
* Creates a CurvePolygon geometry from ring geometries.
2529+
* \param shell A ring that is the exterior ring of the polygon.
2530+
* \param holes An array of rings that are the holes.
2531+
* \param nholes The number of rings in the holes array.
2532+
* \return A newly allocated geometry. NULL on exception.
2533+
* Caller is responsible for freeing with GEOSGeom_destroy().
2534+
* \note The holes argument is an array of GEOSGeometry* objects.
2535+
* The caller **retains ownership** of the containing array,
2536+
* but the ownership of the pointed-to objects is transferred
2537+
* to the returned \ref GEOSGeometry.
2538+
* \since 3.13
2539+
*/
2540+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createCurvePolygon(
2541+
GEOSGeometry* shell,
2542+
GEOSGeometry** holes,
2543+
unsigned int nholes);
2544+
2545+
/**
2546+
* Creates an empty CurvePolygon geometry.
2547+
* \return A newly allocated CurvePolygon geometry. NULL on exception.
2548+
* Caller is responsible for freeing with GEOSGeom_destroy().
2549+
* \since 3.13
2550+
*/
2551+
extern GEOSGeometry GEOS_DLL *GEOSGeom_createEmptyCurvePolygon();
2552+
24612553
/**
24622554
* Create a geometry collection.
24632555
* \param type The geometry type, enumerated by \ref GEOSGeomTypes

capi/geos_ts_c.cpp

+117
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@
3131
#include <geos/coverage/CoverageValidator.h>
3232
#include <geos/coverage/CoverageSimplifier.h>
3333
#include <geos/coverage/CoverageUnion.h>
34+
#include <geos/geom/CircularString.h>
35+
#include <geos/geom/CompoundCurve.h>
3436
#include <geos/geom/Coordinate.h>
3537
#include <geos/geom/CoordinateSequence.h>
3638
#include <geos/geom/Curve.h>
39+
#include <geos/geom/CurvePolygon.h>
3740
#include <geos/geom/Envelope.h>
3841
#include <geos/geom/Geometry.h>
3942
#include <geos/geom/GeometryCollection.h>
@@ -46,6 +49,7 @@
4649
#include <geos/geom/MultiLineString.h>
4750
#include <geos/geom/MultiPoint.h>
4851
#include <geos/geom/MultiPolygon.h>
52+
#include <geos/geom/MultiSurface.h>
4953
#include <geos/geom/Point.h>
5054
#include <geos/geom/Polygon.h>
5155
#include <geos/geom/PrecisionModel.h>
@@ -2078,6 +2082,12 @@ extern "C" {
20782082
case GEOS_MULTIPOLYGON:
20792083
g = gf->createMultiPolygon(std::move(vgeoms));
20802084
break;
2085+
case GEOS_MULTICURVE:
2086+
g = gf->createMultiCurve(std::move(vgeoms));
2087+
break;
2088+
case GEOS_MULTISURFACE:
2089+
g = gf->createMultiSurface(std::move(vgeoms));
2090+
break;
20812091
default:
20822092
handle->ERROR_MESSAGE("Unsupported type request for GEOSGeom_createCollection_r");
20832093
}
@@ -2991,6 +3001,113 @@ extern "C" {
29913001
});
29923002
}
29933003

3004+
Geometry*
3005+
GEOSGeom_createCircularString_r(GEOSContextHandle_t extHandle, CoordinateSequence* cs)
3006+
{
3007+
return execute(extHandle, [&]() {
3008+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3009+
const GeometryFactory* gf = handle->geomFactory;
3010+
3011+
return gf->createCircularString(std::unique_ptr<CoordinateSequence>(cs)).release();
3012+
});
3013+
}
3014+
3015+
Geometry*
3016+
GEOSGeom_createEmptyCircularString_r(GEOSContextHandle_t extHandle)
3017+
{
3018+
return execute(extHandle, [&]() {
3019+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3020+
const GeometryFactory* gf = handle->geomFactory;
3021+
3022+
return gf->createCircularString(false, false).release();
3023+
});
3024+
}
3025+
3026+
Geometry*
3027+
GEOSGeom_createCompoundCurve_r(GEOSContextHandle_t extHandle, Geometry** geoms, unsigned int ngeoms)
3028+
{
3029+
return execute(extHandle, [&]() -> Geometry* {
3030+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3031+
const GeometryFactory* gf = handle->geomFactory;
3032+
3033+
bool invalid_input = false;
3034+
std::vector<std::unique_ptr<SimpleCurve>> geom_vec(ngeoms);
3035+
for (std::size_t i = 0; i < ngeoms; i++) {
3036+
if (SimpleCurve* c = dynamic_cast<SimpleCurve*>(geoms[i])) {
3037+
geom_vec[i].reset(c);
3038+
} else {
3039+
delete geoms[i];
3040+
invalid_input = true;
3041+
}
3042+
}
3043+
3044+
if (invalid_input) {
3045+
throw IllegalArgumentException("Input is not a SimpleCurve");
3046+
}
3047+
3048+
return gf->createCompoundCurve(std::move(geom_vec)).release();
3049+
});
3050+
}
3051+
3052+
Geometry*
3053+
GEOSGeom_createEmptyCompoundCurve_r(GEOSContextHandle_t extHandle)
3054+
{
3055+
return execute(extHandle, [&]() {
3056+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3057+
const GeometryFactory* gf = handle->geomFactory;
3058+
3059+
return gf->createCompoundCurve().release();
3060+
});
3061+
}
3062+
3063+
Geometry*
3064+
GEOSGeom_createCurvePolygon_r(GEOSContextHandle_t extHandle, Geometry* p_shell, Geometry** p_holes, unsigned int nholes)
3065+
{
3066+
return execute(extHandle, [&]() {
3067+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3068+
const GeometryFactory* gf = handle->geomFactory;
3069+
bool good_holes = true, good_shell = true;
3070+
3071+
std::unique_ptr<Curve> shell;
3072+
std::vector<std::unique_ptr<Curve>> holes(nholes);
3073+
3074+
if (Curve* c = dynamic_cast<Curve*>(p_shell)) {
3075+
shell.reset(c);
3076+
} else {
3077+
good_shell = false;
3078+
delete p_shell;
3079+
}
3080+
3081+
for (std::size_t i = 0; i < nholes; i++) {
3082+
if (Curve* c = dynamic_cast<Curve*>(p_holes[i])) {
3083+
holes[i].reset(c);
3084+
} else {
3085+
good_shell = false;
3086+
delete p_holes[i];
3087+
}
3088+
}
3089+
3090+
if (good_shell && good_holes) {
3091+
return gf->createCurvePolygon(std::move(shell), std::move(holes)).release();
3092+
} else if (!good_shell) {
3093+
throw IllegalArgumentException("Shell is not a Curve");
3094+
} else {
3095+
throw IllegalArgumentException("Hole is not a Curve");
3096+
}
3097+
});
3098+
}
3099+
3100+
3101+
Geometry*
3102+
GEOSGeom_createEmptyCurvePolygon_r(GEOSContextHandle_t extHandle)
3103+
{
3104+
return execute(extHandle, [&]() {
3105+
GEOSContextHandleInternal_t* handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
3106+
const GeometryFactory* gf = handle->geomFactory;
3107+
return gf->createCurvePolygon(false, false).release();
3108+
});
3109+
}
3110+
29943111
Geometry*
29953112
GEOSGeom_clone_r(GEOSContextHandle_t extHandle, const Geometry* g)
29963113
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <tut/tut.hpp>
2+
#include "capi_test_utils.h"
3+
4+
namespace tut {
5+
//
6+
// Test Group
7+
//
8+
9+
struct test_geosgeom_createcircularstring_data : public capitest::utility {};
10+
11+
typedef test_group<test_geosgeom_createcircularstring_data> group;
12+
typedef group::object object;
13+
14+
group test_geosgeom_createcircularstring("capi::GEOSGeom_createCircularString");
15+
16+
template<>
17+
template<>
18+
void object::test<1>
19+
()
20+
{
21+
GEOSCoordSequence* seq = GEOSCoordSeq_create(3, 2);
22+
GEOSCoordSeq_setXY(seq, 0, 1, 2);
23+
GEOSCoordSeq_setXY(seq, 1, 4, 5);
24+
GEOSCoordSeq_setXY(seq, 2, 9, -2);
25+
26+
result_ = GEOSGeom_createCircularString(seq);
27+
expected_ = fromWKT("CIRCULARSTRING (1 2, 4 5, 9 -2)");
28+
29+
ensure_geometry_equals_identical(result_, expected_);
30+
}
31+
32+
template<>
33+
template<>
34+
void object::test<2>
35+
()
36+
{
37+
result_ = GEOSGeom_createEmptyCircularString();
38+
ensure(GEOSisEmpty(result_));
39+
ensure(!GEOSHasZ(result_));
40+
ensure(!GEOSHasM(result_));
41+
}
42+
43+
} // namespace tut
44+

tests/unit/capi/GEOSGeom_createCollectionTest.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,38 @@ void object::test<7>
172172
}
173173
}
174174

175+
// Create MultiCurve
176+
template<>
177+
template<>
178+
void object::test<8>
179+
()
180+
{
181+
GEOSGeometry* geoms[2];
182+
geoms[0] = fromWKT("CIRCULARSTRING (0 0, 1 1, 2 0)");
183+
geoms[1] = fromWKT("LINESTRING (2 0, 3 3)");
184+
185+
result_ = GEOSGeom_createCollection(GEOS_MULTICURVE, geoms, 2);
186+
expected_ = fromWKT("MULTICURVE (CIRCULARSTRING (0 0, 1 1, 2 0), (2 0, 3 3))");
187+
188+
ensure_geometry_equals_identical(result_, expected_);
189+
}
190+
191+
// Create MultiSurface
192+
template<>
193+
template<>
194+
void object::test<9>
195+
()
196+
{
197+
GEOSGeometry* geoms[2];
198+
geoms[0] = fromWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))");
199+
geoms[1] = fromWKT("CURVEPOLYGON (CIRCULARSTRING (10 10, 20 10, 15 15, 10 10))");
200+
201+
result_ = GEOSGeom_createCollection(GEOS_MULTISURFACE, geoms, 2);
202+
expected_ = fromWKT("MULTISURFACE (((0 0, 1 0, 1 1, 0 0)), CURVEPOLYGON (CIRCULARSTRING (10 10, 20 10, 15 15, 10 10)))");
203+
204+
ensure_geometry_equals_identical(result_, expected_);
205+
}
206+
207+
175208
} // namespace tut
176209

0 commit comments

Comments
 (0)