Commit 67e0c94b authored by Paul Ramsey's avatar Paul Ramsey

#2093, Add extra policy argument to control ST_Simplify behavior


git-svn-id: http://svn.osgeo.org/postgis/[email protected] b70326c6-7e19-0410-871a-916f4a2858ee
parent 7823e2c1
......@@ -903,15 +903,41 @@ static void test_lwgeom_simplify(void)
LWGEOM *l;
char *ewkt;
/* Simplify but only so far... */
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)", LW_PARSER_CHECK_NONE), 10, LW_TRUE);
ewkt = lwgeom_to_ewkt(l);
CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,0 0)");
lwgeom_free(l);
lwfree(ewkt);
/* Simplify but only so far... */
l = lwgeom_simplify(lwgeom_from_wkt("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))", LW_PARSER_CHECK_NONE), 10, LW_TRUE);
ewkt = lwgeom_to_ewkt(l);
CU_ASSERT_STRING_EQUAL(ewkt, "POLYGON((0 0,1 0,1 1,0 0))");
lwgeom_free(l);
lwfree(ewkt);
/* Simplify and collapse */
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)", LW_PARSER_CHECK_NONE), 10, LW_FALSE);
CU_ASSERT_EQUAL(l, NULL);
lwgeom_free(l);
lwfree(ewkt);
/* Simplify and collapse */
l = lwgeom_simplify(lwgeom_from_wkt("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))", LW_PARSER_CHECK_NONE), 10, LW_FALSE);
CU_ASSERT_EQUAL(l, NULL);
lwgeom_free(l);
lwfree(ewkt);
/* Not simplifiable */
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0, 50 1.00001, 100 0)", LW_PARSER_CHECK_NONE), 1.0);
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0, 50 1.00001, 100 0)", LW_PARSER_CHECK_NONE), 1.0, LW_FALSE);
ewkt = lwgeom_to_ewkt(l);
CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,50 1.00001,100 0)");
lwgeom_free(l);
lwfree(ewkt);
/* Simplifiable */
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0,50 0.99999,100 0)", LW_PARSER_CHECK_NONE), 1.0);
l = lwgeom_simplify(lwgeom_from_wkt("LINESTRING(0 0,50 0.99999,100 0)", LW_PARSER_CHECK_NONE), 1.0, LW_FALSE);
ewkt = lwgeom_to_ewkt(l);
CU_ASSERT_STRING_EQUAL(ewkt, "LINESTRING(0 0,100 0)");
lwgeom_free(l);
......
......@@ -48,7 +48,7 @@ static void test_misc_simplify(void)
char *wkt_out;
geom = lwgeom_from_wkt("LINESTRING(0 0,0 10,0 51,50 20,30 20,7 32)", LW_PARSER_CHECK_NONE);
geom2d = lwgeom_simplify(geom,2);
geom2d = lwgeom_simplify(geom, 2, LW_FALSE);
wkt_out = lwgeom_to_ewkt(geom2d);
CU_ASSERT_STRING_EQUAL("LINESTRING(0 0,0 51,50 20,30 20,7 32)",wkt_out);
lwgeom_free(geom);
......@@ -56,7 +56,7 @@ static void test_misc_simplify(void)
lwfree(wkt_out);
geom = lwgeom_from_wkt("MULTILINESTRING((0 0,0 10,0 51,50 20,30 20,7 32))", LW_PARSER_CHECK_NONE);
geom2d = lwgeom_simplify(geom,2);
geom2d = lwgeom_simplify(geom, 2, LW_FALSE);
wkt_out = lwgeom_to_ewkt(geom2d);
CU_ASSERT_STRING_EQUAL("MULTILINESTRING((0 0,0 51,50 20,30 20,7 32))",wkt_out);
lwgeom_free(geom);
......
......@@ -964,8 +964,8 @@ extern LWGEOM* lwgeom_force_3dz(const LWGEOM *geom);
extern LWGEOM* lwgeom_force_3dm(const LWGEOM *geom);
extern LWGEOM* lwgeom_force_4d(const LWGEOM *geom);
extern LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist);
extern LWGEOM* lwgeom_set_effective_area(const LWGEOM *igeom,int set_area, double area);
extern LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed);
extern LWGEOM* lwgeom_set_effective_area(const LWGEOM *igeom, int set_area, double area);
/*
* Force to use SFS 1.1 geometry type
......
......@@ -185,9 +185,9 @@ extern int32_t lw_get_int32_t(const uint8_t *loc);
* @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);
LWLINE* lwline_simplify(const LWLINE *iline, double dist, int preserve_collapsed);
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed);
LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist, int preserve_collapsed);
/*
* Computational geometry
......
......@@ -503,7 +503,7 @@ int lwcollection_count_vertices(LWCOLLECTION *col)
return v;
}
LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist)
LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist, int preserve_collapsed)
{
int i;
LWCOLLECTION *out = lwcollection_construct_empty(igeom->type, igeom->srid, FLAGS_GET_Z(igeom->flags), FLAGS_GET_M(igeom->flags));
......@@ -513,7 +513,7 @@ LWCOLLECTION* lwcollection_simplify(const LWCOLLECTION *igeom, double dist)
for( i = 0; i < igeom->ngeoms; i++ )
{
LWGEOM *ngeom = lwgeom_simplify(igeom->geoms[i], dist);
LWGEOM *ngeom = lwgeom_simplify(igeom->geoms[i], dist, preserve_collapsed);
if ( ngeom ) out = lwcollection_add_lwgeom(out, ngeom);
}
......
......@@ -1549,7 +1549,7 @@ void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
}
}
LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist)
LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
{
switch (igeom->type)
{
......@@ -1557,15 +1557,15 @@ LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist)
case MULTIPOINTTYPE:
return lwgeom_clone(igeom);
case LINETYPE:
return (LWGEOM*)lwline_simplify((LWLINE*)igeom, dist);
return (LWGEOM*)lwline_simplify((LWLINE*)igeom, dist, preserve_collapsed);
case POLYGONTYPE:
return (LWGEOM*)lwpoly_simplify((LWPOLY*)igeom, dist);
return (LWGEOM*)lwpoly_simplify((LWPOLY*)igeom, dist, preserve_collapsed);
case MULTILINETYPE:
case MULTIPOLYGONTYPE:
case COLLECTIONTYPE:
return (LWGEOM*)lwcollection_simplify((LWCOLLECTION *)igeom, dist);
return (LWGEOM*)lwcollection_simplify((LWCOLLECTION *)igeom, dist, preserve_collapsed);
default:
lwerror("lwgeom_simplify: unsupported geometry type: %s",lwtype_name(igeom->type));
lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(igeom->type));
}
return NULL;
}
......
......@@ -503,18 +503,40 @@ int lwline_count_vertices(LWLINE *line)
return line->points->npoints;
}
LWLINE* lwline_simplify(const LWLINE *iline, double dist)
LWLINE* lwline_simplify(const LWLINE *iline, double dist, int preserve_collapsed)
{
static const int minvertices = 2; /* TODO: allow setting this */
LWLINE *oline;
POINTARRAY *pa;
LWDEBUG(2, "function called");
/* Skip empty case */
if( lwline_is_empty(iline) )
return lwline_clone(iline);
return NULL;
pa = ptarray_simplify(iline->points, dist, minvertices);
if ( ! pa ) return NULL;
/* Make sure single-point collapses have two points */
if ( pa->npoints == 1 )
{
/* Make sure single-point collapses have two points */
if ( preserve_collapsed )
{
POINT4D pt;
getPoint4d_p(pa, 0, &pt);
ptarray_append_point(pa, &pt, LW_TRUE);
}
/* Return null for collapse */
else
{
ptarray_free(pa);
return NULL;
}
}
static const int minvertices = 0; /* TODO: allow setting this */
oline = lwline_construct(iline->srid, NULL, ptarray_simplify(iline->points, dist, minvertices));
oline = lwline_construct(iline->srid, NULL, pa);
oline->type = iline->type;
return oline;
}
......
......@@ -348,20 +348,27 @@ int lwpoly_count_vertices(LWPOLY *poly)
return v;
}
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist)
LWPOLY* lwpoly_simplify(const LWPOLY *ipoly, double dist, int preserve_collapsed)
{
int i;
LWPOLY *opoly = lwpoly_construct_empty(ipoly->srid, FLAGS_GET_Z(ipoly->flags), FLAGS_GET_M(ipoly->flags));
LWDEBUGF(2, "simplify_polygon3d: simplifying polygon with %d rings", ipoly->nrings);
LWDEBUGF(2, "%s: simplifying polygon with %d rings", __func__, ipoly->nrings);
if( lwpoly_is_empty(ipoly) )
return opoly; /* should we return NULL instead ? */
if ( lwpoly_is_empty(ipoly) )
return NULL;
for (i = 0; i < ipoly->nrings; i++)
for ( i = 0; i < ipoly->nrings; i++ )
{
static const int minvertices = 0; /* TODO: allow setting this */
POINTARRAY *opts = ptarray_simplify(ipoly->rings[i], dist, minvertices);
POINTARRAY *opts;
int minvertices = 0;
/* We'll still let holes collapse, but if we're preserving */
/* and this is a shell, we ensure it is kept */
if ( preserve_collapsed && i == 0 )
minvertices = 4;
opts = ptarray_simplify(ipoly->rings[i], dist, minvertices);
LWDEBUGF(3, "ring%d simplified from %d to %d points", i, ipoly->rings[i]->npoints, opts->npoints);
......
......@@ -44,19 +44,23 @@ PG_FUNCTION_INFO_V1(LWGEOM_simplify2d);
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS)
{
GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
double dist = PG_GETARG_FLOAT8(1);
GSERIALIZED *result;
int type = gserialized_get_type(geom);
LWGEOM *in;
LWGEOM *out;
double dist;
LWGEOM *in, *out;
bool preserve_collapsed = false;
/* Handle optional argument to preserve collapsed features */
if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
preserve_collapsed = true;
/* Can't simplify points! */
if ( type == POINTTYPE || type == MULTIPOINTTYPE )
PG_RETURN_POINTER(geom);
dist = PG_GETARG_FLOAT8(1);
in = lwgeom_from_gserialized(geom);
out = lwgeom_simplify(in, dist);
out = lwgeom_simplify(in, dist, preserve_collapsed);
if ( ! out ) PG_RETURN_NULL();
/* COMPUTE_BBOX TAINTING */
......
......@@ -2927,6 +2927,12 @@ CREATE OR REPLACE FUNCTION ST_Simplify(geometry, float8)
AS 'MODULE_PATHNAME', 'LWGEOM_simplify2d'
LANGUAGE 'c' IMMUTABLE STRICT;
-- Availability: 2.2.0
CREATE OR REPLACE FUNCTION ST_Simplify(geometry, float8, boolean)
RETURNS geometry
AS 'MODULE_PATHNAME', 'LWGEOM_simplify2d'
LANGUAGE 'c' IMMUTABLE STRICT;
-- Availability: 2.2.0
CREATE OR REPLACE FUNCTION ST_SimplifyVW(geometry, float8)
RETURNS geometry
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment