From cce54f75236dfff9977447cbac796331b365fbe5 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Sat, 14 Jan 2012 01:03:37 +0000 Subject: [PATCH] Add ST_InterpolatePoint, deprecate ST_Locate_Between_Measures and ST_Locate_Along_Measure. Document new functions. Alter regressions and docs to use AsText instead of AsEWKT. git-svn-id: http://svn.osgeo.org/postgis/trunk@8811 b70326c6-7e19-0410-871a-916f4a2858ee --- doc/reference_lrs.xml | 113 ++++++--- liblwgeom/cunit/cu_node.c | 4 +- liblwgeom/cunit/cu_ptarray.c | 32 +-- liblwgeom/liblwgeom.h.in | 16 +- liblwgeom/liblwgeom_internal.h | 5 +- liblwgeom/lwgeom_geos_split.c | 6 +- liblwgeom/lwlinearreferencing.c | 52 +++- liblwgeom/ptarray.c | 55 ++-- postgis/lwgeom_functions_analytic.c | 40 --- postgis/lwgeom_functions_lrs.c | 372 +++++++++++++++++----------- postgis/postgis.sql.in.c | 6 +- regress/regress_lrs.sql | 69 +++--- regress/regress_lrs_expected | 48 ++-- regress/tickets_expected | 2 + 14 files changed, 505 insertions(+), 315 deletions(-) diff --git a/doc/reference_lrs.xml b/doc/reference_lrs.xml index f4a94c3f5..c25b44fed 100644 --- a/doc/reference_lrs.xml +++ b/doc/reference_lrs.xml @@ -1,6 +1,7 @@ Linear Referencing + ST_Line_Interpolate_Point @@ -263,9 +264,9 @@ WHERE n*100.00/length < 1; - + - ST_Locate_Along_Measure + ST_LocateAlong Return a derived geometry collection value with elements that match the specified measure. Polygonal elements are not @@ -275,9 +276,10 @@ WHERE n*100.00/length < 1; - geometry ST_Locate_Along_Measure + geometry ST_LocateAlong geometry ageom_with_measure float a_measure + float offset @@ -288,6 +290,11 @@ WHERE n*100.00/length < 1; Return a derived geometry collection value with elements that match the specified measure. Polygonal elements are not supported. + + If an offset is provided, the resultant will be offset to the + left or right of the input line by the specified number of units. + A positive offset will be to the left, and a negative one to the + right. Semantic is specified by: ISO/IEC CD 13249-3:200x(E) - Text for Continuation CD Editing Meeting @@ -301,22 +308,22 @@ WHERE n*100.00/length < 1; Examples - SELECT ST_AsEWKT(the_geom) + SELECT ST_AsText(the_geom) FROM - (SELECT ST_Locate_Along_Measure( - ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), + (SELECT ST_LocateAlong( + ST_GeomFromText('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), (1 2 3, 5 4 5))'),3) As the_geom) As foo; st_asewkt ----------------------------------------------------------- - GEOMETRYCOLLECTIONM(MULTIPOINT(1 2 3,9 4 3),POINT(1 2 3)) + MULTIPOINT M (1 2 3) --Geometry collections are difficult animals so dump them --to make them more digestable -SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) +SELECT ST_AsText((ST_Dump(the_geom)).geom) FROM - (SELECT ST_Locate_Along_Measure( - ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), + (SELECT ST_LocateAlong( + ST_GeomFromText('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), (1 2 3, 5 4 5))'),3) As the_geom) As foo; st_asewkt @@ -331,13 +338,13 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) See Also - , + , - + - ST_Locate_Between_Measures + ST_LocateBetween Return a derived geometry collection value with elements that match the specified range of measures inclusively. Polygonal @@ -347,10 +354,11 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) - geometry ST_Locate_Between_Measures + geometry ST_LocateBetween geometry geomA float measure_start float measure_end + float offset @@ -374,35 +382,35 @@ SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) Examples - SELECT ST_AsEWKT(the_geom) + SELECT ST_AsText(the_geom) FROM - (SELECT ST_Locate_Between_Measures( - ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), + (SELECT ST_LocateBetween( + ST_GeomFromText('MULTILINESTRING M ((1 2 3, 3 4 2, 9 4 3), (1 2 3, 5 4 5))'),1.5, 3) As the_geom) As foo; st_asewkt ------------------------------------------------------------------ - GEOMETRYCOLLECTIONM(LINESTRING(1 2 3,3 4 2,9 4 3),POINT(1 2 3)) +------------------------------------------------------------------------ + GEOMETRYCOLLECTION M (LINESTRING M (1 2 3,3 4 2,9 4 3),POINT M (1 2 3)) --Geometry collections are difficult animals so dump them --to make them more digestable -SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) +SELECT ST_AsText((ST_Dump(the_geom)).geom) FROM - (SELECT ST_Locate_Between_Measures( - ST_GeomFromEWKT('MULTILINESTRINGM((1 2 3, 3 4 2, 9 4 3), + (SELECT ST_LocateBetween( + ST_GeomFromText('MULTILINESTRING M ((1 2 3, 3 4 2, 9 4 3), (1 2 3, 5 4 5))'),1.5, 3) As the_geom) As foo; st_asewkt -------------------------------- - LINESTRINGM(1 2 3,3 4 2,9 4 3) - POINTM(1 2 3) + LINESTRING M (1 2 3,3 4 2,9 4 3) + POINT M (1 2 3) See Also - , + , @@ -478,6 +486,53 @@ LINESTRING(6.1 7.1 6,7 8 9) + + + ST_InterpolatePoint + + Return the value of the measure dimension of a geometry at the point closed to the provided point. + + + + + + float ST_InterpolatePoint + geometry line + geometry point + + + + + + + Description + + Return the value of the measure dimension of a geometry at the point closed to the provided point. + + Availability: 2.0.0 + + &Z_support; + + + + Examples + + SELECT ST_InterpolatePoint('LINESTRING M (0 0 0, 10 0 20)', 'POINT(5 5)'); + st_interpolatepoint + --------------------- + 10 + + + + + See Also + + + + + + + ST_AddMeasure @@ -510,25 +565,25 @@ LINESTRING(6.1 7.1 6,7 8 9) Examples - SELECT ST_AsEWKT(ST_AddMeasure( + SELECT ST_AsText(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( +SELECT ST_AsText(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( +SELECT ST_AsText(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) -SELECT ST_AsEWKT(ST_AddMeasure( +SELECT ST_AsText(ST_AddMeasure( ST_GeomFromEWKT('MULTILINESTRINGM((1 0 4, 2 0 4, 4 0 4),(1 0 4, 2 0 4, 4 0 4))'),10,70)) As ewelev; ewelev ----------------------------------------------------------------- diff --git a/liblwgeom/cunit/cu_node.c b/liblwgeom/cunit/cu_node.c index 1c5196e5e..350ae1d99 100644 --- a/liblwgeom/cunit/cu_node.c +++ b/liblwgeom/cunit/cu_node.c @@ -44,7 +44,7 @@ static void test_lwgeom_node(void) in = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE); out = lwgeom_node(in); tmp = lwgeom_to_ewkt(out); - printf("%s\n", tmp); + /* printf("%s\n", tmp); */ CU_ASSERT_STRING_EQUAL("MULTILINESTRING((0 0,5 5,10 0),(10 0,11 0,12 0,20 0),(20 0,22 0))", tmp); lwfree(tmp); lwgeom_free(out); lwgeom_free(in); @@ -52,7 +52,7 @@ static void test_lwgeom_node(void) in = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE); out = lwgeom_node(in); tmp = lwgeom_to_ewkt(out); - printf("%s\n", tmp); + /* printf("%s\n", tmp); */ CU_ASSERT_STRING_EQUAL( "MULTILINESTRING((0 0,2.5 2.5),(0 5,2.5 2.5),(22 0,20 0),(20 0,12 0,11 0,10 0),(10 0,5 5,2.5 2.5),(2.5 2.5,5 0))", tmp); diff --git a/liblwgeom/cunit/cu_ptarray.c b/liblwgeom/cunit/cu_ptarray.c index 086d179d8..9082a7233 100644 --- a/liblwgeom/cunit/cu_ptarray.c +++ b/liblwgeom/cunit/cu_ptarray.c @@ -64,29 +64,29 @@ static void test_ptarray_append_ptarray(void) static void test_ptarray_locate_point(void) { - LWLINE *line; + LWLINE *line; double loc, dist; - POINT2D p; + POINT4D p, l; - line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)")); + line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)")); - p = getPoint2d(line->points, 0); - loc = ptarray_locate_point(line->points, &p, &dist); + p = getPoint4d(line->points, 0); + loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0); CU_ASSERT_EQUAL(dist, 0.0); - p = getPoint2d(line->points, 1); - loc = ptarray_locate_point(line->points, &p, &dist); + p = getPoint4d(line->points, 1); + loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 1); CU_ASSERT_EQUAL(dist, 0.0); p.x = 21; p.y = 4; - loc = ptarray_locate_point(line->points, &p, &dist); + loc = ptarray_locate_point(line->points, &p, &dist, NULL); CU_ASSERT_EQUAL(loc, 1); CU_ASSERT_EQUAL(dist, 1.0); p.x = 0; p.y = 2; - loc = ptarray_locate_point(line->points, &p, &dist); + loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0); CU_ASSERT_EQUAL(dist, 1.0); @@ -94,7 +94,7 @@ static void test_ptarray_locate_point(void) line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,20 0,40 0)")); p.x = 20; p.y = 0; - loc = ptarray_locate_point(line->points, &p, &dist); + loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0.5); CU_ASSERT_EQUAL(dist, 0.0); @@ -102,7 +102,7 @@ static void test_ptarray_locate_point(void) line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-40 0,0 0,20 0,40 0)")); p.x = 20; p.y = 0; - loc = ptarray_locate_point(line->points, &p, &dist); + loc = ptarray_locate_point(line->points, &p, &dist, &l); CU_ASSERT_EQUAL(loc, 0.75); CU_ASSERT_EQUAL(dist, 0.0); @@ -111,30 +111,30 @@ static void test_ptarray_locate_point(void) static void test_ptarray_isccw(void) { - LWLINE *line; + LWLINE *line; LWPOLY* poly; int ccw; /* clockwise rectangle */ - line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)")); + line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 0); lwline_free(line); /* clockwise triangle */ - line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)")); + line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 0); lwline_free(line); /* counterclockwise triangle */ - line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)")); + line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)")); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 1); lwline_free(line); /* counterclockwise narrow ring (see ticket #1302) */ - line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE)); + line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE)); ccw = ptarray_isccw(line->points); CU_ASSERT_EQUAL(ccw, 1); lwline_free(line); diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index e3c53cc73..bdcdf3aca 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1220,7 +1220,7 @@ extern int lwgeom_ndims(const LWGEOM *geom); * If not-null, the third argument will be set to the actual distance * of the point from the pointarray. */ -extern double ptarray_locate_point(POINTARRAY *, POINT2D *, double *); +extern double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located); /** * Add a measure dimension to a line, interpolating linearly from the start @@ -1231,10 +1231,22 @@ extern LWMLINE* lwmline_measured_from_lwmline(const LWMLINE *lwmline, double m_s /** * Determine the location(s) along a measured line where m occurs and -* return as a multipoint. Offset to left (negative) or right (positive). +* return as a multipoint. Offset to left (positive) or right (negative). */ extern LWGEOM* lwgeom_locate_along(const LWGEOM *lwin, double m, double offset); +/** +* Determine the segments along a measured line that fall within the m-range +* given. Return as a multiline or geometrycollection. +* Offset to left (positive) or right (negative). +*/ +extern LWCOLLECTION* lwgeom_locate_between(const LWGEOM *lwin, double from, double to, double offset); + +/** +* Find the measure value at the location on the line closest to the point. +*/ +extern double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt); + /* * Ensure every segment is at most 'dist' long. * Returned LWGEOM might is unchanged if a POINT. diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index f128f93ae..d2017376a 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -250,7 +250,8 @@ char *geohash_point(double longitude, double latitude, int precision); /* * Point comparisons */ -int p4d_same(POINT4D p1, POINT4D p2); +int p4d_same(const POINT4D *p1, const POINT4D *p2); +int p2d_same(const POINT2D *p1, const POINT2D *p2); /* * Area calculations @@ -318,7 +319,7 @@ LWCOLLECTION *lwcollection_clone_deep(const LWCOLLECTION *lwgeom); * Write into *ret the coordinates of the closest point on * segment A-B to the reference input point R */ -void closest_point_on_segment(POINT2D *R, POINT2D *A, POINT2D *B, POINT2D *ret); +void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret); /* * Repeated points diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c index b550a48f7..c0f8320af 100644 --- a/liblwgeom/lwgeom_geos_split.c +++ b/liblwgeom/lwgeom_geos_split.c @@ -160,7 +160,7 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, LWMLINE* v) { double loc, dist; - POINT2D pt; + POINT4D pt, pt_projected; POINTARRAY* pa1; POINTARRAY* pa2; double vstol; /* vertex snap tolerance */ @@ -176,8 +176,8 @@ lwline_split_by_point_to(const LWLINE* lwline_in, const LWPOINT* blade_in, * -> Return 1 */ - getPoint2d_p(blade_in->point, 0, &pt); - loc = ptarray_locate_point(lwline_in->points, &pt, &dist); + getPoint4d_p(blade_in->point, 0, &pt); + loc = ptarray_locate_point(lwline_in->points, &pt, &dist, &pt_projected); /* lwnotice("Location: %g -- Distance: %g", loc, dist); */ diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index 988e13147..e80b62875 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -154,15 +154,17 @@ lwmline_locate_along(const LWMLINE *lwmline, double m, double offset) return lwmpoint; } -static LWPOINT* +static LWMPOINT* lwpoint_locate_along(const LWPOINT *lwpoint, double m, double offset) { - LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint); double point_m = lwpoint_get_m(lwpoint); + LWGEOM *lwg = lwpoint_as_lwgeom(lwpoint); + LWMPOINT *r = lwmpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg)); if ( FP_EQUALS(m, point_m) ) - return lwpoint_clone(lwpoint); - else - return lwpoint_construct_empty(lwgeom_get_srid(lwg), lwgeom_has_z(lwg), lwgeom_has_m(lwg)); + { + lwmpoint_add_lwpoint(r, lwpoint_clone(lwpoint)); + } + return r; } static LWMPOINT* @@ -807,3 +809,43 @@ lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, do return out_offset; } + +LWCOLLECTION* +lwgeom_locate_between(const LWGEOM *lwin, double from, double to, double offset) +{ + if ( ! lwgeom_has_m(lwin) ) + lwerror("Input geometry does not have a measure dimension"); + + return lwgeom_clip_to_ordinate_range(lwin, 'M', from, to, offset); +} + +double +lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt) +{ + POINT4D p, p_proj; + double ret = 0.0; + + if ( ! lwin ) + lwerror("lwgeom_interpolate_point: null input geometry!"); + + if ( ! lwgeom_has_m(lwin) ) + lwerror("Input geometry does not have a measure dimension"); + + if ( lwgeom_is_empty(lwin) || lwpoint_is_empty(lwpt) ) + lwerror("Input geometry is empty"); + + switch ( lwin->type ) + { + case LINETYPE: + { + LWLINE *lwline = lwgeom_as_lwline(lwin); + lwpoint_getPoint4d_p(lwpt, &p); + ret = ptarray_locate_point(lwline->points, &p, NULL, &p_proj); + ret = p_proj.m; + break; + } + default: + lwerror("This function does not accept %s geometries.", lwtype_name(lwin->type)); + } + return ret; +} \ No newline at end of file diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 51da16992..701996bd7 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -191,7 +191,7 @@ ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, int splice_ends) getPoint4d_p(pa2, 0, &tmp2); /* If the end point and start point are the same, then strip off the end point */ - if (p4d_same(tmp1, tmp2)) + if (p4d_same(&tmp1, &tmp2)) { pa1->npoints--; } @@ -879,11 +879,11 @@ END: * the given segment to the reference input point. */ void -closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret) +closest_point_on_segment(const POINT4D *p, const POINT4D *A, const POINT4D *B, POINT4D *ret) { double r; - if ( ( A->x == B->x) && (A->y == B->y) ) + if ( FP_EQUALS(A->x, B->x) && FP_EQUALS(A->y, B->y) ) { *ret = *A; return; @@ -918,6 +918,8 @@ closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret) ret->x = A->x + ( (B->x - A->x) * r ); ret->y = A->y + ( (B->y - A->y) * r ); + ret->z = A->z + ( (B->z - A->z) * r ); + ret->m = A->m + ( (B->m - A->m) * r ); } /* @@ -925,20 +927,26 @@ closest_point_on_segment(POINT2D *p, POINT2D *A, POINT2D *B, POINT2D *ret) * and, optionally, it's actual distance from the point array. */ double -ptarray_locate_point(POINTARRAY *pa, POINT2D *p, double* mindistout) +ptarray_locate_point(const POINTARRAY *pa, const POINT4D *p4d, double *mindistout, POINT4D *proj4d) { double mindist=-1; double tlen, plen; int t, seg=-1; - POINT2D start, end; - POINT2D proj; + POINT4D start4d, end4d, projtmp; + POINT2D start, end, proj, p; + + /* Initialize our 2D copy of the input parameter */ + p.x = p4d->x; + p.y = p4d->y; + + if ( ! proj4d ) proj4d = &projtmp; getPoint2d_p(pa, 0, &start); for (t=1; tnpoints; t++) { double dist; getPoint2d_p(pa, t, &end); - dist = distance2d_pt_seg(p, &start, &end); + dist = distance2d_pt_seg(&p, &start, &end); if (t==1 || dist < mindist ) { @@ -964,24 +972,28 @@ ptarray_locate_point(POINTARRAY *pa, POINT2D *p, double* mindistout) * If mindist is not 0 we need to project the * point on the closest segment. */ - if ( mindist > 0 ) + if ( FP_GT(mindist, 0.0) ) { - getPoint2d_p(pa, seg, &start); - getPoint2d_p(pa, seg+1, &end); - closest_point_on_segment(p, &start, &end, &proj); + getPoint4d_p(pa, seg, &start4d); + getPoint4d_p(pa, seg+1, &end4d); + closest_point_on_segment(p4d, &start4d, &end4d, proj4d); } else { - proj = *p; + if ( proj4d) + *proj4d = *p4d; } + + /* Copy 4D values into 2D holder */ + proj.x = proj4d->x; + proj.y = proj4d->y; LWDEBUGF(3, "Closest segment:%d, npoints:%d", seg, pa->npoints); /* For robustness, force 1 when closest point == endpoint */ - if ( seg >= (pa->npoints-2) && - ( proj.x == end.x) && (proj.y == end.y) ) + if ( (seg >= (pa->npoints-2)) && p2d_same(&proj, &end) ) { - return 1; + return 1.0; } LWDEBUGF(3, "Closest point on segment: %g,%g", proj.x, proj.y); @@ -1238,9 +1250,18 @@ ptarray_length(const POINTARRAY *pts) int -p4d_same(POINT4D p1, POINT4D p2) +p4d_same(const POINT4D *p1, const POINT4D *p2) +{ + if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) && FP_EQUALS(p1->z,p2->z) && FP_EQUALS(p1->m,p2->m) ) + return LW_TRUE; + else + return LW_FALSE; +} + +int +p2d_same(const POINT2D *p1, const POINT2D *p2) { - if( FP_EQUALS(p1.x,p2.x) && FP_EQUALS(p1.y,p2.y) && FP_EQUALS(p1.z,p2.z) && FP_EQUALS(p1.m,p2.m) ) + if( FP_EQUALS(p1->x,p2->x) && FP_EQUALS(p1->y,p2->y) ) return LW_TRUE; else return LW_FALSE; diff --git a/postgis/lwgeom_functions_analytic.c b/postgis/lwgeom_functions_analytic.c index 98da739df..b8a4f96ac 100644 --- a/postgis/lwgeom_functions_analytic.c +++ b/postgis/lwgeom_functions_analytic.c @@ -820,46 +820,6 @@ Datum LWGEOM_line_substring(PG_FUNCTION_ARGS) } -Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(LWGEOM_line_locate_point); -Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) -{ - GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - LWLINE *lwline; - LWPOINT *lwpoint; - POINTARRAY *pa; - POINT2D p; - double ret; - - if ( gserialized_get_type(geom1) != LINETYPE ) - { - elog(ERROR,"line_locate_point: 1st arg isnt a line"); - PG_RETURN_NULL(); - } - if ( gserialized_get_type(geom2) != POINTTYPE ) - { - elog(ERROR,"line_locate_point: 2st arg isnt a point"); - PG_RETURN_NULL(); - } - if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) ) - { - elog(ERROR, "Operation on two geometries with different SRIDs"); - PG_RETURN_NULL(); - } - - lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); - lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); - - pa = lwline->points; - lwpoint_getPoint2d_p(lwpoint, &p); - - ret = ptarray_locate_point(pa, &p, NULL); - - PG_RETURN_FLOAT8(ret); -} - /******************************************************************************* * The following is based on the "Fast Winding Number Inclusion of a Point * in a Polygon" algorithm by Dan Sunday. diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index a39abbf87..a9cdaf023 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -16,8 +16,235 @@ #include "lwgeom_pg.h" #include "math.h" +/* +* Add a measure dimension to a line, interpolating linearly from the +* start value to the end value. +* ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry +*/ +Datum ST_AddMeasure(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_AddMeasure); +Datum ST_AddMeasure(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *gout; + double start_measure = PG_GETARG_FLOAT8(1); + double end_measure = PG_GETARG_FLOAT8(2); + LWGEOM *lwin, *lwout; + int type = gserialized_get_type(gin); + + /* Raise an error if input is not a linestring or multilinestring */ + if ( type != LINETYPE && type != MULTILINETYPE ) + { + lwerror("Only LINESTRING and MULTILINESTRING are supported"); + PG_RETURN_NULL(); + } + + lwin = lwgeom_from_gserialized(gin); + if ( type == LINETYPE ) + lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); + else + lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure); + + lwgeom_release(lwin); + + if ( lwout == NULL ) + PG_RETURN_NULL(); + + gout = geometry_serialize(lwout); + lwgeom_free(lwout); + + PG_RETURN_POINTER(gout); +} + + +/* +* Locate a point along a feature based on a measure value. +* ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry +*/ +Datum ST_LocateAlong(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_LocateAlong); +Datum ST_LocateAlong(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *gout; + LWGEOM *lwin = NULL, *lwout = NULL; + double measure = PG_GETARG_FLOAT8(1); + double offset = PG_GETARG_FLOAT8(2);; + + lwin = lwgeom_from_gserialized(gin); + lwout = lwgeom_locate_along(lwin, measure, offset); + lwgeom_free(lwin); + PG_FREE_IF_COPY(gin, 0); + + if ( ! lwout ) + PG_RETURN_NULL(); + + gout = geometry_serialize(lwout); + lwgeom_free(lwout); + + PG_RETURN_POINTER(gout); +} + + +/* +* Locate the portion of a line between the specified measures +*/ +Datum ST_LocateBetween(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_LocateBetween); +Datum ST_LocateBetween(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + double from = PG_GETARG_FLOAT8(1); + double to = PG_GETARG_FLOAT8(2); + double offset = PG_GETARG_FLOAT8(3); + LWCOLLECTION *geom_out = NULL; + LWGEOM *line_in = NULL; + static char ordinate = 'M'; /* M */ + + if ( ! gserialized_has_m(geom_in) ) + { + elog(ERROR,"This function only accepts geometries that have an M dimension."); + PG_RETURN_NULL(); + } + + /* This should be a call to ST_LocateAlong! */ + if ( to == from ) + { + PG_RETURN_DATUM(DirectFunctionCall3(ST_LocateAlong, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), PG_GETARG_DATUM(3))); + } + + line_in = lwgeom_from_gserialized(geom_in); + geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); + lwgeom_free(line_in); + PG_FREE_IF_COPY(geom_in, 0); + + if ( ! geom_out ) + { + elog(ERROR,"lwline_clip_to_ordinate_range returned null"); + PG_RETURN_NULL(); + } + + PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); +} + +/* +* Locate the portion of a line between the specified elevations +*/ +Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_LocateBetweenElevations); +Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + double from = PG_GETARG_FLOAT8(1); + double to = PG_GETARG_FLOAT8(2); + LWCOLLECTION *geom_out = NULL; + LWGEOM *line_in = NULL; + static char ordinate = 'Z'; /* Z */ + static double offset = 0.0; + + if ( ! gserialized_has_z(geom_in) ) + { + elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions."); + PG_RETURN_NULL(); + } + + line_in = lwgeom_from_gserialized(geom_in); + geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); + lwgeom_free(line_in); + PG_FREE_IF_COPY(geom_in, 0); + + if ( ! geom_out ) + { + elog(ERROR,"lwline_clip_to_ordinate_range returned null"); + PG_RETURN_NULL(); + } + + PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); +} + + +Datum ST_InterpolatePoint(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(ST_InterpolatePoint); +Datum ST_InterpolatePoint(PG_FUNCTION_ARGS) +{ + GSERIALIZED *gser_line = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *gser_point = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + LWGEOM *lwline; + LWPOINT *lwpoint; + + if ( gserialized_get_type(gser_line) != LINETYPE ) + { + elog(ERROR,"ST_InterpolatePoint: 1st argument isn't a line"); + PG_RETURN_NULL(); + } + if ( gserialized_get_type(gser_point) != POINTTYPE ) + { + elog(ERROR,"ST_InterpolatePoint: 2st argument isn't a point"); + PG_RETURN_NULL(); + } + if ( gserialized_get_srid(gser_line) != gserialized_get_srid(gser_point) ) + { + elog(ERROR, "Operation on two geometries with different SRIDs"); + PG_RETURN_NULL(); + } + if ( ! gserialized_has_m(gser_line) ) + { + elog(ERROR,"ST_InterpolatePoint only accepts geometries that have an M dimension"); + PG_RETURN_NULL(); + } + + lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point)); + lwline = lwgeom_from_gserialized(gser_line); + + PG_RETURN_FLOAT8(lwgeom_interpolate_point(lwline, lwpoint)); +} + + +Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(LWGEOM_line_locate_point); +Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) +{ + GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + LWLINE *lwline; + LWPOINT *lwpoint; + POINTARRAY *pa; + POINT4D p, p_proj; + double ret; + + if ( gserialized_get_type(geom1) != LINETYPE ) + { + elog(ERROR,"line_locate_point: 1st arg isnt a line"); + PG_RETURN_NULL(); + } + if ( gserialized_get_type(geom2) != POINTTYPE ) + { + elog(ERROR,"line_locate_point: 2st arg isnt a point"); + PG_RETURN_NULL(); + } + if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) ) + { + elog(ERROR, "Operation on two geometries with different SRIDs"); + PG_RETURN_NULL(); + } + + lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); + lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); + + pa = lwline->points; + lwpoint_getPoint4d_p(lwpoint, &p); + + ret = ptarray_locate_point(pa, &p, NULL, &p_proj); + + PG_RETURN_FLOAT8(ret); +} + + +/*********************************************************************** +* LEGACY SUPPORT FOR locate_between_measures and locate_along_measure +* Deprecated at PostGIS 2.0. To be removed. +*/ -Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS); typedef struct { @@ -459,6 +686,7 @@ lwgeom_locate_between_m(LWGEOM *lwin, double m0, double m1) * See ISO/IEC CD 13249-3:200x(E) * */ +Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(LWGEOM_locate_between_m); Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) { @@ -471,6 +699,8 @@ Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) int hasm = gserialized_has_m(gin); int type; + elog(NOTICE,"ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween."); + if ( end_measure < start_measure ) { lwerror("locate_between_m: 2nd arg must be bigger then 1st arg"); @@ -517,143 +747,3 @@ Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) PG_RETURN_POINTER(gout); } - -/* -* Add a measure dimension to a line, interpolating linearly from the -* start value to the end value. -* ST_AddMeasure(Geometry, StartMeasure, EndMeasure) returns Geometry -*/ -Datum ST_AddMeasure(PG_FUNCTION_ARGS); -PG_FUNCTION_INFO_V1(ST_AddMeasure); -Datum ST_AddMeasure(PG_FUNCTION_ARGS) -{ - GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GSERIALIZED *gout; - double start_measure = PG_GETARG_FLOAT8(1); - double end_measure = PG_GETARG_FLOAT8(2); - LWGEOM *lwin, *lwout; - int type = gserialized_get_type(gin); - - /* Raise an error if input is not a linestring or multilinestring */ - if ( type != LINETYPE && type != MULTILINETYPE ) - { - lwerror("Only LINESTRING and MULTILINESTRING are supported"); - PG_RETURN_NULL(); - } - - lwin = lwgeom_from_gserialized(gin); - if ( type == LINETYPE ) - lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); - else - lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure); - - lwgeom_release(lwin); - - if ( lwout == NULL ) - PG_RETURN_NULL(); - - gout = geometry_serialize(lwout); - lwgeom_free(lwout); - - PG_RETURN_POINTER(gout); -} - - -/* -* Locate a point along a feature based on a measure value. -* ST_LocateAlong(Geometry, Measure, [Offset]) returns Geometry -*/ -Datum ST_LocateAlong(PG_FUNCTION_ARGS); -PG_FUNCTION_INFO_V1(ST_LocateAlong); -Datum ST_LocateAlong(PG_FUNCTION_ARGS) -{ - GSERIALIZED *gin = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - GSERIALIZED *gout; - LWGEOM *lwin = NULL, *lwout = NULL; - double measure = PG_GETARG_FLOAT8(1); - double offset = PG_GETARG_FLOAT8(2);; - - lwin = lwgeom_from_gserialized(gin); - lwout = lwgeom_locate_along(lwin, measure, offset); - lwgeom_free(lwin); - PG_FREE_IF_COPY(gin, 0); - - if ( ! lwout ) - PG_RETURN_NULL(); - - gout = geometry_serialize(lwout); - lwgeom_free(lwout); - - PG_RETURN_POINTER(gout); -} - - -/* -* Locate the portion of a line between the specified measures -*/ -Datum ST_LocateBetween(PG_FUNCTION_ARGS); -PG_FUNCTION_INFO_V1(ST_LocateBetween); -Datum ST_LocateBetween(PG_FUNCTION_ARGS) -{ - GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - double from = PG_GETARG_FLOAT8(1); - double to = PG_GETARG_FLOAT8(2); - double offset = PG_GETARG_FLOAT8(3); - LWCOLLECTION *geom_out = NULL; - LWGEOM *line_in = NULL; - static char ordinate = 'M'; /* M */ - - if ( ! gserialized_has_m(geom_in) ) - { - elog(ERROR,"This function only accepts geometries that have an M dimension."); - PG_RETURN_NULL(); - } - - line_in = lwgeom_from_gserialized(geom_in); - geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); - lwgeom_free(line_in); - PG_FREE_IF_COPY(geom_in, 0); - - if ( ! geom_out ) - { - elog(ERROR,"lwline_clip_to_ordinate_range returned null"); - PG_RETURN_NULL(); - } - - PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); -} - -/* -* Locate the portion of a line between the specified elevations -*/ -Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS); -PG_FUNCTION_INFO_V1(ST_LocateBetweenElevations); -Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS) -{ - GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - double from = PG_GETARG_FLOAT8(1); - double to = PG_GETARG_FLOAT8(2); - LWCOLLECTION *geom_out = NULL; - LWGEOM *line_in = NULL; - static char ordinate = 'Z'; /* Z */ - static double offset = 0.0; - - if ( ! gserialized_has_z(geom_in) ) - { - elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z dimensions."); - PG_RETURN_NULL(); - } - - line_in = lwgeom_from_gserialized(geom_in); - geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); - lwgeom_free(line_in); - PG_FREE_IF_COPY(geom_in, 0); - - if ( ! geom_out ) - { - elog(ERROR,"lwline_clip_to_ordinate_range returned null"); - PG_RETURN_NULL(); - } - - PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); -} \ No newline at end of file diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index 7ac11cc4a..daf51bd46 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -4536,8 +4536,12 @@ CREATE OR REPLACE FUNCTION ST_LocateBetweenElevations(Geometry geometry, FromEle AS 'MODULE_PATHNAME', 'ST_LocateBetweenElevations' LANGUAGE 'C' IMMUTABLE STRICT; +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_InterpolatePoint(Line geometry, Point geometry) + RETURNS float8 + AS 'MODULE_PATHNAME', 'ST_InterpolatePoint' + LANGUAGE 'C' IMMUTABLE STRICT; - --------------------------------------------------------------- -- END --------------------------------------------------------------- diff --git a/regress/regress_lrs.sql b/regress/regress_lrs.sql index 5e58afa22..45f7df61f 100644 --- a/regress/regress_lrs.sql +++ b/regress/regress_lrs.sql @@ -1,28 +1,28 @@ -- Repeat all tests with the new function names. -- No M value -select '2d',ST_asewkt(ST_locate_along_measure('POINT(1 2)', 1)); -select '3dz',ST_asewkt(ST_locate_along_measure('POINT(1 2 3)', 1)); +select '2d',ST_AsText(ST_LocateAlong('POINT(1 2)', 1)); +select '3dz',ST_AsText(ST_LocateAlong('POINT(1 2 3)', 1)); -- Points -select 'PNTM_1',ST_asewkt(ST_locate_along_measure('POINTM(1 2 3)', 1)); -select 'PNTM_2',ST_asewkt(ST_locate_along_measure('POINTM(1 2 3)', 3)); -select 'PNTM_3',ST_asewkt(ST_locate_between_measures('POINTM(1 2 3)', 2, 3)); -select 'PNTM_4',ST_asewkt(ST_locate_between_measures('POINTM(1 2 3)', 3, 4)); -select 'PNTM_5',ST_asewkt(ST_locate_between_measures('POINTM(1 2 4.00001)', 3, 4)); +select 'PNTM_1',ST_AsText(ST_LocateAlong('POINTM(1 2 3)', 1)); +select 'PNTM_2',ST_AsText(ST_LocateAlong('POINTM(1 2 3)', 3)); +select 'PNTM_3',ST_AsText(ST_LocateBetween('POINTM(1 2 3)', 2, 3)); +select 'PNTM_4',ST_AsText(ST_LocateBetween('POINTM(1 2 3)', 3, 4)); +select 'PNTM_5',ST_AsText(ST_LocateBetween('POINTM(1 2 4.00001)', 3, 4)); -- Multipoints -select 'MPNT_1',ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 2)', 2, 5)); -select 'MPNT_2', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 2, 5)); -select 'MPNT_3', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5.1, 2 1 0)', 2, 5)); -select 'MPNT_4', ST_asewkt(ST_locate_between_measures('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 4, 8)); +select 'MPNT_1',ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 2)', 2, 5)); +select 'MPNT_2', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 2, 5)); +select 'MPNT_3', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5.1, 2 1 0)', 2, 5)); +select 'MPNT_4', ST_AsText(ST_LocateBetween('MULTIPOINTM(1 2 8, 2 2 5, 2 1 0)', 4, 8)); -- Linestrings -select 'LINEZM_1', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 10)', 2, 18)); -select 'LINEZM_2', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 0 0, 0 0 100 10)', 2, 18)); -select 'LINEZM_3', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 10, 10 0 0 0)', 2, 18)); -select 'LINEZM_4', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 20, 10 0 0 0)', 2, 18)); -select 'LINEZM_5', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 100 0, 0 0 0 20, 0 10 10 40, 10 0 0 0)', 2, 18)); -select 'LINEZM_6', ST_asewkt(ST_locate_between_measures('LINESTRING(0 10 10 40, 10 0 0 0)', 2, 2)); +select 'LINEZM_1', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 10)', 2, 18)); +select 'LINEZM_2', ST_AsText(ST_LocateBetween('LINESTRING(0 10 0 0, 0 0 100 10)', 2, 18)); +select 'LINEZM_3', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 10, 10 0 0 0)', 2, 18)); +select 'LINEZM_4', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 20, 10 0 0 0)', 2, 18)); +select 'LINEZM_5', ST_AsText(ST_LocateBetween('LINESTRING(0 10 100 0, 0 0 0 20, 0 10 10 40, 10 0 0 0)', 2, 18)); +select 'LINEZM_6', ST_AsText(ST_LocateBetween('LINESTRING(0 10 10 40, 10 0 0 0)', 2, 2)); --- line_locate_point @@ -35,22 +35,25 @@ select 'line_locate_point_3', ST_line_locate_point(ST_geomfromtext('LINESTRING(- --- line_substring / line_interpolate_point --- postgis-devel/2006-January/001951.html -select 'line_substring_1', ST_asewkt(ST_line_substring(ST_geomfromewkt('SRID=4326;LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)'), 0.5, 0.8)); - -select 'line_substring_2', ST_asewkt(ST_line_substring('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)', 0.5, 0.75)); -select 'line_substring_3', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0, 0.5)); -select 'line_substring_4', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0.5, 1)); -select 'line_substring_5', ST_asewkt(ST_line_substring('LINESTRING(0 0, 2 2)', 0.5, 1)); -select 'line_substring_6', ST_asewkt(ST_line_substring('LINESTRING(0 0, 2 2)', 0, 0.5)); -select 'line_substring_7', ST_asewkt(ST_line_substring('LINESTRING(0 0, 4 4)', .25, 0.5)); -select 'line_substring_8', ST_asewkt(ST_line_substring('LINESTRINGM(0 0 0, 4 4 4)', .25, 0.5)); -select 'line_substring_9', ST_asewkt(ST_line_substring('LINESTRINGM(0 0 4, 4 4 0)', .25, 0.5)); -select 'line_substring_10', ST_asewkt(ST_line_substring('LINESTRING(0 0 4, 4 4 0)', .25, 0.5)); - -select 'line_substring_11', ST_asewkt(ST_line_substring('LINESTRING(0 0, 1 1)', 0, 0)); -select 'line_substring_12', ST_asewkt(ST_line_substring('LINESTRING(0 0 10, 1 1 5)', 0.5, .5)); +with substr as ( + select ST_line_substring(ST_geomfromewkt('SRID=4326;LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)'), 0.5, 0.8) as ln +) +select 'line_substring_1', ST_SRID(ln), ST_AsText(ln) from substr; + +select 'line_substring_2', ST_AsText(ST_line_substring('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4)', 0.5, 0.75)); +select 'line_substring_3', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0, 0.5)); +select 'line_substring_4', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1, 2 2)', 0.5, 1)); +select 'line_substring_5', ST_AsText(ST_line_substring('LINESTRING(0 0, 2 2)', 0.5, 1)); +select 'line_substring_6', ST_AsText(ST_line_substring('LINESTRING(0 0, 2 2)', 0, 0.5)); +select 'line_substring_7', ST_AsText(ST_line_substring('LINESTRING(0 0, 4 4)', .25, 0.5)); +select 'line_substring_8', ST_AsText(ST_line_substring('LINESTRINGM(0 0 0, 4 4 4)', .25, 0.5)); +select 'line_substring_9', ST_AsText(ST_line_substring('LINESTRINGM(0 0 4, 4 4 0)', .25, 0.5)); +select 'line_substring_10', ST_AsText(ST_line_substring('LINESTRING(0 0 4, 4 4 0)', .25, 0.5)); + +select 'line_substring_11', ST_AsText(ST_line_substring('LINESTRING(0 0, 1 1)', 0, 0)); +select 'line_substring_12', ST_AsText(ST_line_substring('LINESTRING(0 0 10, 1 1 5)', 0.5, .5)); --- line_interpolate_point -select 'line_interpolate_point', ST_asewkt(ST_line_interpolate_point('LINESTRING(0 0, 1 1)', 0)); -select 'line_interpolate_point', ST_asewkt(ST_line_interpolate_point('LINESTRING(0 0 10, 1 1 5)', 0.5)); +select 'line_interpolate_point', ST_AsText(ST_line_interpolate_point('LINESTRING(0 0, 1 1)', 0)); +select 'line_interpolate_point', ST_AsText(ST_line_interpolate_point('LINESTRING(0 0 10, 1 1 5)', 0.5)); diff --git a/regress/regress_lrs_expected b/regress/regress_lrs_expected index 75a3918b0..aac897515 100644 --- a/regress/regress_lrs_expected +++ b/regress/regress_lrs_expected @@ -1,34 +1,34 @@ -ERROR: Geometry argument does not have an 'M' ordinate -ERROR: Geometry argument does not have an 'M' ordinate -PNTM_1|GEOMETRYCOLLECTIONM EMPTY -PNTM_2|POINTM(1 2 3) -PNTM_3|POINTM(1 2 3) -PNTM_4|POINTM(1 2 3) -PNTM_5|GEOMETRYCOLLECTIONM EMPTY -MPNT_1|GEOMETRYCOLLECTIONM(POINTM(1 2 2)) -MPNT_2|GEOMETRYCOLLECTIONM(POINTM(2 2 5)) -MPNT_3|GEOMETRYCOLLECTIONM EMPTY -MPNT_4|GEOMETRYCOLLECTIONM(POINTM(1 2 8),POINTM(2 2 5)) -LINEZM_1|LINESTRING(0 8 80 2,0 0 0 10) -LINEZM_2|LINESTRING(0 8 20 2,0 0 100 10) -LINEZM_3|LINESTRING(0 8 80 2,0 0 0 10,8 0 0 2) -LINEZM_4|GEOMETRYCOLLECTION(LINESTRING(0 9 90 2,0 1 10 18),LINESTRING(1 0 0 18,9 0 0 2)) -LINEZM_5|GEOMETRYCOLLECTION(LINESTRING(0 9 90 2,0 1 10 18),LINESTRING(5.5 4.5 4.5 18,9.5 0.5 0.5 2)) -LINEZM_6|POINT(9.5 0.5 0.5 2) +ERROR: Input geometry does not have a measure dimension +ERROR: Input geometry does not have a measure dimension +PNTM_1|MULTIPOINT M EMPTY +PNTM_2|MULTIPOINT M (1 2 3) +PNTM_3|MULTIPOINT M (1 2 3) +PNTM_4|MULTIPOINT M (1 2 3) +PNTM_5|MULTIPOINT M EMPTY +MPNT_1|MULTIPOINT M (1 2 2) +MPNT_2|MULTIPOINT M (2 2 5) +MPNT_3|MULTIPOINT M EMPTY +MPNT_4|MULTIPOINT M (1 2 8,2 2 5) +LINEZM_1|MULTILINESTRING ZM ((0 8 80 2,0 0 0 10)) +LINEZM_2|MULTILINESTRING ZM ((0 8 20 2,0 0 100 10)) +LINEZM_3|MULTILINESTRING ZM ((0 8 80 2,0 0 0 10,8 0 0 2)) +LINEZM_4|MULTILINESTRING ZM ((0 9 90 2,0 1 10 18),(1 0 0 18,9 0 0 2)) +LINEZM_5|MULTILINESTRING ZM ((0 9 90 2,0 1 10 18),(5.5 4.5 4.5 18,9.5 0.5 0.5 2)) +LINEZM_6|MULTIPOINT ZM (9.5 0.5 0.5 2) line_locate_point_1|0.528602749909894 line_locate_point_2|1 line_locate_point_3|0 -line_substring_1|SRID=4326;LINESTRING(2 2 2 2,3 3 3 3,3.2 3.2 3.2 3.2) -line_substring_2|LINESTRING(2 2 2 2,3 3 3 3) +line_substring_1|4326|LINESTRING ZM (2 2 2 2,3 3 3 3,3.2 3.2 3.2 3.2) +line_substring_2|LINESTRING ZM (2 2 2 2,3 3 3 3) line_substring_3|LINESTRING(0 0,1 1) line_substring_4|LINESTRING(1 1,2 2) line_substring_5|LINESTRING(1 1,2 2) line_substring_6|LINESTRING(0 0,1 1) line_substring_7|LINESTRING(1 1,2 2) -line_substring_8|LINESTRINGM(1 1 1,2 2 2) -line_substring_9|LINESTRINGM(1 1 3,2 2 2) -line_substring_10|LINESTRING(1 1 3,2 2 2) +line_substring_8|LINESTRING M (1 1 1,2 2 2) +line_substring_9|LINESTRING M (1 1 3,2 2 2) +line_substring_10|LINESTRING Z (1 1 3,2 2 2) line_substring_11|POINT(0 0) -line_substring_12|POINT(0.5 0.5 7.5) +line_substring_12|POINT Z (0.5 0.5 7.5) line_interpolate_point|POINT(0 0) -line_interpolate_point|POINT(0.5 0.5 7.5) +line_interpolate_point|POINT Z (0.5 0.5 7.5) diff --git a/regress/tickets_expected b/regress/tickets_expected index 5df001be1..f8f17acf9 100644 --- a/regress/tickets_expected +++ b/regress/tickets_expected @@ -1,5 +1,6 @@ #2|POLYGON((1 1,1 2,2 2,3 2,3 1,2 1,1 1)) #11|0 +NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween. #21|SRID=31293;POINTM(6220.13 5337367.145 4566) t ERROR: AddGeometryColumn() - invalid SRID @@ -16,6 +17,7 @@ ERROR: lwgeom_longitude_shift: unsupported geom type: CircularString #83|MULTICURVE(CIRCULARSTRING(220268 150415,220227 150505,220227 150406)) ERROR: Unsupported geometry type: CircularString #112|GEOMETRYCOLLECTION(POINT(-10 50)) +NOTICE: ST_Locate_Between_Measures and ST_Locate_Along_Measure are deprecated. Use ST_LocateAlong and ST_LocateBetween. ERROR: Geometry argument does not have an 'M' ordinate #116|POLYGON EMPTY #122|CIRCULARSTRING(220268 150415,220227 150505,220227 150406) -- 2.40.0