postgis/liblwgeom/lwout_gml.c
2023-01-26 08:45:08 -08:00

1098 lines
30 KiB
C

/**********************************************************************
*
* PostGIS - Spatial Types for PostgreSQL
* http://postgis.net
*
* PostGIS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* PostGIS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
*
**********************************************************************
*
* Copyright 2011 Sandro Santilli <strk@kbt.io>
* Copyright 2010-2012 Oslandia
* Copyright 2001-2003 Refractions Research Inc.
*
**********************************************************************/
/**
* @file GML output routines.
*
**********************************************************************/
#include <string.h>
#include "liblwgeom_internal.h"
#include "liblwgeom.h"
#include "stringbuffer.h"
typedef struct
{
const char *srs;
int precision;
int opts;
int is_patch;
const char *prefix;
const char *id;
} GML_Options;
static void
asgml2_ptarray(stringbuffer_t* sb, const POINTARRAY *pa, const GML_Options* opts)
{
uint32_t i;
if ( ! FLAGS_GET_Z(pa->flags) )
{
for (i=0; i<pa->npoints; i++)
{
const POINT2D *pt = getPoint2d_cp(pa, i);
if (i) stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->x, opts->precision);
stringbuffer_append_char(sb, ',');
stringbuffer_append_double(sb, pt->y, opts->precision);
}
}
else
{
for (i=0; i<pa->npoints; i++)
{
const POINT3D *pt = getPoint3d_cp(pa, i);
if (i) stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->x, opts->precision);
stringbuffer_append_char(sb, ',');
stringbuffer_append_double(sb, pt->y, opts->precision);
stringbuffer_append_char(sb, ',');
stringbuffer_append_double(sb, pt->z, opts->precision);
}
}
}
static void
asgml2_gbox(stringbuffer_t* sb, const GBOX *bbox, const GML_Options* opts)
{
if (!bbox)
{
stringbuffer_aprintf(sb, "<%sBox", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
stringbuffer_append(sb, "/>");
return;
}
else
{
POINT4D pt = { bbox->xmin, bbox->ymin, bbox->zmin, 0.0 };
POINTARRAY *pa = ptarray_construct_empty(FLAGS_GET_Z(bbox->flags), 0, 2);
ptarray_append_point(pa, &pt, LW_TRUE);
pt.x = bbox->xmax; pt.y = bbox->ymax; pt.z = bbox->zmax;
ptarray_append_point(pa, &pt, LW_TRUE);
if (opts->srs) stringbuffer_aprintf(sb, "<%sBox srsName=\"%s\">", opts->prefix, opts->srs);
else stringbuffer_aprintf(sb, "<%sBox>", opts->prefix);
stringbuffer_aprintf(sb, "<%scoordinates>", opts->prefix);
asgml2_ptarray(sb, pa, opts);
stringbuffer_aprintf(sb, "</%scoordinates>", opts->prefix);
stringbuffer_aprintf(sb, "</%sBox>", opts->prefix);
ptarray_free(pa);
}
}
static void
asgml3_ptarray(stringbuffer_t* sb, const POINTARRAY *pa, const GML_Options* opts)
{
uint32_t i;
if ( ! FLAGS_GET_Z(pa->flags) )
{
for (i=0; i<pa->npoints; i++)
{
const POINT2D *pt = getPoint2d_cp(pa, i);
if (i) stringbuffer_append_char(sb, ' ');
if (IS_DEGREE(opts->opts))
{
stringbuffer_append_double(sb, pt->y, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->x, opts->precision);
}
else
{
stringbuffer_append_double(sb, pt->x, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->y, opts->precision);
}
}
}
else
{
for (i=0; i<pa->npoints; i++)
{
const POINT3D *pt = getPoint3d_cp(pa, i);
if (i) stringbuffer_append_char(sb, ' ');
if (IS_DEGREE(opts->opts))
{
stringbuffer_append_double(sb, pt->y, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->x, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->z, opts->precision);
}
else
{
stringbuffer_append_double(sb, pt->x, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->y, opts->precision);
stringbuffer_append_char(sb, ' ');
stringbuffer_append_double(sb, pt->z, opts->precision);
}
}
}
}
static void
asgml3_gbox(stringbuffer_t* sb, const GBOX *bbox, const GML_Options* opts)
{
if (!bbox)
{
stringbuffer_aprintf(sb, "<%sEnvelope", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
stringbuffer_append(sb, "/>");
return;
}
else
{
int dimension = FLAGS_GET_Z(bbox->flags) ? 3 : 2;
POINTARRAY *pa = ptarray_construct_empty(FLAGS_GET_Z(bbox->flags), 0, 1);
POINT4D pt = { bbox->xmin, bbox->ymin, bbox->zmin, 0.0 };
ptarray_append_point(pa, &pt, LW_TRUE);
stringbuffer_aprintf(sb, "<%sEnvelope", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (IS_DIMS(opts->opts)) stringbuffer_aprintf(sb, " srsDimension=\"%d\"", dimension);
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%slowerCorner>", opts->prefix);
asgml3_ptarray(sb, pa, opts);
stringbuffer_aprintf(sb, "</%slowerCorner>", opts->prefix);
pt.x = bbox->xmax; pt.y = bbox->ymax; pt.z =bbox->zmax;
ptarray_remove_point(pa, 0);
ptarray_append_point(pa, &pt, LW_TRUE);
stringbuffer_aprintf(sb, "<%supperCorner>", opts->prefix);
asgml3_ptarray(sb, pa, opts);
stringbuffer_aprintf(sb, "</%supperCorner>", opts->prefix);
stringbuffer_aprintf(sb, "</%sEnvelope>", opts->prefix);
ptarray_free(pa);
}
}
static void
asgml2_point(stringbuffer_t* sb, const LWPOINT *point, const GML_Options* opts)
{
stringbuffer_aprintf(sb, "<%sPoint", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (lwpoint_is_empty(point))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%scoordinates>", opts->prefix);
asgml2_ptarray(sb, point->point, opts);
stringbuffer_aprintf(sb, "</%scoordinates>", opts->prefix);
stringbuffer_aprintf(sb, "</%sPoint>", opts->prefix);
}
static void
asgml2_line(stringbuffer_t* sb, const LWLINE *line, const GML_Options* opts)
{
stringbuffer_aprintf(sb, "<%sLineString", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (lwline_is_empty(line))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%scoordinates>", opts->prefix);
asgml2_ptarray(sb, line->points, opts);
stringbuffer_aprintf(sb, "</%scoordinates>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLineString>", opts->prefix);
}
static void
asgml2_poly(stringbuffer_t* sb, const LWPOLY *poly, const GML_Options* opts)
{
uint32_t i;
stringbuffer_aprintf(sb, "<%sPolygon", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (lwpoly_is_empty(poly))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%souterBoundaryIs>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "<%scoordinates>", opts->prefix);
asgml2_ptarray(sb, poly->rings[0], opts);
stringbuffer_aprintf(sb, "</%scoordinates>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "</%souterBoundaryIs>", opts->prefix);
for (i=1; i<poly->nrings; i++)
{
stringbuffer_aprintf(sb, "<%sinnerBoundaryIs>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "<%scoordinates>", opts->prefix);
asgml2_ptarray(sb, poly->rings[i], opts);
stringbuffer_aprintf(sb, "</%scoordinates>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "</%sinnerBoundaryIs>", opts->prefix);
}
stringbuffer_aprintf(sb, "</%sPolygon>", opts->prefix);
}
static void
asgml2_multi(stringbuffer_t* sb, const LWCOLLECTION *col, const GML_Options* opts)
{
uint32_t i;
const char* gmltype = "";
int type = col->type;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
if (type == MULTIPOINTTYPE) gmltype = "MultiPoint";
else if (type == MULTILINETYPE) gmltype = "MultiLineString";
else if (type == MULTIPOLYGONTYPE) gmltype = "MultiPolygon";
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%s%s", opts->prefix, gmltype);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (!col->ngeoms)
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
for (i=0; i<col->ngeoms; i++)
{
LWGEOM* subgeom = col->geoms[i];
if (subgeom->type == POINTTYPE)
{
stringbuffer_aprintf(sb, "<%spointMember>", opts->prefix);
asgml2_point(sb, (LWPOINT*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%spointMember>", opts->prefix);
}
else if (subgeom->type == LINETYPE)
{
stringbuffer_aprintf(sb, "<%slineStringMember>", opts->prefix);
asgml2_line(sb, (LWLINE*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%slineStringMember>", opts->prefix);
}
else if (subgeom->type == POLYGONTYPE)
{
stringbuffer_aprintf(sb, "<%spolygonMember>", opts->prefix);
asgml2_poly(sb, (LWPOLY*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%spolygonMember>", opts->prefix);
}
}
/* Close outmost tag */
stringbuffer_aprintf(sb, "</%s%s>", opts->prefix, gmltype);
}
static void
asgml2_collection(stringbuffer_t* sb, const LWCOLLECTION *col, const GML_Options* opts)
{
uint32_t i;
LWGEOM *subgeom;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%sMultiGeometry", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (!col->ngeoms)
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
for (i=0; i<col->ngeoms; i++)
{
subgeom = col->geoms[i];
stringbuffer_aprintf(sb, "<%sgeometryMember>", opts->prefix);
switch (subgeom->type)
{
case POINTTYPE:
asgml2_point(sb, (LWPOINT*)subgeom, &subopts);
break;
case LINETYPE:
asgml2_line(sb, (LWLINE*)subgeom, &subopts);;
break;
case POLYGONTYPE:
asgml2_poly(sb, (LWPOLY*)subgeom, &subopts);
break;
case MULTIPOINTTYPE:
case MULTILINETYPE:
case MULTIPOLYGONTYPE:
asgml2_multi(sb, (LWCOLLECTION*)subgeom, &subopts);
break;
case COLLECTIONTYPE:
asgml2_collection(sb, (LWCOLLECTION*)subgeom, &subopts);
break;
}
stringbuffer_aprintf(sb, "</%sgeometryMember>", opts->prefix);
}
stringbuffer_aprintf(sb, "</%sMultiGeometry>", opts->prefix);
}
static void
asgml3_point(stringbuffer_t* sb, const LWPOINT *point, const GML_Options* opts)
{
int dimension = FLAGS_GET_Z(point->flags) ? 3 : 2;
stringbuffer_aprintf(sb, "<%sPoint", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
if (lwpoint_is_empty(point))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
if (IS_DIMS(opts->opts))
stringbuffer_aprintf(sb, "<%spos srsDimension=\"%d\">", opts->prefix, dimension);
else
stringbuffer_aprintf(sb, "<%spos>", opts->prefix);
asgml3_ptarray(sb, point->point, opts);
stringbuffer_aprintf(sb, "</%spos></%sPoint>", opts->prefix, opts->prefix);
}
static void
asgml3_line(stringbuffer_t* sb, const LWLINE *line, const GML_Options* opts)
{
int dimension = FLAGS_GET_Z(line->flags) ? 3 : 2;
int shortline = (opts->opts & LW_GML_SHORTLINE);
if (shortline)
{
stringbuffer_aprintf(sb, "<%sLineString", opts->prefix);
}
else
{
stringbuffer_aprintf(sb, "<%sCurve", opts->prefix);
}
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
if (lwline_is_empty(line))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
if (!shortline)
{
stringbuffer_aprintf(sb, "<%ssegments>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLineStringSegment>", opts->prefix);
}
if (IS_DIMS(opts->opts))
{
stringbuffer_aprintf(sb, "<%sposList srsDimension=\"%d\">", opts->prefix, dimension);
}
else
{
stringbuffer_aprintf(sb, "<%sposList>", opts->prefix);
}
asgml3_ptarray(sb, line->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
if (shortline)
{
stringbuffer_aprintf(sb, "</%sLineString>", opts->prefix);
}
else
{
stringbuffer_aprintf(sb, "</%sLineStringSegment>", opts->prefix);
stringbuffer_aprintf(sb, "</%ssegments>", opts->prefix);
stringbuffer_aprintf(sb, "</%sCurve>", opts->prefix);
}
}
static void
asgml3_poly(stringbuffer_t* sb, const LWPOLY *poly, const GML_Options* opts)
{
uint32_t i;
int dimension = FLAGS_GET_Z(poly->flags) ? 3 : 2;
stringbuffer_aprintf(sb,
opts->is_patch ? "<%sPolygonPatch" : "<%sPolygon",
opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
if (lwpoly_is_empty(poly))
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%sexterior>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
if (IS_DIMS(opts->opts))
stringbuffer_aprintf(sb, "<%sposList srsDimension=\"%d\">", opts->prefix, dimension);
else
stringbuffer_aprintf(sb, "<%sposList>", opts->prefix);
asgml3_ptarray(sb, poly->rings[0], opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "</%sexterior>", opts->prefix);
for (i=1; i<poly->nrings; i++)
{
stringbuffer_aprintf(sb, "<%sinterior>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
if (IS_DIMS(opts->opts))
stringbuffer_aprintf(sb, "<%sposList srsDimension=\"%d\">", opts->prefix, dimension);
else
stringbuffer_aprintf(sb, "<%sposList>", opts->prefix);
asgml3_ptarray(sb, poly->rings[i], opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "</%sinterior>", opts->prefix);
}
stringbuffer_aprintf(sb,
opts->is_patch ? "</%sPolygonPatch>" : "</%sPolygon>",
opts->prefix);
}
static void
asgml3_circstring(stringbuffer_t* sb, const LWCIRCSTRING *circ, const GML_Options* opts)
{
int dimension = FLAGS_GET_Z(circ->flags) ? 3 : 2;
stringbuffer_aprintf(sb, "<%sCurve", opts->prefix);
if (opts->srs)
{
stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
}
if (opts->id)
{
stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
}
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%ssegments>", opts->prefix);
stringbuffer_aprintf(sb, "<%sArcString>", opts->prefix);
stringbuffer_aprintf(sb, "<%sposList", opts->prefix);
if (IS_DIMS(opts->opts))
{
stringbuffer_aprintf(sb, " srsDimension=\"%d\"", dimension);
}
stringbuffer_append(sb, ">");
asgml3_ptarray(sb, circ->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sArcString>", opts->prefix);
stringbuffer_aprintf(sb, "</%ssegments>", opts->prefix);
stringbuffer_aprintf(sb, "</%sCurve>", opts->prefix);
}
static void
asgml3_compound(stringbuffer_t* sb, const LWCOMPOUND *col, const GML_Options* opts)
{
LWGEOM *subgeom;
uint32_t i;
int dimension = FLAGS_GET_Z(col->flags) ? 3 : 2;
stringbuffer_aprintf(sb, "<%sCurve", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%ssegments>", opts->prefix);
for (i = 0; i < col->ngeoms; ++i)
{
subgeom = col->geoms[i];
if (subgeom->type != LINETYPE && subgeom->type != CIRCSTRINGTYPE)
continue;
if (subgeom->type == LINETYPE)
{
stringbuffer_aprintf(sb, "<%sLineStringSegment>", opts->prefix);
stringbuffer_aprintf(sb, "<%sposList", opts->prefix);
if (IS_DIMS(opts->opts))
stringbuffer_aprintf(sb, " srsDimension=\"%d\"", dimension);
stringbuffer_append(sb, ">");
asgml3_ptarray(sb, ((LWCIRCSTRING*)subgeom)->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLineStringSegment>", opts->prefix);
}
else if( subgeom->type == CIRCSTRINGTYPE )
{
stringbuffer_aprintf(sb, "<%sArcString>", opts->prefix);
stringbuffer_aprintf(sb, "<%sposList", opts->prefix);
if (IS_DIMS(opts->opts))
{
stringbuffer_aprintf(sb, " srsDimension=\"%d\"", dimension);
}
stringbuffer_append(sb, ">");
asgml3_ptarray(sb, ((LWLINE*)subgeom)->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sArcString>", opts->prefix);
}
}
stringbuffer_aprintf(sb, "</%ssegments>", opts->prefix);
stringbuffer_aprintf(sb, "</%sCurve>", opts->prefix);
}
static void
asgml3_curvepoly(stringbuffer_t* sb, const LWCURVEPOLY* poly, const GML_Options* opts)
{
uint32_t i;
LWGEOM* subgeom;
int dimension = FLAGS_GET_Z(poly->flags) ? 3 : 2;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
stringbuffer_aprintf(sb, "<%sPolygon", opts->prefix);
if (opts->srs)
{
stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
}
if (opts->id)
{
stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
}
stringbuffer_append(sb, ">");
for (i = 0; i < poly->nrings; ++i)
{
stringbuffer_aprintf(sb,
i ? "<%sinterior>" : "<%sexterior>",
opts->prefix);
subgeom = poly->rings[i];
if (subgeom->type == LINETYPE)
{
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "<%sposList", opts->prefix);
if (IS_DIMS(opts->opts))
{
stringbuffer_aprintf(sb, " srsDimension=\"%d\"", dimension);
}
stringbuffer_append(sb, ">");
asgml3_ptarray(sb, ((LWLINE*)subgeom)->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
}
else if (subgeom->type == CIRCSTRINGTYPE)
{
stringbuffer_aprintf(sb, "<%sRing>", opts->prefix);
stringbuffer_aprintf(sb, "<%scurveMember>", opts->prefix);
asgml3_circstring(sb, (LWCIRCSTRING*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%scurveMember>", opts->prefix);
stringbuffer_aprintf(sb, "</%sRing>", opts->prefix);
}
else if (subgeom->type == COMPOUNDTYPE)
{
stringbuffer_aprintf(sb, "<%sRing>", opts->prefix);
stringbuffer_aprintf(sb, "<%scurveMember>", opts->prefix);
asgml3_compound(sb, (LWCOMPOUND*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%scurveMember>", opts->prefix);
stringbuffer_aprintf(sb, "</%sRing>", opts->prefix);
}
stringbuffer_aprintf(sb,
i ? "</%sinterior>" : "</%sexterior>",
opts->prefix);
}
stringbuffer_aprintf(sb, "</%sPolygon>", opts->prefix);
}
static void
asgml3_triangle(stringbuffer_t* sb, const LWTRIANGLE *triangle, const GML_Options* opts)
{
int dimension = FLAGS_GET_Z(triangle->flags) ? 3 : 2;
stringbuffer_aprintf(sb, "<%sTriangle", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%sexterior>", opts->prefix);
stringbuffer_aprintf(sb, "<%sLinearRing>", opts->prefix);
if (IS_DIMS(opts->opts))
stringbuffer_aprintf(sb, "<%sposList srsDimension=\"%d\">", opts->prefix, dimension);
else
stringbuffer_aprintf(sb, "<%sposList>", opts->prefix);
asgml3_ptarray(sb, triangle->points, opts);
stringbuffer_aprintf(sb, "</%sposList>", opts->prefix);
stringbuffer_aprintf(sb, "</%sLinearRing>", opts->prefix);
stringbuffer_aprintf(sb, "</%sexterior>", opts->prefix);
stringbuffer_aprintf(sb, "</%sTriangle>", opts->prefix);
}
static void
asgml3_multi(stringbuffer_t* sb, const LWCOLLECTION *col, const GML_Options* opts)
{
int type = col->type;
uint32_t i;
LWGEOM *subgeom;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
const char* gmltype = "";
if (type == MULTIPOINTTYPE) gmltype = "MultiPoint";
else if (type == MULTILINETYPE) gmltype = "MultiCurve";
else if (type == MULTIPOLYGONTYPE) gmltype = "MultiSurface";
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%s%s", opts->prefix, gmltype);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
if (!col->ngeoms)
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
for (i=0; i<col->ngeoms; i++)
{
subgeom = col->geoms[i];
if (subgeom->type == POINTTYPE)
{
stringbuffer_aprintf(sb, "<%spointMember>", opts->prefix);
asgml3_point(sb, (LWPOINT*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%spointMember>", opts->prefix);
}
else if (subgeom->type == LINETYPE)
{
stringbuffer_aprintf(sb, "<%scurveMember>", opts->prefix);
asgml3_line(sb, (LWLINE*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%scurveMember>", opts->prefix);
}
else if (subgeom->type == POLYGONTYPE)
{
stringbuffer_aprintf(sb, "<%ssurfaceMember>", opts->prefix);
asgml3_poly(sb, (LWPOLY*)subgeom, &subopts);
stringbuffer_aprintf(sb, "</%ssurfaceMember>", opts->prefix);
}
}
/* Close outmost tag */
stringbuffer_aprintf(sb, "</%s%s>", opts->prefix, gmltype);
}
/*
* Don't call this with single-geoms inspected!
*/
static void
asgml3_tin(stringbuffer_t* sb, const LWTIN *tin, const GML_Options* opts)
{
uint32_t i;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%sTin", opts->prefix);
if (opts->srs)
stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id)
stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%strianglePatches>", opts->prefix);
for (i=0; i<tin->ngeoms; i++)
{
asgml3_triangle(sb, tin->geoms[i], &subopts);
}
/* Close outmost tag */
stringbuffer_aprintf(sb, "</%strianglePatches>", opts->prefix);
stringbuffer_aprintf(sb, "</%sTin>", opts->prefix);
}
static void
asgml3_psurface(stringbuffer_t* sb, const LWPSURFACE *psur, const GML_Options* opts)
{
uint32_t i;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
subopts.is_patch = 1;
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%sPolyhedralSurface", opts->prefix);
if (opts->srs)
stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id)
stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
stringbuffer_append(sb, ">");
stringbuffer_aprintf(sb, "<%spolygonPatches>", opts->prefix);
for (i=0; i<psur->ngeoms; i++)
{
asgml3_poly(sb, psur->geoms[i], &subopts);
}
/* Close outmost tag */
stringbuffer_aprintf(sb, "</%spolygonPatches>", opts->prefix);
stringbuffer_aprintf(sb, "</%sPolyhedralSurface>", opts->prefix);
}
static void
asgml3_collection(stringbuffer_t* sb, const LWCOLLECTION *col, const GML_Options* opts)
{
uint32_t i;
LWGEOM *subgeom;
/* Subgeoms don't get an SRS */
GML_Options subopts = *opts;
subopts.srs = 0;
/* Open outmost tag */
stringbuffer_aprintf(sb, "<%sMultiGeometry", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
if (!col->ngeoms)
{
stringbuffer_append(sb, "/>");
return;
}
stringbuffer_append(sb, ">");
for (i=0; i<col->ngeoms; i++)
{
subgeom = col->geoms[i];
stringbuffer_aprintf(sb, "<%sgeometryMember>", opts->prefix);
switch (subgeom->type)
{
case POINTTYPE:
asgml3_point(sb, (LWPOINT*)subgeom, &subopts);
break;
case LINETYPE:
asgml3_line(sb, (LWLINE*)subgeom, &subopts);
break;
case POLYGONTYPE:
asgml3_poly(sb, (LWPOLY*)subgeom, &subopts);
break;
case MULTIPOINTTYPE:
case MULTILINETYPE:
case MULTIPOLYGONTYPE:
asgml3_multi(sb, (LWCOLLECTION*)subgeom, &subopts);
break;
case COLLECTIONTYPE:
asgml3_collection(sb, (LWCOLLECTION*)subgeom, &subopts);
break;
default:
lwerror("asgml3_collection: unknown geometry type");
}
stringbuffer_aprintf(sb, "</%sgeometryMember>", opts->prefix);
}
/* Close outmost tag */
stringbuffer_aprintf(sb, "</%sMultiGeometry>", opts->prefix);
}
static void
asgml3_multicurve(stringbuffer_t*sb, const LWMCURVE* cur, const GML_Options* opts)
{
LWGEOM* subgeom;
uint32_t i;
stringbuffer_aprintf(sb, "<%sMultiCurve", opts->prefix);
if (opts->srs)
{
stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
}
if (opts->id)
{
stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
}
stringbuffer_append(sb, ">");
for (i = 0; i < cur->ngeoms; ++i)
{
stringbuffer_aprintf(sb, "<%scurveMember>", opts->prefix);
subgeom = cur->geoms[i];
if (subgeom->type == LINETYPE)
{
asgml3_line(sb, (LWLINE*)subgeom, opts);
}
else if (subgeom->type == CIRCSTRINGTYPE)
{
asgml3_circstring(sb, (LWCIRCSTRING*)subgeom, opts);
}
else if (subgeom->type == COMPOUNDTYPE)
{
asgml3_compound(sb, (LWCOMPOUND*)subgeom, opts);
}
stringbuffer_aprintf(sb, "</%scurveMember>", opts->prefix);
}
stringbuffer_aprintf(sb, "</%sMultiCurve>", opts->prefix);
}
static void
asgml3_multisurface(stringbuffer_t* sb, const LWMSURFACE *sur, const GML_Options* opts)
{
uint32_t i;
LWGEOM* subgeom;
stringbuffer_aprintf(sb, "<%sMultiSurface", opts->prefix);
if (opts->srs) stringbuffer_aprintf(sb, " srsName=\"%s\"", opts->srs);
if (opts->id) stringbuffer_aprintf(sb, " %sid=\"%s\"", opts->prefix, opts->id);
stringbuffer_append(sb, ">");
for (i = 0; i < sur->ngeoms; ++i)
{
subgeom = sur->geoms[i];
if (subgeom->type == POLYGONTYPE)
{
asgml3_poly(sb, (LWPOLY*)sur->geoms[i], opts);
}
else if (subgeom->type == CURVEPOLYTYPE)
{
asgml3_curvepoly(sb, (LWCURVEPOLY*)sur->geoms[i], opts);
}
}
stringbuffer_aprintf(sb, "</%sMultiSurface>", opts->prefix);
}
extern lwvarlena_t *
lwgeom_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
{
stringbuffer_t sb;
/* Initialize options */
GML_Options gmlopts;
memset(&gmlopts, 0, sizeof(gmlopts));
gmlopts.srs = srs;
gmlopts.precision = precision;
gmlopts.prefix = prefix;
/* Return null for empty (#1377) */
if (lwgeom_is_empty(geom))
return NULL;
stringbuffer_init_varlena(&sb);
switch (geom->type)
{
case POINTTYPE:
asgml2_point(&sb, (LWPOINT*)geom, &gmlopts);
break;
case LINETYPE:
asgml2_line(&sb, (LWLINE*)geom, &gmlopts);
break;
case POLYGONTYPE:
asgml2_poly(&sb, (LWPOLY*)geom, &gmlopts);
break;
case MULTIPOINTTYPE:
case MULTILINETYPE:
case MULTIPOLYGONTYPE:
asgml2_multi(&sb, (LWCOLLECTION*)geom, &gmlopts);
break;
case COLLECTIONTYPE:
asgml2_collection(&sb, (LWCOLLECTION*)geom, &gmlopts);
break;
case TRIANGLETYPE:
case POLYHEDRALSURFACETYPE:
case TINTYPE:
lwerror("Cannot convert %s to GML2. Try ST_AsGML(3, <geometry>) to generate GML3.", lwtype_name(geom->type));
stringbuffer_release(&sb);
return NULL;
default:
lwerror("lwgeom_to_gml2: '%s' geometry type not supported", lwtype_name(geom->type));
stringbuffer_release(&sb);
return NULL;
}
return stringbuffer_getvarlena(&sb);
}
extern lwvarlena_t *
lwgeom_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix, const char *id)
{
stringbuffer_t sb;
/* Initialize options */
GML_Options gmlopts;
memset(&gmlopts, 0, sizeof(gmlopts));
gmlopts.srs = srs;
gmlopts.precision = precision;
gmlopts.opts = opts;
gmlopts.prefix = prefix;
gmlopts.id = id;
/* Return null for empty (#1377) */
if (lwgeom_is_empty(geom))
return NULL;
stringbuffer_init_varlena(&sb);
switch (geom->type)
{
case POINTTYPE:
asgml3_point(&sb, (LWPOINT*)geom, &gmlopts);
break;
case LINETYPE:
asgml3_line(&sb, (LWLINE*)geom, &gmlopts);
break;
case CIRCSTRINGTYPE:
asgml3_circstring(&sb, (LWCIRCSTRING*)geom, &gmlopts );
break;
case POLYGONTYPE:
asgml3_poly(&sb, (LWPOLY*)geom, &gmlopts);
break;
case CURVEPOLYTYPE:
asgml3_curvepoly(&sb, (LWCURVEPOLY*)geom, &gmlopts);
break;
case TRIANGLETYPE:
asgml3_triangle(&sb, (LWTRIANGLE*)geom, &gmlopts);
break;
case MULTIPOINTTYPE:
case MULTILINETYPE:
case MULTIPOLYGONTYPE:
asgml3_multi(&sb, (LWCOLLECTION*)geom, &gmlopts);
break;
case POLYHEDRALSURFACETYPE:
asgml3_psurface(&sb, (LWPSURFACE*)geom, &gmlopts);
break;
case TINTYPE:
asgml3_tin(&sb, (LWTIN*)geom, &gmlopts);
break;
case COLLECTIONTYPE:
asgml3_collection(&sb, (LWCOLLECTION*)geom, &gmlopts);
break;
case COMPOUNDTYPE:
asgml3_compound(&sb, (LWCOMPOUND*)geom, &gmlopts );
break;
case MULTICURVETYPE:
asgml3_multicurve(&sb, (LWMCURVE*)geom, &gmlopts );
break;
case MULTISURFACETYPE:
asgml3_multisurface(&sb, (LWMSURFACE*)geom, &gmlopts );
break;
default:
lwerror("lwgeom_to_gml3: '%s' geometry type not supported", lwtype_name(geom->type));
stringbuffer_release(&sb);
return NULL;
}
return stringbuffer_getvarlena(&sb);
}
extern lwvarlena_t *
lwgeom_extent_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
{
const GBOX* bbox = lwgeom_get_bbox(geom);
stringbuffer_t sb;
/* Initialize options */
GML_Options gmlopts;
memset(&gmlopts, 0, sizeof(gmlopts));
gmlopts.srs = srs;
gmlopts.precision = precision;
gmlopts.prefix = prefix;
stringbuffer_init_varlena(&sb);
asgml2_gbox(&sb, bbox, &gmlopts);
return stringbuffer_getvarlena(&sb);
}
extern lwvarlena_t *
lwgeom_extent_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix)
{
const GBOX* bbox = lwgeom_get_bbox(geom);
stringbuffer_t sb;
/* Initialize options */
GML_Options gmlopts;
memset(&gmlopts, 0, sizeof(gmlopts));
gmlopts.srs = srs;
gmlopts.precision = precision;
gmlopts.opts = opts;
gmlopts.prefix = prefix;
stringbuffer_init_varlena(&sb);
asgml3_gbox(&sb, bbox, &gmlopts);
return stringbuffer_getvarlena(&sb);
}