Added RemovePoint() and ReplacePoint() to complete Geometry editiong function.

Added regress tests for them.


git-svn-id: http://svn.osgeo.org/postgis/trunk@2173 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Sandro Santilli 2005-12-13 18:39:08 +00:00
parent c0aaceaaf0
commit bd80617203
12 changed files with 291 additions and 5 deletions

View file

@ -14,6 +14,8 @@ PostGIS 1.1.0CVS
- BuildArea(any_geometry)
- OGC BdPolyFromText(linestring_wkt, srid)
- OGC BdMPolyFromText(linestring_wkt, srid)
- RemovePoint(linestring, offset)
- ReplacePoint(linestring, offset, point)
- Function semantic changes:
- SnapToGrid doesn't discard higher dimensions
@ -45,9 +47,6 @@ PostGIS 1.1.0CVS
string attributes
- Wider and cleaner regression test suite
PostGIS 1.0.7CVS
- Fixed memory leak in polygonize()
PostGIS 1.0.6
2005/12/06
- Fixed palloc(0) call in collection deserializer (only gives

View file

@ -4621,12 +4621,38 @@ FROM geometry_table;</literallayout>
<term>AddPoint(linestring, point, [&lt;position&gt;])</term>
<listitem>
<para>Adds a point to a LineString at position &lt;pos&gt;.
<para>Adds a point to a LineString before point &lt;pos&gt;
(0-based index).
Third parameter can be omitted or set to -1 for appending.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>RemovePoint(linestring, offset)</term>
<listitem>
<para>
Removes point from a linestring. Offset is 0-based.
</para>
<para>
Availability: 1.1.0
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ReplacePoint(linestring, N, point)</term>
<listitem>
<para>
Replace point N of linestring with given point.
Index is 0-based.
</para>
<para>
Availability: 1.1.0
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Force_collection(geometry)</term>

View file

@ -1005,6 +1005,8 @@ extern LWPOINT *make_lwpoint4d(int SRID, double x, double y, double z, double m)
extern LWLINE *lwline_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points);
extern LWLINE *lwline_from_lwmpoint(int SRID, LWMPOINT *mpoint);
extern LWLINE *lwline_addpoint(LWLINE *line, LWPOINT *point, unsigned int where);
extern LWLINE *lwline_removepoint(LWLINE *line, unsigned int which);
extern void lwline_setPoint4d(LWLINE *line, unsigned int which, POINT4D *newpoint);
extern LWPOLY *lwpoly_from_lwlines(const LWLINE *shell, unsigned int nholes, const LWLINE **holes);
/* Return a char string with ASCII versionf of type flags */
@ -1023,6 +1025,7 @@ extern POINTARRAY *ptarray_construct(char hasz, char hasm,
extern POINTARRAY *ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims,
unsigned int where);
extern POINTARRAY *ptarray_removePoint(POINTARRAY *pa, unsigned int where);
extern int ptarray_isclosed2d(const POINTARRAY *pa);

View file

@ -57,6 +57,8 @@ Datum LWGEOM_makeline(PG_FUNCTION_ARGS);
Datum LWGEOM_makepoly(PG_FUNCTION_ARGS);
Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS);
Datum LWGEOM_addpoint(PG_FUNCTION_ARGS);
Datum LWGEOM_removepoint(PG_FUNCTION_ARGS);
Datum LWGEOM_replacepoint(PG_FUNCTION_ARGS);
Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS);
Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS);
Datum LWGEOM_azimuth(PG_FUNCTION_ARGS);
@ -3095,6 +3097,105 @@ Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
}
PG_FUNCTION_INFO_V1(LWGEOM_removepoint);
Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
{
PG_LWGEOM *pglwg1, *result;
LWLINE *line, *outline;
unsigned int which;
pglwg1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
which = PG_GETARG_INT32(1);
if ( ! TYPE_GETTYPE(pglwg1->type) == LINETYPE )
{
elog(ERROR, "First argument must be a LINESTRING");
PG_RETURN_NULL();
}
line = lwline_deserialize(SERIALIZED_FORM(pglwg1));
if ( which > line->points->npoints-1 )
{
elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
PG_RETURN_NULL();
}
if ( line->points->npoints < 3 )
{
elog(ERROR, "Can't remove points from a single segment line");
PG_RETURN_NULL();
}
outline = lwline_removepoint(line, which);
result = pglwgeom_serialize((LWGEOM *)outline);
// Release memory
PG_FREE_IF_COPY(pglwg1, 0);
lwgeom_release((LWGEOM *)line);
lwgeom_release((LWGEOM *)outline);
PG_RETURN_POINTER(result);
}
PG_FUNCTION_INFO_V1(LWGEOM_replacepoint);
Datum LWGEOM_replacepoint(PG_FUNCTION_ARGS)
{
PG_LWGEOM *pglwg1, *pglwg2, *result;
LWGEOM *lwg;
LWLINE *line;
LWPOINT *lwpoint;
POINT4D newpoint;
unsigned int which;
/* we copy input as we're going to modify it */
pglwg1 = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
which = PG_GETARG_INT32(1);
pglwg2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
/* Extract a POINT4D from the point */
lwg = pglwgeom_deserialize(pglwg2);
lwpoint = lwgeom_as_lwpoint(lwg);
if ( ! lwpoint )
{
elog(ERROR, "Third argument must be a POINT");
PG_RETURN_NULL();
}
getPoint4d_p(lwpoint->point, 0, &newpoint);
lwgeom_release((LWGEOM *)lwpoint);
PG_FREE_IF_COPY(pglwg2, 2);
lwg = pglwgeom_deserialize(pglwg1);
line = lwgeom_as_lwline(lwg);
if ( ! line )
{
elog(ERROR, "First argument must be a LINESTRING");
PG_RETURN_NULL();
}
if ( which > line->points->npoints-1 )
{
elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
PG_RETURN_NULL();
}
/*
* This will change pointarray of the serialized pglwg1,
*/
lwline_setPoint4d(line, which, &newpoint);
result = pglwgeom_serialize((LWGEOM *)line);
// Release memory
pfree(pglwg1); // we forced copy, POINARRAY is released now
lwgeom_release((LWGEOM *)line);
PG_RETURN_POINTER(result);
}
//convert LWGEOM to wwkt (in TEXT format)
PG_FUNCTION_INFO_V1(LWGEOM_asEWKT);
Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)

View file

@ -484,3 +484,25 @@ lwline_addpoint(LWLINE *line, LWPOINT *point, unsigned int where)
return ret;
}
LWLINE *
lwline_removepoint(LWLINE *line, unsigned int index)
{
POINTARRAY *newpa;
LWLINE *ret;
newpa = ptarray_removePoint(line->points, index);
ret = lwline_construct(line->SRID, NULL, newpa);
return ret;
}
/*
* Note: input will be changed, make sure you have permissions for this.
*/
void
lwline_setPoint4d(LWLINE *line, unsigned int index, POINT4D *newpoint)
{
setPoint4d(line->points, index, newpoint);
}

View file

@ -1290,6 +1290,16 @@ CREATEFUNCTION AddPoint(geometry, geometry, integer)
AS '@MODULE_FILENAME@', 'LWGEOM_addpoint'
LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (iscachable,isstrict);
CREATEFUNCTION RemovePoint(geometry, integer)
RETURNS geometry
AS '@MODULE_FILENAME@', 'LWGEOM_removepoint'
LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (iscachable,isstrict);
CREATEFUNCTION ReplacePoint(geometry, integer, geometry)
RETURNS geometry
AS '@MODULE_FILENAME@', 'LWGEOM_replacepoint'
LANGUAGE 'C' _IMMUTABLE_STRICT; -- WITH (iscachable,isstrict);
CREATE AGGREGATE makeline (
sfunc = geom_accum,
basetype = geometry,

View file

@ -337,6 +337,56 @@ ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims, unsigned int where)
return ret;
}
/*
* Remove a point from a pointarray.
* 'which' is the offset (starting at 0)
* Returned pointarray is newly allocated
*/
POINTARRAY *
ptarray_removePoint(POINTARRAY *pa, unsigned int which)
{
POINTARRAY *ret;
POINT4D pbuf;
size_t ptsize = pointArray_ptsize(pa);
#ifdef PGIS_DEBUG_CALLS
lwnotice("ptarray_removePoint: pa %x p %x size %d where %d",
pa, p, pdims, where);
#endif
#if PARANOIA_LEVEL > 0
if ( which > pa->npoints-1 )
{
lwerror("ptarray_removePoint: offset (%d) out of range (%d..%d)",
which, 0, pa->npoints-1);
return NULL;
}
if ( pa->npoints < 3 )
{
lwerror("ptarray_removePointe: can't remove a point from a 2-vertex POINTARRAY");
}
#endif
ret = ptarray_construct(TYPE_HASZ(pa->dims),
TYPE_HASM(pa->dims), pa->npoints-1);
/* copy initial part */
if ( which )
{
memcpy(getPoint_internal(ret, 0), getPoint_internal(pa, 0), ptsize*which);
}
/* copy final part */
if ( which < pa->npoints-2 )
{
memcpy(getPoint_internal(ret, which), getPoint_internal(pa, which+1),
ptsize*(pa->npoints-which-1));
}
return ret;
}
/*
* Clone a pointarray
*/

View file

@ -2,7 +2,7 @@ TMPDIR?=/tmp
include ../Makefile.config
TESTS=regress regress_index lwgeom_regress regress_lrs regress_proj
TESTS=regress regress_index lwgeom_regress regress_lrs regress_proj replacepoint removepoint
ifeq ($(USE_GEOS),1)
TESTS += regress_ogc regress_bdpoly

24
regress/removepoint.sql Normal file
View file

@ -0,0 +1,24 @@
-- Can't remove points from a 2-point linestring
SELECT removepoint('LINESTRING(0 0, 1 1)', 0);
-- Out of range indexes
SELECT removepoint('LINESTRING(0 0, 1 1, 2 2)', 3);
SELECT removepoint('LINESTRING(0 0, 1 1, 2 2)', -1);
-- Removing first/last points
SELECT asewkt(removepoint('LINESTRING(0 0, 1 1, 2 2)', 0));
SELECT asewkt(removepoint('LINESTRING(0 0, 1 1, 2 2)', 2));
-- Removing first/last points with higher dimension
SELECT asewkt(removepoint('LINESTRING(0 0 0, 1 1 1, 2 2 2)', 0));
SELECT asewkt(removepoint('LINESTRING(0 0 0, 1 1 1, 2 2 2)', 2));
SELECT asewkt(removepoint('LINESTRINGM(0 0 0, 1 1 1, 2 2 2)', 0));
SELECT asewkt(removepoint('LINESTRINGM(0 0 0, 1 1 1, 2 2 2)', 2));
SELECT asewkt(removepoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2)', 0));
SELECT asewkt(removepoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2)', 2));
-- Removing intermediate points with higher dimension
SELECT asewkt(removepoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4, 5 5 5 5, 6 6 6 6, 7 7 7 7)', 2));
SELECT asewkt(removepoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 3 3 3 3, 4 4 4 4, 5 5 5 5, 6 6 6 6, 7 7 7 7)', 4));

View file

@ -0,0 +1,13 @@
ERROR: Can't remove points from a single segment line
ERROR: Point index out of range (0..2)
ERROR: Point index out of range (0..2)
LINESTRING(1 1,2 2)
LINESTRING(0 0,1 1)
LINESTRING(1 1 1,2 2 2)
LINESTRING(0 0 0,1 1 1)
LINESTRINGM(1 1 1,2 2 2)
LINESTRINGM(0 0 0,1 1 1)
LINESTRING(1 1 1 1,2 2 2 2)
LINESTRING(0 0 0 0,1 1 1 1)
LINESTRING(0 0 0 0,1 1 1 1,3 3 3 3,4 4 4 4,5 5 5 5,6 6 6 6,7 7 7 7)
LINESTRING(0 0 0 0,1 1 1 1,2 2 2 2,3 3 3 3,5 5 5 5,6 6 6 6,7 7 7 7)

26
regress/replacepoint.sql Normal file
View file

@ -0,0 +1,26 @@
-- Out of range indexes
SELECT ReplacePoint('LINESTRING(0 0, 1 1, 2 2)', 3, 'POINT(9 9)');
SELECT ReplacePoint('LINESTRING(0 0, 1 1, 2 2)', -1, 'POINT(9 9)');
-- Invalid inputs
SELECT ReplacePoint('MULTIPOINT(0 0, 1 1, 2 2)', 3, 'POINT(9 9)');
SELECT ReplacePoint('LINESTRING(0 0, 1 1, 2 2)', -1, 'MULTIPOINT(9 9, 0 0)');
-- Replacing 3dz line with 3dm point
SELECT asewkt(ReplacePoint('LINESTRING(-1 -1 -1, 1 1 1, 2 2 2)', 0, 'POINT(90 91 92)'));
-- Replacing 3dm line with 3dz point
SELECT asewkt(ReplacePoint('LINESTRINGM(0 0 0, 1 1 1, 2 2 2)', 1, 'POINTM(90 91 92)'));
-- Replacing 3dm line with 4d point
SELECT asewkt(ReplacePoint('LINESTRINGM(0 0 0, 1 1 1, 2 2 2)', 2, 'POINT(90 91 92 93)'));
-- Replacing 3dz line with 4d point
SELECT asewkt(ReplacePoint('LINESTRING(0 0 0, 1 1 1, 2 2 2)', 1, 'POINT(90 91 92 93)'));
-- Replacing 4d line with 2d/3dm/3dz/4d point
SELECT asewkt(ReplacePoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 4 4 4 4)', 3, 'POINT(90 91)'));
SELECT asewkt(ReplacePoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 4 4 4 4)', 2, 'POINT(90 91 92)'));
SELECT asewkt(ReplacePoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 4 4 4 4)', 1, 'POINTM(90 91 92)'));
SELECT asewkt(ReplacePoint('LINESTRING(0 0 0 0, 1 1 1 1, 2 2 2 2, 4 4 4 4)', 0, 'POINT(90 91 92 93)'));

View file

@ -0,0 +1,12 @@
ERROR: Point index out of range (0..2)
ERROR: Point index out of range (0..2)
ERROR: First argument must be a LINESTRING
ERROR: Third argument must be a POINT
LINESTRING(90 91 92,1 1 1,2 2 2)
LINESTRINGM(0 0 0,90 91 92,2 2 2)
LINESTRINGM(0 0 0,1 1 1,90 91 93)
LINESTRING(0 0 0,90 91 92,2 2 2)
LINESTRING(0 0 0 0,1 1 1 1,2 2 2 2,90 91 0 0)
LINESTRING(0 0 0 0,1 1 1 1,90 91 92 0,4 4 4 4)
LINESTRING(0 0 0 0,90 91 0 92,2 2 2 2,4 4 4 4)
LINESTRING(90 91 92 93,1 1 1 1,2 2 2 2,4 4 4 4)