From: Sandro Santilli Date: Thu, 23 Sep 2004 15:09:07 +0000 (+0000) Subject: Modified GML output as suggested by Martin Daly. X-Git-Tag: pgis_1_0_0RC1~384 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=40bd206c26aafb5634a57db253924c4b95581bec;p=postgis Modified GML output as suggested by Martin Daly. git-svn-id: http://svn.osgeo.org/postgis/trunk@888 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/lwgeom/lwgeom_gml.c b/lwgeom/lwgeom_gml.c index ab20d3591..e48374b3f 100644 --- a/lwgeom/lwgeom_gml.c +++ b/lwgeom/lwgeom_gml.c @@ -16,18 +16,31 @@ #include "postgres.h" +#include "executor/spi.h" #include "lwgeom.h" Datum LWGEOM_asGML(PG_FUNCTION_ARGS); -char *geometry_to_gml(LWGEOM *geometry, int version); -static char *asgml_point(LWPOINT *point, int version); -static char *asgml_line(LWLINE *line, int version); -static char *asgml_poly(LWPOLY *poly, int version); -static size_t pointArray_GMLsize(POINTARRAY *pa, int version); -static size_t pointArray_toGML(POINTARRAY *pa, int version, char *buf); +char *geometry_to_gml(char *lwgeom, char *srs); + +static size_t asgml_point_size(LWPOINT *point, char *srs); +static char *asgml_point(LWPOINT *point, char *srs); +static size_t asgml_line_size(LWLINE *line, char *srs); +static char *asgml_line(LWLINE *line, char *srs); +static size_t asgml_poly_size(LWPOLY *poly, char *srs); +static char *asgml_poly(LWPOLY *poly, char *srs); +static size_t asgml_inspected_size(LWGEOM_INSPECTED *geom, char *srs); +static char *asgml_inspected(LWGEOM_INSPECTED *geom, char *srs); +static size_t pointArray_GMLsize(POINTARRAY *pa); +static size_t pointArray_toGML(POINTARRAY *pa, char *buf); +static char *getSRSbySRID(int SRID); + +#define DEF_PRECISION 15 +// Add dot, sign, exponent sign, 'e', exponent digits +#define SHOW_DIGS (precision + 8) + +/* Globals */ +unsigned int precision; -#define SHOW_DIGS_DOUBLE 15 -#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) /** * Encode feature in GML @@ -39,151 +52,360 @@ Datum LWGEOM_asGML(PG_FUNCTION_ARGS) char *gml; char *result; int len; - int version=0; + int version = 2; + precision = DEF_PRECISION; + char *srs; + int SRID; if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - // check for relative path notation + // Get precision (if provided) if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) ) - version = PG_GETARG_INT32(1); + precision = PG_GETARG_INT32(1); + + if ( precision < 1 || precision > 15 ) + { + elog(ERROR, "Precision out of range 1..15"); + PG_RETURN_NULL(); + } + + // Get version (if provided) + if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) ) + version = PG_GETARG_INT32(2); + + + if ( version != 2 ) + { + elog(ERROR, "Only GML 2 is supported"); + PG_RETURN_NULL(); + } + + SRID = lwgeom_getsrid(SERIALIZED_FORM(geom)); + if ( SRID != -1 ) srs = getSRSbySRID(SRID); + else srs = NULL; - gml = geometry_to_gml(geom, version); + //elog(NOTICE, "srs=%s", srs); + + gml = geometry_to_gml(SERIALIZED_FORM(geom), srs); + PG_FREE_IF_COPY(geom, 0); len = strlen(gml) + 5; - result= palloc(len); + result = palloc(len); *((int *) result) = len; - memcpy(result +4, gml, len-4); + memcpy(result+4, gml, len-4); pfree(gml); - PG_FREE_IF_COPY(geom, 0); PG_RETURN_CSTRING(result); } - // takes a GEOMETRY and returns a GML representation -char *geometry_to_gml(LWGEOM *geometry, int version) +char *geometry_to_gml(char *geom, char *srs) { - char *result = NULL; + int type; + LWPOINT *point; + LWLINE *line; + LWPOLY *poly; LWGEOM_INSPECTED *inspected; - int i; - if (lwgeom_getType(geometry->type) >= 4 ) + type = lwgeom_getType(geom[0]); + + switch (type) { - return pstrdup(""); + + case POINTTYPE: + point = lwpoint_deserialize(geom); + return asgml_point(point, srs); + + case LINETYPE: + line = lwline_deserialize(geom); + return asgml_line(line, srs); + + case POLYGONTYPE: + poly = lwpoly_deserialize(geom); + return asgml_poly(poly, srs); + + default: + inspected = lwgeom_inspect(geom); + return asgml_inspected(inspected, srs); } +} - inspected = lwgeom_inspect(SERIALIZED_FORM(geometry)); - for(i=0; ingeometries; i++) - { - char *subgeom = lwgeom_getsubgeometry_inspected(inspected, i); - LWPOINT *point; - LWLINE *line; - LWPOLY *poly; +static size_t +asgml_point_size(LWPOINT *point, char *srs) +{ + int size; + size = pointArray_GMLsize(point->point); + size += sizeof("/") * 2; + if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); + return size; +} - if (lwgeom_getType(subgeom[0]) == POINTTYPE) - { - point = lwpoint_deserialize(subgeom); - return asgml_point(point, version); - } - if (lwgeom_getType(subgeom[0]) == LINETYPE) - { - line = lwline_deserialize(subgeom); - return asgml_line(line, version); - } - if (lwgeom_getType(subgeom[0]) == POLYGONTYPE) - { - poly = lwpoly_deserialize(subgeom); - return asgml_poly(poly, version); - } +static size_t +asgml_point_buf(LWPOINT *point, char *srs, char *output) +{ + char *ptr = output; + + if ( srs ) { + ptr += sprintf(ptr, "", srs); + } else { + ptr += sprintf(ptr, ""); } - return(result); + ptr += sprintf(ptr, ""); + ptr += pointArray_toGML(point->point, ptr); + ptr += sprintf(ptr, ""); + + return (ptr-output); } static char * -asgml_point(LWPOINT *point, int version) +asgml_point(LWPOINT *point, char *srs) { char *output; int size; - char *ptr; - size = pointArray_GMLsize(point->point, version); - size += sizeof("/") * 2; - + size = asgml_point_size(point, srs); output = palloc(size); - ptr = output; + asgml_point_buf(point, srs, output); + return output; +} - ptr += sprintf(ptr, ""); - ptr += pointArray_toGML(point->point, version, ptr); - ptr += sprintf(ptr, ""); +static size_t +asgml_line_size(LWLINE *line, char *srs) +{ + int size; + size = pointArray_GMLsize(line->points); + size += sizeof("/") * 2; + if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); + return size; +} - return output; +static size_t +asgml_line_buf(LWLINE *line, char *srs, char *output) +{ + char *ptr=output; + + if ( srs ) { + ptr += sprintf(ptr, "", srs); + } else { + ptr += sprintf(ptr, ""); + } + ptr += sprintf(ptr, ""); + ptr += pointArray_toGML(line->points, ptr); + ptr += sprintf(ptr, ""); + + return (ptr-output); } static char * -asgml_line(LWLINE *line, int version) +asgml_line(LWLINE *line, char *srs) { char *output; int size; - char *ptr; - - size = pointArray_GMLsize(line->points, version); - size += sizeof("/") * 2; + size = asgml_line_size(line, srs); output = palloc(size); - ptr = output; + asgml_line_buf(line, srs, output); + return output; +} + +static size_t +asgml_poly_size(LWPOLY *poly, char *srs) +{ + size_t size; + int i; - ptr += sprintf(ptr, ""); - ptr += pointArray_toGML(line->points, version, ptr); - ptr += sprintf(ptr, ""); + size = sizeof(""); + size += sizeof("/") * 2; + size += sizeof("/") * 2 * + poly->nrings; + if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); - return output; + for (i=0; inrings; i++) + size += pointArray_GMLsize(poly->rings[i]); + + return size; +} + +static size_t +asgml_poly_buf(LWPOLY *poly, char *srs, char *output) +{ + int i; + char *ptr=output; + + if ( srs ) { + ptr += sprintf(ptr, "", srs); + } else { + ptr += sprintf(ptr, ""); + } + ptr += sprintf(ptr, ""); + ptr += pointArray_toGML(poly->rings[0], ptr); + ptr += sprintf(ptr, ""); + for (i=1; inrings; i++) + { + ptr += sprintf(ptr, ""); + ptr += pointArray_toGML(poly->rings[i], ptr); + ptr += sprintf(ptr, ""); + } + ptr += sprintf(ptr, ""); + + return (ptr-output); } static char * -asgml_poly(LWPOLY *poly, int version) +asgml_poly(LWPOLY *poly, char *srs) { char *output; int size; + + size = asgml_poly_size(poly, srs); + output = palloc(size); + asgml_poly_buf(poly, srs, output); + return output; +} + +/* + * Compute max size required for GML version of this + * inspected geometry. Will recurse when needed. + * Don't call this with single-geoms inspected. + */ +static size_t +asgml_inspected_size(LWGEOM_INSPECTED *insp, char *srs) +{ int i; - char *ptr; + size_t size; - size = sizeof("") * 2; - size += sizeof("/") * 2 * poly->nrings; + // the longest possible multi version + size = sizeof(""); + if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); + + for (i=0; ingeometries; i++) + { + LWPOINT *point; + LWLINE *line; + LWPOLY *poly; + LWGEOM_INSPECTED *subinsp; + char *subgeom; + + if ((point=lwgeom_getpoint_inspected(insp, i))) + { + size += asgml_point_size(point, 0); + pfree_point(point); + } + else if ((line=lwgeom_getline_inspected(insp, i))) + { + size += asgml_line_size(line, 0); + pfree_line(line); + } + else if ((poly=lwgeom_getpoly_inspected(insp, i))) + { + size += asgml_poly_size(poly, 0); + pfree_polygon(poly); + } + else + { + subgeom = lwgeom_getsubgeometry_inspected(insp, i); + subinsp = lwgeom_inspect(subgeom); + size += asgml_inspected_size(subinsp, 0); + pfree_inspected(subinsp); + } + } + + return size; +} + +/* + * Don't call this with single-geoms inspected! + */ +static size_t +asgml_inspected_buf(LWGEOM_INSPECTED *insp, char *srs, char *output) +{ + int type = lwgeom_getType(insp->serialized_form[0]); + char *ptr, *gmltype; + int i; - for (i=0; inrings; i++) - size += pointArray_GMLsize(poly->rings[i], version); - - output = palloc(size); ptr = output; - ptr += sprintf(ptr, ""); - ptr += sprintf(ptr, ""); - ptr += pointArray_toGML(poly->rings[0], version, ptr); - ptr += sprintf(ptr, ""); - for (i=1; inrings; i++) + if (type == MULTIPOINTTYPE) gmltype = "MultiPoint"; + else if (type == MULTILINETYPE) gmltype = "MultiLineString"; + else if (type == MULTIPOLYGONTYPE) gmltype = "MultiPolygon"; + else gmltype = "MultiGeometry"; + + // Open outmost tag + if ( srs ) { + ptr += sprintf(ptr, "", gmltype, srs); + } else { + ptr += sprintf(ptr, "", gmltype); + } + + for (i=0; ingeometries; i++) { - ptr += sprintf(ptr, ""); - ptr += pointArray_toGML(poly->rings[i], version, ptr); - ptr += sprintf(ptr, ""); + LWPOINT *point; + LWLINE *line; + LWPOLY *poly; + LWGEOM_INSPECTED *subinsp; + char *subgeom; + + if ((point=lwgeom_getpoint_inspected(insp, i))) + { + ptr += asgml_point_buf(point, 0, ptr); + pfree_point(point); + } + else if ((line=lwgeom_getline_inspected(insp, i))) + { + ptr += asgml_line_buf(line, 0, ptr); + pfree_line(line); + } + else if ((poly=lwgeom_getpoly_inspected(insp, i))) + { + ptr += asgml_poly_buf(poly, 0, ptr); + pfree_polygon(poly); + } + else + { + subgeom = lwgeom_getsubgeometry_inspected(insp, i); + subinsp = lwgeom_inspect(subgeom); + ptr += asgml_inspected_buf(subinsp, 0, ptr); + pfree_inspected(subinsp); + } } - ptr += sprintf(ptr, ""); - return output; + // Close outmost tag + ptr += sprintf(ptr, "", gmltype); + + return (ptr-output); +} + +/* + * Don't call this with single-geoms inspected! + */ +static char * +asgml_inspected(LWGEOM_INSPECTED *insp, char *srs) +{ + char *gml; + size_t size; + + size = asgml_inspected_size(insp, srs); + gml = palloc(size); + asgml_inspected_buf(insp, srs, gml); + return gml; } +/* + * Returns maximum size of rendered pointarray in bytes. + */ static size_t -pointArray_GMLsize(POINTARRAY *pa, int version) +pointArray_GMLsize(POINTARRAY *pa) { - return pa->ndims * (MAX_DIGS_DOUBLE+(pa->ndims-1)); + return pa->ndims * pa->npoints * (SHOW_DIGS+(pa->ndims-1)); } static size_t -pointArray_toGML(POINTARRAY *pa, int version, char *output) +pointArray_toGML(POINTARRAY *pa, char *output) { int i; POINT4D *pt; @@ -197,8 +419,9 @@ pointArray_toGML(POINTARRAY *pa, int version, char *output) { pt = (POINT4D *)getPoint(pa, i); if ( i ) ptr += sprintf(ptr, " "); - ptr += sprintf(ptr, "%g,%g", - pt->x, pt->y); + ptr += sprintf(ptr, "%.*g,%.*g", + precision, pt->x, + precision, pt->y); } } else if ( pa->ndims == 3 ) @@ -207,8 +430,10 @@ pointArray_toGML(POINTARRAY *pa, int version, char *output) { pt = (POINT4D *)getPoint(pa, i); if ( i ) ptr += sprintf(ptr, " "); - ptr += sprintf(ptr, "%g,%g,%g", - pt->x, pt->y, pt->z); + ptr += sprintf(ptr, "%.*g,%.*g,%.*g", + precision, pt->x, + precision, pt->y, + precision, pt->z); } } else if ( pa->ndims == 4 ) @@ -217,17 +442,80 @@ pointArray_toGML(POINTARRAY *pa, int version, char *output) { pt = (POINT4D *)getPoint(pa, i); if ( i ) ptr += sprintf(ptr, " "); - ptr += sprintf(ptr, "%g,%g,%g,%g", - pt->x, pt->y, pt->z, pt->m); + ptr += sprintf(ptr, "%.*g,%.*g,%.*g,%.*g", + precision, pt->x, + precision, pt->y, + precision, pt->z, + precision, pt->m); } } return ptr-output; } +static char * +getSRSbySRID(int SRID) +{ + char query[128]; + char *srs, *srscopy; + int size, err; + + // connect to SPI + if (SPI_OK_CONNECT != SPI_connect ()) { + elog(NOTICE, "getSRSbySRID: could not connect to SPI manager"); + SPI_finish(); + return NULL; + } + + // write query + sprintf(query, "SELECT textcat(auth_name, textcat(':', auth_srid)) \ + FROM spatial_ref_sys WHERE srid = '%d'", SRID); +#ifdef DEBUG + elog(NOTICE, "Query: %s", query); +#endif + + // execute query + err = SPI_exec(query, 1); + if ( err < 0 ) { + elog(NOTICE, "getSRSbySRID: error executing query %d", err); + SPI_finish(); + return NULL; + } + + // no entry in spatial_ref_sys + if (SPI_processed <= 0) { + //elog(NOTICE, "getSRSbySRID: no record for SRID %d", SRID); + SPI_finish(); + return NULL; + } + + // get result + srs = SPI_getvalue(SPI_tuptable->vals[0], + SPI_tuptable->tupdesc, 1); + + // NULL result + if ( ! srs ) { + //elog(NOTICE, "getSRSbySRID: null result"); + SPI_finish(); + return NULL; + } + + // copy result to upper executor context + size = strlen(srs)+1; + srscopy = SPI_palloc(size); + memcpy(srscopy, srs, size); + + // disconnect from SPI + SPI_finish(); + + return srscopy; +} /********************************************************************** * $Log$ + * Revision 1.2 2004/09/23 15:09:07 strk + * Modified GML output as suggested by Martin Daly. + * * Revision 1.1 2004/09/23 11:12:47 strk * Initial GML output routines. * diff --git a/lwgeom/lwpostgis.sql.in b/lwgeom/lwpostgis.sql.in index 04303a1aa..dbdb2e014 100644 --- a/lwgeom/lwpostgis.sql.in +++ b/lwgeom/lwpostgis.sql.in @@ -2925,11 +2925,19 @@ CREATEFUNCTION AsSVG(geometry) ----------------------------------------------------------------------- -- GML OUTPUT ----------------------------------------------------------------------- +-- AsGML(geom, precision, version) +CREATEFUNCTION AsGML(geometry, int4, int4) + RETURNS TEXT + AS '@MODULE_FILENAME@','LWGEOM_asGML' + LANGUAGE 'C'; + +-- AsGML(geom, precision) / version=2 CREATEFUNCTION AsGML(geometry, int4) RETURNS TEXT AS '@MODULE_FILENAME@','LWGEOM_asGML' LANGUAGE 'C'; +-- AsGML(geom) / precision=15 version=2 CREATEFUNCTION AsGML(geometry) RETURNS TEXT AS '@MODULE_FILENAME@','LWGEOM_asGML'