From: Sandro Santilli Date: Wed, 25 Aug 2004 13:41:43 +0000 (+0000) Subject: Added force_3d X-Git-Tag: pgis_0_9_1~47 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ea9fd3e3d399cd2c3516023e469fb6c6bbdd50de;p=postgis Added force_3d git-svn-id: http://svn.osgeo.org/postgis/trunk@747 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/lwgeom/MISSING_OBJECTS b/lwgeom/MISSING_OBJECTS index 8928427ee..d804b737a 100644 --- a/lwgeom/MISSING_OBJECTS +++ b/lwgeom/MISSING_OBJECTS @@ -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)] diff --git a/lwgeom/lwgeom_functions_basic.c b/lwgeom/lwgeom_functions_basic.c index ee15122aa..fa8a942bd 100644 --- a/lwgeom/lwgeom_functions_basic.c +++ b/lwgeom/lwgeom_functions_basic.c @@ -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; jpoints->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; jnrings; 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; knpoints; 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; ingeometries; 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); +} diff --git a/lwgeom/lwpostgis.sql.in b/lwgeom/lwpostgis.sql.in index bfda37af2..062571328 100644 --- a/lwgeom/lwpostgis.sql.in +++ b/lwgeom/lwpostgis.sql.in @@ -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); + ------------------------------------------------------------------------ --