From f74cdad7df69a412200867f3ae440bdd0ed25c17 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Thu, 26 Jan 2012 13:00:08 +0000 Subject: [PATCH] Add support for linestrings in ST_MakeLine (#1500) Affects both the aggregate and the 2-parameters function. Regression testing included. Documentation was updated, but lacks examples. git-svn-id: http://svn.osgeo.org/postgis/trunk@8931 b70326c6-7e19-0410-871a-916f4a2858ee --- doc/reference_constructor.xml | 20 +++++++++---- postgis/lwgeom_functions_basic.c | 50 +++++++++++++++++--------------- regress/ctors.sql | 12 ++++++++ regress/ctors_expected | 2 ++ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/doc/reference_constructor.xml b/doc/reference_constructor.xml index 5417f7d4d..67eaf33be 100644 --- a/doc/reference_constructor.xml +++ b/doc/reference_constructor.xml @@ -1226,25 +1226,25 @@ BOX3D(-989502.1875 528439.5625 10,-987121.375 529933.1875 10) ST_MakeLine - Creates a Linestring from point geometries. + Creates a Linestring from point or line geometries. geometry ST_MakeLine - geometry set pointfield + geometry set geoms geometry ST_MakeLine - geometry point1 - geometry point2 + geometry geom1 + geometry geom2 geometry ST_MakeLine - geometry[] point_array + geometry[] geoms_array @@ -1253,12 +1253,17 @@ BOX3D(-989502.1875 528439.5625 10,-987121.375 529933.1875 10) Description ST_MakeLine comes in 3 forms: a spatial aggregate that takes - rows of point geometries and returns a line string, a function that takes an array of points, and a regular function that takes two point geometries. You + rows of point-or-line geometries and returns a line string, a function that takes an array of point-or-lines, and a regular function that takes two point-or-line geometries. You might want to use a subselect to order points before feeding them to the aggregate version of this function. + + When adding line components a common node is removed from the output. + + &Z_support; Availability: 1.4.0 - ST_MakeLine(geomarray) was introduced. ST_MakeLine aggregate functions was enhanced to handle more points faster. + Availability: 2.0.0 - Support for linestring input elements was introduced @@ -1319,6 +1324,9 @@ SELECT ST_AsEWKT(ST_MakeLine(ARRAY[ST_MakePoint(1,2,3), LINESTRING(1 2 3,3 4 5,6 6 6) + + + See Also , , , diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index a3680763f..9fdfcc8f0 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -1326,9 +1326,9 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) ArrayType *array; int nelems; GSERIALIZED *result=NULL; - LWPOINT **lwpoints; + LWGEOM **geoms; LWGEOM *outlwg; - uint32 npoints; + uint32 ngeoms; int i; size_t offset; int srid=SRID_UNKNOWN; @@ -1367,13 +1367,13 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) /* * Deserialize all point geometries in array into the - * lwpoints pointers array. + * geoms pointers array. * Count actual number of points. */ /* possibly more then required */ - lwpoints = palloc(sizeof(LWGEOM *)*nelems); - npoints = 0; + geoms = palloc(sizeof(LWGEOM *)*nelems); + ngeoms = 0; offset = 0; bitmap = ARR_NULLBITMAP(array); bitmask = 1; @@ -1385,20 +1385,21 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) GSERIALIZED *geom = (GSERIALIZED *)(ARR_DATA_PTR(array)+offset); offset += INTALIGN(VARSIZE(geom)); - if ( gserialized_get_type(geom) != POINTTYPE ) continue; + if ( gserialized_get_type(geom) != POINTTYPE && gserialized_get_type(geom) != LINETYPE ) continue; - lwpoints[npoints++] = - lwgeom_as_lwpoint(lwgeom_from_gserialized(geom)); + geoms[ngeoms++] = + lwgeom_from_gserialized(geom); /* Check SRID homogeneity */ - if ( npoints == 1 ) + if ( ngeoms == 1 ) { /* Get first geometry SRID */ - srid = lwpoints[npoints-1]->srid; + srid = geoms[ngeoms-1]->srid; + /* TODO: also get ZMflags */ } else { - if ( lwpoints[npoints-1]->srid != srid ) + if ( geoms[ngeoms-1]->srid != srid ) { elog(ERROR, "Operation on mixed SRID geometries"); @@ -1422,15 +1423,16 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) } /* Return null on 0-points input array */ - if ( npoints == 0 ) + if ( ngeoms == 0 ) { - elog(NOTICE, "No points in input array"); + /* TODO: should we return LINESTRING EMPTY here ? */ + elog(NOTICE, "No points or linestrings in input array"); PG_RETURN_NULL(); } - POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: point elements: %d", npoints); + POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms); - outlwg = (LWGEOM *)lwline_from_ptarray(srid, npoints, lwpoints); + outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms); result = geometry_serialize(outlwg); @@ -1446,7 +1448,7 @@ Datum LWGEOM_makeline(PG_FUNCTION_ARGS) { GSERIALIZED *pglwg1, *pglwg2; GSERIALIZED *result=NULL; - LWPOINT *lwpoints[2]; + LWGEOM *lwgeoms[2]; LWLINE *outline; POSTGIS_DEBUG(2, "LWGEOM_makeline called."); @@ -1455,26 +1457,26 @@ Datum LWGEOM_makeline(PG_FUNCTION_ARGS) pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); pglwg2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - if ( gserialized_get_type(pglwg1) != POINTTYPE || - gserialized_get_type(pglwg2) != POINTTYPE ) + if ( (gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) || + (gserialized_get_type(pglwg2) != POINTTYPE && gserialized_get_type(pglwg2) != LINETYPE) ) { - elog(ERROR, "Input geometries must be points"); + elog(ERROR, "Input geometries must be points or lines"); PG_RETURN_NULL(); } error_if_srid_mismatch(gserialized_get_srid(pglwg1), gserialized_get_srid(pglwg2)); - lwpoints[0] = lwgeom_as_lwpoint(lwgeom_from_gserialized(pglwg1)); - lwpoints[1] = lwgeom_as_lwpoint(lwgeom_from_gserialized(pglwg2)); + lwgeoms[0] = lwgeom_from_gserialized(pglwg1); + lwgeoms[1] = lwgeom_from_gserialized(pglwg2); - outline = lwline_from_ptarray(lwpoints[0]->srid, 2, lwpoints); + outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms); result = geometry_serialize((LWGEOM *)outline); PG_FREE_IF_COPY(pglwg1, 0); PG_FREE_IF_COPY(pglwg2, 1); - lwgeom_release((LWGEOM *)lwpoints[0]); - lwgeom_release((LWGEOM *)lwpoints[1]); + lwgeom_release((LWGEOM *)lwgeoms[0]); + lwgeom_release((LWGEOM *)lwgeoms[1]); PG_RETURN_POINTER(result); } diff --git a/regress/ctors.sql b/regress/ctors.sql index da6f289d2..84084ebf7 100644 --- a/regress/ctors.sql +++ b/regress/ctors.sql @@ -7,6 +7,18 @@ SELECT ST_Collect('SRID=32749;POINT(0 0)', 'SRID=32740;POINT(1 1)'); select ST_asewkt(ST_makeline('SRID=3;POINT(0 0)', 'SRID=3;POINT(1 1)')); select ST_makeline('POINT(0 0)', 'SRID=3;POINT(1 1)'); +select 'ST_MakeLine1', ST_AsText(ST_MakeLine( + 'POINT(0 0)'::geometry, + 'LINESTRING(1 1, 10 0)'::geometry +)); + +select 'ST_MakeLine_agg1', ST_AsText(ST_MakeLine(g)) from ( + values ('POINT(0 0)'), + ('LINESTRING(1 1, 10 0)'), + ('LINESTRING(10 0, 20 20)'), + ('POINT(40 4)') +) as foo(g); + -- postgis-users/2006-July/012788.html select ST_makebox2d('SRID=3;POINT(0 0)', 'SRID=3;POINT(1 1)'); select ST_makebox2d('POINT(0 0)', 'SRID=3;POINT(1 1)'); diff --git a/regress/ctors_expected b/regress/ctors_expected index 84ca34ada..cbb39882c 100644 --- a/regress/ctors_expected +++ b/regress/ctors_expected @@ -2,6 +2,8 @@ ERROR: Operation on mixed SRID geometries SRID=3;LINESTRING(0 0,1 1) ERROR: Operation on mixed SRID geometries +ST_MakeLine1|LINESTRING(0 0,1 1,10 0) +ST_MakeLine_agg1|LINESTRING(0 0,1 1,10 0,20 20,40 4) BOX(0 0,1 1) ERROR: Operation on mixed SRID geometries BOX3D(0 0 0,1 1 0) -- 2.50.1