From 7b65335f336ba36872fad3bb575ea84a32ae3cd6 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Mon, 25 Jan 2010 21:03:42 +0000 Subject: [PATCH] Add ST_AddMeasure and associated documentations (#390) git-svn-id: http://svn.osgeo.org/postgis/trunk@5162 b70326c6-7e19-0410-871a-916f4a2858ee --- doc/reference_lrs.xml | 132 +++++++++++++++++++++++++++++++++ liblwgeom/liblwgeom.h | 1 + liblwgeom/lwline.c | 56 ++++++++++++++ postgis/lwgeom_functions_lrs.c | 37 +++++++++ postgis/postgis.sql.in.c | 18 +++++ 5 files changed, 244 insertions(+) diff --git a/doc/reference_lrs.xml b/doc/reference_lrs.xml index afa328e6b..e30902ea5 100644 --- a/doc/reference_lrs.xml +++ b/doc/reference_lrs.xml @@ -477,4 +477,136 @@ LINESTRING(6.1 7.1 6,7 8 9) + + + + + ST_AddMeasure + + Return a derived geometry with measure elements linearly interpolated between the start and end points. If the geometry has no measure dimension, one is added. If the geometry has a measure dimension, it is over-written with new values. Only LINESTRINGS and MULTILINESTRINGS are supported. + + + + + + geometry ST_AddMeasure + geometry geom_mline + float measure_start + float measure_end + + + + + + + Description + + Return a derived geometry with measure elements linearly interpolated between the start and end points. If the geometry has no measure dimension, one is added. If the geometry has a measure dimension, it is over-written with new values. Only LINESTRINGS and MULTILINESTRINGS are supported. + + Availability: 1.5.0 + + &Z_support; + + + + Examples + + SELECT ST_AsEWKT(ST_AddMeasure( +ST_GeomFromEWKT('LINESTRING(1 0, 2 0, 4 0)'),1,4)) As ewelev; + ewelev +-------------------------------- + LINESTRINGM(1 0 1,2 0 2,4 0 4) + +SELECT ST_AsEWKT(ST_AddMeasure( +ST_GeomFromEWKT('LINESTRING(1 0 4, 2 0 4, 4 0 4)'),10,40)) As ewelev; + ewelev +---------------------------------------- + LINESTRING(1 0 4 10,2 0 4 20,4 0 4 40) + +SELECT ST_AsEWKT(ST_AddMeasure( +ST_GeomFromEWKT('LINESTRINGM(1 0 4, 2 0 4, 4 0 4)'),10,40)) As ewelev; + ewelev +---------------------------------------- + LINESTRINGM(1 0 10,2 0 20,4 0 40) + + + + + + See Also + + , + + + + + + ST_StartMeasure + + Return the measure value at the first vertex of a geometry. + + + + + + float ST_StartMeasure + geometry geom + + + + + + + Description + + Return the measure value at the first vertex of a geometry. + + Availability: 1.5.0 + + &Z_support; + + + + + See Also + + + + + + + + ST_EndMeasure + + Return the measure value at the last vertex of a geometry. + + + + + + float ST_EndMeasure + geometry geom + + + + + + + Description + + Return the measure value at the last vertex of a geometry. + + Availability: 1.5.0 + + &Z_support; + + + + + See Also + + + + + diff --git a/liblwgeom/liblwgeom.h b/liblwgeom/liblwgeom.h index 20ea1add8..f3ce1ef35 100644 --- a/liblwgeom/liblwgeom.h +++ b/liblwgeom/liblwgeom.h @@ -1379,6 +1379,7 @@ extern void ptarray_reverse(POINTARRAY *pa); extern POINTARRAY *ptarray_substring(POINTARRAY *, double, double); extern double ptarray_locate_point(POINTARRAY *, POINT2D *); extern void closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret); +extern LWLINE *lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end); /* * Ensure every segment is at most 'dist' long. diff --git a/liblwgeom/lwline.c b/liblwgeom/lwline.c index 272514481..614496cdb 100644 --- a/liblwgeom/lwline.c +++ b/liblwgeom/lwline.c @@ -524,3 +524,59 @@ lwline_setPoint4d(LWLINE *line, unsigned int index, POINT4D *newpoint) { setPoint4d(line->points, index, newpoint); } + +/** +* Re-write the measure ordinate (or add one, if it isn't already there) interpolating +* the measure between the supplied start and end values. +*/ +LWLINE* +lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end) +{ + int i = 0; + int hasm = 0, hasz = 0; + int npoints = 0; + double length = 0.0; + double length_so_far = 0.0; + double m_range = m_end - m_start; + double m; + POINTARRAY *pa = NULL; + POINT3DZ p1, p2; + + if( TYPE_GETTYPE(lwline->type) != LINETYPE ) + { + lwerror("lwmline_construct_from_lwline: only line types supported"); + return NULL; + } + + hasz = TYPE_HASZ(lwline->type); + hasm = 1; + + /* Null points or npoints == 0 will result in empty return geometry */ + if( lwline->points ) + { + npoints = lwline->points->npoints; + length = lwgeom_pointarray_length2d(lwline->points); + getPoint3dz_p(lwline->points, 0, &p1); + } + + pa = ptarray_construct(hasz, hasm, npoints); + + for( i = 0; i < npoints; i++ ) + { + POINT4D q; + getPoint3dz_p(lwline->points, i, &p2); + length_so_far += distance2d_pt_pt((POINT2D*)&p1, (POINT2D*)&p2); + if ( length > 0.0 ) + m = m_start + m_range * length_so_far / length; + else + m = 0.0; + q.x = p2.x; + q.y = p2.y; + q.z = p2.z; + q.m = m; + setPoint4d(pa, i, &q); + p1 = p2; + } + + return lwline_construct(lwline->SRID, NULL, pa); +} diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index 50032f73b..c9ba726ab 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -18,6 +18,7 @@ Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS); +Datum ST_AddMeasure(PG_FUNCTION_ARGS); typedef struct { @@ -535,3 +536,39 @@ Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) PG_RETURN_POINTER(gout); } + +/* +* CREATE OR REPLACE FUNCTION ST_AddMeasure(geometry, float8, float8) +* RETURNS geometry +* AS '$libdir/postgis-1.5', 'ST_AddMeasure' +* LANGUAGE 'C' IMMUTABLE STRICT; +*/ +PG_FUNCTION_INFO_V1(ST_AddMeasure); +Datum ST_AddMeasure(PG_FUNCTION_ARGS) +{ + PG_LWGEOM *gin = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + PG_LWGEOM *gout; + double start_measure = PG_GETARG_FLOAT8(1); + double end_measure = PG_GETARG_FLOAT8(2); + LWGEOM *lwin, *lwout; + + /* Raise an error if input is not a linestring */ + if ( TYPE_GETTYPE(gin->type) != LINETYPE ) + { + lwerror("Only LINESTRING is supported"); + PG_RETURN_NULL(); + } + + lwin = pglwgeom_deserialize(gin); + lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); + lwgeom_release(lwin); + + if ( lwout == NULL ) + PG_RETURN_NULL(); + + gout = pglwgeom_serialize(lwout); + lwgeom_release(lwout); + + PG_RETURN_POINTER(gout); +} + diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index ebc99ddb1..68b893969 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -3803,6 +3803,24 @@ CREATE OR REPLACE FUNCTION ST_locate_along_measure(geometry, float8) AS $$ SELECT locate_between_measures($1, $2, $2) $$ LANGUAGE 'sql' IMMUTABLE STRICT; +-- Availability: 1.5.0 +CREATE OR REPLACE FUNCTION ST_AddMeasure(geometry, float8, float8) + RETURNS geometry + AS 'MODULE_PATHNAME', 'ST_AddMeasure' + LANGUAGE 'C' IMMUTABLE STRICT; + +-- Availability: 1.5.0 +CREATE OR REPLACE FUNCTION ST_StartMeasure(geometry) + RETURNS float8 + AS $$ SELECT ST_M(ST_StartPoint($1)) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + +-- Availability: 1.5.0 +CREATE OR REPLACE FUNCTION ST_EndMeasure(geometry) + RETURNS float8 + AS $$ SELECT ST_M(ST_EndPoint($1)) $$ + LANGUAGE 'SQL' IMMUTABLE STRICT; + --------------------------------------------------------------- -- GEOS --------------------------------------------------------------- -- 2.40.0