]> granicus.if.org Git - postgis/commitdiff
Added RemovePoint() and ReplacePoint() to complete Geometry editiong function.
authorSandro Santilli <strk@keybit.net>
Tue, 13 Dec 2005 18:39:08 +0000 (18:39 +0000)
committerSandro Santilli <strk@keybit.net>
Tue, 13 Dec 2005 18:39:08 +0000 (18:39 +0000)
Added regress tests for them.

git-svn-id: http://svn.osgeo.org/postgis/trunk@2173 b70326c6-7e19-0410-871a-916f4a2858ee

12 files changed:
CHANGES
doc/postgis.xml
lwgeom/liblwgeom.h
lwgeom/lwgeom_functions_basic.c
lwgeom/lwline.c
lwgeom/lwpostgis.sql.in
lwgeom/ptarray.c
regress/Makefile
regress/removepoint.sql [new file with mode: 0644]
regress/removepoint_expected [new file with mode: 0644]
regress/replacepoint.sql [new file with mode: 0644]
regress/replacepoint_expected [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 6ed682d6e086852f921e0c05a59e4ec51c6d1594..8899866ab241a672e39ceb945eed9a95c971afbb 100644 (file)
--- a/CHANGES
+++ b/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
index 1b86b629d1a77c638ac01dc2bbcee4319e12bbdc..2a88a69a70f5424e91ac831a22b2e97e758b7dd2 100644 (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>
 
index f6e70b1b8e26fae888ebbb155cb4db36a977c343..33ea68a9cce8032727cf7837e0b1da64c6fe7428 100644 (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);
 
index 954e73f34214314677af7f5b3bac4c3e973d6142..80fa61beae8bc3455f784dd59f4a2ebd145361bb 100644 (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)
index 9c21124e0224767b97a1a2101b0d2d1aed42a13c..4cfe1036ed2ebb2a2d59c3997ac6712f4de39e6c 100644 (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);
+}
index a6a11a37c00e03c12a481f1f5e8828e4110d8ab7..fd74a2392ecefb3c2c8937748867766ab2d09c40 100644 (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,
index 5d4a851598b62db373b2c0f67d86afae489bdb77..4b97a01f0a7fbaa92a210471a5f411070d7d5acf 100644 (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 
  */
index f47a4ba0274552d10b75e27d080d5f9a32021f37..4414aaf9ffcd393cefc75e7bfa098d148420fcec 100644 (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
diff --git a/regress/removepoint.sql b/regress/removepoint.sql
new file mode 100644 (file)
index 0000000..4d86e46
--- /dev/null
@@ -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));
+
+
diff --git a/regress/removepoint_expected b/regress/removepoint_expected
new file mode 100644 (file)
index 0000000..bbbd405
--- /dev/null
@@ -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)
diff --git a/regress/replacepoint.sql b/regress/replacepoint.sql
new file mode 100644 (file)
index 0000000..cd6bd2a
--- /dev/null
@@ -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)'));
+
diff --git a/regress/replacepoint_expected b/regress/replacepoint_expected
new file mode 100644 (file)
index 0000000..dcc2051
--- /dev/null
@@ -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)