From: Darafei Praliaskouski Date: Fri, 5 Jan 2018 13:16:12 +0000 (+0000) Subject: Fix ST_RemoveRepeatedPoints dropping one extra point in certain ptarrays X-Git-Tag: 2.5.0alpha~228 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b3deaf9eebe9314c074e0e54cef758f0fd13bcc0;p=postgis Fix ST_RemoveRepeatedPoints dropping one extra point in certain ptarrays Patch by Raúl Marín Rodríguez. Closes #3969 Closes https://github.com/postgis/postgis/pull/182 git-svn-id: http://svn.osgeo.org/postgis/trunk@16221 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/cunit/cu_algorithm.c b/liblwgeom/cunit/cu_algorithm.c index 27f121c03..76fdcd7ba 100644 --- a/liblwgeom/cunit/cu_algorithm.c +++ b/liblwgeom/cunit/cu_algorithm.c @@ -1012,7 +1012,6 @@ static void test_lwgeom_remove_repeated_points(void) 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)"); - // printf("%s\n", ewkt); lwgeom_free(g); lwfree(ewkt); @@ -1020,20 +1019,22 @@ static void test_lwgeom_remove_repeated_points(void) 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)"); - // printf("%s\n", ewkt); 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)"); - // printf("%s\n", ewkt); 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))"); + lwgeom_free(g); + lwfree(ewkt); } static void test_lwgeom_simplify(void) diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 639e7b5a3..b1857dabb 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -1452,52 +1452,48 @@ ptarray_remove_repeated_points_in_place(POINTARRAY *pa, double tolerance, int mi const POINT2D *last = NULL; const POINT2D *pt; int n_points = pa->npoints; - int n_points_out = 0; - int pt_size = ptarray_point_size(pa); + int n_points_out = 1; double dsq = FLT_MAX; /* No-op on short inputs */ - if ( n_points <= 2 ) return; + if ( n_points <= min_points ) return; - for (i = 0; i < n_points; i++) + last = getPoint2d_cp(pa, 0); + for (i = 1; i < n_points; i++) { int last_point = (i == n_points-1); /* Look straight into the abyss */ pt = getPoint2d_cp(pa, i); - /* Preserve first point always */ - if (last) + /* Don't drop points if we are running short of points */ + if (n_points - i > min_points - n_points_out) { - /* Don't drop points if we are running short of points */ - if (n_points - i > min_points - n_points_out) + if (tolerance > 0.0) { - if (tolerance > 0.0) + /* Only drop points that are within our tolerance */ + dsq = distance2d_sqr_pt_pt(last, pt); + /* Allow any point but the last one to be dropped */ + if (!last_point && dsq <= tolsq) { - /* Only drop points that are within our tolerance */ - dsq = distance2d_sqr_pt_pt(last, pt); - /* Allow any point but the last one to be dropped */ - if (!last_point && dsq <= tolsq) - { - continue; - } - } - else - { - /* At tolerance zero, only skip exact dupes */ - if (memcmp((char*)pt, (char*)last, pt_size) == 0) - continue; + continue; } } - } + else + { + /* At tolerance zero, only skip exact dupes */ + if (memcmp((char*)pt, (char*)last, ptarray_point_size(pa)) == 0) + continue; + } - /* Got to last point, and it's not very different from */ - /* the point that preceded it. We want to keep the last */ - /* point, not the second-to-last one, so we pull our write */ - /* index back one value */ - if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq) - { - n_points_out--; + /* Got to last point, and it's not very different from */ + /* the point that preceded it. We want to keep the last */ + /* point, not the second-to-last one, so we pull our write */ + /* index back one value */ + if (last_point && n_points_out > 1 && tolerance > 0.0 && dsq <= tolsq) + { + n_points_out--; + } } /* Compact all remaining values to front of array */ diff --git a/regress/remove_repeated_points.sql b/regress/remove_repeated_points.sql index e8bf3ba8b..4b6b4a04a 100644 --- a/regress/remove_repeated_points.sql +++ b/regress/remove_repeated_points.sql @@ -27,5 +27,6 @@ SELECT 14, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(10 0,10 9,10 10)', 2)); SELECT 15, ST_AsText(ST_RemoveRepeatedPoints('MULTIPOINT(0 0, 0 0, 1 1, 2 2)'::geometry)); SELECT 16, ST_AsText(ST_RemoveRepeatedPoints('MULTIPOINT(0 0, 0 0, 1 1, 2 2)'::geometry,0.1)); SELECT 17, ST_AsText(ST_RemoveRepeatedPoints('MULTIPOINT(0 0, 0 0, 1 1, 4 4)'::geometry,2)); +SELECT 18, ST_AsText(ST_RemoveRepeatedPoints('POLYGON((-215922 5325694,-218080 5321866,-218693 5322119,-216112 5325812,-215922 5325694))'::geometry, 10000)); diff --git a/regress/remove_repeated_points_expected b/regress/remove_repeated_points_expected index e15d235b5..13e07ff42 100644 --- a/regress/remove_repeated_points_expected +++ b/regress/remove_repeated_points_expected @@ -16,3 +16,4 @@ 15|MULTIPOINT(0 0,1 1,2 2) 16|MULTIPOINT(0 0,1 1,2 2) 17|MULTIPOINT(0 0,4 4) +18|POLYGON((-215922 5325694,-218693 5322119,-216112 5325812,-215922 5325694))