]> granicus.if.org Git - postgis/commitdiff
Add a ptarray_simplify parameter to preserve min vertices (#1698)
authorSandro Santilli <strk@keybit.net>
Thu, 22 Mar 2012 15:07:03 +0000 (15:07 +0000)
committerSandro Santilli <strk@keybit.net>
Thu, 22 Mar 2012 15:07:03 +0000 (15:07 +0000)
A polygon ring collapsed to a segment is still better handled by
mapnik than the same ring collapsed to a single point. This commit
retains at least 3 vertices for polygons.

git-svn-id: http://svn.osgeo.org/postgis/trunk@9528 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/liblwgeom_internal.h
liblwgeom/lwline.c
liblwgeom/lwpoly.c
liblwgeom/ptarray.c
regress/simplify.sql

index a7a5579f3f35a9260233e79d3df8833487f22f5a..37c6e1e620c01e141c669012460bf60d98d541e6 100644 (file)
@@ -3,7 +3,7 @@
  * PostGIS - Spatial Types for PostgreSQL
  * http://postgis.refractions.net
  *
- * Copyright (C) 2011 Sandro Santilli <strk@keybit.net>
+ * Copyright (C) 2011-2012 Sandro Santilli <strk@keybit.net>
  * Copyright (C) 2011 Paul Ramsey <pramsey@cleverelephant.ca>
  * Copyright (C) 2007-2008 Mark Cave-Ayland
  * Copyright (C) 2001-2006 Refractions Research Inc.
@@ -171,7 +171,11 @@ extern int32_t lw_get_int32_t(const uint8_t *loc);
 /*
 * DP simplification
 */
-POINTARRAY* ptarray_simplify(POINTARRAY *inpts, double epsilon);
+
+/**
+ * @param minpts minimun number of points to retain, if possible.
+ */
+POINTARRAY* ptarray_simplify(POINTARRAY *inpts, double epsilon, unsigned int minpts);
 LWLINE* lwline_simplify(const LWLINE *iline, double dist);
 LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist);
 LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist);
index a920f9eab3c79adfea86ee3c9196bf97b9b9cf80..46061f3c7d2f9c6b242cfff47b8028839f9cc662 100644 (file)
@@ -3,6 +3,7 @@
  * PostGIS - Spatial Types for PostgreSQL
  * http://postgis.refractions.net
  *
+ * Copyright (C) 2012 Sandro Santilli <strk@keybit.net>
  * Copyright (C) 2001-2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -479,7 +480,7 @@ LWLINE* lwline_simplify(const LWLINE *iline, double dist)
        if( lwline_is_empty(iline) )
                return lwline_clone(iline);
                
-       oline = lwline_construct(iline->srid, NULL, ptarray_simplify(iline->points, dist));
+       oline = lwline_construct(iline->srid, NULL, ptarray_simplify(iline->points, dist, 2));
        oline->type = iline->type;
        return oline;
 }
index e73b42293495abcc1009ac9da4b49c471e42f687..aad9edb7fe6d597b48e4fd2c03736248fd33f289 100644 (file)
@@ -3,6 +3,7 @@
  * PostGIS - Spatial Types for PostgreSQL
  * http://postgis.refractions.net
  *
+ * Copyright (C) 2012 Sandro Santilli <strk@keybit.net>
  * Copyright (C) 2001-2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
@@ -353,23 +354,14 @@ LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist)
 
        for (i = 0; i < ipoly->nrings; i++)
        {
-               POINTARRAY *opts = ptarray_simplify(ipoly->rings[i], dist);
-
-               /* One point implies an error in the ptarray_simplify */
-               if ( i && ( opts->npoints < 2 ) )
-               {
-                       LWDEBUG(2, "ptarray_simplify returned a <2 pts array");
-                       ptarray_free(opts);
-                       continue;
-               }
+               POINTARRAY *opts = ptarray_simplify(ipoly->rings[i], dist, 3);
 
                /* Less points than are needed to form a closed ring, we can't use this */
-               if ( i && ( opts->npoints < 4 ) )
+               if ( i && opts->npoints < 4 )
                {
-                       LWDEBUGF(3, "ring%d skipped (<4 pts)", i);
+                       LWDEBUGF(3, "ring%d skipped (% pts)", i, opts->npoints);
                        ptarray_free(opts);
-                       if ( i ) continue;
-                       else break;
+                       continue;
                }
 
                LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints);
@@ -377,6 +369,13 @@ LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist)
                /* Add ring to simplified polygon */
                if( lwpoly_add_ring(opoly, opts) == LW_FAILURE )
                        return NULL;
+
+    /* Don't scan holes if shell is collapsed */
+               if (  !i && opts->npoints < 4 )
+               {
+                 LWDEBUG(3, "nothing more to do for collapsed shell");
+                       break;
+               }
        }
 
        LWDEBUGF(3, "simplified polygon with %d rings", ipoly->nrings);
index b623c02e25ddc8a9e33f49d3522ba9053aca0889..08ebd7b0b71a1c3ca98dd8ddd01121ddab419ad9 100644 (file)
@@ -2,7 +2,9 @@
  *
  * PostGIS - Spatial Types for PostgreSQL
  * http://postgis.refractions.net
- * Copyright 2001-2006 Refractions Research Inc.
+ *
+ * Copyright (C) 2012 Sandro Santilli <strk@keybit.net>
+ * Copyright (C) 2001-2006 Refractions Research Inc.
  *
  * This is free software; you can redistribute and/or modify it under
  * the terms of the GNU General Public Licence. See the COPYING file.
@@ -1174,7 +1176,7 @@ ptarray_dp_findsplit(POINTARRAY *pts, int p1, int p2, int *split, double *dist)
 }
 
 POINTARRAY *
-ptarray_simplify(POINTARRAY *inpts, double epsilon)
+ptarray_simplify(POINTARRAY *inpts, double epsilon, unsigned int minpts)
 {
        int *stack;                     /* recursion stack */
        int sp=-1;                      /* recursion stack pointer */
@@ -1189,7 +1191,8 @@ ptarray_simplify(POINTARRAY *inpts, double epsilon)
        p1 = 0;
        stack[++sp] = inpts->npoints-1;
 
-       LWDEBUGF(2, "Input has %d pts and %d dims", inpts->npoints, inpts->flags);
+       LWDEBUGF(2, "Input has %d pts and %d dims", inpts->npoints,
+                                                   FLAGS_NDIMS(inpts->flags));
 
        /* Allocate output POINTARRAY, and add first point. */
        outpts = ptarray_construct_empty(FLAGS_GET_Z(inpts->flags), FLAGS_GET_M(inpts->flags), inpts->npoints);
@@ -1205,8 +1208,9 @@ ptarray_simplify(POINTARRAY *inpts, double epsilon)
 
                LWDEBUGF(3, "Farthest point from P%d-P%d is P%d (dist. %g)", p1, stack[sp], split, dist);
 
-               if (dist > epsilon)
+               if (dist > epsilon || ( outpts->npoints+sp+1 < minpts && dist > 0 ) )
                {
+                       LWDEBUGF(4, "Added P%d to stack (outpts:%d, minpts:%d)", split, sp, minsplits);
                        stack[++sp] = split;
                }
                else
index 907aaec95cc2379a25cea63ede1dc982d0c3201d..3c8c2476cd4c66a9cef05c835f8f5cf50ba9fdc6 100644 (file)
@@ -7,3 +7,5 @@ SELECT '5', ST_astext(ST_Simplify('MULTIPOINT(0 0 3 2, 0 10 6 1, 0 51 1 6, 50 20
 SELECT '6', ST_astext(ST_Simplify('MULTILINESTRING((0 0 3 2, 0 10 6 1, 0 51 1 6, 50 20 6 7, 30 20 9 9, 7 32 10 5), (0 0 4 3, 1 1 2 3, 20 20 5 30))', 20));
 SELECT '7', ST_astext(ST_Simplify('POLYGON((0 0 3 2, 0 10 6 1, 0 51 1 6, 50 20 6 7, 30 20 9 9, 7 32 10 5, 0 0 3 2), (1 1 4 3, 1 3 2 3, 18 18 5 30, 1 1 4 3))', 20));
 SELECT '8', ST_astext(ST_Simplify('POLYGON((0 0 3 2, 0 10 6 1, 0 51 1 6, 50 20 6 7, 30 20 9 9, 7 32 10 5, 0 0 3 2), (1 1 4 3, 1 3 2 3, 18 18 5 30, 1 1 4 3))', 1));
+
+SELECT '9', ST_astext(ST_Simplify('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', 20));