mirror of
https://git.osgeo.org/gitea/postgis/postgis
synced 2024-10-25 09:32:46 +00:00
a9109daf57
git-svn-id: http://svn.osgeo.org/postgis/trunk@2842 b70326c6-7e19-0410-871a-916f4a2858ee
927 lines
22 KiB
C
927 lines
22 KiB
C
/**********************************************************************
|
|
* $Id:$
|
|
*
|
|
* PostGIS - Spatial Types for PostgreSQL
|
|
* http://postgis.refractions.net
|
|
* Copyright 2001-2003 Refractions Research Inc.
|
|
*
|
|
* This is free software; you can redistribute and/or modify it under
|
|
* the terms of hte GNU General Public Licence. See the COPYING file.
|
|
*
|
|
**********************************************************************
|
|
*
|
|
* GeoJSON output routines.
|
|
* Originally written by Olivier Courtin (Camptocamp)
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include "postgres.h"
|
|
#include "executor/spi.h"
|
|
|
|
#include "lwgeom_pg.h"
|
|
#include "liblwgeom.h"
|
|
|
|
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS);
|
|
|
|
char *geometry_to_geojson(uchar *srl, char *srs, bool has_bbox, int precision);
|
|
|
|
static char *asgeojson_point(LWPOINT *point, char *srs, BOX3D *bbox, int precision);
|
|
static char *asgeojson_line(LWLINE *line, char *srs, BOX3D *bbox, int precision);
|
|
static char *asgeojson_poly(LWPOLY *poly, char *srs, BOX3D *bbox, int precision);
|
|
static char * asgeojson_multipoint(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision);
|
|
static char * asgeojson_multiline(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision);
|
|
static char * asgeojson_multipolygon(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision);
|
|
static char * asgeojson_collection(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision);
|
|
static size_t asgeojson_inspected_size(LWGEOM_INSPECTED *insp, BOX3D *bbox, int precision);
|
|
static size_t asgeojson_inspected_buf(LWGEOM_INSPECTED *insp, char *output, BOX3D *bbox, int precision);
|
|
|
|
static size_t pointArray_to_geojson(POINTARRAY *pa, char *buf, int precision);
|
|
static size_t pointArray_geojson_size(POINTARRAY *pa, int precision);
|
|
static char *getSRSbySRID(int SRID);
|
|
|
|
|
|
#define SHOW_DIGS_DOUBLE 15
|
|
#define MAX_DOUBLE_PRECISION 15
|
|
#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 2) /* +2 mean add dot and sign */
|
|
|
|
|
|
/**
|
|
* Encode Feature in GeoJson
|
|
*/
|
|
PG_FUNCTION_INFO_V1(LWGEOM_asGeoJson);
|
|
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
|
|
{
|
|
PG_LWGEOM *geom;
|
|
char *geojson;
|
|
text *result;
|
|
int SRID;
|
|
int len;
|
|
int version;
|
|
int option = 0;
|
|
bool has_bbox = 0;
|
|
int precision = MAX_DOUBLE_PRECISION;
|
|
char * srs = NULL;
|
|
|
|
/* Get the version */
|
|
version = PG_GETARG_INT32(0);
|
|
if ( version != 1) {
|
|
elog(ERROR, "Only GeoJSON 1 is supported");
|
|
PG_RETURN_NULL();
|
|
}
|
|
|
|
/* Get the geometry */
|
|
if (PG_ARGISNULL(1) ) PG_RETURN_NULL();
|
|
geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
|
|
|
/* Retrieve precision if any (default is max) */
|
|
if (PG_NARGS() >2 && !PG_ARGISNULL(2)) {
|
|
precision = PG_GETARG_INT32(2);
|
|
if ( precision > MAX_DOUBLE_PRECISION )
|
|
precision = MAX_DOUBLE_PRECISION;
|
|
else if ( precision < 0 ) precision = 0;
|
|
}
|
|
|
|
/* Retrieve output option
|
|
* 0 = without option (default)
|
|
* 1 = crs
|
|
* 2 = bbox
|
|
* 3 = crs & bbox
|
|
*/
|
|
if (PG_NARGS() >3 && !PG_ARGISNULL(3))
|
|
option = PG_GETARG_INT32(3);
|
|
|
|
if (option & 1) {
|
|
SRID = lwgeom_getsrid(SERIALIZED_FORM(geom));
|
|
if ( SRID != -1 ) {
|
|
srs = getSRSbySRID(SRID);
|
|
if (!srs) {
|
|
elog(ERROR, "SRID %i unknown in spatial_ref_sys table", SRID);
|
|
PG_RETURN_NULL();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (option & 2) has_bbox = 1;
|
|
|
|
geojson = geometry_to_geojson(SERIALIZED_FORM(geom), srs, has_bbox, precision);
|
|
PG_FREE_IF_COPY(geom, 1);
|
|
if (srs) pfree(srs);
|
|
|
|
len = strlen(geojson) + VARHDRSZ;
|
|
result = palloc(len);
|
|
SET_VARSIZE(result, len);
|
|
memcpy(VARDATA(result), geojson, len-VARHDRSZ);
|
|
|
|
pfree(geojson);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Takes a GEOMETRY and returns a GeoJson representation
|
|
*/
|
|
char *
|
|
geometry_to_geojson(uchar *geom, char *srs, bool has_bbox, int precision)
|
|
{
|
|
int type;
|
|
LWPOINT *point;
|
|
LWLINE *line;
|
|
LWPOLY *poly;
|
|
LWGEOM_INSPECTED *insp;
|
|
BOX3D * bbox = NULL;
|
|
char * ret = NULL;
|
|
|
|
type = lwgeom_getType(geom[0]);
|
|
|
|
if (has_bbox) {
|
|
if (lwgeom_hasBBOX(geom[0]) && !TYPE_HASZ(geom[0])) {
|
|
/* Use 2D Bbox cache if any */
|
|
BOX2DFLOAT4 * box2d;
|
|
box2d = lwalloc(sizeof(BOX2DFLOAT4));
|
|
memcpy(box2d, geom + 1, sizeof(BOX2DFLOAT4));
|
|
bbox = lwalloc(sizeof(BOX3D));
|
|
box2df_to_box3d_p(box2d, bbox);
|
|
lwfree(box2d);
|
|
} else bbox = compute_serialized_box3d(geom);
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case POINTTYPE:
|
|
point = lwpoint_deserialize(geom);
|
|
ret = asgeojson_point(point, srs, bbox, precision);
|
|
break;
|
|
|
|
case LINETYPE:
|
|
line = lwline_deserialize(geom);
|
|
ret = asgeojson_line(line, srs, bbox, precision);
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
poly = lwpoly_deserialize(geom);
|
|
ret = asgeojson_poly(poly, srs, bbox, precision);
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
insp = lwgeom_inspect(geom);
|
|
ret = asgeojson_multipoint(insp, srs, bbox, precision);
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
insp = lwgeom_inspect(geom);
|
|
ret = asgeojson_multiline(insp, srs, bbox, precision);
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
insp = lwgeom_inspect(geom);
|
|
ret = asgeojson_multipolygon(insp, srs, bbox, precision);
|
|
break;
|
|
|
|
case COLLECTIONTYPE:
|
|
insp = lwgeom_inspect(geom);
|
|
ret = asgeojson_collection(insp, srs, bbox, precision);
|
|
break;
|
|
|
|
default:
|
|
if (bbox) { lwfree(bbox); bbox = NULL; }
|
|
lwerror("GeoJson: '%s' geometry type not supported.",
|
|
lwgeom_typename(type));
|
|
}
|
|
|
|
if (bbox) { lwfree(bbox); bbox = NULL; }
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle SRS
|
|
*/
|
|
static size_t
|
|
asgeojson_srs_size(char *srs) {
|
|
int size;
|
|
|
|
size = sizeof("'crs':{'type':'',");
|
|
size += sizeof("'properties':{'code':}");
|
|
size += strlen(srs) * sizeof(char) * 2; /* a bit more than really needed
|
|
but avoid to search : separator */
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_srs_buf(char *output, char *srs) {
|
|
char *ptr_sep;
|
|
char buf[256+1];
|
|
char *ptr = output;
|
|
int size;
|
|
|
|
ptr_sep = strchr(srs, ':');
|
|
if ( ptr_sep == NULL ) {
|
|
lwerror("GeoJson: SRS dont't use a valid ':' separator !");
|
|
return (ptr-output);
|
|
}
|
|
|
|
size = ptr_sep - srs;
|
|
if (size > 256) size = 256;
|
|
memcpy(buf, srs, size);
|
|
buf[size] = '\0';
|
|
ptr += sprintf(ptr, "\"crs\":{\"type\":\"%s\",", buf);
|
|
ptr += sprintf(ptr, "\"properties\":{\"%s\":", buf);
|
|
|
|
size = srs + strlen(srs) - ptr_sep;
|
|
if (size > 256) size = 256;
|
|
memcpy(buf, ptr_sep + 1, size);
|
|
buf[size] = '\0';
|
|
ptr += sprintf(ptr, "%s}},", buf);
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle Bbox
|
|
*/
|
|
static size_t
|
|
asgeojson_bbox_size(bool hasz, int precision) {
|
|
|
|
int size;
|
|
|
|
if (!hasz) {
|
|
size = sizeof("\"bbox\":[,,,],");
|
|
size += 2 * 2 * (MAX_DIGS_DOUBLE + precision);
|
|
} else {
|
|
size = sizeof("\"bbox\":[,,,,,],");
|
|
size += 2 * 3 * (MAX_DIGS_DOUBLE + precision);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_bbox_buf(char *output, BOX3D *bbox, bool hasz, int precision)
|
|
{
|
|
char *ptr = output;
|
|
|
|
if (!hasz)
|
|
ptr += sprintf(ptr, "\"bbox\":[%.*f,%.*f,%.*f,%.*f],",
|
|
precision, bbox->xmin, precision, bbox->ymin,
|
|
precision, bbox->xmax, precision, bbox->ymax);
|
|
else
|
|
ptr += sprintf(ptr, "\"bbox\":[%.*f,%.*f,%.*f,%.*f,%.*f,%.*f],",
|
|
precision, bbox->xmin, precision, bbox->ymin, precision, bbox->zmin,
|
|
precision, bbox->xmax, precision, bbox->ymax, precision, bbox->zmax);
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Point Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_point_size(LWPOINT *point, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
int size;
|
|
|
|
size = pointArray_geojson_size(point->point, precision);
|
|
size += sizeof("{'type':'Point',");
|
|
size += sizeof("'coordinates':}");
|
|
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(point->type), precision);
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_point_buf(LWPOINT *point, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
char *ptr = output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"Point\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(point->type), precision);
|
|
|
|
ptr += sprintf(ptr, "\"coordinates\":");
|
|
ptr += pointArray_to_geojson(point->point, ptr, precision);
|
|
ptr += sprintf(ptr, "}");
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_point(LWPOINT *point, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_point_size(point, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_point_buf(point, srs, output, bbox, precision);
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Line Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_line_size(LWLINE *line, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
int size;
|
|
|
|
size = sizeof("{'type':'LineString',");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(line->type), precision);
|
|
size += sizeof("'coordinates':[]}");
|
|
size += pointArray_geojson_size(line->points, precision);
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_line_buf(LWLINE *line, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
char *ptr=output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"LineString\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(line->type), precision);
|
|
ptr += sprintf(ptr, "\"coordinates\":[");
|
|
ptr += pointArray_to_geojson(line->points, ptr, precision);
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_line(LWLINE *line, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_line_size(line, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_line_buf(line, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Polygon Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_poly_size(LWPOLY *poly, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
size_t size;
|
|
int i;
|
|
|
|
size = sizeof("{\"type\":\"Polygon\",");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(poly->type), precision);
|
|
size += sizeof("\"coordinates\":[");
|
|
for (i=0, size=0; i<poly->nrings; i++) {
|
|
size += pointArray_geojson_size(poly->rings[i], precision);
|
|
size += sizeof("[]");
|
|
}
|
|
size += sizeof(",") * i;
|
|
size += sizeof("]}");
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_poly_buf(LWPOLY *poly, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
int i;
|
|
char *ptr=output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"Polygon\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(poly->type), precision);
|
|
ptr += sprintf(ptr, "\"coordinates\":[");
|
|
for (i=0; i<poly->nrings; i++)
|
|
{
|
|
if (i) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[");
|
|
ptr += pointArray_to_geojson(poly->rings[i], ptr, precision);
|
|
ptr += sprintf(ptr, "]");
|
|
}
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_poly(LWPOLY *poly, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_poly_size(poly, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_poly_buf(poly, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Multipoint Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_multipoint_size(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
LWPOINT * point;
|
|
int size;
|
|
int i;
|
|
|
|
size = sizeof("{'type':'MultiPoint',");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(insp->type), precision);
|
|
size += sizeof("'coordinates':[]}");
|
|
|
|
for (i=0; i<insp->ngeometries; i++) {
|
|
point = lwgeom_getpoint_inspected(insp, i);
|
|
size += pointArray_geojson_size(point->point, precision);
|
|
}
|
|
size += sizeof(",") * i;
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_multipoint_buf(LWGEOM_INSPECTED *insp, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
LWPOINT *point;
|
|
int i;
|
|
char *ptr=output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"MultiPoint\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(insp->type), precision);
|
|
ptr += sprintf(ptr, "\"coordinates\":[");
|
|
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
{
|
|
if (i) ptr += sprintf(ptr, ",");
|
|
point=lwgeom_getpoint_inspected(insp, i);
|
|
ptr += pointArray_to_geojson(point->point, ptr, precision);
|
|
pfree_point(point);
|
|
}
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr - output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_multipoint(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_multipoint_size(insp, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_multipoint_buf(insp, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Multiline Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_multiline_size(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
LWLINE * line;
|
|
int size;
|
|
int i;
|
|
|
|
size = sizeof("{'type':'MultiLineString',");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(insp->type), precision);
|
|
size += sizeof("'coordinates':[]}");
|
|
|
|
for (i=0 ; i<insp->ngeometries; i++) {
|
|
line = lwgeom_getline_inspected(insp, i);
|
|
size += pointArray_geojson_size(line->points, precision);
|
|
size += sizeof("[]");
|
|
}
|
|
size += sizeof(",") * i;
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_multiline_buf(LWGEOM_INSPECTED *insp, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
LWLINE *line;
|
|
int i;
|
|
char *ptr=output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"MultiLineString\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(insp->type), precision);
|
|
ptr += sprintf(ptr, "\"coordinates\":[");
|
|
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
{
|
|
if (i) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[");
|
|
line = lwgeom_getline_inspected(insp, i);
|
|
ptr += pointArray_to_geojson(line->points, ptr, precision);
|
|
ptr += sprintf(ptr, "]");
|
|
|
|
pfree_line(line);
|
|
}
|
|
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr - output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_multiline(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_multiline_size(insp, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_multiline_buf(insp, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* MultiPolygon Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_multipolygon_size(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
LWPOLY *poly;
|
|
int size;
|
|
int i, j;
|
|
|
|
size = sizeof("{'type':'MultiPolygon',");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(insp->type), precision);
|
|
size += sizeof("'coordinates':[]}");
|
|
|
|
for (i=0; i < insp->ngeometries; i++) {
|
|
poly = lwgeom_getpoly_inspected(insp, i);
|
|
for (j=0 ; j <poly->nrings ; j++) {
|
|
size += pointArray_geojson_size(poly->rings[j], precision);
|
|
size += sizeof("[]");
|
|
}
|
|
size += sizeof("[]");
|
|
}
|
|
size += sizeof(",") * i;
|
|
size += sizeof("]}");
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_multipolygon_buf(LWGEOM_INSPECTED *insp, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
LWPOLY *poly;
|
|
int i, j;
|
|
char *ptr=output;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"MultiPolygon\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(insp->type), precision);
|
|
ptr += sprintf(ptr, "\"coordinates\":[");
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
{
|
|
if (i) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[");
|
|
poly = lwgeom_getpoly_inspected(insp, i);
|
|
for (j=0 ; j < poly->nrings ; j++) {
|
|
if (j) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[");
|
|
ptr += pointArray_to_geojson(poly->rings[j], ptr, precision);
|
|
ptr += sprintf(ptr, "]");
|
|
}
|
|
ptr += sprintf(ptr, "]");
|
|
pfree_polygon(poly);
|
|
}
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr - output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_multipolygon(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_multipolygon_size(insp, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_multipolygon_buf(insp, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Collection Geometry
|
|
*/
|
|
|
|
static size_t
|
|
asgeojson_collection_size(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
int i;
|
|
int size;
|
|
LWGEOM_INSPECTED *subinsp;
|
|
uchar *subgeom;
|
|
|
|
size = sizeof("{'type':'GeometryCollection',");
|
|
if (srs) size += asgeojson_srs_size(srs);
|
|
if (bbox) size += asgeojson_bbox_size(TYPE_HASZ(insp->type), precision);
|
|
size += sizeof("'geometries':");
|
|
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
{
|
|
subgeom = lwgeom_getsubgeometry_inspected(insp, i);
|
|
subinsp = lwgeom_inspect(subgeom);
|
|
size += asgeojson_inspected_size(subinsp, bbox, precision);
|
|
pfree_inspected(subinsp);
|
|
}
|
|
size += sizeof(",") * i;
|
|
size += sizeof("]}");
|
|
|
|
return size;
|
|
}
|
|
|
|
static size_t
|
|
asgeojson_collection_buf(LWGEOM_INSPECTED *insp, char *srs, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
int i;
|
|
char *ptr=output;
|
|
LWGEOM_INSPECTED *subinsp;
|
|
uchar *subgeom;
|
|
|
|
ptr += sprintf(ptr, "{\"type\":\"GeometryCollection\",");
|
|
if (srs) ptr += asgeojson_srs_buf(ptr, srs);
|
|
if (bbox) ptr += asgeojson_bbox_buf(ptr, bbox, TYPE_HASZ(insp->type), precision);
|
|
ptr += sprintf(ptr, "\"geometries\":[");
|
|
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
{
|
|
if (i) ptr += sprintf(ptr, ",");
|
|
subgeom = lwgeom_getsubgeometry_inspected(insp, i);
|
|
subinsp = lwgeom_inspect(subgeom);
|
|
ptr += asgeojson_inspected_buf(subinsp, ptr, bbox, precision);
|
|
pfree_inspected(subinsp);
|
|
}
|
|
|
|
ptr += sprintf(ptr, "]}");
|
|
|
|
return (ptr - output);
|
|
}
|
|
|
|
static char *
|
|
asgeojson_collection(LWGEOM_INSPECTED *insp, char *srs, BOX3D *bbox, int precision)
|
|
{
|
|
char *output;
|
|
int size;
|
|
|
|
size = asgeojson_collection_size(insp, srs, bbox, precision);
|
|
output = palloc(size);
|
|
asgeojson_collection_buf(insp, srs, output, bbox, precision);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
asgeojson_inspected_size(LWGEOM_INSPECTED *insp, BOX3D *bbox, int precision)
|
|
{
|
|
int type = lwgeom_getType(insp->serialized_form[0]);
|
|
size_t size = 0;
|
|
LWPOINT *point;
|
|
LWLINE *line;
|
|
LWPOLY *poly;
|
|
|
|
switch(type) {
|
|
case POINTTYPE:
|
|
point=lwgeom_getpoint_inspected(insp, 0);
|
|
size = asgeojson_point_size(point, NULL, bbox, precision);
|
|
pfree_point(point);
|
|
break;
|
|
|
|
case LINETYPE:
|
|
line=lwgeom_getline_inspected(insp, 0);
|
|
size = asgeojson_line_size(line, NULL, bbox, precision);
|
|
pfree_line(line);
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
poly=lwgeom_getpoly_inspected(insp, 0);
|
|
size = asgeojson_poly_size(poly, NULL, bbox, precision);
|
|
pfree_polygon(poly);
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
size = asgeojson_multipoint_size(insp, NULL, bbox, precision);
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
size = asgeojson_multiline_size(insp, NULL, bbox, precision);
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
size = asgeojson_multipolygon_size(insp, NULL, bbox, precision);
|
|
break;
|
|
|
|
default: lwerror("GeoJson: geometry not supported.");
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
static size_t
|
|
asgeojson_inspected_buf(LWGEOM_INSPECTED *insp, char *output, BOX3D *bbox, int precision)
|
|
{
|
|
LWPOINT *point;
|
|
LWLINE *line;
|
|
LWPOLY *poly;
|
|
int type = lwgeom_getType(insp->serialized_form[0]);
|
|
char *ptr=output;
|
|
|
|
/* Compute 3D BBOX on the sub geometry */
|
|
if ( bbox ) {
|
|
lwfree(bbox);
|
|
bbox = NULL;
|
|
bbox = compute_serialized_box3d(
|
|
lwgeom_getsubgeometry(insp->serialized_form, 0));
|
|
}
|
|
|
|
switch(type) {
|
|
case POINTTYPE:
|
|
point=lwgeom_getpoint_inspected(insp, 0);
|
|
ptr += asgeojson_point_buf(point, NULL, ptr, bbox, precision);
|
|
pfree_point(point);
|
|
break;
|
|
|
|
case LINETYPE:
|
|
line=lwgeom_getline_inspected(insp, 0);
|
|
ptr += asgeojson_line_buf(line, NULL, ptr, bbox, precision);
|
|
pfree_line(line);
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
poly=lwgeom_getpoly_inspected(insp, 0);
|
|
ptr += asgeojson_poly_buf(poly, NULL, ptr, bbox, precision);
|
|
pfree_polygon(poly);
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
ptr += asgeojson_multipoint_buf(insp, NULL, ptr, bbox, precision);
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
ptr += asgeojson_multiline_buf(insp, NULL, ptr, bbox, precision);
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
ptr += asgeojson_multipolygon_buf(insp, NULL, ptr, bbox, precision);
|
|
break;
|
|
|
|
default:
|
|
if (bbox) lwfree(bbox);
|
|
lwerror("GeoJson: geometry not supported.");
|
|
}
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
|
|
static size_t
|
|
pointArray_to_geojson(POINTARRAY *pa, char *output, int precision)
|
|
{
|
|
int i;
|
|
char *ptr;
|
|
|
|
ptr = output;
|
|
|
|
if (!TYPE_HASZ(pa->dims)) {
|
|
for (i=0; i<pa->npoints; i++) {
|
|
POINT2D pt;
|
|
getPoint2d_p(pa, i, &pt);
|
|
if ( i ) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[%.*f,%.*f]",
|
|
precision, pt.x,
|
|
precision, pt.y);
|
|
}
|
|
} else {
|
|
for (i=0; i<pa->npoints; i++) {
|
|
POINT4D pt;
|
|
getPoint4d_p(pa, i, &pt);
|
|
if ( i ) ptr += sprintf(ptr, ",");
|
|
ptr += sprintf(ptr, "[%.*f,%.*f,%.*f]",
|
|
precision, pt.x,
|
|
precision, pt.y,
|
|
precision, pt.z);
|
|
}
|
|
}
|
|
|
|
return (ptr-output);
|
|
}
|
|
|
|
|
|
/*
|
|
* Common geojson routines
|
|
*/
|
|
|
|
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::text)) \
|
|
FROM spatial_ref_sys WHERE srid = '%d'", SRID);
|
|
|
|
/* 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) {
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns maximum size of rendered pointarray in bytes.
|
|
*/
|
|
static size_t
|
|
pointArray_geojson_size(POINTARRAY *pa, int precision)
|
|
{
|
|
if (TYPE_NDIMS(pa->dims) == 2)
|
|
return (MAX_DIGS_DOUBLE + precision + sizeof(","))
|
|
* 2 * pa->npoints + sizeof(",[]");
|
|
|
|
return (MAX_DIGS_DOUBLE + precision + sizeof(",,"))
|
|
* 3 * pa->npoints + sizeof(",[]");
|
|
}
|