]> granicus.if.org Git - postgis/commitdiff
Added force_3d
authorSandro Santilli <strk@keybit.net>
Wed, 25 Aug 2004 13:41:43 +0000 (13:41 +0000)
committerSandro Santilli <strk@keybit.net>
Wed, 25 Aug 2004 13:41:43 +0000 (13:41 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@747 b70326c6-7e19-0410-871a-916f4a2858ee

lwgeom/MISSING_OBJECTS
lwgeom/lwgeom_functions_basic.c
lwgeom/lwpostgis.sql.in

index 8928427ee23e53501ee11bdad96a68faf6a3cb70..d804b737ab4aff785fb7e37f8f6b6d341307be83 100644 (file)
@@ -76,8 +76,6 @@ FUNC: KEEPING FUNCTION: [isring(geometry)]
 FUNC: KEEPING FUNCTION: [pointonsurface(geometry)]
 FUNC: KEEPING FUNCTION: [collector(geometry, geometry)]
 
-FUNC: KEEPING FUNCTION: [force_3d(geometry)]
-
 FUNC: KEEPING FUNCTION: [force_collection(geometry)]
 FUNC: KEEPING FUNCTION: [intersection(geometry, geometry)]
 FUNC: KEEPING FUNCTION: [buffer(geometry, double precision)]
index ee15122aa5ef70450bb6cc432d6e7087bb5c237e..fa8a942bd2124004ccc5f537416044b32a551dba 100644 (file)
@@ -38,10 +38,13 @@ Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS);
 Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS);
 Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS);
 Datum LWGEOM_force_2d(PG_FUNCTION_ARGS);
+Datum LWGEOM_force_3d(PG_FUNCTION_ARGS);
 
 // internal
 char * lwgeom_summary_recursive(char *serialized, int offset);
 int32 lwgeom_npoints_recursive(char *serialized);
+
+// general utilities (might be moved in lwgeom_api.c)
 double lwgeom_polygon_area(LWPOLY *poly);
 double lwgeom_polygon_perimeter(LWPOLY *poly);
 double lwgeom_polygon_perimeter2d(LWPOLY *poly);
@@ -49,6 +52,7 @@ double lwgeom_line_length2d(LWLINE *line);
 double lwgeom_pointarray_length2d(POINTARRAY *pts);
 double lwgeom_pointarray_length(POINTARRAY *pts);
 void lwgeom_force2d_recursive(char *serialized, char *optr, int *retsize);
+void lwgeom_force3d_recursive(char *serialized, char *optr, int *retsize);
 
 /*------------------------------------------------------------------*/
 
@@ -572,6 +576,7 @@ Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
 /*
  * Write to already allocated memory 'optr' a 2d version of
  * the given serialized form. 
+ * Higher dimensions in input geometry are discarder.
  * Return number bytes written in given int pointer.
  */
 void
@@ -685,6 +690,177 @@ elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize);
        *retsize = totsize;
 }
 
+/*
+ * Write to already allocated memory 'optr' a 3d version of
+ * the given serialized form. 
+ * Higher dimensions in input geometry are discarder.
+ * If the given version is 2d Z is set to 0.
+ * Return number bytes written in given int pointer.
+ */
+void
+lwgeom_force3d_recursive(char *serialized, char *optr, int *retsize)
+{
+       LWGEOM_INSPECTED *inspected;
+       int i,j,k;
+       int totsize=0;
+       int size=0;
+       int type;
+       LWPOINT *point = NULL;
+       LWLINE *line = NULL;
+       LWPOLY *poly = NULL;
+       POINTARRAY newpts;
+       POINTARRAY **nrings;
+       char *loc;
+
+               
+#ifdef DEBUG
+       elog(NOTICE, "lwgeom_force3d_recursive: call");
+#endif
+
+       type = lwgeom_getType(serialized[0]);
+
+       if ( type == POINTTYPE )
+       {
+               point = lwpoint_deserialize(serialized);
+               if ( point->ndims < 3 )
+               {
+                       newpts.ndims = 3;
+                       newpts.npoints = 1;
+                       newpts.serialized_pointlist = palloc(sizeof(POINT3D));
+                       loc = newpts.serialized_pointlist;
+                       getPoint3d_p(point->point, 0, loc);
+                       point->point = &newpts;
+               }
+               point->ndims = 3;
+               lwpoint_serialize_buf(point, optr, retsize);
+#ifdef DEBUG
+elog(NOTICE, "lwgeom_force3d_recursive: it's a point, size:%d", *retsize);
+#endif
+               return;
+       }
+
+       if ( type == LINETYPE )
+       {
+#ifdef DEBUG
+elog(NOTICE, "lwgeom_force3d_recursive: it's a line");
+#endif
+               line = lwline_deserialize(serialized);
+               if ( line->ndims < 3 )
+               {
+                       newpts.ndims = 3;
+                       newpts.npoints = line->points->npoints;
+                       newpts.serialized_pointlist = palloc(24*line->points->npoints);
+                       loc = newpts.serialized_pointlist;
+                       for (j=0; j<line->points->npoints; j++)
+                       {
+                               getPoint3d_p(line->points, j, loc);
+                               loc+=24;
+                       }
+                       line->points = &newpts;
+               }
+
+               line->ndims = 3;
+               lwline_serialize_buf(line, optr, retsize);
+#ifdef DEBUG
+elog(NOTICE, "lwgeom_force3d_recursive: it's a line, size:%d", *retsize);
+#endif
+               return;
+       }
+
+       if ( type == POLYGONTYPE )
+       {
+               poly = lwpoly_deserialize(serialized);
+               if ( poly->ndims < 3 )
+               {
+                       newpts.ndims = 3;
+                       newpts.npoints = 0;
+                       newpts.serialized_pointlist = palloc(1);
+                       nrings = palloc(sizeof(POINTARRAY *)*poly->nrings);
+                       loc = newpts.serialized_pointlist;
+                       for (j=0; j<poly->nrings; j++)
+                       {
+                               POINTARRAY *ring = poly->rings[j];
+                               POINTARRAY *nring = palloc(sizeof(POINTARRAY));
+                               nring->ndims = 2;
+                               nring->npoints = ring->npoints;
+                               nring->serialized_pointlist =
+                                       palloc(ring->npoints*24);
+                               loc = nring->serialized_pointlist;
+                               for (k=0; k<ring->npoints; k++)
+                               {
+                                       getPoint3d_p(ring, k, loc);
+                                       loc+=24;
+                               }
+                               nrings[j] = nring;
+                       }
+                       poly->rings = nrings;
+               }
+               poly->ndims = 3;
+               lwpoly_serialize_buf(poly, optr, retsize);
+#ifdef DEBUG
+elog(NOTICE, "lwgeom_force3d_recursive: it's a poly, size:%d", *retsize);
+#endif
+               return;
+       }
+
+       // OK, this is a collection, so we write down its metadata
+       // first and then call us again
+
+#ifdef DEBUG
+elog(NOTICE, "lwgeom_force3d_recursive: it's a collection (type:%d)", type);
+#endif
+
+       // Add type
+       *optr = lwgeom_makeType_full(3, lwgeom_hasSRID(serialized[0]),
+               type, lwgeom_hasBBOX(serialized[0]));
+       optr++;
+       totsize++;
+       loc=serialized+1;
+
+       // Add BBOX if any
+       if (lwgeom_hasBBOX(serialized[0]))
+       {
+               memcpy(optr, loc, sizeof(BOX2DFLOAT4));
+               optr += sizeof(BOX2DFLOAT4);
+               totsize += sizeof(BOX2DFLOAT4);
+               loc += sizeof(BOX2DFLOAT4);
+       }
+
+       // Add SRID if any
+       if (lwgeom_hasSRID(serialized[0]))
+       {
+               memcpy(optr, loc, 4);
+               optr += 4;
+               totsize += 4;
+               loc += 4;
+       }
+
+       // Add numsubobjects
+       memcpy(optr, loc, 4);
+       optr += 4;
+       totsize += 4;
+
+#ifdef DEBUG
+elog(NOTICE, " collection header size:%d", totsize);
+#endif
+
+       // Now recurse for each suboject
+       inspected = lwgeom_inspect(serialized);
+       for (i=0; i<inspected->ngeometries; i++)
+       {
+               char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
+               lwgeom_force3d_recursive(subgeom, optr, &size);
+               totsize += size;
+               optr += size;
+#ifdef DEBUG
+elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize);
+#endif
+       }
+       pfree_inspected(inspected);
+
+       *retsize = totsize;
+}
+
 // transform input geometry to 2d if not 2d already
 PG_FUNCTION_INFO_V1(LWGEOM_force_2d);
 Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
@@ -710,3 +886,36 @@ Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
 
        PG_RETURN_POINTER(result);
 }
+
+// transform input geometry to 3d if not 2d already
+PG_FUNCTION_INFO_V1(LWGEOM_force_3d);
+Datum LWGEOM_force_3d(PG_FUNCTION_ARGS)
+{
+       LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       LWGEOM *result;
+       int olddims;
+       int32 size = 0;
+
+       olddims = lwgeom_ndims(geom->type);
+       
+       // already 3d
+       if ( olddims == 3 ) PG_RETURN_POINTER(geom);
+
+       if ( olddims > 3 ) {
+               result = (LWGEOM *) palloc(geom->size);
+       } else {
+               // allocate double as memory a larger for safety 
+               result = (LWGEOM *) palloc(geom->size*1.5);
+       }
+
+       lwgeom_force3d_recursive(SERIALIZED_FORM(geom),
+               SERIALIZED_FORM(result), &size);
+
+       // we can safely avoid this... memory will be freed at
+       // end of query processing anyway.
+       //result = repalloc(result, size+4);
+
+       result->size = size+4;
+
+       PG_RETURN_POINTER(result);
+}
index bfda37af2ef9ef58aade40ce00a1429207d808b0..062571328ea052410252dc75754bc6589cd0c712 100644 (file)
@@ -942,6 +942,11 @@ CREATEFUNCTION force_2d(geometry)
        AS '@MODULE_FILENAME@', 'LWGEOM_force_2d'
        LANGUAGE 'C' WITH (isstrict);
 
+CREATEFUNCTION force_3d(geometry) 
+       RETURNS geometry
+       AS '@MODULE_FILENAME@', 'LWGEOM_force_3d'
+       LANGUAGE 'C' WITH (isstrict);
+
 ------------------------------------------------------------------------
 
 --