From c86d9084bde2723629b28fb8f2600e1b55ca8383 Mon Sep 17 00:00:00 2001 From: Sandro Santilli <strk@keybit.net> Date: Wed, 14 Aug 2013 22:40:16 +0000 Subject: [PATCH] Implement ST_ForceCurve (#2430) git-svn-id: http://svn.osgeo.org/postgis/trunk@11803 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 2 ++ liblwgeom/cunit/cu_libgeom.c | 56 ++++++++++++++++++++++++++++++++ liblwgeom/liblwgeom.h.in | 7 ++++ liblwgeom/lwcompound.c | 9 +++++ liblwgeom/lwgeom.c | 48 +++++++++++++++++++++++++-- libpgcommon/lwgeom_pg.h | 1 + postgis/lwgeom_functions_basic.c | 23 +++++++++++++ postgis/postgis.sql.in | 6 ++++ regress/Makefile.in | 1 + regress/forcecurve.sql | 12 +++++++ regress/forcecurve_expected | 12 +++++++ 11 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 regress/forcecurve.sql create mode 100644 regress/forcecurve_expected diff --git a/NEWS b/NEWS index cd08fd79a..e28c707d0 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PostGIS 2.2.0 * New Features * + - #2430, ST_ForceCurve + * Enhancements * - Added missing variants of ST_TPI(), ST_TRI() and ST_Roughness() diff --git a/liblwgeom/cunit/cu_libgeom.c b/liblwgeom/cunit/cu_libgeom.c index ae0e319f5..18c8deeba 100644 --- a/liblwgeom/cunit/cu_libgeom.c +++ b/liblwgeom/cunit/cu_libgeom.c @@ -891,6 +891,61 @@ static void test_lwgeom_same(void) } +/* + * Test lwgeom_force_curve + */ +static void test_lwgeom_as_curve(void) +{ + LWGEOM *geom; + LWGEOM *geom2; + char *in_ewkt, *out_ewkt; + + geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE); + geom2 = lwgeom_as_curve(geom); + in_ewkt = "COMPOUNDCURVE((0 0,10 0))"; + out_ewkt = lwgeom_to_ewkt(geom2); + if (strcmp(in_ewkt, out_ewkt)) + fprintf(stderr, "\nExp: %s\nObt: %s\n", in_ewkt, out_ewkt); + CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt); + lwfree(out_ewkt); + lwgeom_free(geom); + lwgeom_free(geom2); + + geom = lwgeom_from_wkt("MULTILINESTRING((0 0, 10 0))", LW_PARSER_CHECK_NONE); + geom2 = lwgeom_as_curve(geom); + in_ewkt = "MULTICURVE((0 0,10 0))"; + out_ewkt = lwgeom_to_ewkt(geom2); + if (strcmp(in_ewkt, out_ewkt)) + fprintf(stderr, "\nExp: %s\nObt: %s\n", in_ewkt, out_ewkt); + CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt); + lwfree(out_ewkt); + lwgeom_free(geom); + lwgeom_free(geom2); + + geom = lwgeom_from_wkt("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", LW_PARSER_CHECK_NONE); + geom2 = lwgeom_as_curve(geom); + in_ewkt = "CURVEPOLYGON((0 0,10 0,10 10,0 10,0 0))"; + out_ewkt = lwgeom_to_ewkt(geom2); + if (strcmp(in_ewkt, out_ewkt)) + fprintf(stderr, "\nExp: %s\nObt: %s\n", in_ewkt, out_ewkt); + CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt); + lwfree(out_ewkt); + lwgeom_free(geom); + lwgeom_free(geom2); + + geom = lwgeom_from_wkt("MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))", LW_PARSER_CHECK_NONE); + geom2 = lwgeom_as_curve(geom); + in_ewkt = "MULTISURFACE(((0 0,10 0,10 10,0 10,0 0)))"; + out_ewkt = lwgeom_to_ewkt(geom2); + if (strcmp(in_ewkt, out_ewkt)) + fprintf(stderr, "\nExp: %s\nObt: %s\n", in_ewkt, out_ewkt); + CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt); + lwfree(out_ewkt); + lwgeom_free(geom); + lwgeom_free(geom2); + +} + /* ** Used by test harness to register the tests in this file. */ @@ -914,6 +969,7 @@ CU_TestInfo libgeom_tests[] = PG_TEST(test_lwgeom_calculate_gbox), PG_TEST(test_lwgeom_is_empty), PG_TEST(test_lwgeom_same), + PG_TEST(test_lwgeom_as_curve), CU_TEST_INFO_NULL }; CU_SuiteInfo libgeom_suite = {"libgeom", NULL, NULL, libgeom_tests}; diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 688e7830c..5d3ff05d8 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -580,6 +580,7 @@ extern LWPSURFACE *lwgeom_as_lwpsurface(const LWGEOM *lwgeom); extern LWTRIANGLE *lwgeom_as_lwtriangle(const LWGEOM *lwgeom); extern LWTIN *lwgeom_as_lwtin(const LWGEOM *lwgeom); extern LWGEOM *lwgeom_as_multi(const LWGEOM *lwgeom); +extern LWGEOM *lwgeom_as_curve(const LWGEOM *lwgeom); /* Casts LW*->LWGEOM (always cast) */ extern LWGEOM *lwtin_as_lwgeom(const LWTIN *obj); @@ -946,6 +947,12 @@ extern int lwcurvepoly_add_ring(LWCURVEPOLY *poly, LWGEOM *ring); */ extern int lwcompound_add_lwgeom(LWCOMPOUND *comp, LWGEOM *geom); +/** +* Construct an equivalent compound curve from a linestring. +* Compound curves can have linear components, so this works fine +*/ +extern LWCOMPOUND* lwcompound_construct_from_lwline(const LWLINE *lwpoly); + /** * Construct an equivalent curve polygon from a polygon. Curve polygons * can have linear rings as their rings, so this works fine (in theory?) diff --git a/liblwgeom/lwcompound.c b/liblwgeom/lwcompound.c index 8ff92e4cf..a61374693 100644 --- a/liblwgeom/lwcompound.c +++ b/liblwgeom/lwcompound.c @@ -191,3 +191,12 @@ lwcompound_contains_point(const LWCOMPOUND *comp, const POINT2D *pt) /* Inside */ return LW_INSIDE; } + +LWCOMPOUND * +lwcompound_construct_from_lwline(const LWLINE *lwline) +{ + LWCOMPOUND* ogeom = lwcompound_construct_empty(lwline->srid, FLAGS_GET_Z(lwline->flags), FLAGS_GET_M(lwline->flags)); + lwcompound_add_lwgeom(ogeom, lwgeom_clone((LWGEOM*)lwline)); + /* ogeom->bbox = lwline->bbox; */ + return ogeom; +} diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index 55a5ccd56..4221f1c47 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -261,7 +261,7 @@ LWGEOM *lwpoint_as_lwgeom(const LWPOINT *obj) /** ** Look-up for the correct MULTI* type promotion for singleton types. */ -static uint8_t MULTITYPE[17] = +static uint8_t MULTITYPE[NUMTYPES] = { 0, MULTIPOINTTYPE, /* 1 */ @@ -274,7 +274,7 @@ static uint8_t MULTITYPE[17] = POLYHEDRALSURFACETYPE, /* 11 */ 0, 0, TINTYPE, /* 14 */ - 0,0 + 0 }; /** @@ -317,6 +317,50 @@ lwgeom_as_multi(const LWGEOM *lwgeom) return ogeom; } +/** +* Create a new LWGEOM of the appropriate CURVE* type. +*/ +LWGEOM * +lwgeom_as_curve(const LWGEOM *lwgeom) +{ + LWGEOM *ogeom; + int type = lwgeom->type; +/* + int hasz = FLAGS_GET_Z(lwgeom->flags); + int hasm = FLAGS_GET_M(lwgeom->flags); + int srid = lwgeom->srid; +*/ + + switch(type) + { + case LINETYPE: + /* turn to COMPOUNDCURVE */ + ogeom = (LWGEOM*)lwcompound_construct_from_lwline((LWLINE*)lwgeom); + break; + case POLYGONTYPE: + ogeom = (LWGEOM*)lwcurvepoly_construct_from_lwpoly(lwgeom_as_lwpoly(lwgeom)); + break; + case MULTILINETYPE: + /* turn to MULTICURVE */ + ogeom = lwgeom_clone(lwgeom); + ogeom->type = MULTICURVETYPE; + break; + case MULTIPOLYGONTYPE: + /* turn to MULTISURFACE */ + ogeom = lwgeom_clone(lwgeom); + ogeom->type = MULTISURFACETYPE; + break; + case COLLECTIONTYPE: + default: + ogeom = lwgeom_clone(lwgeom); + break; + } + + /* TODO: copy bbox from input geom ? */ + + return ogeom; +} + /** * Free the containing LWGEOM and the associated BOX. Leave the underlying diff --git a/libpgcommon/lwgeom_pg.h b/libpgcommon/lwgeom_pg.h index 3d392e84f..90526be47 100644 --- a/libpgcommon/lwgeom_pg.h +++ b/libpgcommon/lwgeom_pg.h @@ -150,6 +150,7 @@ Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS); Datum LWGEOM_force_4d(PG_FUNCTION_ARGS); Datum LWGEOM_force_collection(PG_FUNCTION_ARGS); Datum LWGEOM_force_multi(PG_FUNCTION_ARGS); +Datum LWGEOM_force_curve(PG_FUNCTION_ARGS); Datum LWGEOMFromWKB(PG_FUNCTION_ARGS); Datum WKBFromLWGEOM(PG_FUNCTION_ARGS); diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index bb975e991..2e5727b24 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -519,6 +519,29 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS) PG_RETURN_POINTER(result); } +/** transform input geometry to a curved type */ +PG_FUNCTION_INFO_V1(LWGEOM_force_curve); +Datum LWGEOM_force_curve(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *result; + LWGEOM *lwgeom; + LWGEOM *ogeom; + + POSTGIS_DEBUG(2, "LWGEOM_force_curve called"); + + /* TODO: early out if input is already a curve */ + + lwgeom = lwgeom_from_gserialized(geom); + ogeom = lwgeom_as_curve(lwgeom); + + result = geometry_serialize(ogeom); + + PG_FREE_IF_COPY(geom, 0); + + PG_RETURN_POINTER(result); +} + /** transform input geometry to a SFS 1.1 geometry type compliant */ PG_FUNCTION_INFO_V1(LWGEOM_force_sfs); Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS) diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 42d871dc6..f5c3d1c1c 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -1277,6 +1277,12 @@ CREATE OR REPLACE FUNCTION ST_Multi(geometry) AS 'MODULE_PATHNAME', 'LWGEOM_force_multi' LANGUAGE 'c' IMMUTABLE STRICT; +-- Availability: 2.2.0 +CREATE OR REPLACE FUNCTION ST_ForceCurve(geometry) + RETURNS geometry + AS 'MODULE_PATHNAME', 'LWGEOM_force_curve' + LANGUAGE 'c' IMMUTABLE STRICT; + -- Availability: 2.1.0 CREATE OR REPLACE FUNCTION ST_ForceSFS(geometry) RETURNS geometry diff --git a/regress/Makefile.in b/regress/Makefile.in index 06c723eee..d975a518f 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -81,6 +81,7 @@ TESTS = \ summary \ affine \ empty \ + forcecurve \ measures \ legacy \ long_xact \ diff --git a/regress/forcecurve.sql b/regress/forcecurve.sql new file mode 100644 index 000000000..b655ba36e --- /dev/null +++ b/regress/forcecurve.sql @@ -0,0 +1,12 @@ +SELECT '1', ST_AsText(ST_ForceCurve('POINT(0 0)')); +SELECT '2', ST_AsText(ST_ForceCurve('MULTIPOINT((0 0))')); +SELECT '3', ST_AsText(ST_ForceCurve('LINESTRING(0 0, 10 0)')); +SELECT '4', ST_AsText(ST_ForceCurve('MULTILINESTRING((0 0, 10 0),(30 0, 30 2))')); +SELECT '5', ST_AsText(ST_ForceCurve('POLYGON((0 0,10 0,10 10,0 10,0 0))')); +SELECT '6', ST_AsText(ST_ForceCurve('MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))')); +SELECT '7', ST_AsText(ST_ForceCurve('GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0))))')); +SELECT '8', ST_AsText(ST_ForceCurve('CIRCULARSTRING(0 0,10 1,20 0)')); +SELECT '9', ST_AsText(ST_ForceCurve('COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0))')); +SELECT '10', ST_AsText(ST_ForceCurve('MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0)))')); +SELECT '11', ST_AsText(ST_ForceCurve('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0)))')); +SELECT '12', ST_AsText(ST_ForceCurve('MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0))))')); diff --git a/regress/forcecurve_expected b/regress/forcecurve_expected new file mode 100644 index 000000000..e4e784627 --- /dev/null +++ b/regress/forcecurve_expected @@ -0,0 +1,12 @@ +1|POINT(0 0) +2|MULTIPOINT(0 0) +3|COMPOUNDCURVE((0 0,10 0)) +4|MULTICURVE((0 0,10 0),(30 0,30 2)) +5|CURVEPOLYGON((0 0,10 0,10 10,0 10,0 0)) +6|MULTISURFACE(((0 0,10 0,10 10,0 10,0 0))) +7|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))) +8|CIRCULARSTRING(0 0,10 1,20 0) +9|COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0)) +10|MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0))) +11|CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0))) +12|MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0)))) -- 2.40.0