- 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)
- 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)
- #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 *
<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>
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>
/**
* 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);
/*
* 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
}
LWGEOM*
-lwcollection_remove_repeated_points(LWCOLLECTION *coll)
+lwcollection_remove_repeated_points(LWCOLLECTION *coll, double tolerance)
{
uint32_t 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]);
+ newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i], tolerance);
}
return (LWGEOM*)lwcollection_construct(coll->type,
return lwline_get_lwpoint(lwline, lwline->points->npoints-1);
}
-
\ No newline at end of file
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));
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:
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;
}
}
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,
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;
}
}
LWGEOM*
-lwmpoint_remove_repeated_points(LWMPOINT *mpoint)
+lwmpoint_remove_repeated_points(LWMPOINT *mpoint, double tolerance)
{
uint32_t nnewgeoms;
uint32_t i, j;
}
LWGEOM*
-lwpoly_remove_repeated_points(LWPOLY *poly)
+lwpoly_remove_repeated_points(LWPOLY *poly, double tolerance)
{
uint32_t 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]);
+ newrings[i] = ptarray_remove_repeated_points(poly->rings[i], tolerance);
}
return (LWGEOM*)lwpoly_construct(poly->srid,
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);
}
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);
*
*/
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),
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);
}
}
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);
-- 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
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);
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));
+
10|LINESTRING(0 0,0 0)
11|LINESTRING(0 0,0 0)
12|3
+13|LINESTRING(0 0,2 0,4 0)