From 533361f15d4393fe8bd535cfebb4be96f65e25a1 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Wed, 17 Jun 2015 13:10:33 +0000 Subject: [PATCH] Add ST_ApproximateMedialAxis (#3169) Requires SFCGAL (any version). Uses SFCGAL specific API if available (1.2+), post-processes StraightSkeleton output otherwise. Includes regression test and documentation. git-svn-id: http://svn.osgeo.org/postgis/trunk@13678 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 11 ++-- doc/html/image_src/Makefile.in | 1 + .../image_src/st_approximatemedialaxis01.wkt | 2 + doc/reference_sfcgal.xml | 63 +++++++++++++++++++ postgis/lwgeom_sfcgal.c | 34 ++++++++++ postgis/sfcgal.sql.in | 30 +++++++++ regress/Makefile.in | 3 +- regress/sfcgal/approximatemedialaxis.sql | 3 + regress/sfcgal/approximatemedialaxis_expected | 2 + 9 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 doc/html/image_src/st_approximatemedialaxis01.wkt create mode 100644 regress/sfcgal/approximatemedialaxis.sql create mode 100644 regress/sfcgal/approximatemedialaxis_expected diff --git a/NEWS b/NEWS index 66c093205..bef3afd35 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,7 @@ PostGIS 2.2.0 * New Features * + - #3169, ST_ApproximateMedialAxis (Sandro Santilli) - Add |=| operator with CPA semantic and KNN support with PgSQL 9.5+ (Sandro Santilli / Boundless) - #3131, KNN support for the geography type (Paul Ramsey / CartoDB) @@ -53,7 +54,7 @@ PostGIS 2.2.0 - #899, -m shp2pgsql attribute names mapping -m switch (Regina Obe / Sandro Santilli) - #1678, Added GUC postgis.gdal_datapath to specify GDAL config - variable GDAL_DATA + variable GDAL_DATA - #2843, Support reprojection on raster import (Sandro Santilli / Vizzuality) - #2349, Support for encoded_polyline input/output (Kashif Rasul) @@ -65,8 +66,8 @@ PostGIS 2.2.0 variable GDAL_SKIP - Added GUC postgis.enable_outdb_rasters to enable access to rasters with out-db bands - - #2387 address_standardizer extension as part of PostGIS - Stephen Woodbridge (imaptools.com), Walter Sinclair + - #2387, address_standardizer extension as part of PostGIS + Stephen Woodbridge (imaptools.com), Walter Sinclair - #2341, New mask parameter for ST_MapAlgebra - #2397, read encoding info automatically in shapefile loader - #2430, ST_ForceCurve @@ -74,11 +75,11 @@ PostGIS 2.2.0 - #2567, ST_CountAgg() - #2632, ST_AsGML() support for curved features - #2652, Add --upgrade-path switch to run_test.pl - - #2754 sfcgal wrapped as an extension + - #2754, sfcgal wrapped as an extension - #2227, Simplification with Visvalingam-Whyatt algorithm ST_SimplifyVW, ST_SetEffectiveArea (Nicklas Avén) - Functions to encode and decode TWKB - ST_AsTWKB, ST_GeomFromTWKB (Paul Ramsey / Nicklas Avén / CartoDB) + ST_AsTWKB, ST_GeomFromTWKB (Paul Ramsey / Nicklas Avén / CartoDB) * Enhancements * diff --git a/doc/html/image_src/Makefile.in b/doc/html/image_src/Makefile.in index 41974ded3..ce0ae378d 100644 --- a/doc/html/image_src/Makefile.in +++ b/doc/html/image_src/Makefile.in @@ -112,6 +112,7 @@ IMAGES= \ ../images/st_split03.png \ ../images/st_split04.png \ ../images/st_straightskeleton01.png \ + ../images/st_approximatemedialaxis01.png \ ../images/st_subdivide01.png \ ../images/st_subdivide02.png \ ../images/st_symdifference01.png \ diff --git a/doc/html/image_src/st_approximatemedialaxis01.wkt b/doc/html/image_src/st_approximatemedialaxis01.wkt new file mode 100644 index 000000000..b40222e07 --- /dev/null +++ b/doc/html/image_src/st_approximatemedialaxis01.wkt @@ -0,0 +1,2 @@ +Style1;POLYGON (( 190 190, 10 190, 10 10, 190 10, 190 20, 160 30, 60 30, 60 130, 190 140, 190 190 )) +Style2;MULTILINESTRING((184.188611699158 15.8113883008419,158.377223398316 20),(50 20,158.377223398316 20),(50 20,35 35),(35 153.150778481549,35 35),(35 153.150778481549,40.6970772062924 159.302922793708),(164.039879739868 164.039879739868,40.6970772062924 159.302922793708)) diff --git a/doc/reference_sfcgal.xml b/doc/reference_sfcgal.xml index 2769903d5..830d88027 100644 --- a/doc/reference_sfcgal.xml +++ b/doc/reference_sfcgal.xml @@ -200,6 +200,69 @@ + + + ST_ApproximateMedialAxis + + Compute the approximate medial axis of an areal geometry. + + + + + + geometry ST_ApproximateMedialAxis + geometry geom + + + + + + Description + + +Return an approximate medial axis for the areal input based on +its straight skeleton. Uses an SFCGAL specific API when built against +a capable version (1.2.0+). Otherwise the function is just a wrapper +around ST_StraightSkeleton (slower case). + + + Availability: 2.2.0 + &sfcgal_required; + &Z_support; + &P_support; + &T_support; + + + Examples + SELECT ST_ApproximateMedialAxis(ST_GeomFromText('POLYGON (( 190 190, 10 190, 10 10, 190 10, 190 20, 160 30, 60 30, 60 130, 190 140, 190 190 ))')); + + + + + + + + + + + A polygon and its approximate medial axis + + + + + + + + + + + See Also + + + + + + diff --git a/postgis/lwgeom_sfcgal.c b/postgis/lwgeom_sfcgal.c index fe91ccb85..18243da2a 100644 --- a/postgis/lwgeom_sfcgal.c +++ b/postgis/lwgeom_sfcgal.c @@ -18,6 +18,7 @@ #include "lwgeom_pg.h" #include "lwgeom_sfcgal.h" +#include "../postgis_config.h" Datum postgis_sfcgal_version(PG_FUNCTION_ARGS); @@ -33,6 +34,7 @@ Datum sfcgal_intersection(PG_FUNCTION_ARGS); Datum sfcgal_intersection3D(PG_FUNCTION_ARGS); Datum sfcgal_extrude(PG_FUNCTION_ARGS); Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS); +Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS); Datum sfcgal_is_planar(PG_FUNCTION_ARGS); Datum sfcgal_orientation(PG_FUNCTION_ARGS); Datum sfcgal_force_lhr(PG_FUNCTION_ARGS); @@ -414,6 +416,38 @@ Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS) PG_RETURN_POINTER(output); } +PG_FUNCTION_INFO_V1(sfcgal_approximate_medial_axis); +Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS) +{ +#if POSTGIS_SFCGAL_VERSION < 12 + lwpgerror("The SFCGAL version this PostGIS binary " + "was compiled against (%d) doesn't support " + "'sfcgal_geometry_approximate_medial_axis' function (1.2.0+ required)", + POSTGIS_SFCGAL_VERSION); + PG_RETURN_NULL(); +#else /* POSTGIS_SFCGAL_VERSION >= 12 */ + GSERIALIZED *input, *output; + sfcgal_geometry_t *geom; + sfcgal_geometry_t *result; + srid_t srid; + + sfcgal_postgis_init(); + + input = PG_GETARG_GSERIALIZED_P(0); + srid = gserialized_get_srid(input); + geom = POSTGIS2SFCGALGeometry(input); + PG_FREE_IF_COPY(input, 0); + + result = sfcgal_geometry_approximate_medial_axis(geom); + sfcgal_geometry_delete(geom); + + output = SFCGALGeometry2POSTGIS(result, 0, srid); + sfcgal_geometry_delete(result); + + PG_RETURN_POINTER(output); +#endif /* POSTGIS_SFCGAL_VERSION >= 12 */ +} + PG_FUNCTION_INFO_V1(sfcgal_intersection); Datum sfcgal_intersection(PG_FUNCTION_ARGS) diff --git a/postgis/sfcgal.sql.in b/postgis/sfcgal.sql.in index 7144f4dc5..a2341981c 100644 --- a/postgis/sfcgal.sql.in +++ b/postgis/sfcgal.sql.in @@ -79,6 +79,36 @@ CREATE OR REPLACE FUNCTION ST_StraightSkeleton(geometry) LANGUAGE 'c' IMMUTABLE STRICT COST 100; +-- Availability: 2.2.0 +CREATE OR REPLACE FUNCTION ST_ApproximateMedialAxis(geometry) + RETURNS geometry +#if POSTGIS_SFCGAL_VERSION < 12 + AS $$ + DECLARE + poly alias for $1; + ret GEOMETRY; + BEGIN + WITH components AS ( + SELECT (ST_Dump(ST_StraightSkeleton(poly))).geom + ), + filtered AS ( + SELECT ST_Collect(geom) g + FROM components + WHERE NOT ST_Touches(geom, ST_Boundary(poly)) + ) + SELECT + COALESCE(g, ST_SetSRID('MULTILINESTRING EMPTY', ST_Srid(poly))) + INTO ret + FROM filtered; + RETURN ret; + END; $$ + LANGUAGE 'plpgsql' +#else // POSTGIS_SFCGAL_VERSION >= 12 + AS 'MODULE_PATHNAME','sfcgal_approximate_medial_axis' + LANGUAGE 'c' +#endif // POSTGIS_SFCGAL_VERSION >= 12 + IMMUTABLE STRICT COST 100; + -- Availability: 2.2.0 CREATE OR REPLACE FUNCTION ST_IsPlanar(geometry) RETURNS boolean diff --git a/regress/Makefile.in b/regress/Makefile.in index 56769292a..54447745e 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -216,7 +216,8 @@ ifeq ($(HAVE_SFCGAL),yes) sfcgal/regress.sql \ sfcgal/tickets.sql \ sfcgal/concave_hull.sql \ - sfcgal/wmsservers.sql + sfcgal/wmsservers.sql \ + sfcgal/approximatemedialaxis.sql SFCGALTESTFLAGS = --sfcgal endif diff --git a/regress/sfcgal/approximatemedialaxis.sql b/regress/sfcgal/approximatemedialaxis.sql new file mode 100644 index 000000000..dfbdf3b49 --- /dev/null +++ b/regress/sfcgal/approximatemedialaxis.sql @@ -0,0 +1,3 @@ +SELECT 'square', ST_AsText(ST_ApproximateMedialAxis('POLYGON((0 0,1 0,1 1,0 1,0 0))')); +SELECT 'rect1', ST_AsText(ST_ApproximateMedialAxis('POLYGON((0 0,2 0,2 1,0 1,0 0))')); + diff --git a/regress/sfcgal/approximatemedialaxis_expected b/regress/sfcgal/approximatemedialaxis_expected new file mode 100644 index 000000000..dfcc72ec7 --- /dev/null +++ b/regress/sfcgal/approximatemedialaxis_expected @@ -0,0 +1,2 @@ +square|MULTILINESTRING EMPTY +rect1|MULTILINESTRING((0.5 0.5,1.5 0.5)) -- 2.50.1