mirror of
https://git.osgeo.org/gitea/postgis/postgis
synced 2024-10-23 16:42:35 +00:00
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:
parent
c0aaceaaf0
commit
bd80617203
5
CHANGES
5
CHANGES
|
@ -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
|
||||
|
|
|
@ -4621,12 +4621,38 @@ FROM geometry_table;</literallayout>
|
|||
<term>AddPoint(linestring, point, [<position>])</term>
|
||||
|
||||
<listitem>
|
||||
<para>Adds a point to a LineString at position <pos>.
|
||||
<para>Adds a point to a LineString before point <pos>
|
||||
(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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
24
regress/removepoint.sql
Normal 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));
|
||||
|
||||
|
13
regress/removepoint_expected
Normal file
13
regress/removepoint_expected
Normal 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
26
regress/replacepoint.sql
Normal 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)'));
|
||||
|
12
regress/replacepoint_expected
Normal file
12
regress/replacepoint_expected
Normal 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)
|
Loading…
Reference in a new issue