diff --git a/doc/reference_processing.xml b/doc/reference_processing.xml index 92acc3a95..af17d0db4 100644 --- a/doc/reference_processing.xml +++ b/doc/reference_processing.xml @@ -898,12 +898,13 @@ Return a Delaunay triangulation around the vertices of the input geometry. Output is a COLLECTION of polygons (for flags=0) or a MULTILINESTRING -(for flags=1). The tolerance, if any, is used to snap input vertices +(for flags=1) or TIN (for flags=2). The tolerance, if any, is used to snap input vertices togheter. Availability: 2.1.0 - requires GEOS >= 3.4.0. &Z_support; + &T_support; diff --git a/liblwgeom/lwgeom_geos.c b/liblwgeom/lwgeom_geos.c index 64906cfde..50bdba9c5 100644 --- a/liblwgeom/lwgeom_geos.c +++ b/liblwgeom/lwgeom_geos.c @@ -17,6 +17,8 @@ #include +LWTIN *lwtin_from_geos(const GEOSGeometry *geom, int want3d); + #undef LWGEOM_PROFILE_BUILDAREA #define LWGEOM_GEOS_ERRMSG_MAXSIZE 256 @@ -1298,9 +1300,10 @@ lwgeom_offsetcurve(const LWLINE *lwline, double size, int quadsegs, int joinStyl #endif /* POSTGIS_GEOS_VERSION < 32 */ } -LWGEOM* -lwgeom_delaunay_triangulation(const LWGEOM *lwgeom_in, double tolerance, int edgeOnly) -{ +/* + * output = 1 for edges, 2 for TIN, 0 for polygons + */ +LWGEOM* lwgeom_delaunay_triangulation(const LWGEOM *lwgeom_in, double tolerance, int output) { #if POSTGIS_GEOS_VERSION < 34 lwerror("lwgeom_delaunay_triangulation: GEOS 3.4 or higher required"); return NULL; @@ -1308,6 +1311,11 @@ lwgeom_delaunay_triangulation(const LWGEOM *lwgeom_in, double tolerance, int edg GEOSGeometry *g1, *g3; LWGEOM *lwgeom_result; + if (output < 0 || output > 2) { + lwerror("lwgeom_delaunay_triangulation: invalid output type specified %d", output); + return NULL; + } + initGEOS(lwnotice, lwgeom_geos_error); g1 = (GEOSGeometry *)LWGEOM2GEOS(lwgeom_in); @@ -1317,7 +1325,8 @@ lwgeom_delaunay_triangulation(const LWGEOM *lwgeom_in, double tolerance, int edg return NULL; } - g3 = GEOSDelaunayTriangulation(g1, tolerance, edgeOnly); + /* if output != 1 we want polys */ + g3 = GEOSDelaunayTriangulation(g1, tolerance, output == 1); /* Don't need input geometry anymore */ GEOSGeom_destroy(g1); @@ -1331,12 +1340,21 @@ lwgeom_delaunay_triangulation(const LWGEOM *lwgeom_in, double tolerance, int edg /* LWDEBUGF(3, "result: %s", GEOSGeomToWKT(g3)); */ GEOSSetSRID(g3, lwgeom_get_srid(lwgeom_in)); - lwgeom_result = GEOS2LWGEOM(g3, lwgeom_has_z(lwgeom_in)); + + if (output == 2) { + lwgeom_result = (LWGEOM *)lwtin_from_geos(g3, lwgeom_has_z(lwgeom_in)); + } else { + lwgeom_result = GEOS2LWGEOM(g3, lwgeom_has_z(lwgeom_in)); + } + GEOSGeom_destroy(g3); - if (lwgeom_result == NULL) - { - lwerror("lwgeom_delaunay_triangulation: GEOS2LWGEOM returned null"); + if (lwgeom_result == NULL) { + if (output != 2) { + lwerror("lwgeom_delaunay_triangulation: GEOS2LWGEOM returned null"); + } else { + lwerror("lwgeom_delaunay_triangulation: lwtin_from_geos returned null"); + } return NULL; } diff --git a/liblwgeom/lwtin.c b/liblwgeom/lwtin.c index d7fef8524..daf001204 100644 --- a/liblwgeom/lwtin.c +++ b/liblwgeom/lwtin.c @@ -13,9 +13,12 @@ #include #include #include + +#include "lwgeom_geos.h" #include "liblwgeom_internal.h" #include "lwgeom_log.h" +LWTIN *lwtin_from_geos(const GEOSGeometry *geom, int want3d); LWTIN* lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj) @@ -23,6 +26,68 @@ LWTIN* lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj) return (LWTIN*)lwcollection_add_lwgeom((LWCOLLECTION*)mobj, (LWGEOM*)obj); } +LWTIN *lwtin_from_geos(const GEOSGeometry *geom, int want3d) { + int type = GEOSGeomTypeId(geom); + int hasZ; + int SRID = GEOSGetSRID(geom); + + /* GEOS's 0 is equivalent to our unknown as for SRID values */ + if ( SRID == 0 ) SRID = SRID_UNKNOWN; + + if ( want3d ) { + hasZ = GEOSHasZ(geom); + if ( ! hasZ ) { + LWDEBUG(3, "Geometry has no Z, won't provide one"); + want3d = 0; + } + } + + switch (type) { + LWTRIANGLE **geoms; + uint32_t i, ngeoms; + case GEOS_GEOMETRYCOLLECTION: + LWDEBUG(4, "lwgeom_from_geometry: it's a Collection or Multi"); + + ngeoms = GEOSGetNumGeometries(geom); + geoms = NULL; + if ( ngeoms ) { + geoms = lwalloc(ngeoms * sizeof *geoms); + if (!geoms) { + lwerror("lwtin_from_geos: can't allocate geoms"); + return NULL; + } + for (i=0; i