- 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
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
<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>
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 */
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);
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);
}
+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)
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);
+}
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,
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
*/
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
--- /dev/null
+-- 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));
+
+
--- /dev/null
+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)
--- /dev/null
+-- 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)'));
+
--- /dev/null
+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)