]> granicus.if.org Git - postgis/commitdiff
#1137, Add a tolerance distance to ST_RemoveRepeatedPoints
authorPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 12 Jun 2015 18:35:14 +0000 (18:35 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 12 Jun 2015 18:35:14 +0000 (18:35 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13666 b70326c6-7e19-0410-871a-916f4a2858ee

19 files changed:
NEWS
doc/reference_processing.xml
liblwgeom/liblwgeom.h.in
liblwgeom/liblwgeom_internal.h
liblwgeom/lwcollection.c
liblwgeom/lwcompound.c
liblwgeom/lwgeom.c
liblwgeom/lwline.c
liblwgeom/lwlinearreferencing.c
liblwgeom/lwmpoint.c
liblwgeom/lwpoly.c
liblwgeom/lwsegmentize.c
liblwgeom/lwtriangle.c
liblwgeom/ptarray.c
postgis/lwgeom_functions_basic.c
postgis/postgis.sql.in
postgis/postgis_drop_after.sql
regress/remove_repeated_points.sql
regress/remove_repeated_points_expected

diff --git a/NEWS b/NEWS
index c55dff09e83234c030a12b752c636049253e9234..66c093205294072b79be4e828e91700ae47fa784 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -32,6 +32,9 @@ PostGIS 2.2.0
 
   - Add |=| operator with CPA semantic and KNN support with PgSQL 9.5+
     (Sandro Santilli / Boundless)
+  - #3131, KNN support for the geography type (Paul Ramsey / CartoDB)
+  - #2703, Exact KNN results for all geometry types, aka "KNN re-check" (Paul Ramsey / CartoDB)
+  - #1137, Allow a tolerance value in ST_RemoveRepeatedPoints (Paul Ramsey / CartoDB)
   - #3062, Allow passing M factor to ST_Scale (Sandro Santilli / Boundless)
   - #3139, ST_BoundingDiagonal (Sandro Santilli / Boundless)
   - #3129, ST_IsValidTrajectory (Sandro Santilli / Boundless)
@@ -40,8 +43,8 @@ PostGIS 2.2.0
   - Canonical output for index key types
   - ST_SwapOrdinates (Sandro Santilli / Boundless)
   - #2918, Use GeographicLib functions for geodetics (Mike Toews)
-  - #3074, ST_Subdivide (Paul Ramsey / CartoDB)
-  - #3040, KNN GiST index based centroid (<<->>) and box (<<#>>)
+  - #3074, ST_Subdivide to break up large geometry (Paul Ramsey / CartoDB)
+  - #3040, KNN GiST index based centroid (<<->>)
            n-D distance operators (Sandro Santilli / Boundless)
   - Interruptibility API for liblwgeom (Sandro Santilli / CartoDB)
   - #2939, ST_ClipByBox2D (Sandro Santilli / CartoDB)
@@ -75,7 +78,7 @@ PostGIS 2.2.0
   - #2227, Simplification with Visvalingam-Whyatt algorithm
            ST_SimplifyVW, ST_SetEffectiveArea (Nicklas Avén)
   - Functions to encode and decode TWKB
-           ST_AsTWKB, ST_GeomFromTWKB (Paul Ramsey / Nicklas Avén)
+           ST_AsTWKB, ST_GeomFromTWKB (Paul Ramsey / Nicklas Avén / CartoDB)
 
  * Enhancements *
 
index 8392e854a59065f2b3cf240d8455d17631a0eeee..e1805c28478994cf0dddba1f200baf1d583121e4 100644 (file)
@@ -2438,6 +2438,7 @@ MULTILINESTRING((164 1,11.7867965644036 1,1 11.7867965644036,1 195),
                  <funcprototype>
                        <funcdef>geometry <function>ST_RemoveRepeatedPoints</function></funcdef>
                        <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+                       <paramdef choice="opt"><type>float8</type> <parameter>tolerance</parameter></paramdef>
                  </funcprototype>
                </funcsynopsis>
          </refsynopsisdiv>
@@ -2450,8 +2451,10 @@ MULTILINESTRING((164 1,11.7867965644036 1,1 11.7867965644036,1 195),
                                any kind of geometry. Since simplification occurs on a
                                object-by-object basis you can also feed a GeometryCollection to
                                this function.</para>
+        <para>If the tolerance parameter is provided, vertices within the tolerance 
+        of one another will be considered the "same" for the purposes of removal.</para>
 
-               <para>Availability: 2.0.0</para>
+               <para>Availability: 2.2.0</para>
                <para>&P_support;</para>
                <para>&Z_support;</para>
          </refsection>
index 9bac3af5ebf30cc6ef3ff06311bbf9436fa4f10f..7c7641f6364ed360681dc1ca90b39d0b460b4ed6 100644 (file)
@@ -1545,7 +1545,7 @@ extern int lwgeom_covers_lwgeom_sphere(const LWGEOM *lwgeom1, const LWGEOM *lwge
 /**
 * Remove repeated points!
 */
-extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in);
+extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in, double tolerance);
 
 extern char lwtriangle_is_repeated_points(LWTRIANGLE *triangle);
 
index e2f3def2205bf29e0430a37087855262ef5d48fc..b8ff9807a77cee6f225a0d4c2c03e9d0d868fd2a 100644 (file)
@@ -345,11 +345,11 @@ void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D
 /* 
 * Repeated points
 */
-POINTARRAY *ptarray_remove_repeated_points(POINTARRAY *in);
-LWGEOM* lwmpoint_remove_repeated_points(LWMPOINT *in);
-LWGEOM* lwline_remove_repeated_points(LWLINE *in);
-LWGEOM* lwcollection_remove_repeated_points(LWCOLLECTION *in);
-LWGEOM* lwpoly_remove_repeated_points(LWPOLY *in);
+POINTARRAY *ptarray_remove_repeated_points(POINTARRAY *in, double tolerance);
+LWGEOM* lwmpoint_remove_repeated_points(LWMPOINT *in, double tolerance);
+LWGEOM* lwline_remove_repeated_points(LWLINE *in, double tolerance);
+LWGEOM* lwcollection_remove_repeated_points(LWCOLLECTION *in, double tolerance);
+LWGEOM* lwpoly_remove_repeated_points(LWPOLY *in, double tolerance);
 
 /*
 * Closure test
index 7d44352c9a00d14035f097acc3819d552809f860..be254dc89c601784ccb80237476dacdf9a125410 100644 (file)
@@ -437,7 +437,7 @@ LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type)
 }
 
 LWGEOM*
-lwcollection_remove_repeated_points(LWCOLLECTION *coll)
+lwcollection_remove_repeated_points(LWCOLLECTION *coll, double tolerance)
 {
        uint32_t i;
        LWGEOM **newgeoms;
@@ -445,7 +445,7 @@ lwcollection_remove_repeated_points(LWCOLLECTION *coll)
        newgeoms = lwalloc(sizeof(LWGEOM *)*coll->ngeoms);
        for (i=0; i<coll->ngeoms; i++)
        {
-               newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i]);
+               newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i], tolerance);
        }
 
        return (LWGEOM*)lwcollection_construct(coll->type,
index 8c28400e23ddc1a799247a82e44cef5c5100ef35..b5dd4a927b4a3de5b35d20eddb1a6f437da16271 100644 (file)
@@ -261,4 +261,3 @@ lwcompound_get_endpoint(const LWCOMPOUND *lwcmp)
        return lwline_get_lwpoint(lwline, lwline->points->npoints-1);
 }
 
-       
\ No newline at end of file
index a9bb312d8932ecb8f71335ee81f51fdaec66c806..0823f3d1f4726a732492001f324cfb3ae7397e0e 100644 (file)
@@ -1404,7 +1404,7 @@ extern int lwgeom_dimensionality(LWGEOM *geom)
        return 0;
 }
 
-extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in)
+extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in, double tolerance)
 {
        LWDEBUGF(4, "lwgeom_remove_repeated_points got type %s",
                 lwtype_name(in->type));
@@ -1412,19 +1412,19 @@ extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in)
        switch (in->type)
        {
        case MULTIPOINTTYPE:
-               return lwmpoint_remove_repeated_points((LWMPOINT*)in);
+               return lwmpoint_remove_repeated_points((LWMPOINT*)in, tolerance);
                break;
        case LINETYPE:
-               return lwline_remove_repeated_points((LWLINE*)in);
+               return lwline_remove_repeated_points((LWLINE*)in, tolerance);
 
        case MULTILINETYPE:
        case COLLECTIONTYPE:
        case MULTIPOLYGONTYPE:
        case POLYHEDRALSURFACETYPE:
-               return lwcollection_remove_repeated_points((LWCOLLECTION *)in);
+               return lwcollection_remove_repeated_points((LWCOLLECTION *)in, tolerance);
 
        case POLYGONTYPE:
-               return lwpoly_remove_repeated_points((LWPOLY *)in);
+               return lwpoly_remove_repeated_points((LWPOLY *)in, tolerance);
                break;
 
        case POINTTYPE:
@@ -1442,8 +1442,8 @@ extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in)
                return in;
 
        default:
-               lwnotice("lwgeom_remove_repeated_points: unsupported geometry type: %s",
-                        lwtype_name(in->type));
+               lwnotice("%s: unsupported geometry type: %s",
+                        __func__, lwtype_name(in->type));
                return in;
                break;
        }
index f28a0498663d222bba31f218351249f07d7aff7d..582ac91f683f8b2348a623dc412e43c48463f3b2 100644 (file)
@@ -421,11 +421,11 @@ lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end)
 }
 
 LWGEOM*
-lwline_remove_repeated_points(LWLINE *lwline)
+lwline_remove_repeated_points(LWLINE *lwline, double tolerance)
 {
-       POINTARRAY* npts = ptarray_remove_repeated_points(lwline->points);
+       POINTARRAY* npts = ptarray_remove_repeated_points(lwline->points, tolerance);
 
-       LWDEBUGF(3, "lwline_remove_repeated_points: npts %p", npts);
+       LWDEBUGF(3, "%s: npts %p", __func__, npts);
 
        return (LWGEOM*)lwline_construct(lwline->srid,
                                         lwline->bbox ? gbox_copy(lwline->bbox) : 0,
index d61423339e3b54cdacb49a44834e6872d156001b..27fa2174953df528a572ee290b9f5af068d05f3b 100644 (file)
@@ -1101,7 +1101,7 @@ lwgeom_tcpa(const LWGEOM *g1, const LWGEOM *g2, double *mindist)
   tmax = FP_MIN(gbox1->mmax, gbox2->mmax);
 
   if ( tmax < tmin ) {
-               LWDEBUGF(1, "Inputs never exist at the same time");
+         LWDEBUG(1, "Inputs never exist at the same time");
     return -2;
   }
 
index 2169560b9ae4db74de4b49df3b8eaf8248ec6e48..17b5bac535068982de811e110edeee999b304fb9 100644 (file)
@@ -76,7 +76,7 @@ void lwmpoint_free(LWMPOINT *mpt)
 }
 
 LWGEOM*
-lwmpoint_remove_repeated_points(LWMPOINT *mpoint)
+lwmpoint_remove_repeated_points(LWMPOINT *mpoint, double tolerance)
 {
        uint32_t nnewgeoms;
        uint32_t i, j;
index 03ba68dc22f4ced5e170e55b38789f65e4523e5e..2c21e378368451133ac1265760e74191e7687fa3 100644 (file)
@@ -286,7 +286,7 @@ lwpoly_from_lwlines(const LWLINE *shell,
 }
 
 LWGEOM*
-lwpoly_remove_repeated_points(LWPOLY *poly)
+lwpoly_remove_repeated_points(LWPOLY *poly, double tolerance)
 {
        uint32_t i;
        POINTARRAY **newrings;
@@ -294,7 +294,7 @@ lwpoly_remove_repeated_points(LWPOLY *poly)
        newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
        for (i=0; i<poly->nrings; i++)
        {
-               newrings[i] = ptarray_remove_repeated_points(poly->rings[i]);
+               newrings[i] = ptarray_remove_repeated_points(poly->rings[i], tolerance);
        }
 
        return (LWGEOM*)lwpoly_construct(poly->srid,
index d67c9ba12c6f8429618c35d50e502fd18415f90b..12b5668adee6f32d8133209e95c737de46ec7f62 100644 (file)
@@ -280,7 +280,7 @@ lwcompound_segmentize(const LWCOMPOUND *icompound, uint32_t perQuad)
                        return NULL;
                }
        }
-       ptarray_out = ptarray_remove_repeated_points(ptarray);
+       ptarray_out = ptarray_remove_repeated_points(ptarray, 0.0);
        ptarray_free(ptarray);
        return lwline_construct(icompound->srid, NULL, ptarray_out);
 }
index ce106cd3496fcab0c37dda4fe9561cd24032aaee..905d088faf65dda42ac43d49781de29c767f77ee 100644 (file)
@@ -152,7 +152,7 @@ lwtriangle_is_repeated_points(LWTRIANGLE *triangle)
        char ret;
        POINTARRAY *pa;
 
-       pa = ptarray_remove_repeated_points(triangle->points);
+       pa = ptarray_remove_repeated_points(triangle->points, 0.0);
        ret = ptarray_same(pa, triangle->points);
        ptarray_free(pa);
 
index 3a21ac44203cef9c14f33fba6a1cd529aa8b1964..1058d4acf6cfd70abe1c3adbd91fd82dbdc7bd4b 100644 (file)
@@ -1423,20 +1423,21 @@ ptarray_longitude_shift(POINTARRAY *pa)
  *
  */
 POINTARRAY *
-ptarray_remove_repeated_points(POINTARRAY *in)
+ptarray_remove_repeated_points(POINTARRAY *in, double tolerance)
 {
        POINTARRAY* out;
        size_t ptsize;
        size_t ipn, opn;
+       const POINT2D *last_point, *this_point;
 
-       LWDEBUG(3, "ptarray_remove_repeated_points called.");
+       LWDEBUGF(3, "%s called", __func__);
 
        /* Single or zero point arrays can't have duplicates */
        if ( in->npoints < 3 ) return ptarray_clone_deep(in);
 
        ptsize = ptarray_point_size(in);
 
-       LWDEBUGF(3, "ptsize: %d", ptsize);
+       LWDEBUGF(3, " ptsize: %d", ptsize);
 
        /* Allocate enough space for all points */
        out = ptarray_construct(FLAGS_GET_Z(in->flags),
@@ -1446,18 +1447,20 @@ ptarray_remove_repeated_points(POINTARRAY *in)
 
        opn=1;
        memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize);
+       last_point = getPoint2d_cp(in, 0);
        LWDEBUGF(3, " first point copied, out points: %d", opn);
-       for (ipn=1; ipn<in->npoints; ++ipn)
+       for ( ipn = 1; ipn < in->npoints; ++ipn)
        {
-               if ( (ipn==in->npoints-1 && opn==1) || memcmp(getPoint_internal(in, ipn-1),
-                       getPoint_internal(in, ipn), ptsize) )
+               this_point = getPoint2d_cp(in, ipn);
+               if ( (ipn == in->npoints-1 && opn==1) || 
+                    (tolerance == 0 && memcmp(getPoint_internal(in, ipn-1), getPoint_internal(in, ipn), ptsize) != 0) ||
+                    (tolerance > 0.0 && distance2d_pt_pt(last_point, this_point) > tolerance) )
                {
                        /* The point is different from the previous,
                         * we add it to output */
-                       memcpy(getPoint_internal(out, opn++),
-                              getPoint_internal(in, ipn), ptsize);
-                       LWDEBUGF(3, " Point %d differs from point %d. Out points: %d",
-                                ipn, ipn-1, opn);
+                       memcpy(getPoint_internal(out, opn++), getPoint_internal(in, ipn), ptsize);
+                       last_point = this_point;
+                       LWDEBUGF(3, " Point %d differs from point %d. Out points: %d", ipn, ipn-1, opn);
                }
        }
 
index 45884790c9e43fe4d0d54ddda4ebcef9d595adca..4c2e585e08d17a787ef976b4426a40f13c392565 100644 (file)
@@ -2659,20 +2659,24 @@ Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(ST_RemoveRepeatedPoints);
 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
 {
-       GSERIALIZED *input = PG_GETARG_GSERIALIZED_P_COPY(0);
-       GSERIALIZED *output;
-       LWGEOM *lwgeom_in = lwgeom_from_gserialized(input);
-       LWGEOM *lwgeom_out;
+       GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P_COPY(0);
+       GSERIALIZED *g_out;
+       LWGEOM *lwgeom_in = lwgeom_from_gserialized(g_in);
+       LWGEOM *lwgeom_out = NULL;
+       double tolerance = 0.0;
 
-       /* lwpgnotice("ST_RemoveRepeatedPoints got %p", lwgeom_in); */
+       if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
+               tolerance = PG_GETARG_FLOAT8(1);
 
-       lwgeom_out = lwgeom_remove_repeated_points(lwgeom_in);
-       output = geometry_serialize(lwgeom_out);
+       lwgeom_out = lwgeom_remove_repeated_points(lwgeom_in, tolerance);
+       g_out = geometry_serialize(lwgeom_out);
 
+       if ( lwgeom_out != lwgeom_in )
+               lwgeom_free(lwgeom_out);
        lwgeom_free(lwgeom_in);
-       PG_FREE_IF_COPY(input, 0);
 
-       PG_RETURN_POINTER(output);
+       PG_FREE_IF_COPY(g_in, 0);
+       PG_RETURN_POINTER(g_out);
 }
 
 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
index ae133f75e8095257e507623af2a30e6a27414139..6127f0b61ae3128666471d2c723e926240f6c4f0 100644 (file)
@@ -3286,8 +3286,8 @@ CREATE OR REPLACE FUNCTION ST_UnaryUnion(geometry)
 -- Only checks consecutive points for lineal and polygonal geoms.
 -- Checks all points for multipoint geoms.
 --
--- Availability: 2.0.0
-CREATE OR REPLACE FUNCTION ST_RemoveRepeatedPoints(geometry)
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_RemoveRepeatedPoints(geom geometry, tolerance float8 default 0.0)
        RETURNS geometry
        AS 'MODULE_PATHNAME', 'ST_RemoveRepeatedPoints'
        LANGUAGE 'c' IMMUTABLE STRICT
index 185cfca7cfd1388118ef8984be12d1de005d6c6b..ab9c8eda1fe0ca7fab982c44586fcb9c8a404a49 100644 (file)
@@ -137,6 +137,7 @@ DROP FUNCTION IF EXISTS st_geometry_ge(geometry, geometry);
 DROP FUNCTION IF EXISTS st_geometry_eq(geometry, geometry);
 DROP FUNCTION IF EXISTS st_geometry_cmp(geometry, geometry);
 DROP FUNCTION IF EXISTS SnapToGrid(geometry, float8, float8);
+DROP FUNCTION IF EXISTS st_removerepeatedpoints(geometry);
 
 DROP FUNCTION IF EXISTS geometry_gist_sel_2d (internal, oid, internal, int4);
 DROP FUNCTION IF EXISTS geometry_gist_joinsel_2d(internal, oid, internal, smallint);
index e3060b5b5a0d50b46122f9fc4de2c4b5d0b53366..96021364fd293eb88f20916f44abec65af09140a 100644 (file)
@@ -20,3 +20,5 @@ SELECT 9, ST_AsText(ST_RemoveRepeatedPoints('CURVEPOLYGON(CIRCULARSTRING(
 SELECT 10, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 0 0)'));
 SELECT 11, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 0 0, 0 0, 0 0, 0 0)'));
 SELECT 12, ST_SRID(ST_RemoveRepeatedPoints('SRID=3;LINESTRING(0 0, 0 0, 0 0, 0 0, 0 0)'));
+SELECT 13, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 1 0, 2 0, 3 0, 4 0)',1.5));
+
index 410a73b6ed6e8770c67addd9f4431423d1b9b3bf..753cc521200e94a118c1c09cd81ce8f63fd8bf55 100644 (file)
@@ -11,3 +11,4 @@
 10|LINESTRING(0 0,0 0)
 11|LINESTRING(0 0,0 0)
 12|3
+13|LINESTRING(0 0,2 0,4 0)