* New Features *
- ST_isValidDetail (Sandro Santilli - work done for Regione Toscana-SIGTA)
+ - ST_RemoveRepeatedPoints (Sandro Santilli for RT-SIGTA)
PostGIS 1.5.0
2010/02/04
</refsection>
</refentry>
+ <refentry id="ST_RemoveRepeatedPoints">
+ <refnamediv>
+ <refname>ST_RemoveRepeatedPoints</refname>
+ <refpurpose>Returns a version of the given geometry with
+ duplicated points removed.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_RemoveRepeatedPoints</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+ <para>Returns a version of the given geometry with
+ duplicated points emoved. Will actually do something only with
+ (multi)lines, (multi)polygons and multipoints but you can safely call it with
+ any kind of geometry. Since simplification occurs on a
+ object-by-object basis you can also feed a GeometryCollection to
+ this function.</para>
+
+ <para>Availability: 2.0.0</para>
+ </refsection>
+
+ <refsection>
+ <title>See Also</title>
+ <para><xref linkend="ST_Simplify" /></para>
+ </refsection>
+ </refentry>
+
<refentry id="ST_SymDifference">
<refnamediv>
<refname>ST_SymDifference</refname>
*
* PostGIS - Spatial Types for PostgreSQL
* http://postgis.refractions.net
- * Copyright 2001-2006 Refractions Research Inc.
- * Copyright 2007-2008 Mark Cave-Ayland
+ * Copyright 2010 Sandro Santilli <strk@keybit.net>
* Copyright 2008 Paul Ramsey <pramsey@cleverelephant.ca>
+ * Copyright 2007-2008 Mark Cave-Ayland
+ * Copyright 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.
unsigned int where);
extern POINTARRAY *ptarray_removePoint(POINTARRAY *pa, unsigned int where);
extern POINTARRAY *ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2);
-extern POINTARRAY *ptarray_remove_repeated_points(POINTARRAY *in);
extern int ptarray_isclosed2d(const POINTARRAY *pa);
extern int ptarray_isclosed3d(const POINTARRAY *pa);
extern LWLINE *lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end);
extern LWMLINE* lwmline_measured_from_lwmline(const LWMLINE *lwmline, double m_start, double m_end);
+/*
+ * Remove adjacent duplicated points from given argument.
+ *
+ * Always return a newly allocated object.
+ */
+extern POINTARRAY *ptarray_remove_repeated_points(POINTARRAY *in);
+extern LWGEOM *lwmpoint_remove_repeated_points(LWMPOINT *in);
+extern LWGEOM *lwline_remove_repeated_points(LWLINE *in);
+extern LWGEOM *lwpoly_remove_repeated_points(LWPOLY *in);
+extern LWGEOM *lwcollection_remove_repeated_points(LWCOLLECTION *in);
+extern LWGEOM *lwgeom_remove_repeated_points(LWGEOM *in);
+
/*
* Ensure every segment is at most 'dist' long.
* Returned LWGEOM might is unchanged if a POINT.
return outcol;
}
+LWGEOM*
+lwcollection_remove_repeated_points(LWCOLLECTION *coll)
+{
+ unsigned int i;
+ LWGEOM **newgeoms;
+
+ newgeoms = lwalloc(sizeof(LWGEOM *)*coll->ngeoms);
+ for (i=0; i<coll->ngeoms; i++)
+ {
+ newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i]);
+ }
+
+ return (LWGEOM*)lwcollection_construct(coll->type,
+ coll->SRID, coll->bbox ? box2d_clone(coll->bbox) : NULL,
+ coll->ngeoms, newgeoms);
+
+}
}
return 0;
}
+
+extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in)
+{
+ LWDEBUGF(3, "lwgeom_remove_repeated_points got type %d", TYPE_GETTYPE(in->type));
+ switch (TYPE_GETTYPE(in->type))
+ {
+ case MULTIPOINTTYPE:
+ return lwmpoint_remove_repeated_points((LWMPOINT*)in);
+ break;
+ case LINETYPE:
+ return lwline_remove_repeated_points((LWLINE*)in);
+
+ case MULTILINETYPE:
+ case COLLECTIONTYPE:
+ case MULTIPOLYGONTYPE:
+ return lwcollection_remove_repeated_points((LWCOLLECTION *)in);
+
+ case POLYGONTYPE:
+ return lwpoly_remove_repeated_points((LWPOLY *)in);
+ break;
+
+ case POINTTYPE:
+ /* No point is repeated for a single point */
+ return in;
+
+ case CIRCSTRINGTYPE:
+ case COMPOUNDTYPE:
+ case MULTICURVETYPE:
+ case CURVEPOLYTYPE:
+ case MULTISURFACETYPE:
+ /* Dunno how to handle these, will return untouched */
+ return in;
+
+ default:
+ lwnotice("unsupported input geometry type: %d",
+ TYPE_GETTYPE(in->type));
+ return in;
+ break;
+ }
+ return 0;
+}
return lwline_construct(lwline->SRID, NULL, pa);
}
+
+LWGEOM*
+lwline_remove_repeated_points(LWLINE *lwline)
+{
+ POINTARRAY* npts = ptarray_remove_repeated_points(lwline->points);
+
+ LWDEBUGF(3, "lwline_remove_repeated_points: npts %p", npts);
+
+ return (LWGEOM*)lwline_construct(lwline->SRID,
+ lwline->bbox ? box2d_clone(lwline->bbox) : 0,
+ npts);
+}
}
+LWGEOM*
+lwmpoint_remove_repeated_points(LWMPOINT *mpoint)
+{
+ unsigned int nnewgeoms;
+ unsigned int i, j;
+ LWGEOM **newgeoms;
+
+ newgeoms = lwalloc(sizeof(LWGEOM *)*mpoint->ngeoms);
+ nnewgeoms = 0;
+ for (i=0; i<mpoint->ngeoms; ++i)
+ {
+ /* Brute force, may be optimized by building an index */
+ int seen=0;
+ for (j=0; j<nnewgeoms; ++j)
+ {
+ if ( lwpoint_same((LWPOINT*)newgeoms[j],
+ (LWPOINT*)mpoint->geoms[i]) )
+ {
+ seen=1;
+ break;
+ }
+ }
+ if ( seen ) continue;
+ newgeoms[nnewgeoms++] = (LWGEOM*)lwpoint_clone(mpoint->geoms[i]);
+ }
+
+ return (LWGEOM*)lwcollection_construct(mpoint->type,
+ mpoint->SRID, mpoint->bbox ? box2d_clone(mpoint->bbox) : NULL,
+ nnewgeoms, newgeoms);
+
+}
+
ret = lwpoly_construct(SRID, NULL, nrings, rings);
return ret;
}
+
+LWGEOM*
+lwpoly_remove_repeated_points(LWPOLY *poly)
+{
+ unsigned int i;
+ POINTARRAY **newrings;
+
+ newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
+ for (i=0; i<poly->nrings; i++)
+ {
+ newrings[i] = ptarray_remove_repeated_points(poly->rings[i]);
+ }
+
+ return (LWGEOM*)lwpoly_construct(poly->SRID,
+ poly->bbox ? box2d_clone(poly->bbox) : NULL,
+ poly->nrings, newrings);
+
+}
* Returns a POINTARRAY with consecutive equal points
* removed. Equality test on all dimensions of input.
*
- * May return the input untouched, or a newly allocated
- * POINTARRAY (and point list)
+ * Always returns a newly allocated object.
*
*/
POINTARRAY *
LWDEBUG(3, "ptarray_remove_repeated_points called.");
/* Single or zero point arrays can't have duplicates */
- if ( in->npoints < 2 ) return in;
+ if ( in->npoints < 2 ) return ptarray_clone(in);
ptsize = pointArray_ptsize(in);
+ LWDEBUGF(3, "ptsize: %d", ptsize);
+
/* Allocate enough space for all points */
out = ptarray_construct(TYPE_HASZ(in->dims),
TYPE_HASM(in->dims), in->npoints);
/* Now fill up the actual points (NOTE: could be optimized) */
opn=1;
- memcpy(getPoint_internal(in, 0), getPoint_internal(out, 0), ptsize);
+ memcpy(getPoint_internal(out, 0), getPoint_internal(in, 0), ptsize);
+ LWDEBUGF(3, " first point copied, out points: %d", opn);
for (ipn=1; ipn<in->npoints; ++ipn)
{
if ( memcmp(getPoint_internal(in, ipn-1),
{
/* The point is different from the previous,
* we add it to output */
- memcpy(getPoint_internal(in, ipn),
- getPoint_internal(out, opn++), ptsize);
+ 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);
}
}
+ LWDEBUGF(3, " in:%d out:%d", out->npoints, opn);
out->npoints = opn;
return out;
PG_RETURN_POINTER(output);
}
+
+Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_RemoveRepeatedPoints);
+Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
+{
+ PG_LWGEOM *input = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ PG_LWGEOM *output;
+ LWGEOM *lwgeom_in = pglwgeom_deserialize(input);
+ LWGEOM *lwgeom_out;
+
+ /* lwnotice("ST_RemoveRepeatedPoints got %p", lwgeom_in); */
+
+ lwgeom_out = lwgeom_remove_repeated_points(lwgeom_in);
+ output = pglwgeom_serialize(lwgeom_out);
+
+ lwgeom_free(lwgeom_in);
+ PG_FREE_IF_COPY(input, 0);
+
+ PG_RETURN_POINTER(output);
+}
AS 'MODULE_PATHNAME','geomunion'
LANGUAGE 'C' IMMUTABLE STRICT;
+-- ST_RemoveRepeatedPoint(in geometry)
+--
+-- Removes duplicate vertices in input.
+-- 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)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME', 'ST_RemoveRepeatedPoints'
+ LANGUAGE 'C' IMMUTABLE STRICT
+ COST 100;
+
--------------------------------------------------------------------------------
-- ST_CleanGeometry / ST_MakeValid
--------------------------------------------------------------------------------
dumppoints \
wmsservers \
tickets \
- clean
+ clean \
+ remove_repeated_points
# Styled buffer only if GEOS >= 3.2
ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 32),1)
--- /dev/null
+SELECT 0, ST_AsText(ST_RemoveRepeatedPoints('GEOMETRYCOLLECTION EMPTY'));
+SELECT 1, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 1 1, 1 1, 2 2)'));
+SELECT 2, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 1 1, 1 1, 2 2, 2 2, 2 2, 2 2, 3 3, 3 3)'));
+SELECT 3, ST_AsText(ST_RemoveRepeatedPoints('MULTILINESTRING((0 0, 1 1, 1 1, 2 2, 2 2, 2 2, 2 2, 3 3, 3 3),(5 5, 5 5, 5 5, 4 4, 2 2))'));
+SELECT 4, ST_AsText(ST_RemoveRepeatedPoints('POLYGON((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))'));
+SELECT 5, ST_AsText(ST_RemoveRepeatedPoints('MULTIPOLYGON(((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)))'));
+SELECT 6, ST_AsText(ST_RemoveRepeatedPoints('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)'));
+SELECT 7, ST_AsText(ST_RemoveRepeatedPoints('GEOMETRYCOLLECTION(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),MULTIPOLYGON(((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))))'));
+SELECT 8, ST_AsText(ST_RemoveRepeatedPoints('POINT(0 0)'));
+SELECT 9, ST_AsText(ST_RemoveRepeatedPoints('CURVEPOLYGON(CIRCULARSTRING(
+ -2 0 0 0,
+ -1 -1 1 2,
+ 0 0 2 4,
+ 1 -1 3 6,
+ 2 0 4 8,
+ 0 2 2 4,
+ -2 0 0 0),
+ (-1 0 1 2, 0 0.5 2 4,
+ 1 0 3 6, 0 1 3 4, -1 0 1 2))'));
+SELECT 0, ST_AsText(ST_RemoveRepeatedPoints('GEOMETRYCOLLECTION EMPTY'));
+SELECT 1, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 1 1, 1 1, 2 2)'));
+SELECT 2, ST_AsText(ST_RemoveRepeatedPoints('LINESTRING(0 0, 1 1, 1 1, 2 2, 2 2, 2 2, 2 2, 3 3, 3 3)'));
+SELECT 3, ST_AsText(ST_RemoveRepeatedPoints('MULTILINESTRING((0 0, 1 1, 1 1, 2 2, 2 2, 2 2, 2 2, 3 3, 3 3),(5 5, 5 5, 5 5, 4 4, 2 2))'));
+SELECT 4, ST_AsText(ST_RemoveRepeatedPoints('POLYGON((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))'));
+SELECT 5, ST_AsText(ST_RemoveRepeatedPoints('MULTIPOLYGON(((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)))'));
+SELECT 6, ST_AsText(ST_RemoveRepeatedPoints('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)'));
+SELECT 7, ST_AsText(ST_RemoveRepeatedPoints('GEOMETRYCOLLECTION(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),MULTIPOLYGON(((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))))'));
+SELECT 8, ST_AsText(ST_RemoveRepeatedPoints('POINT(0 0)'));
+SELECT 9, ST_AsText(ST_RemoveRepeatedPoints('CURVEPOLYGON(CIRCULARSTRING(
+ -2 0 0 0,
+ -1 -1 1 2,
+ 0 0 2 4,
+ 1 -1 3 6,
+ 2 0 4 8,
+ 0 2 2 4,
+ -2 0 0 0),
+ (-1 0 1 2, 0 0.5 2 4,
+ 1 0 3 6, 0 1 3 4, -1 0 1 2))'));
--- /dev/null
+0|GEOMETRYCOLLECTION EMPTY
+1|LINESTRING(0 0,1 1,2 2)
+2|LINESTRING(0 0,1 1,2 2,3 3)
+3|MULTILINESTRING((0 0,1 1,2 2,3 3),(5 5,4 4,2 2))
+4|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5))
+5|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5)),((50 50,50 60,60 60,60 50,50 50),(55 55,55 58,58 58,58 55,55 55)))
+6|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)
+7|GEOMETRYCOLLECTION(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),MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5)),((50 50,50 60,60 60,60 50,50 50),(55 55,55 58,58 58,58 55,55 55))))
+8|POINT(0 0)
+9|CURVEPOLYGON(CIRCULARSTRING(-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0 0.5,1 0,0 1,-1 0))
+0|GEOMETRYCOLLECTION EMPTY
+1|LINESTRING(0 0,1 1,2 2)
+2|LINESTRING(0 0,1 1,2 2,3 3)
+3|MULTILINESTRING((0 0,1 1,2 2,3 3),(5 5,4 4,2 2))
+4|POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5))
+5|MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5)),((50 50,50 60,60 60,60 50,50 50),(55 55,55 58,58 58,58 55,55 55)))
+6|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)
+7|GEOMETRYCOLLECTION(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),MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(5 5,5 8,8 8,8 5,5 5)),((50 50,50 60,60 60,60 50,50 50),(55 55,55 58,58 58,58 55,55 55))))
+8|POINT(0 0)
+9|CURVEPOLYGON(CIRCULARSTRING(-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0 0.5,1 0,0 1,-1 0))