[postgis-tickets] r14683 - Negative indexing for ST_PointN and ST_SetPoint (R?\195?\169mi Cura)

Daniel Baston dbaston at gmail.com
Wed Feb 24 08:04:07 PST 2016


Author: dbaston
Date: 2016-02-24 08:04:06 -0800 (Wed, 24 Feb 2016)
New Revision: 14683

Modified:
   trunk/doc/introduction.xml
   trunk/doc/reference_accessor.xml
   trunk/doc/reference_editor.xml
   trunk/postgis/lwgeom_functions_basic.c
   trunk/postgis/lwgeom_ogc.c
   trunk/regress/regress_ogc.sql
   trunk/regress/regress_ogc_expected
   trunk/regress/setpoint.sql
   trunk/regress/setpoint_expected
   trunk/regress/sfcgal/regress_ogc_expected
Log:
Negative indexing for ST_PointN and ST_SetPoint (R?\195?\169mi Cura)

Modified: trunk/doc/introduction.xml
===================================================================
--- trunk/doc/introduction.xml	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/doc/introduction.xml	2016-02-24 16:04:06 UTC (rev 14683)
@@ -227,6 +227,7 @@
 Norman Vine,
 Rafal Magda,
 Ralph Mason,
+RĂ©mi Cura,
 Richard Greenwood,
 Silvio Grosso,
 Steffen Macke,

Modified: trunk/doc/reference_accessor.xml
===================================================================
--- trunk/doc/reference_accessor.xml	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/doc/reference_accessor.xml	2016-02-24 16:04:06 UTC (rev 14683)
@@ -2004,8 +2004,8 @@
 	  <refnamediv>
 		<refname>ST_PointN</refname>
 
-		<refpurpose>Return the Nth point in the first linestring or circular linestring in the
-			geometry. Return NULL if there is no linestring in the
+		<refpurpose>Return the Nth point in the first LineString or circular LineString in the
+			geometry. Negative values are counted backwards from the end of the LineString. Returns NULL if there is no linestring in the
 			geometry.</refpurpose>
 	  </refnamediv>
 
@@ -2023,11 +2023,12 @@
 		<title>Description</title>
 
 		<para>Return the Nth point in a single linestring or circular linestring in the
-			geometry. Return NULL if there is no linestring in the
+			geometry. Negative values are counted backwards from the end of the LineString, so that -1 is the last point. Returns NULL if there is no linestring in the
 			geometry.</para>
 
 		<note>
 			  <para>Index is 1-based as for OGC specs since version 0.8.0.
+              Backward indexing (negative index) is not in OGC
 			  Previous versions implemented this as 0-based instead.</para>
 		</note>
 
@@ -2042,7 +2043,10 @@
 		<para>&curve_support;</para>
 		<note><para>Changed: 2.0.0 no longer works with single geometry multilinestrings.  In older
 	  versions of PostGIS -- a single line multilinestring would work happily with this
-	  function and return the start point.  In 2.0.0 it just returns NULL like any other multilinestring.</para></note>
+	  function and return the start point.  In 2.0.0 it just returns NULL like any other multilinestring.</para>
+      <para> Changed: 2.3.0 : negative indexing available (-1 is last point)
+    </para>
+      </note>
 
 	  </refsection>
 
@@ -2071,6 +2075,15 @@
 st_astext
 ----------
 POINT(3 2)
+
+SELECT st_astext(f)
+FROM ST_GeometryFromtext('LINESTRING(0 0 0, 1 1 1, 2 2 2)') as g
+	,ST_PointN(g, -2) AS f -- 1 based index 
+
+st_astext
+----------
+"POINT Z (1 1 1)"
+
 </programlisting>
 	  </refsection>
 

Modified: trunk/doc/reference_editor.xml
===================================================================
--- trunk/doc/reference_editor.xml	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/doc/reference_editor.xml	2016-02-24 16:04:06 UTC (rev 14683)
@@ -1401,7 +1401,7 @@
 		  <refnamediv>
 			<refname>ST_SetPoint</refname>
 			<refpurpose>Replace point N of linestring with given point. Index is
-			0-based.</refpurpose>
+			0-based. Negative indexes are counted backwards, so that -1 is the last point.</refpurpose>
 		  </refnamediv>
 		  <refsynopsisdiv>
 			 <funcsynopsis>
@@ -1418,9 +1418,10 @@
 			<title>Description</title>
 
 			<para>Replace point N of linestring with given point. Index is
-			0-based.
+			0-based.Negative index are counted backwards, so that -1 is last point.
 				This is especially useful in triggers when trying to maintain relationship of joints when one vertex moves.</para>
 			<para>Availability: 1.1.0</para>
+			<para>Updated 2.3.0 : negative indexing</para>
 
 	  		<para>&Z_support;</para>
 		  </refsection>
@@ -1440,6 +1441,14 @@
 	   st_asewkt
 -----------------------
 LINESTRING(-1 2 3,-1 3 4,-1 1 3)
+
+SELECT ST_AsText(ST_SetPoint(g, -3, p))
+FROM ST_GEomFromText('LINESTRING(0 0, 1 1, 2 2, 3 3, 4 4)') AS g
+	, ST_PointN(g,1) as p; 
+	   st_astext
+-----------------------
+LINESTRING(0 0,1 1,0 0,3 3,4 4)
+
 			</programlisting>
 		  </refsection>
 		  <refsection>

Modified: trunk/postgis/lwgeom_functions_basic.c
===================================================================
--- trunk/postgis/lwgeom_functions_basic.c	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/postgis/lwgeom_functions_basic.c	2016-02-24 16:04:06 UTC (rev 14683)
@@ -2249,7 +2249,7 @@
 	LWLINE *line;
 	LWPOINT *lwpoint;
 	POINT4D newpoint;
-	uint32 which;
+	int32 which;
 
 	POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
 
@@ -2279,9 +2279,13 @@
 		elog(ERROR, "First argument must be a LINESTRING");
 		PG_RETURN_NULL();
 	}
-	if ( which > line->points->npoints-1 )
+	if(which < 0){
+		/* Use backward indexing for negative values */
+		which = which + line->points->npoints ;
+	}
+	if ( which > line->points->npoints-1 || which < 0 )
 	{
-		elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
+		elog(ERROR, "abs(Point index) out of range (-)(%d..%d)", 0, line->points->npoints-1);
 		PG_RETURN_NULL();
 	}
 

Modified: trunk/postgis/lwgeom_ogc.c
===================================================================
--- trunk/postgis/lwgeom_ogc.c	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/postgis/lwgeom_ogc.c	2016-02-24 16:04:06 UTC (rev 14683)
@@ -545,11 +545,23 @@
 	LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
 	LWPOINT *lwpoint = NULL;
 	int type = lwgeom->type;
+
+	/* If index is negative, count backward */  
+	if( where < 1 )
+	{
+		int count = -1; 
+		if ( type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE )
+			count = lwgeom_count_vertices(lwgeom);
+		if(count >0)
+		{
+			/* only work if we found the total point number */
+			/* converting where to positive backward indexing, +1 because 1 indexing */
+			where = where + count + 1;
+		}
+		if (where < 1)
+			PG_RETURN_NULL();
+	}
 	
-	/* Can't handle crazy index! */
-	if ( where < 1 )
-		PG_RETURN_NULL();
-
 	if ( type == LINETYPE || type == CIRCSTRINGTYPE )
 	{
 		/* OGC index starts at one, so we substract first. */

Modified: trunk/regress/regress_ogc.sql
===================================================================
--- trunk/regress/regress_ogc.sql	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/regress/regress_ogc.sql	2016-02-24 16:04:06 UTC (rev 14683)
@@ -192,6 +192,9 @@
 select 'ST_PointN4', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)'::geometry,0));
 select 'ST_PointN5', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2)'::geometry,1));
 select 'ST_PointN6', ST_AsText(ST_PointN('POLYGON((0 0, 1 1, 0 1, 0 0))'::geometry,1));
+select 'ST_PointN7', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2,3 3, 4 4)'::geometry,-2)); --testing negativ index
+select 'ST_PointN8', ST_AsText(ST_PointN('LINESTRING(0 0, 1 1, 2 2,3 3, 4 4)'::geometry,-6));
+select 'ST_PointN9', ST_AsText(ST_PointN('LINESTRING(0 0 0, 1 1 1,2 2 2,3 3 3,4 4 4)'::geometry,2)); --testing 3D
 
 -- issues with EMPTY --
 select 'ST_Buffer(empty)', ST_AsText(ST_Buffer('POLYGON EMPTY'::geometry, 0.5));

Modified: trunk/regress/regress_ogc_expected
===================================================================
--- trunk/regress/regress_ogc_expected	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/regress/regress_ogc_expected	2016-02-24 16:04:06 UTC (rev 14683)
@@ -112,4 +112,7 @@
 ST_PointN4|
 ST_PointN5|POINT(0 0)
 ST_PointN6|
+ST_PointN7|POINT(3 3)
+ST_PointN8|
+ST_PointN9|POINT Z (1 1 1)
 ST_Buffer(empty)|POLYGON EMPTY

Modified: trunk/regress/setpoint.sql
===================================================================
--- trunk/regress/setpoint.sql	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/regress/setpoint.sql	2016-02-24 16:04:06 UTC (rev 14683)
@@ -1,7 +1,8 @@
 -- Repeat all tests with new function names.
 --  Out of range indexes
 SELECT ST_SetPoint('LINESTRING(0 0, 1 1, 2 2)', 3, 'POINT(9 9)');
-SELECT ST_SetPoint('LINESTRING(0 0, 1 1, 2 2)', -1, 'POINT(9 9)');
+SELECT ST_asewkt(ST_SetPoint('LINESTRING(0 0, 1 1, 2 2)', -1, 'POINT(9 9)'));
+SELECT ST_SetPoint('LINESTRING(0 0, 1 1, 2 2)', -10, 'POINT(9 9)');
 
 --  Invalid inputs
 SELECT ST_SetPoint('MULTIPOINT(0 0, 1 1, 2 2)', 3, 'POINT(9 9)');

Modified: trunk/regress/setpoint_expected
===================================================================
--- trunk/regress/setpoint_expected	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/regress/setpoint_expected	2016-02-24 16:04:06 UTC (rev 14683)
@@ -1,5 +1,6 @@
-ERROR:  Point index out of range (0..2)
-ERROR:  Point index out of range (0..2)
+ERROR:  abs(Point index) out of range (-)(0..2)
+LINESTRING(0 0,1 1,9 9)
+ERROR:  abs(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)

Modified: trunk/regress/sfcgal/regress_ogc_expected
===================================================================
--- trunk/regress/sfcgal/regress_ogc_expected	2016-02-24 16:02:25 UTC (rev 14682)
+++ trunk/regress/sfcgal/regress_ogc_expected	2016-02-24 16:04:06 UTC (rev 14683)
@@ -112,4 +112,7 @@
 ST_PointN4|
 ST_PointN5|POINT(0 0)
 ST_PointN6|
+ST_PointN7|POINT(3 3)
+ST_PointN8|
+ST_PointN9|POINT Z (1 1 1)
 ST_Buffer(empty)|POLYGON EMPTY



More information about the postgis-tickets mailing list