From af3b7fe1dbc3c4da80ee49376eda6a81f9b5bbff Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Thu, 12 Jan 2012 19:07:02 +0000 Subject: [PATCH] Flip ST_LocateBetween to use the same LRS code as ST_LocateBetweenElevations git-svn-id: http://svn.osgeo.org/postgis/trunk@8792 b70326c6-7e19-0410-871a-916f4a2858ee --- liblwgeom/cunit/cu_algorithm.c | 60 +++++++------- liblwgeom/liblwgeom.h.in | 11 ++- liblwgeom/liblwgeom_internal.h | 6 +- liblwgeom/lwalgorithm.c | 2 +- liblwgeom/lwlinearreferencing.c | 117 +++++++++++++++++----------- postgis/lwgeom_functions_analytic.c | 44 ----------- postgis/lwgeom_functions_basic.c | 24 +++--- postgis/lwgeom_functions_lrs.c | 69 ++++++++++++++++ postgis/postgis.sql.in.c | 43 +++++----- 9 files changed, 217 insertions(+), 159 deletions(-) diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 0341e02fa..ad03d08e6 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -382,13 +382,13 @@ static void test_lwpoint_set_ordinate(void) p.z = 0.0; p.m = 0.0; - lwpoint_set_ordinate(&p, 0, 1.5); + lwpoint_set_ordinate(&p, 'X', 1.5); CU_ASSERT_EQUAL( p.x, 1.5 ); - lwpoint_set_ordinate(&p, 3, 2.5); + lwpoint_set_ordinate(&p, 'M', 2.5); CU_ASSERT_EQUAL( p.m, 2.5 ); - lwpoint_set_ordinate(&p, 2, 3.5); + lwpoint_set_ordinate(&p, 'Z', 3.5); CU_ASSERT_EQUAL( p.z, 3.5 ); } @@ -402,10 +402,10 @@ static void test_lwpoint_get_ordinate(void) p.z = 30.0; p.m = 40.0; - CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 0), 10.0 ); - CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 1), 20.0 ); - CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 2), 30.0 ); - CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 3), 40.0 ); + CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 'X'), 10.0 ); + CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 'Y'), 20.0 ); + CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 'Z'), 30.0 ); + CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 'M'), 40.0 ); } @@ -424,16 +424,16 @@ static void test_lwpoint_interpolate(void) q.z = 40.0; q.m = 50.0; - rv = lwpoint_interpolate(&p, &q, &r, 4, 2, 35.0); + rv = lwpoint_interpolate(&p, &q, &r, 1, 1, 'Z', 35.0); CU_ASSERT_EQUAL( r.x, 15.0); - rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 41.0); + rv = lwpoint_interpolate(&p, &q, &r, 1, 1, 'M', 41.0); CU_ASSERT_EQUAL( r.y, 21.0); - rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 50.0); + rv = lwpoint_interpolate(&p, &q, &r, 1, 1, 'M', 50.0); CU_ASSERT_EQUAL( r.y, 30.0); - rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 40.0); + rv = lwpoint_interpolate(&p, &q, &r, 1, 1, 'M', 40.0); CU_ASSERT_EQUAL( r.y, 20.0); } @@ -449,7 +449,7 @@ static void test_lwline_clip(void) l51 = (LWLINE*)lwgeom_from_wkt("LINESTRING(0 0, 0 1, 0 2, 0 3, 0 4)", LW_PARSER_CHECK_NONE); /* Clip in the middle, mid-range. */ - c = lwline_clip_to_ordinate_range(l51, 1, 1.5, 2.5); + c = lwline_clip_to_ordinate_range(l51, 'Y', 1.5, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1.5,0 2,0 2.5))"); @@ -457,7 +457,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Clip off the top. */ - c = lwline_clip_to_ordinate_range(l51, 1, 3.5, 5.5); + c = lwline_clip_to_ordinate_range(l51, 'Y', 3.5, 5.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 3.5,0 4))"); @@ -465,7 +465,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Clip off the bottom. */ - c = lwline_clip_to_ordinate_range(l51, 1, -1.5, 2.5); + c = lwline_clip_to_ordinate_range(l51, 'Y', -1.5, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2,0 2.5))" ); @@ -473,7 +473,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Range holds entire object. */ - c = lwline_clip_to_ordinate_range(l51, 1, -1.5, 5.5); + c = lwline_clip_to_ordinate_range(l51, 'Y', -1.5, 5.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2,0 3,0 4))" ); @@ -481,7 +481,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Clip on vertices. */ - c = lwline_clip_to_ordinate_range(l51, 1, 1.0, 2.0); + c = lwline_clip_to_ordinate_range(l51, 'Y', 1.0, 2.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1,0 2))" ); @@ -489,7 +489,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Clip on vertices off the bottom. */ - c = lwline_clip_to_ordinate_range(l51, 1, -1.0, 2.0); + c = lwline_clip_to_ordinate_range(l51, 'Y', -1.0, 2.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2))" ); @@ -497,7 +497,7 @@ static void test_lwline_clip(void) lwcollection_free(c); /* Clip on top. */ - c = lwline_clip_to_ordinate_range(l51, 1, -1.0, 0.0); + c = lwline_clip_to_ordinate_range(l51, 'Y', -1.0, 0.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(0 0))" ); @@ -506,7 +506,7 @@ static void test_lwline_clip(void) /* ST_LocateBetweenElevations(ST_GeomFromEWKT('LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)'), 1, 2)) */ line = (LWLINE*)lwgeom_from_wkt("LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)", LW_PARSER_CHECK_NONE); - c = lwline_clip_to_ordinate_range(line, 2, 1.0, 2.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 1.0, 2.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))" ); lwfree(ewkt); @@ -515,7 +515,7 @@ static void test_lwline_clip(void) /* ST_LocateBetweenElevations('LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)', 1, 2)) */ line = (LWLINE*)lwgeom_from_wkt("LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)", LW_PARSER_CHECK_NONE); - c = lwline_clip_to_ordinate_range(line, 2, 1.0, 2.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 1.0, 2.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("a = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))" ); @@ -525,7 +525,7 @@ static void test_lwline_clip(void) /* ST_LocateBetweenElevations('LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)', 1, 1)) */ line = (LWLINE*)lwgeom_from_wkt("LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)", LW_PARSER_CHECK_NONE); - c = lwline_clip_to_ordinate_range(line, 2, 1.0, 1.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 1.0, 1.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("b = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))" ); @@ -535,7 +535,7 @@ static void test_lwline_clip(void) /* ST_LocateBetweenElevations('LINESTRING(1 1 1, 1 2 2)', 1,1) */ line = (LWLINE*)lwgeom_from_wkt("LINESTRING(1 1 1, 1 2 2)", LW_PARSER_CHECK_NONE); - c = lwline_clip_to_ordinate_range(line, 2, 1.0, 1.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 1.0, 1.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))" ); @@ -560,7 +560,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip in the middle, mid-range. */ - c = lwmline_clip_to_ordinate_range(mline, 1, 1.5, 2.5); + c = lwmline_clip_to_ordinate_range(mline, 'Y', 1.5, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1.5,0 2,0 2.5))"); @@ -575,7 +575,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((1 0,1 1,1 2,1 3,1 4), (0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip off the top. */ - c = lwmline_clip_to_ordinate_range(mline, 1, 3.5, 5.5); + c = lwmline_clip_to_ordinate_range(mline, 'Y', 3.5, 5.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((1 3.5,1 4),(0 3.5,0 4))"); @@ -590,7 +590,7 @@ static void test_lwmline_clip(void) mline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((1 0,1 -1,1 -2,1 -3,1 -4), (0 0,0 1,0 2,0 3,0 4))", LW_PARSER_CHECK_NONE); /* Clip from 0 upwards.. */ - c = lwmline_clip_to_ordinate_range(mline, 1, 0.0, 2.5); + c = lwmline_clip_to_ordinate_range(mline, 'Y', 0.0, 2.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 0),LINESTRING(0 0,0 1,0 2,0 2.5))"); @@ -605,7 +605,7 @@ static void test_lwmline_clip(void) line = (LWLINE*)lwgeom_from_wkt("LINESTRING(0 0 0 0,1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,3 3 3 5,2 2 2 6,1 1 1 7,0 0 0 8)", LW_PARSER_CHECK_NONE); /* Clip from 3 to 3.5 */ - c = lwline_clip_to_ordinate_range(line, 2, 3.0, 3.5); + c = lwline_clip_to_ordinate_range(line, 'Z', 3.0, 3.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((3 3 3 3,3.5 3.5 3.5 3.5),(3.5 3.5 3.5 4.5,3 3 3 5))"); @@ -613,7 +613,7 @@ static void test_lwmline_clip(void) lwcollection_free(c); /* Clip from 2 to 3.5 */ - c = lwline_clip_to_ordinate_range(line, 2, 2.0, 3.5); + c = lwline_clip_to_ordinate_range(line, 'Z', 2.0, 3.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2 2,3 3 3 3,3.5 3.5 3.5 3.5),(3.5 3.5 3.5 4.5,3 3 3 5,2 2 2 6))"); @@ -621,7 +621,7 @@ static void test_lwmline_clip(void) lwcollection_free(c); /* Clip from 3 to 4 */ - c = lwline_clip_to_ordinate_range(line, 2, 3.0, 4.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 3.0, 4.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((3 3 3 3,4 4 4 4,3 3 3 5))"); @@ -629,7 +629,7 @@ static void test_lwmline_clip(void) lwcollection_free(c); /* Clip from 2 to 3 */ - c = lwline_clip_to_ordinate_range(line, 2, 2.0, 3.0); + c = lwline_clip_to_ordinate_range(line, 'Z', 2.0, 3.0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2 2,3 3 3 3),(3 3 3 5,2 2 2 6))"); @@ -666,7 +666,7 @@ static void test_lwline_clip_big(void) p.z = 2.0; ptarray_set_point4d(pa, 2, &p); - c = lwline_clip_to_ordinate_range(line, 2, 0.5, 1.5); + c = lwline_clip_to_ordinate_range(line, 'Z', 0.5, 1.5); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0.5 0.5 0.5,1 1 1,1.5 1.5 1.5))" ); diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index b4f340d7b..c09463755 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -1267,17 +1267,22 @@ enum CG_LINE_CROSS_TYPE { /** * Given two lines, characterize how (and if) they cross each other */ -int lwline_crossing_direction(LWLINE *l1, LWLINE *l2); +int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2); + +/** +* Given a geometry clip based on the from/to range of one of its ordinates (x, y, z, m). Use for m- and z- clipping. +*/ +LWCOLLECTION* lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to); /** * Clip a line based on the from/to range of one of its ordinates. Use for m- and z- clipping */ -LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to); +LWCOLLECTION *lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to); /** * Clip a multi-line based on the from/to range of one of its ordinates. Use for m- and z- clipping */ -LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to); +LWCOLLECTION *lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to); /* * Export functions diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index d050fbf1f..b770459f6 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -210,13 +210,13 @@ int lw_segment_envelope_intersects(const POINT2D *p1, const POINT2D *p2, const P /* * Get/Set an enumeratoed ordinate. (x,y,z,m) */ -double lwpoint_get_ordinate(const POINT4D *p, int ordinate); -void lwpoint_set_ordinate(POINT4D *p, int ordinate, double value); +double lwpoint_get_ordinate(const POINT4D *p, char ordinate); +void lwpoint_set_ordinate(POINT4D *p, char ordinate, double value); /* * Generate an interpolated coordinate p given an interpolation value and ordinate to apply it to */ -int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value); +int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz, int hasm, char ordinate, double interpolation_value); /* * Geohash diff --git a/liblwgeom/lwalgorithm.c b/liblwgeom/lwalgorithm.c index 7ee4e563f..2f8b98f66 100644 --- a/liblwgeom/lwalgorithm.c +++ b/liblwgeom/lwalgorithm.c @@ -165,7 +165,7 @@ int lw_segment_intersects(const POINT2D *p1, const POINT2D *p2, const POINT2D *q ** LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3 ** */ -int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) +int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2) { int i = 0, j = 0, rv = 0; POINT2D p1, p2, q1, q2; diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index 093fafbb1..6391856dd 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -222,7 +222,7 @@ lwgeom_locate_along(const LWGEOM *lwin, double m, double offset) * @param ordinate number (1=x, 2=y, 3=z, 4=m) * @return d value at that ordinate */ -double lwpoint_get_ordinate(const POINT4D *p, int ordinate) +double lwpoint_get_ordinate(const POINT4D *p, char ordinate) { if ( ! p ) { @@ -230,19 +230,22 @@ double lwpoint_get_ordinate(const POINT4D *p, int ordinate) return 0.0; } - if ( ordinate > 3 || ordinate < 0 ) + if ( ! ( ordinate == 'X' || ordinate == 'Y' || ordinate == 'Z' || ordinate == 'M' ) ) { - lwerror("Cannot extract ordinate %d.", ordinate); + lwerror("Cannot extract %c ordinate.", ordinate); return 0.0; } - if ( ordinate == 3 ) - return p->m; - if ( ordinate == 2 ) - return p->z; - if ( ordinate == 1 ) + if ( ordinate == 'X' ) + return p->x; + if ( ordinate == 'Y' ) return p->y; + if ( ordinate == 'Z' ) + return p->z; + if ( ordinate == 'M' ) + return p->m; + /* X */ return p->x; } @@ -251,7 +254,7 @@ double lwpoint_get_ordinate(const POINT4D *p, int ordinate) * Given a point, ordinate number and value, set that ordinate on the * point. */ -void lwpoint_set_ordinate(POINT4D *p, int ordinate, double value) +void lwpoint_set_ordinate(POINT4D *p, char ordinate, double value) { if ( ! p ) { @@ -259,27 +262,27 @@ void lwpoint_set_ordinate(POINT4D *p, int ordinate, double value) return; } - if ( ordinate > 3 || ordinate < 0 ) + if ( ! ( ordinate == 'X' || ordinate == 'Y' || ordinate == 'Z' || ordinate == 'M' ) ) { - lwerror("Cannot extract ordinate %d.", ordinate); + lwerror("Cannot set %c ordinate.", ordinate); return; } - LWDEBUGF(4, " setting ordinate %d to %g", ordinate, value); + LWDEBUGF(4, " setting ordinate %c to %g", ordinate, value); switch ( ordinate ) { - case 3: - p->m = value; - return; - case 2: - p->z = value; + case 'X': + p->x = value; return; - case 1: + case 'Y': p->y = value; return; - case 0: - p->x = value; + case 'Z': + p->z = value; + return; + case 'M': + p->m = value; return; } } @@ -289,21 +292,22 @@ void lwpoint_set_ordinate(POINT4D *p, int ordinate, double value) * generate a new point that is proportionally between the input points, * using the values in the provided dimension as the scaling factors. */ -int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value) +int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int hasz, int hasm, char ordinate, double interpolation_value) { + static char* dims = "XYZM"; double p1_value = lwpoint_get_ordinate(p1, ordinate); double p2_value = lwpoint_get_ordinate(p2, ordinate); double proportion; int i = 0; - if ( ordinate < 0 || ordinate >= ndims ) + if ( ! ( ordinate == 'X' || ordinate == 'Y' || ordinate == 'Z' || ordinate == 'M' ) ) { - lwerror("Ordinate (%d) is not within ndims (%d).", ordinate, ndims); + lwerror("Cannot set %c ordinate.", ordinate); return 0; } if ( FP_MIN(p1_value, p2_value) > interpolation_value || - FP_MAX(p1_value, p2_value) < interpolation_value ) + FP_MAX(p1_value, p2_value) < interpolation_value ) { lwerror("Cannot interpolate to a value (%g) not between the input points (%g, %g).", interpolation_value, p1_value, p2_value); return 0; @@ -311,14 +315,16 @@ int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int nd proportion = fabs((interpolation_value - p1_value) / (p2_value - p1_value)); - for ( i = 0; i < ndims; i++ ) + for ( i = 0; i < 4; i++ ) { double newordinate = 0.0; - p1_value = lwpoint_get_ordinate(p1, i); - p2_value = lwpoint_get_ordinate(p2, i); + if ( dims[i] == 'Z' && ! hasz ) continue; + if ( dims[i] == 'M' && ! hasm ) continue; + p1_value = lwpoint_get_ordinate(p1, dims[i]); + p2_value = lwpoint_get_ordinate(p2, dims[i]); newordinate = p1_value + proportion * (p2_value - p1_value); - lwpoint_set_ordinate(p, i, newordinate); - LWDEBUGF(4, " clip ordinate(%d) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) ", i, p1_value, p2_value, proportion, newordinate ); + lwpoint_set_ordinate(p, dims[i], newordinate); + LWDEBUGF(4, " clip ordinate(%c) p1_value(%g) p2_value(%g) proportion(%g) newordinate(%g) ", dims[i], p1_value, p2_value, proportion, newordinate ); } return 1; @@ -327,7 +333,8 @@ int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int nd /** * Clip an input MULTILINESTRING between two values, on any ordinate input. */ -LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to) +LWCOLLECTION* +lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; @@ -344,8 +351,8 @@ LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, doubl else { LWCOLLECTION *col; - char hasz = FLAGS_GET_Z(mline->flags); - char hasm = FLAGS_GET_M(mline->flags); + char hasz = lwgeom_has_z(lwmline_as_lwgeom(mline)); + char hasm = lwgeom_has_m(lwmline_as_lwgeom(mline)); int i, j; char homogeneous = 1; size_t geoms_size = 0; @@ -407,7 +414,8 @@ LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, doubl * Take in a LINESTRING and return a MULTILINESTRING of those portions of the * LINESTRING between the from/to range for the specified ordinate (XYZM) */ -LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to) +LWCOLLECTION* +lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to) { POINTARRAY *pa_in = NULL; @@ -417,8 +425,8 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f int added_last_point = 0; POINT4D *p = NULL, *q = NULL, *r = NULL; double ordinate_value_p = 0.0, ordinate_value_q = 0.0; - char hasz = FLAGS_GET_Z(line->flags); - char hasm = FLAGS_GET_M(line->flags); + char hasz = lwgeom_has_z(lwline_as_lwgeom(line)); + char hasm = lwgeom_has_m(lwline_as_lwgeom(line)); char dims = FLAGS_NDIMS(line->flags); /* Null input, nothing we can do. */ @@ -436,11 +444,11 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f to = t; } - LWDEBUGF(4, "from = %g, to = %g, ordinate = %d", from, to, ordinate); + LWDEBUGF(4, "from = %g, to = %g, ordinate = %c", from, to, ordinate); LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line)); /* Asking for an ordinate we don't have. Error. */ - if ( ordinate >= dims ) + if ( (ordinate == 'Z' && ! hasz) || (ordinate == 'M' && ! hasm) ) { lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims); return NULL; @@ -494,7 +502,7 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f { double interpolation_value; (ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from); - rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value); + rv = lwpoint_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, "[0] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } @@ -520,7 +528,7 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f * to the point array at the range boundary. */ double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); - rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value); + rv = lwpoint_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [1] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } @@ -535,7 +543,7 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f { double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); - rv = lwpoint_interpolate(q, p, r, dims, ordinate, interpolation_value); + rv = lwpoint_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [2] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } @@ -546,10 +554,10 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate lower point. */ - rv = lwpoint_interpolate(p, q, r, dims, ordinate, from); + rv = lwpoint_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 0, r); /* Interpolate upper point. */ - rv = lwpoint_interpolate(p, q, r, dims, ordinate, to); + rv = lwpoint_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 1, r); } else if ( i && ordinate_value_q > to && ordinate_value_p < from ) @@ -558,10 +566,10 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate upper point. */ - rv = lwpoint_interpolate(p, q, r, dims, ordinate, to); + rv = lwpoint_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 0, r); /* Interpolate lower point. */ - rv = lwpoint_interpolate(p, q, r, dims, ordinate, from); + rv = lwpoint_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 1, r); } /* We have an extant point-array, save it out to a multi-line. */ @@ -628,4 +636,23 @@ LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double f return NULL; -} \ No newline at end of file +} + +LWCOLLECTION* +lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to) +{ + if ( ! lwin ) + lwerror("lwgeom_clip_to_ordinate_range: null input geometry!"); + + switch ( lwin->type ) + { + case LINETYPE: + return lwline_clip_to_ordinate_range((LWLINE*)lwin, ordinate, from, to); + case MULTILINETYPE: + return lwmline_clip_to_ordinate_range((LWMLINE*)lwin, ordinate, from, to); + default: + lwerror("This function only accepts LINESTRING or MULTILINESTRING as arguments."); + } + + return NULL; +} diff --git a/postgis/lwgeom_functions_analytic.c b/postgis/lwgeom_functions_analytic.c index 45682795b..98da739df 100644 --- a/postgis/lwgeom_functions_analytic.c +++ b/postgis/lwgeom_functions_analytic.c @@ -32,7 +32,6 @@ /* Prototypes */ Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS); Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS); -Datum ST_LocateBetweenElevations(PG_FUNCTION_ARGS); double determineSide(POINT2D *seg1, POINT2D *seg2, POINT2D *point); int isOnSegment(POINT2D *seg1, POINT2D *seg2, POINT2D *point); @@ -667,50 +666,7 @@ Datum ST_LineCrossingDirection(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; - char geomtype = gserialized_get_type(geom_in); - static int ordinate = 2; /* Z */ - - if ( ! ( geomtype == LINETYPE || geomtype == MULTILINETYPE ) ) - { - elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING as arguments."); - PG_RETURN_NULL(); - } - - line_in = lwgeom_from_gserialized(geom_in); - - if ( ! FLAGS_GET_Z(line_in->flags) ) - { - elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z values as arguments."); - PG_RETURN_NULL(); - } - - if ( geomtype == LINETYPE ) - { - geom_out = lwline_clip_to_ordinate_range((LWLINE*)line_in, ordinate, from, to); - } - else if ( geomtype == MULTILINETYPE ) - { - geom_out = lwmline_clip_to_ordinate_range((LWMLINE*)line_in, ordinate, from, to); - } - lwgeom_free(line_in); - if ( ! geom_out ) - { - elog(ERROR,"The lwline_clip_to_ordinate_range returned null."); - PG_RETURN_NULL(); - } - - PG_FREE_IF_COPY(geom_in, 0); - PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); -} /*********************************************************************** * --strk@keybit.net diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c index f526391b1..a3680763f 100644 --- a/postgis/lwgeom_functions_basic.c +++ b/postgis/lwgeom_functions_basic.c @@ -1033,7 +1033,7 @@ Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(LWGEOM_collect); Datum LWGEOM_collect(PG_FUNCTION_ARGS) { - GSERIALIZED *pglwgeom1, *pglwgeom2, *result; + GSERIALIZED *gser1, *gser2, *result; LWGEOM *lwgeoms[2], *outlwg; uint32 type1, type2; uint8_t outtype; @@ -1053,22 +1053,22 @@ Datum LWGEOM_collect(PG_FUNCTION_ARGS) if (PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); - pglwgeom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - pglwgeom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + gser1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + gser2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - POSTGIS_DEBUGF(3, "LWGEOM_collect(%s, %s): call", lwtype_name(gserialized_get_type(pglwgeom1)), lwtype_name(gserialized_get_type(pglwgeom2))); + POSTGIS_DEBUGF(3, "LWGEOM_collect(%s, %s): call", lwtype_name(gserialized_get_type(gser1)), lwtype_name(gserialized_get_type(gser2))); - if ( FLAGS_GET_ZM(pglwgeom1->flags) != FLAGS_GET_ZM(pglwgeom2->flags) ) + if ( FLAGS_GET_ZM(gser1->flags) != FLAGS_GET_ZM(gser2->flags) ) { elog(ERROR,"Cannot ST_Collect geometries with differing dimensionality."); PG_RETURN_NULL(); } - srid = gserialized_get_srid(pglwgeom1); - error_if_srid_mismatch(srid, gserialized_get_srid(pglwgeom2)); + srid = gserialized_get_srid(gser1); + error_if_srid_mismatch(srid, gserialized_get_srid(gser2)); - lwgeoms[0] = lwgeom_from_gserialized(pglwgeom1); - lwgeoms[1] = lwgeom_from_gserialized(pglwgeom2); + lwgeoms[0] = lwgeom_from_gserialized(gser1); + lwgeoms[1] = lwgeom_from_gserialized(gser2); type1 = lwgeoms[0]->type; type2 = lwgeoms[1]->type; @@ -1092,8 +1092,8 @@ Datum LWGEOM_collect(PG_FUNCTION_ARGS) lwgeom_free(lwgeoms[0]); lwgeom_free(lwgeoms[1]); - PG_FREE_IF_COPY(pglwgeom1, 0); - PG_FREE_IF_COPY(pglwgeom2, 1); + PG_FREE_IF_COPY(gser1, 0); + PG_FREE_IF_COPY(gser2, 1); PG_RETURN_POINTER(result); } @@ -1575,7 +1575,7 @@ Datum LWGEOM_expand(PG_FUNCTION_ARGS) gbox_expand(&gbox, d); - pa = ptarray_construct_empty(FLAGS_GET_Z(lwgeom->flags), FLAGS_GET_M(lwgeom->flags), 5); + pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 5); /* Assign coordinates to POINT2D array */ pt.x = gbox.xmin; diff --git a/postgis/lwgeom_functions_lrs.c b/postgis/lwgeom_functions_lrs.c index 137b47633..8e55c3f44 100644 --- a/postgis/lwgeom_functions_lrs.c +++ b/postgis/lwgeom_functions_lrs.c @@ -587,3 +587,72 @@ Datum ST_LocateAlong(PG_FUNCTION_ARGS) 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); + 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 */ + + 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); + 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 f2fdc4b59..68f50b67f 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -2592,14 +2592,6 @@ CREATE OR REPLACE FUNCTION ST_LineCrossingDirection(geom1 geometry, geom2 geomet $$ SELECT CASE WHEN NOT $1 && $2 THEN 0 ELSE _ST_LineCrossingDirection($1,$2) END $$ LANGUAGE 'sql' IMMUTABLE; - --- Only accepts LINESTRING as parameters. --- Availability: 1.4.0 -CREATE OR REPLACE FUNCTION ST_LocateBetweenElevations(geometry, float8, float8) - RETURNS geometry - AS 'MODULE_PATHNAME', 'ST_LocateBetweenElevations' - LANGUAGE 'C' IMMUTABLE STRICT; - -- Requires GEOS >= 3.0.0 -- Availability: 1.3.3 CREATE OR REPLACE FUNCTION ST_SimplifyPreserveTopology(geometry, float8) @@ -4444,7 +4436,7 @@ CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry) -- SQL-MM --------------------------------------------------------------- -- PostGIS equivalent function: ST_ndims(geometry) -CREATE OR REPLACE FUNCTION ST_CoordDim(geometry) +CREATE OR REPLACE FUNCTION ST_CoordDim(Geometry geometry) RETURNS smallint AS 'MODULE_PATHNAME', 'LWGEOM_ndims' LANGUAGE 'C' IMMUTABLE STRICT; @@ -4472,25 +4464,25 @@ CREATE OR REPLACE FUNCTION ST_CurveToLine(geometry) RETURNS geometry AS 'SELECT ST_CurveToLine($1, 32)' LANGUAGE 'SQL' IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION ST_HasArc(geometry) +CREATE OR REPLACE FUNCTION ST_HasArc(Geometry geometry) RETURNS boolean AS 'MODULE_PATHNAME', 'LWGEOM_has_arc' LANGUAGE 'C' IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION ST_LineToCurve(geometry) +CREATE OR REPLACE FUNCTION ST_LineToCurve(Geometry geometry) RETURNS geometry AS 'MODULE_PATHNAME', 'LWGEOM_line_desegmentize' LANGUAGE 'C' IMMUTABLE STRICT; -- Availability: 1.5.0 -CREATE OR REPLACE FUNCTION _ST_OrderingEquals(geometry, geometry) +CREATE OR REPLACE FUNCTION _ST_OrderingEquals(GeometryA geometry, GeometryB geometry) RETURNS boolean AS 'MODULE_PATHNAME', 'LWGEOM_same' LANGUAGE 'C' IMMUTABLE STRICT COST 100; -- Availability: 1.3.0 -CREATE OR REPLACE FUNCTION ST_OrderingEquals(geometry, geometry) +CREATE OR REPLACE FUNCTION ST_OrderingEquals(GeometryA geometry, GeometryB geometry) RETURNS boolean AS $$ SELECT $1 ~= $2 AND _ST_OrderingEquals($1, $2) @@ -4501,13 +4493,13 @@ CREATE OR REPLACE FUNCTION ST_OrderingEquals(geometry, geometry) -- SQL/MM - SQL Functions on type ST_Point ------------------------------------------------------------------------------- --- PostGIS equivalent function: ST_MakePoint(float8,float8) +-- PostGIS equivalent function: ST_MakePoint(XCoordinate float8,YCoordinate float8) CREATE OR REPLACE FUNCTION ST_Point(float8, float8) RETURNS geometry AS 'MODULE_PATHNAME', 'LWGEOM_makepoint' LANGUAGE 'C' IMMUTABLE STRICT; --- PostGIS equivalent function: ST_MakePolygon(geometry) +-- PostGIS equivalent function: ST_MakePolygon(Geometry geometry) CREATE OR REPLACE FUNCTION ST_Polygon(geometry, int) RETURNS geometry AS $$ @@ -4515,10 +4507,9 @@ CREATE OR REPLACE FUNCTION ST_Polygon(geometry, int) $$ LANGUAGE 'SQL' IMMUTABLE STRICT; --- PostGIS equivalent function: GeomFromWKB(bytea)) +-- PostGIS equivalent function: GeomFromWKB(WKB bytea)) -- Note: Defaults to an SRID=-1, not 0 as per SQL/MM specs. - -CREATE OR REPLACE FUNCTION ST_WKBToSQL(bytea) +CREATE OR REPLACE FUNCTION ST_WKBToSQL(WKB bytea) RETURNS geometry AS 'MODULE_PATHNAME','LWGEOM_from_WKB' LANGUAGE 'C' IMMUTABLE STRICT; @@ -4526,16 +4517,26 @@ CREATE OR REPLACE FUNCTION ST_WKBToSQL(bytea) --- -- Linear referencing functions --- -CREATE OR REPLACE FUNCTION ST_LocateBetween(Geometry geometry, Measure1 float8, Measure2 float8, Offsets float8 default 0.0) +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_LocateBetween(Geometry geometry, FromMeasure float8, ToMeasure float8, LeftRightOffset float8 default 0.0) RETURNS geometry - AS 'MODULE_PATHNAME', 'LWGEOM_locate_between_m' + AS 'MODULE_PATHNAME', 'ST_LocateBetween' LANGUAGE 'C' IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION ST_LocateAlong(Geometry geometry, Measure float8, Offsets float8 default 0.0) +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_LocateAlong(Geometry geometry, Measure float8, LeftRightOffset float8 default 0.0) RETURNS geometry AS 'MODULE_PATHNAME', 'ST_LocateAlong' LANGUAGE 'C' IMMUTABLE STRICT; +-- Only accepts LINESTRING as parameters. +-- Availability: 1.4.0 +CREATE OR REPLACE FUNCTION ST_LocateBetweenElevations(Geometry geometry, FromElevation float8, ToElevation float8) + RETURNS geometry + AS 'MODULE_PATHNAME', 'ST_LocateBetweenElevations' + LANGUAGE 'C' IMMUTABLE STRICT; + + --------------------------------------------------------------- -- END -- 2.50.1