[postgis-commits] svn - r2713 - trunk/lwgeom

postgis-commits at postgis.refractions.net postgis-commits at postgis.refractions.net
Mon Oct 29 06:44:31 PDT 2007


Author: mcayland
Date: 2007-10-29 06:44:29 -0700 (Mon, 29 Oct 2007)
New Revision: 2713

Modified:
   trunk/lwgeom/lwgeom_box2dfloat4.c
   trunk/lwgeom/lwgeom_box3d.c
   trunk/lwgeom/lwgeom_functions_basic.c
Log:
Commit Charlie Savage's patches (with additional comments) to the bounding box/envelope functions to ensure that valid geometries are always returned; in more specific terms, if a bounding box is a point then a POINT is returned, and if a bounding box is 1-dimensional a LINESTRING is returned. Otherwise a POLYGON is returned as per the old behaviour. For details see the thread in the postgis-users archives Sept 2007 'How to get the centroid of an bounding box using st_extent'.

Modified: trunk/lwgeom/lwgeom_box2dfloat4.c
===================================================================
--- trunk/lwgeom/lwgeom_box2dfloat4.c	2007-10-29 12:34:17 UTC (rev 2712)
+++ trunk/lwgeom/lwgeom_box2dfloat4.c	2007-10-29 13:44:29 UTC (rev 2713)
@@ -456,32 +456,69 @@
 Datum BOX2DFLOAT4_to_LWGEOM(PG_FUNCTION_ARGS)
 {
 	BOX2DFLOAT4 *box = (BOX2DFLOAT4 *)PG_GETARG_POINTER(0);
-	POINT2D *pts = palloc(sizeof(POINT2D)*5);
-	POINTARRAY *pa[1];
-	LWPOLY *poly;
+	POINTARRAY *pa;
 	int wantbbox = 0;
 	PG_LWGEOM *result;
 	uchar *ser;
 
-	/* Assign coordinates to POINT2D array */
-	pts[0].x = box->xmin; pts[0].y = box->ymin;
-	pts[1].x = box->xmin; pts[1].y = box->ymax;
-	pts[2].x = box->xmax; pts[2].y = box->ymax;
-	pts[3].x = box->xmax; pts[3].y = box->ymin;
-	pts[4].x = box->xmin; pts[4].y = box->ymin;
 
-	/* Construct point array */
-	pa[0] = palloc(sizeof(POINTARRAY));
-	pa[0]->serialized_pointlist = (uchar *)pts;
-	TYPE_SETZM(pa[0]->dims, 0, 0);
-	pa[0]->npoints = 5;
+	/* 
+	 * Alter BOX2D cast so that a valid geometry is always
+	 * returned depending upon the size of the BOX2D. The
+	 * code makes the following assumptions:
+	 *     - If the BOX2D is a single point then return a
+	 *     POINT geometry
+	 *     - If the BOX2D represents either a horizontal or
+	 *     vertical line, return a LINESTRING geometry
+	 *     - Otherwise return a POLYGON
+	 */
 
-	/* Construct polygon */
-	poly = lwpoly_construct(-1, NULL, 1, pa);
+	if (box->xmin == box->xmax &&
+	    box->ymin == box->ymax)
+        {
+	  /* Construct and serialize point */
+          LWPOINT *point = make_lwpoint2d(-1, box->xmin, box->ymin);
+   	  ser = lwpoint_serialize(point);
+        }
+	else if (box->xmin == box->xmax ||
+	         box->ymin == box->ymax)
+        {
+  	  LWLINE *line;
+	  POINT2D *pts = palloc(sizeof(POINT2D)*2);
+	  
+	  /* Assign coordinates to POINT2D array */
+	  pts[0].x = box->xmin; pts[0].y = box->ymin;
+	  pts[1].x = box->xmax; pts[1].y = box->ymax;
+	  
+	  /* Construct point array */
+          pa = pointArray_construct((uchar *)pts, 0, 0, 2);	  
 
-	/* Serialize polygon */
-	ser = lwpoly_serialize(poly);
+	  /* Construct and serialize linestring */
+	  line = lwline_construct(-1, NULL, pa);
+	  ser = lwline_serialize(line);
+        }
+        else
+        {
+  	  LWPOLY *poly;
+	  POINT2D *pts = palloc(sizeof(POINT2D)*5);
 
+	  /* Assign coordinates to POINT2D array */
+	  pts[0].x = box->xmin; pts[0].y = box->ymin;
+	  pts[1].x = box->xmin; pts[1].y = box->ymax;
+	  pts[2].x = box->xmax; pts[2].y = box->ymax;
+	  pts[3].x = box->xmax; pts[3].y = box->ymin;
+	  pts[4].x = box->xmin; pts[4].y = box->ymin;
+
+	  /* Construct point array */
+          pa = pointArray_construct((uchar *)pts, 0, 0, 5);	  
+
+	  /* Construct polygon */
+	  poly = lwpoly_construct(-1, NULL, 1, &pa);
+
+	  /* Serialize polygon */
+	  ser = lwpoly_serialize(poly);
+        }
+        
 	/* Construct PG_LWGEOM  */
 	result = PG_LWGEOM_construct(ser, -1, wantbbox);
 	

Modified: trunk/lwgeom/lwgeom_box3d.c
===================================================================
--- trunk/lwgeom/lwgeom_box3d.c	2007-10-29 12:34:17 UTC (rev 2712)
+++ trunk/lwgeom/lwgeom_box3d.c	2007-10-29 13:44:29 UTC (rev 2713)
@@ -162,32 +162,69 @@
 Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
 {
 	BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
-	POINT2D *pts = palloc(sizeof(POINT2D)*5);
-	POINTARRAY *pa[1];
-	LWPOLY *poly;
+	POINTARRAY *pa;
 	int wantbbox = 0;
 	PG_LWGEOM *result;
 	uchar *ser;
 
-	/* Assign coordinates to POINT2D array */
-	pts[0].x = box->xmin; pts[0].y = box->ymin;
-	pts[1].x = box->xmin; pts[1].y = box->ymax;
-	pts[2].x = box->xmax; pts[2].y = box->ymax;
-	pts[3].x = box->xmax; pts[3].y = box->ymin;
-	pts[4].x = box->xmin; pts[4].y = box->ymin;
 
-	/* Construct point array */
-	pa[0] = palloc(sizeof(POINTARRAY));
-	pa[0]->serialized_pointlist = (uchar *)pts;
-	TYPE_SETZM(pa[0]->dims, 0, 0);
-	pa[0]->npoints = 5;
+	/* 
+	 * Alter BOX3D cast so that a valid geometry is always
+	 * returned depending upon the size of the BOX3D. The
+	 * code makes the following assumptions:
+	 *     - If the BOX3D is a single point then return a
+	 *     POINT geometry
+	 *     - If the BOX3D represents either a horizontal or
+	 *     vertical line, return a LINESTRING geometry
+	 *     - Otherwise return a POLYGON
+	 */
 
-	/* Construct polygon */
-	poly = lwpoly_construct(-1, NULL, 1, pa);
+	if (box->xmin == box->xmax &&
+	    box->ymin == box->ymax)
+        {
+	  /* Construct and serialize point */
+          LWPOINT *point = make_lwpoint2d(-1, box->xmin, box->ymin);
+   	  ser = lwpoint_serialize(point);
+        }
+	else if (box->xmin == box->xmax ||
+	         box->ymin == box->ymax)
+        {
+  	  LWLINE *line;
+	  POINT2D *pts = palloc(sizeof(POINT2D)*2);
+	  
+	  /* Assign coordinates to POINT2D array */
+	  pts[0].x = box->xmin; pts[0].y = box->ymin;
+	  pts[1].x = box->xmax; pts[1].y = box->ymax;
+	  
+	  /* Construct point array */
+          pa = pointArray_construct((uchar *)pts, 0, 0, 2);	  
 
-	/* Serialize polygon */
-	ser = lwpoly_serialize(poly);
+	  /* Construct and serialize linestring */
+	  line = lwline_construct(-1, NULL, pa);
+	  ser = lwline_serialize(line);
+        }
+        else
+        {
+  	  LWPOLY *poly;
+	  POINT2D *pts = palloc(sizeof(POINT2D)*5);
 
+	  /* Assign coordinates to POINT2D array */
+	  pts[0].x = box->xmin; pts[0].y = box->ymin;
+	  pts[1].x = box->xmin; pts[1].y = box->ymax;
+	  pts[2].x = box->xmax; pts[2].y = box->ymax;
+	  pts[3].x = box->xmax; pts[3].y = box->ymin;
+	  pts[4].x = box->xmin; pts[4].y = box->ymin;
+
+	  /* Construct point array */
+          pa = pointArray_construct((uchar *)pts, 0, 0, 5);	  
+
+	  /* Construct polygon */
+	  poly = lwpoly_construct(-1, NULL, 1, &pa);
+
+	  /* Serialize polygon */
+	  ser = lwpoly_serialize(poly);
+        }
+        
 	/* Construct PG_LWGEOM  */
 	result = PG_LWGEOM_construct(ser, -1, wantbbox);
 	

Modified: trunk/lwgeom/lwgeom_functions_basic.c
===================================================================
--- trunk/lwgeom/lwgeom_functions_basic.c	2007-10-29 12:34:17 UTC (rev 2712)
+++ trunk/lwgeom/lwgeom_functions_basic.c	2007-10-29 13:44:29 UTC (rev 2713)
@@ -2493,56 +2493,86 @@
 Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
 {
 	PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-	BOX2DFLOAT4 box;
-	POINT2D *pts = lwalloc(sizeof(POINT2D)*5);
-	POINTARRAY *pa[1];
-	LWPOLY *poly;
+	BOX3D box;
 	int SRID;
+	POINTARRAY *pa;
 	PG_LWGEOM *result;
-	uchar *ser;
+	uchar *ser = NULL;
 
-	if (lwgeom_getType(geom->type) == POINTTYPE ||
-            (lwgeom_getType(geom->type) == MULTIPOINTTYPE && lwgeom_getnumgeometries(SERIALIZED_FORM(geom)) == 1))
-	{
-		int srid = lwgeom_getsrid(SERIALIZED_FORM(geom));
-		LWPOINT* point = lwgeom_getpoint(SERIALIZED_FORM(geom), 0);
-		LWPOINT* envelope = lwpoint_construct(srid, NULL, point->point);
-		ser = lwpoint_serialize(envelope);
-		result = PG_LWGEOM_construct(ser, srid, 0);
-	PG_RETURN_POINTER(result);
-	}
 
 	/* get bounding box  */
-	if ( ! getbox2d_p(SERIALIZED_FORM(geom), &box) )
+	if ( ! compute_serialized_box3d_p(SERIALIZED_FORM(geom), &box) )
 	{
 		/* must be the EMPTY geometry */
 		PG_RETURN_POINTER(geom);
 	}
-
+	
 	/* get geometry SRID */
 	SRID = lwgeom_getsrid(SERIALIZED_FORM(geom));
 
-	PG_FREE_IF_COPY(geom, 0);
+	
+	/* 
+	 * Alter envelope type so that a valid geometry is always
+	 * returned depending upon the size of the geometry. The
+	 * code makes the following assumptions:
+	 *     - If the bounding box is a single point then return a
+	 *     POINT geometry
+	 *     - If the bounding box represents either a horizontal or
+	 *     vertical line, return a LINESTRING geometry
+	 *     - Otherwise return a POLYGON
+	 */
 
-	/* Assign coordinates to POINT2D array */
-	pts[0].x = box.xmin; pts[0].y = box.ymin;
-	pts[1].x = box.xmin; pts[1].y = box.ymax;
-	pts[2].x = box.xmax; pts[2].y = box.ymax;
-	pts[3].x = box.xmax; pts[3].y = box.ymin;
-	pts[4].x = box.xmin; pts[4].y = box.ymin;
 
-	/* Construct point array */
-	pa[0] = lwalloc(sizeof(POINTARRAY));
-	pa[0]->serialized_pointlist = (uchar *)pts;
-	TYPE_SETZM(pa[0]->dims, 0, 0);
-	pa[0]->npoints = 5;
+	if (box.xmin == box.xmax &&
+	    box.ymin == box.ymax)
+        {
+                /* Construct and serialize point */
+                LWPOINT *point = make_lwpoint2d(SRID, box.xmin, box.ymin);
+                ser = lwpoint_serialize(point);
+        }
+	else if (box.xmin == box.xmax ||
+	         box.ymin == box.ymax)
+        {
+                LWLINE *line;
+                POINT2D *pts = palloc(sizeof(POINT2D)*2);
 
-	/* Construct polygon  */
-	poly = lwpoly_construct(SRID, box2d_clone(&box), 1, pa);
+                /* Assign coordinates to POINT2D array */
+                pts[0].x = box.xmin; pts[0].y = box.ymin;
+                pts[1].x = box.xmax; pts[1].y = box.ymax;
 
-	/* Serialize polygon */
-	ser = lwpoly_serialize(poly);
+                /* Construct point array */
+                pa = pointArray_construct((uchar *)pts, 0, 0, 2);	  
 
+                /* Construct and serialize linestring */
+                line = lwline_construct(SRID, NULL, pa);
+                ser = lwline_serialize(line);
+        }
+        else
+        {
+                LWPOLY *poly;
+	        POINT2D *pts = lwalloc(sizeof(POINT2D)*5);
+                BOX2DFLOAT4 box2d;
+                getbox2d_p(SERIALIZED_FORM(geom), &box2d);
+  		
+                /* Assign coordinates to POINT2D array */
+                pts[0].x = box2d.xmin; pts[0].y = box2d.ymin;
+                pts[1].x = box2d.xmin; pts[1].y = box2d.ymax;
+                pts[2].x = box2d.xmax; pts[2].y = box2d.ymax;
+                pts[3].x = box2d.xmax; pts[3].y = box2d.ymin;
+                pts[4].x = box2d.xmin; pts[4].y = box2d.ymin;
+
+                /* Construct point array */
+                pa = pointArray_construct((uchar *)pts, 0, 0, 5);
+
+                /* Construct polygon  */
+                poly = lwpoly_construct(SRID, box2d_clone(&box2d), 1, &pa);
+
+                /* Serialize polygon */
+                ser = lwpoly_serialize(poly);
+        }
+			
+	PG_FREE_IF_COPY(geom, 0);
+
 	/* Construct PG_LWGEOM  */
 	result = PG_LWGEOM_construct(ser, SRID, 1);
 



More information about the postgis-commits mailing list