From: Sandro Santilli Date: Mon, 20 Sep 2004 17:03:41 +0000 (+0000) Subject: Added force_4d(geometry) X-Git-Tag: pgis_1_0_0RC1~417 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=31b86139f9e7e3ff9202122c2c9d9f89f57f9196;p=postgis Added force_4d(geometry) git-svn-id: http://svn.osgeo.org/postgis/trunk@855 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/doc/postgis.xml b/doc/postgis.xml index 82387d617..500e82769 100644 --- a/doc/postgis.xml +++ b/doc/postgis.xml @@ -3572,6 +3572,16 @@ dimension + + force_4d(geometry) + + + Forces the geometries into a "4-dimensional mode" so that + all output representations will have the X, Y, Z and M + coordinates. + + + length2d(geometry) diff --git a/lwgeom/lwgeom.h b/lwgeom/lwgeom.h index a45784a47..0b4828bef 100644 --- a/lwgeom/lwgeom.h +++ b/lwgeom/lwgeom.h @@ -759,6 +759,7 @@ 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); +void lwgeom_force4d_recursive(char *serialized, char *optr, int *retsize); double distance2d_pt_pt(POINT2D *p1, POINT2D *p2); double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B); double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D); diff --git a/lwgeom/lwgeom_functions_basic.c b/lwgeom/lwgeom_functions_basic.c index c3264caf8..1b6574fc5 100644 --- a/lwgeom/lwgeom_functions_basic.c +++ b/lwgeom/lwgeom_functions_basic.c @@ -28,6 +28,7 @@ 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); +Datum LWGEOM_force_4d(PG_FUNCTION_ARGS); Datum LWGEOM_force_collection(PG_FUNCTION_ARGS); Datum LWGEOM_force_multi(PG_FUNCTION_ARGS); Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS); @@ -1451,7 +1452,7 @@ elog(NOTICE, "lwgeom_force3d_recursive: it's a line, size:%d", *retsize); { POINTARRAY *ring = poly->rings[j]; POINTARRAY *nring = palloc(sizeof(POINTARRAY)); - nring->ndims = 2; + nring->ndims = 3; nring->npoints = ring->npoints; nring->serialized_pointlist = palloc(ring->npoints*24); @@ -1531,6 +1532,176 @@ elog(NOTICE, " elem %d size: %d (tot: %d)", i, size, totsize); *retsize = totsize; } +/* + * Write to already allocated memory 'optr' a 4d version of + * the given serialized form. + * Pad dimensions are set to 0. + * Return number bytes written in given int pointer. + */ +void +lwgeom_force4d_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_force4d_recursive: call"); +#endif + + type = lwgeom_getType(serialized[0]); + + if ( type == POINTTYPE ) + { + point = lwpoint_deserialize(serialized); + if ( point->ndims < 4 ) + { + newpts.ndims = 4; + newpts.npoints = 1; + newpts.serialized_pointlist = palloc(sizeof(POINT4D)); + loc = newpts.serialized_pointlist; + getPoint4d_p(point->point, 0, loc); + point->point = &newpts; + } + point->ndims = 4; + lwpoint_serialize_buf(point, optr, retsize); +#ifdef DEBUG +elog(NOTICE, "lwgeom_force4d_recursive: it's a point, size:%d", *retsize); +#endif + return; + } + + if ( type == LINETYPE ) + { +#ifdef DEBUG +elog(NOTICE, "lwgeom_force4d_recursive: it's a line"); +#endif + line = lwline_deserialize(serialized); + if ( line->ndims < 4 ) + { + newpts.ndims = 4; + newpts.npoints = line->points->npoints; + newpts.serialized_pointlist = palloc(sizeof(POINT4D)*line->points->npoints); + loc = newpts.serialized_pointlist; + for (j=0; jpoints->npoints; j++) + { + getPoint4d_p(line->points, j, loc); + loc+=sizeof(POINT4D); + } + line->points = &newpts; + } + + line->ndims = 4; + lwline_serialize_buf(line, optr, retsize); +#ifdef DEBUG +elog(NOTICE, "lwgeom_force4d_recursive: it's a line, size:%d", *retsize); +#endif + return; + } + + if ( type == POLYGONTYPE ) + { + poly = lwpoly_deserialize(serialized); + if ( poly->ndims < 4 ) + { + newpts.ndims = 4; + 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 = 4; + nring->npoints = ring->npoints; + nring->serialized_pointlist = + palloc(ring->npoints*sizeof(POINT4D)); + loc = nring->serialized_pointlist; + for (k=0; knpoints; k++) + { + getPoint4d_p(ring, k, loc); + loc+=sizeof(POINT4D); + } + nrings[j] = nring; + } + poly->rings = nrings; + } + poly->ndims = 4; + lwpoly_serialize_buf(poly, optr, retsize); +#ifdef DEBUG +elog(NOTICE, "lwgeom_force4d_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_force4d_recursive: it's a collection (type:%d)", type); +#endif + + // Add type + *optr = lwgeom_makeType_full(4, 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_force4d_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) @@ -1557,7 +1728,7 @@ Datum LWGEOM_force_2d(PG_FUNCTION_ARGS) PG_RETURN_POINTER(result); } -// transform input geometry to 3d if not 2d already +// transform input geometry to 3d if not 3d already PG_FUNCTION_INFO_V1(LWGEOM_force_3d); Datum LWGEOM_force_3d(PG_FUNCTION_ARGS) { @@ -1590,6 +1761,35 @@ Datum LWGEOM_force_3d(PG_FUNCTION_ARGS) PG_RETURN_POINTER(result); } +// transform input geometry to 4d if not 4d already +PG_FUNCTION_INFO_V1(LWGEOM_force_4d); +Datum LWGEOM_force_4d(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 4d + if ( olddims == 4 ) PG_RETURN_POINTER(geom); + + // allocate double as memory a larger for safety + result = (LWGEOM *) palloc(geom->size*2); + + lwgeom_force4d_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); +} + // transform input geometry to a collection type PG_FUNCTION_INFO_V1(LWGEOM_force_collection); Datum LWGEOM_force_collection(PG_FUNCTION_ARGS) diff --git a/lwgeom/lwpostgis.sql.in b/lwgeom/lwpostgis.sql.in index 06ab72bf0..373883f9a 100644 --- a/lwgeom/lwpostgis.sql.in +++ b/lwgeom/lwpostgis.sql.in @@ -1544,6 +1544,11 @@ CREATEFUNCTION force_3d(geometry) AS '@MODULE_FILENAME@', 'LWGEOM_force_3d' LANGUAGE 'C' WITH (isstrict); +CREATEFUNCTION force_4d(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@', 'LWGEOM_force_4d' + LANGUAGE 'C' WITH (isstrict); + CREATEFUNCTION force_collection(geometry) RETURNS geometry AS '@MODULE_FILENAME@', 'LWGEOM_force_collection'