From 7915c4cb3337a50516f8ce1a3514b1fb86d28340 Mon Sep 17 00:00:00 2001 From: Darafei Praliaskouski Date: Sat, 27 Oct 2018 10:23:03 +0000 Subject: [PATCH] ST_LocateBetween[Elevations]: support TIN and TRIANGLE clipping. Triangle is converted into a TIN that has several triangles with same orientation. Committed in Paris Airport. Closes #4155 git-svn-id: http://svn.osgeo.org/postgis/trunk@16954 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 4 +- doc/reference_lrs.xml | 66 ++++++++++-------- liblwgeom/cunit/cu_algorithm.c | 117 ++++++++++++++++++++++---------- liblwgeom/lwlinearreferencing.c | 47 +++++++++++-- 4 files changed, 160 insertions(+), 74 deletions(-) diff --git a/NEWS b/NEWS index 2f4fd3232..28820cb61 100644 --- a/NEWS +++ b/NEWS @@ -27,8 +27,8 @@ PostGIS 3.0.0 Praliaskouski) - #3457, Fix raster envelope shortcut in ST_Clip (Sai-bot) - #4215, Use floating point compare in ST_DumpAsPolygons (Darafei Praliaskouski) - - #4155, Support for GEOMETRYCOLLECTION and POLYGON in ST_LocateBetween (Darafei - Praliaskouski) + - #4155, Support for GEOMETRYCOLLECTION, POLYGON, TIN, TRIANGLE in + ST_LocateBetween and ST_LocateBetweenElevations (Darafei Praliaskouski) PostGIS 2.5.0 2018/09/23 diff --git a/doc/reference_lrs.xml b/doc/reference_lrs.xml index 5f0fa303f..144b7bd9a 100644 --- a/doc/reference_lrs.xml +++ b/doc/reference_lrs.xml @@ -426,15 +426,14 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) ST_LocateBetween Return a derived geometry collection value with elements - that match the specified range of measures inclusively. Polygonal - elements are not supported. + that match the specified range of measures inclusively. geometry ST_LocateBetween - geometry geomA + geometry geom float8 measure_start float8 measure_end float8 offset @@ -447,7 +446,9 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) Description Return a derived geometry collection with elements that match the specified range of - measures inclusively. Polygonal elements are not supported. + measures inclusively. + + Clipping a non-convex POLYGON may produce invalid geometry. 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 @@ -458,6 +459,7 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) Availability: 1.1.0 by old name ST_Locate_Between_Measures. Changed: 2.0.0 - in prior versions this used to be called ST_Locate_Between_Measures. The old name has been deprecated and will be removed in the future but is still available for backward compatibility. + Enhanced: 3.0.0 - added support for POLYGON, TIN, TRIANGLE. &M_support; @@ -465,11 +467,15 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) Examples - SELECT ST_AsText(the_geom) - FROM - (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; + +SELECT ST_AsText(the_geom) +FROM ( + SELECT ST_LocateBetween( + '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 ------------------------------------------------------------------------ @@ -478,10 +484,13 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) --Geometry collections are difficult animals so dump them --to make them more digestable SELECT ST_AsText((ST_Dump(the_geom)).geom) - FROM - (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; +FROM ( + SELECT ST_LocateBetween( + '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 -------------------------------- @@ -502,15 +511,14 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) ST_LocateBetweenElevations Return a derived geometry (collection) value with elements - that intersect the specified range of elevations inclusively. Only 3D, 4D LINESTRINGS and MULTILINESTRINGS - are supported. + that intersect the specified range of elevations inclusively. geometry ST_LocateBetweenElevations - geometry geom_mline + geometry geom float8 elevation_start float8 elevation_end @@ -521,11 +529,13 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) Description - Return a derived geometry (collection) value with elements - that intersect the specified range of elevations inclusively. Only 3D, 3DM LINESTRINGS and MULTILINESTRINGS - are supported. + Return a derived geometry (collection) value with elements + that intersect the specified range of elevations inclusively. - Availability: 1.4.0 + Clipping a non-convex POLYGON may produce invalid geometry. + + Availability: 1.4.0 + Enhanced: 3.0.0 - added support for POLYGON, TIN, TRIANGLE. &Z_support; @@ -534,24 +544,22 @@ SELECT ST_AsText((ST_Dump(the_geom)).geom) Examples SELECT ST_AsEWKT(ST_LocateBetweenElevations( - ST_GeomFromEWKT('LINESTRING(1 2 3, 4 5 6)'),2,4)) As ewelev; + ST_GeomFromEWKT('LINESTRING(1 2 3, 4 5 6)'), 2, 4)) As ewelev; ewelev ---------------------------------------------------------------- MULTILINESTRING((1 2 3,2 3 4)) -SELECT ST_AsEWKT(ST_LocateBetweenElevations( - ST_GeomFromEWKT('LINESTRING(1 2 6, 4 5 -1, 7 8 9)'),6,9)) As ewelev; +SELECT ST_AsEWKT(ST_LocateBetweenElevations('LINESTRING(1 2 6, 4 5 -1, 7 8 9)', 6, 9)) As ewelev; ewelev ---------------------------------------------------------------- GEOMETRYCOLLECTION(POINT(1 2 6),LINESTRING(6.1 7.1 6,7 8 9)) ---Geometry collections are difficult animals so dump them ---to make them more digestable +-- Geometry collections are difficult animals so dump them +-- to make them more digestable SELECT ST_AsEWKT((ST_Dump(the_geom)).geom) - FROM - (SELECT ST_LocateBetweenElevations( - ST_GeomFromEWKT('LINESTRING(1 2 6, 4 5 -1, 7 8 9)'),6,9) As the_geom) As foo; + FROM + (SELECT ST_LocateBetweenElevations('LINESTRING(1 2 6, 4 5 -1, 7 8 9)', 6, 9) as the_geom) As foo; st_asewkt -------------------------------- @@ -564,7 +572,7 @@ LINESTRING(6.1 7.1 6,7 8 9) See Also - + , diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 9e4ee6329..2e3a145af 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -557,7 +557,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', 1.5, 2.5, 0); 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))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1.5,0 2,0 2.5))"); lwfree(ewkt); lwcollection_free(c); @@ -565,7 +565,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', 3.5, 5.5, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 3.5,0 4))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 3.5,0 4))"); lwfree(ewkt); lwcollection_free(c); @@ -573,7 +573,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', -1.5, 2.5, 0); 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))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2,0 2.5))"); lwfree(ewkt); lwcollection_free(c); @@ -581,7 +581,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', -1.5, 5.5, 0); 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))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2,0 3,0 4))"); lwfree(ewkt); lwcollection_free(c); @@ -589,7 +589,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', 1.0, 2.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1,0 2))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1,0 2))"); lwfree(ewkt); lwcollection_free(c); @@ -597,7 +597,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', -1.0, 2.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 0,0 1,0 2))"); lwfree(ewkt); lwcollection_free(c); @@ -605,7 +605,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(l51, 'Y', -1.0, 0.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(0 0))" ); + ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(0 0))"); lwfree(ewkt); lwcollection_free(c); @@ -613,7 +613,7 @@ static void test_lwline_clip(void) line = lwgeom_from_wkt("LINESTRING(1 2 3, 4 5 6, 6 6 6, 1 1 1)", LW_PARSER_CHECK_NONE); c = lwgeom_clip_to_ordinate_range(line, 'Z', 1.0, 2.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(line); @@ -623,7 +623,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 1.0, 2.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("a = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2,1 1 1))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(line); @@ -633,7 +633,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 1.0, 1.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("b = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))" ); + ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(line); @@ -643,7 +643,7 @@ static void test_lwline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 1.0, 1.0, 0); ewkt = lwgeom_to_ewkt((LWGEOM*)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))" ); + ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 1 1))"); lwfree(ewkt); lwcollection_free(c); lwgeom_free(line); @@ -665,7 +665,7 @@ test_lwpoly_clip(void) ewkt = lwgeom_to_ewkt((LWGEOM *)c); // printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL( + ASSERT_STRING_EQUAL( ewkt, "MULTIPOLYGON(((0.51 -0.25,1 -0.179078947368,1 0.270149253731,0.6 0.3,0.7 0.7,1 0.7,1 0.6,0.8 0.5,1 0.46,1 1.2,0.5 1.2,0.5 -0.1,0.3 -0.1,0.3 1.3,0 1.26875,0 -0.25,0.51 -0.25)))"); lwfree(ewkt); @@ -679,7 +679,7 @@ test_lwpoly_clip(void) ewkt = lwgeom_to_ewkt((LWGEOM *)c); //printf("c = %s\n", ewkt); - CU_ASSERT_STRING_EQUAL( + ASSERT_STRING_EQUAL( ewkt, "MULTIPOLYGON(((1 0,1 0.270149253731,0.6 0.3,0.7 0.7,1 0.7,1 0.6,0.8 0.5,1 0.46,1 1,0.5 1,0.5 0,0.3 0,0.3 1,0 1,0 0,1 0)))"); lwfree(ewkt); @@ -687,6 +687,46 @@ test_lwpoly_clip(void) lwgeom_free(g); } +static void +test_lwtriangle_clip(void) +{ + LWCOLLECTION *c; + LWGEOM *g = NULL; + char *ewkt; + + g = lwgeom_from_wkt("TRIANGLE((0 0 0, 1 1 1, 3 2 2, 0 0 0))", LW_PARSER_CHECK_NONE); + c = lwgeom_clip_to_ordinate_range(g, 'Z', -10.0, 4.0, 0); + + ewkt = lwgeom_to_ewkt((LWGEOM *)c); + // printf("c = %s\n", ewkt); + ASSERT_STRING_EQUAL(ewkt, "TIN(((0 0 0,1 1 1,3 2 2,0 0 0)))"); + lwfree(ewkt); + lwcollection_free(c); + lwgeom_free(g); + + g = lwgeom_from_wkt("TRIANGLE((0 0 0, 1 1 1, 3 2 2, 0 0 0))", LW_PARSER_CHECK_NONE); + c = lwgeom_clip_to_ordinate_range(g, 'Z', 0.0, 1.0, 0); + + ewkt = lwgeom_to_ewkt((LWGEOM *)c); + // printf("c = %s\n", ewkt); + ASSERT_STRING_EQUAL(ewkt, "TIN(((0 0 0,1 1 1,1.5 1 1,0 0 0)))"); + lwfree(ewkt); + lwcollection_free(c); + lwgeom_free(g); + + g = lwgeom_from_wkt("TRIANGLE((0 0 0, 1 1 1, 3 2 3, 0 0 0))", LW_PARSER_CHECK_NONE); + c = lwgeom_clip_to_ordinate_range(g, 'Z', 1.0, 2.0, 0); + + ewkt = lwgeom_to_ewkt((LWGEOM *)c); + // printf("c = %s\n", ewkt); + ASSERT_STRING_EQUAL( + ewkt, + "TIN(((1 1 1,2 1.5 2,2 1.333333333333 2,1 1 1)),((1 1 1,2 1.333333333333 2,1 0.666666666667 1,1 1 1)))"); + lwfree(ewkt); + lwcollection_free(c); + lwgeom_free(g); +} + static void test_lwmline_clip(void) { LWCOLLECTION *c; @@ -703,7 +743,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(mline, 'Y', 1.5, 2.5, 0); 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))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0 1.5,0 2,0 2.5))"); lwfree(ewkt); lwcollection_free(c); @@ -718,7 +758,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(mline, 'Y', 3.5, 5.5, 0); 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))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((1 3.5,1 4),(0 3.5,0 4))"); lwfree(ewkt); lwcollection_free(c); @@ -734,7 +774,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(mline, 'Y', 0.0, 2.5, 0); 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))"); + ASSERT_STRING_EQUAL(ewkt, "GEOMETRYCOLLECTION(POINT(1 0),LINESTRING(0 0,0 1,0 2,0 2.5))"); lwfree(ewkt); lwcollection_free(c); @@ -750,7 +790,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 3.0, 3.5, 0); 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))"); + 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))"); lwfree(ewkt); lwcollection_free(c); @@ -758,7 +798,8 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 2.0, 3.5, 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.5 3.5 3.5 3.5),(3.5 3.5 3.5 4.5,3 3 3 5,2 2 2 6))"); + 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))"); lwfree(ewkt); lwcollection_free(c); @@ -766,7 +807,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 3.0, 4.0, 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))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((3 3 3 3,4 4 4 4,3 3 3 5))"); lwfree(ewkt); lwcollection_free(c); @@ -774,7 +815,7 @@ static void test_lwmline_clip(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 2.0, 3.0, 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))"); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((2 2 2 2,3 3 3 3),(3 3 3 5,2 2 2 6))"); lwfree(ewkt); lwcollection_free(c); @@ -807,7 +848,7 @@ static void test_lwline_clip_big(void) c = lwgeom_clip_to_ordinate_range(line, 'Z', 0.5, 1.5, 0); 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))" ); + ASSERT_STRING_EQUAL(ewkt, "MULTILINESTRING((0.5 0.5 0.5,1 1 1,1.5 1.5 1.5))"); lwfree(ewkt); lwcollection_free(c); @@ -854,17 +895,17 @@ static void test_geohash_point(void) geohash = geohash_point(0, 0, 16); //printf("\ngeohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "s000000000000000"); + ASSERT_STRING_EQUAL(geohash, "s000000000000000"); lwfree(geohash); geohash = geohash_point(90, 0, 16); //printf("\ngeohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "w000000000000000"); + ASSERT_STRING_EQUAL(geohash, "w000000000000000"); lwfree(geohash); geohash = geohash_point(20.012345, -20.012345, 15); //printf("\ngeohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "kkqnpkue9ktbpe5"); + ASSERT_STRING_EQUAL(geohash, "kkqnpkue9ktbpe5"); lwfree(geohash); } @@ -879,35 +920,35 @@ static void test_geohash(void) lwpoint = (LWPOINT*)lwgeom_from_wkt("POINT(23.0 25.2)", LW_PARSER_CHECK_NONE); geohash = lwgeom_geohash((LWGEOM*)lwpoint,0); //printf("\ngeohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "ss2r77s0du7p2ewb8hmx"); + ASSERT_STRING_EQUAL(geohash, "ss2r77s0du7p2ewb8hmx"); lwpoint_free(lwpoint); lwfree(geohash); lwpoint = (LWPOINT*)lwgeom_from_wkt("POINT(23.0 25.2 2.0)", LW_PARSER_CHECK_NONE); geohash = lwgeom_geohash((LWGEOM*)lwpoint,0); //printf("geohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "ss2r77s0du7p2ewb8hmx"); + ASSERT_STRING_EQUAL(geohash, "ss2r77s0du7p2ewb8hmx"); lwpoint_free(lwpoint); lwfree(geohash); lwline = (LWLINE*)lwgeom_from_wkt("LINESTRING(23.0 23.0,23.1 23.1)", LW_PARSER_CHECK_NONE); geohash = lwgeom_geohash((LWGEOM*)lwline,0); //printf("geohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "ss0"); + ASSERT_STRING_EQUAL(geohash, "ss0"); lwline_free(lwline); lwfree(geohash); lwline = (LWLINE*)lwgeom_from_wkt("LINESTRING(23.0 23.0,23.001 23.001)", LW_PARSER_CHECK_NONE); geohash = lwgeom_geohash((LWGEOM*)lwline,0); //printf("geohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "ss06g7h"); + ASSERT_STRING_EQUAL(geohash, "ss06g7h"); lwline_free(lwline); lwfree(geohash); lwmline = (LWMLINE*)lwgeom_from_wkt("MULTILINESTRING((23.0 23.0,23.1 23.1),(23.0 23.0,23.1 23.1))", LW_PARSER_CHECK_NONE); geohash = lwgeom_geohash((LWGEOM*)lwmline,0); //printf("geohash %s\n",geohash); - CU_ASSERT_STRING_EQUAL(geohash, "ss0"); + ASSERT_STRING_EQUAL(geohash, "ss0"); lwmline_free(lwmline); lwfree(geohash); } @@ -1045,28 +1086,29 @@ static void test_lwgeom_remove_repeated_points(void) g = lwgeom_from_wkt("MULTIPOINT(0 0, 10 0, 10 10, 10 10, 0 10, 0 10, 0 10, 0 0, 0 0, 0 0, 5 5, 0 0, 5 5)", LW_PARSER_CHECK_NONE); lwgeom_remove_repeated_points_in_place(g, 1); ewkt = lwgeom_to_ewkt(g); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTIPOINT(0 0,10 0,10 10,0 10,5 5)"); + ASSERT_STRING_EQUAL(ewkt, "MULTIPOINT(0 0,10 0,10 10,0 10,5 5)"); lwgeom_free(g); lwfree(ewkt); g = lwgeom_from_wkt("LINESTRING(1612830.15445 4841287.12672,1612830.15824 4841287.12674,1612829.98813 4841274.56198)", LW_PARSER_CHECK_NONE); lwgeom_remove_repeated_points_in_place(g, 0.01); ewkt = lwgeom_to_ewkt(g); - CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(1612830.15445 4841287.12672,1612829.98813 4841274.56198)"); + ASSERT_STRING_EQUAL(ewkt, "LINESTRING(1612830.15445 4841287.12672,1612829.98813 4841274.56198)"); lwgeom_free(g); lwfree(ewkt); g = lwgeom_from_wkt("MULTIPOINT(0 0,10 0,10 10,10 10,0 10,0 10,0 10,0 0,0 0,0 0,5 5,5 5,5 8,8 8,8 8,8 8,8 5,8 5,5 5,5 5,5 5,5 5,5 5,50 50,50 50,50 50,50 60,50 60,50 60,60 60,60 50,60 50,50 50,55 55,55 58,58 58,58 55,58 55,55 55)", LW_PARSER_CHECK_NONE); lwgeom_remove_repeated_points_in_place(g, 1); ewkt = lwgeom_to_ewkt(g); - CU_ASSERT_STRING_EQUAL(ewkt, "MULTIPOINT(0 0,10 0,10 10,0 10,5 5,5 8,8 8,8 5,50 50,50 60,60 60,60 50,55 55,55 58,58 58,58 55)"); + ASSERT_STRING_EQUAL( + ewkt, "MULTIPOINT(0 0,10 0,10 10,0 10,5 5,5 8,8 8,8 5,50 50,50 60,60 60,60 50,55 55,55 58,58 58,58 55)"); lwgeom_free(g); lwfree(ewkt); g = lwgeom_from_wkt("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))", LW_PARSER_CHECK_NONE); lwgeom_remove_repeated_points_in_place(g, 10000); ewkt = lwgeom_to_ewkt(g); - CU_ASSERT_STRING_EQUAL(ewkt, "POLYGON((0 0,1 1,1 0,0 0))"); + ASSERT_STRING_EQUAL(ewkt, "POLYGON((0 0,1 1,1 0,0 0))"); lwgeom_free(g); lwfree(ewkt); } @@ -1081,7 +1123,7 @@ static void test_lwgeom_simplify(void) g = lwgeom_from_wkt("LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)", LW_PARSER_CHECK_NONE); l = lwgeom_simplify(g, 10, LW_TRUE); ewkt = lwgeom_to_ewkt(l); - CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,0 0)"); + ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,0 0)"); lwgeom_free(g); lwgeom_free(l); lwfree(ewkt); @@ -1090,7 +1132,7 @@ static void test_lwgeom_simplify(void) g = lwgeom_from_wkt("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))", LW_PARSER_CHECK_NONE); l = lwgeom_simplify(g, 10, LW_TRUE); ewkt = lwgeom_to_ewkt(l); - CU_ASSERT_STRING_EQUAL(ewkt, "POLYGON((0 0,1 0,1 1,0 0))"); + ASSERT_STRING_EQUAL(ewkt, "POLYGON((0 0,1 0,1 1,0 0))"); lwgeom_free(g); lwgeom_free(l); lwfree(ewkt); @@ -1113,7 +1155,7 @@ static void test_lwgeom_simplify(void) g = lwgeom_from_wkt("LINESTRING(0 0, 50 1.00001, 100 0)", LW_PARSER_CHECK_NONE); l = lwgeom_simplify(g, 1.0, LW_FALSE); ewkt = lwgeom_to_ewkt(l); - CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,50 1.00001,100 0)"); + ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,50 1.00001,100 0)"); lwgeom_free(g); lwgeom_free(l); lwfree(ewkt); @@ -1122,7 +1164,7 @@ static void test_lwgeom_simplify(void) g = lwgeom_from_wkt("LINESTRING(0 0,50 0.99999,100 0)", LW_PARSER_CHECK_NONE); l = lwgeom_simplify(g, 1.0, LW_FALSE); ewkt = lwgeom_to_ewkt(l); - CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,100 0)"); + ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,100 0)"); lwgeom_free(g); lwgeom_free(l); lwfree(ewkt); @@ -1531,6 +1573,7 @@ void algorithms_suite_setup(void) PG_ADD_TEST(suite,test_lwline_interpolate_points); PG_ADD_TEST(suite,test_lwline_clip); PG_ADD_TEST(suite, test_lwpoly_clip); + PG_ADD_TEST(suite, test_lwtriangle_clip); PG_ADD_TEST(suite,test_lwline_clip_big); PG_ADD_TEST(suite,test_lwmline_clip); PG_ADD_TEST(suite,test_geohash_point); diff --git a/liblwgeom/lwlinearreferencing.c b/liblwgeom/lwlinearreferencing.c index 721686a6a..9cfd63062 100644 --- a/liblwgeom/lwlinearreferencing.c +++ b/liblwgeom/lwlinearreferencing.c @@ -440,7 +440,7 @@ lwmpoint_clip_to_ordinate_range(const LWMPOINT *mpoint, char ordinate, double fr } static inline POINTARRAY * -ptarray_clamp_to_ordinate_range(const POINTARRAY *ipa, char ordinate, double from, double to) +ptarray_clamp_to_ordinate_range(const POINTARRAY *ipa, char ordinate, double from, double to, uint8_t is_closed) { POINT4D p1, p2; POINTARRAY *opa; @@ -524,7 +524,7 @@ ptarray_clamp_to_ordinate_range(const POINTARRAY *ipa, char ordinate, double fro LW_ON_INTERRUPT(ptarray_free(opa); return NULL); } - if (ptarray_is_closed(ipa) && opa->npoints > 0) + if (is_closed && opa->npoints > 2) { getPoint4d_p(opa, 0, &p1); ptarray_append_point(opa, &p1, LW_FALSE); @@ -769,7 +769,7 @@ lwpoly_clip_to_ordinate_range(const LWPOLY *poly, char ordinate, double from, do for (i = 0; i < nrings; i++) { /* Ret number of points */ - POINTARRAY *pa = ptarray_clamp_to_ordinate_range(poly->rings[i], ordinate, from, to); + POINTARRAY *pa = ptarray_clamp_to_ordinate_range(poly->rings[i], ordinate, from, to, LW_TRUE); if (pa->npoints >= 4) lwpoly_add_ring(poly_res, pa); @@ -785,6 +785,41 @@ lwpoly_clip_to_ordinate_range(const LWPOLY *poly, char ordinate, double from, do return lwgeom_out; } +/** + * Clip an input LWTRIANGLE between two values, on any ordinate input. + */ +static inline LWCOLLECTION * +lwtriangle_clip_to_ordinate_range(const LWTRIANGLE *tri, char ordinate, double from, double to) +{ + LWCOLLECTION *lwgeom_out = NULL; + char hasz = FLAGS_GET_Z(tri->flags), hasm = FLAGS_GET_M(tri->flags); + + assert(tri); + lwgeom_out = lwcollection_construct_empty(TINTYPE, tri->srid, hasz, hasm); + + POINTARRAY *pa = ptarray_clamp_to_ordinate_range(tri->points, ordinate, from, to, LW_TRUE); + + if (pa->npoints >= 4) + { + POINT4D first = getPoint4d(pa, 0); + for (uint32_t i = 1; i < pa->npoints - 2; i++) + { + POINT4D p; + POINTARRAY *tpa = ptarray_construct_empty(hasz, hasm, 4); + ptarray_append_point(tpa, &first, LW_TRUE); + getPoint4d_p(pa, i, &p); + ptarray_append_point(tpa, &p, LW_TRUE); + getPoint4d_p(pa, i + 1, &p); + ptarray_append_point(tpa, &p, LW_TRUE); + ptarray_append_point(tpa, &first, LW_TRUE); + LWTRIANGLE *otri = lwtriangle_construct(tri->srid, NULL, tpa); + lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, (LWGEOM *)otri); + } + } + ptarray_free(pa); + return lwgeom_out; +} + /** * Clip an input COLLECTION between two values, on any ordinate input. */ @@ -859,9 +894,9 @@ lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, do case POLYGONTYPE: out_col = lwpoly_clip_to_ordinate_range((LWPOLY *)lwin, ordinate, from, to); break; - // case TRIANGLETYPE: - // out_col = lwtriangle_clip_to_ordinate_range((LWTRIANGLE*)lwin, ordinate, from, to); - // break; + case TRIANGLETYPE: + out_col = lwtriangle_clip_to_ordinate_range((LWTRIANGLE *)lwin, ordinate, from, to); + break; case TINTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: -- 2.40.0