PostGIS  3.4.0dev-r@@SVN_REVISION@@
lwout_geojson.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2001-2003 Refractions Research Inc.
22  * Copyright 2009-2010 Olivier Courtin <olivier.courtin@oslandia.com>
23  *
24  **********************************************************************/
25 
26 
27 #include "liblwgeom_internal.h"
28 #include "stringbuffer.h"
29 #include <string.h> /* strlen */
30 #include <assert.h>
31 
32 
33 typedef struct geojson_opts {
34  const char *srs;
36  int precision;
37  int hasz;
40 
41 enum {
44 };
45 
46 static void asgeojson_geometry(stringbuffer_t *sb, const LWGEOM *geom, const geojson_opts *opts);
47 
48 
49 
50 static void
52 {
53  if (!FLAGS_GET_Z(pa->flags))
54  {
55  const POINT2D *pt = getPoint2d_cp(pa, i);
56  stringbuffer_append_char(sb, '[');
57  stringbuffer_append_double(sb, pt->x, opts->precision);
58  stringbuffer_append_char(sb, ',');
59  stringbuffer_append_double(sb, pt->y, opts->precision);
60  stringbuffer_append_char(sb, ']');
61  }
62  else
63  {
64  const POINT3D *pt = getPoint3d_cp(pa, i);
65  stringbuffer_append_char(sb, '[');
66  stringbuffer_append_double(sb, pt->x, opts->precision);
67  stringbuffer_append_char(sb, ',');
68  stringbuffer_append_double(sb, pt->y, opts->precision);
69  stringbuffer_append_char(sb, ',');
70  stringbuffer_append_double(sb, pt->z, opts->precision);
71  stringbuffer_append_char(sb, ']');
72  }
73 }
74 
75 static void
77 {
78  if (!pa || pa->npoints == 0)
79  {
80  stringbuffer_append_len(sb, "[]", 2);
81  return;
82  }
83 
84  stringbuffer_append_char(sb, '[');
85  for (uint32_t i = 0; i < pa->npoints; i++)
86  {
87  if (i) stringbuffer_append_char(sb, ',');
88  coordinate_to_geojson(sb, pa, i, opts);
89  }
90  stringbuffer_append_char(sb, ']');
91  return;
92 }
93 
94 static void
96 {
97  if (!opts->srs) return;
98  stringbuffer_append_len(sb, "\"crs\":{\"type\":\"name\",", 21);
99  stringbuffer_aprintf(sb, "\"properties\":{\"name\":\"%s\"}},", opts->srs);
100  return;
101 }
102 
103 
104 static void
106 {
107  if (!opts->bbox) return;
108  if (!opts->hasz)
109  stringbuffer_aprintf(sb, "\"bbox\":[%.*f,%.*f,%.*f,%.*f],",
110  opts->precision, opts->bbox->xmin,
111  opts->precision, opts->bbox->ymin,
112  opts->precision, opts->bbox->xmax,
113  opts->precision, opts->bbox->ymax);
114  else
115  stringbuffer_aprintf(sb, "\"bbox\":[%.*f,%.*f,%.*f,%.*f,%.*f,%.*f],",
116  opts->precision, opts->bbox->xmin,
117  opts->precision, opts->bbox->ymin,
118  opts->precision, opts->bbox->zmin,
119  opts->precision, opts->bbox->xmax,
120  opts->precision, opts->bbox->ymax,
121  opts->precision, opts->bbox->zmax);
122  return;
123 }
124 
125 
129 static void
130 asgeojson_point_coords(stringbuffer_t *sb, const LWPOINT *point, const geojson_opts *opts, int tagged)
131 {
132  if (tagged == geojson_tagged) stringbuffer_append_len(sb, "\"coordinates\":", 14);
133  if (lwgeom_is_empty((LWGEOM*)point))
134  stringbuffer_append_len(sb, "[]", 2);
135  else
136  coordinate_to_geojson(sb, point->point, 0, opts);
137  return;
138 }
139 
140 static void
141 asgeojson_line_coords(stringbuffer_t *sb, const LWLINE *line, const geojson_opts *opts, int tagged)
142 {
143  if (tagged == geojson_tagged) stringbuffer_append_len(sb, "\"coordinates\":", 14);
144  if (lwgeom_is_empty((LWGEOM*)line))
145  stringbuffer_append_len(sb, "[]", 2);
146  else
147  pointArray_to_geojson(sb, line->points, opts);
148  return;
149 }
150 
151 static void
152 asgeojson_poly_coords(stringbuffer_t *sb, const LWPOLY *poly, const geojson_opts *opts, int tagged)
153 {
154  uint32_t i;
155  if (tagged == geojson_tagged) stringbuffer_append_len(sb, "\"coordinates\":", 14);
156  if (lwgeom_is_empty((LWGEOM*)poly))
157  stringbuffer_append_len(sb, "[]", 2);
158  else
159  {
160  stringbuffer_append_char(sb, '[');
161  for (i = 0; i < poly->nrings; i++)
162  {
163  if (i) stringbuffer_append_char(sb, ',');
164  pointArray_to_geojson(sb, poly->rings[i], opts);
165  }
166  stringbuffer_append_char(sb, ']');
167  }
168  return;
169 }
170 
174 static void
176 {
177  stringbuffer_append_len(sb, "{\"type\":\"Point\",", 16);
178  asgeojson_srs(sb, opts);
179  asgeojson_bbox(sb, opts);
181  stringbuffer_append_char(sb, '}');
182  return;
183 }
184 
188 static void
190 {
191  stringbuffer_append_len(sb, "{\"type\":\"Polygon\",", 18);
192  asgeojson_srs(sb, opts);
193  asgeojson_bbox(sb, opts);
194  stringbuffer_append_len(sb, "\"coordinates\":[", 15);
195  if (lwtriangle_is_empty(tri))
196  stringbuffer_append_len(sb, "[]", 2);
197  else
198  pointArray_to_geojson(sb, tri->points, opts);
199  stringbuffer_append_len(sb, "]}", 2);
200  return;
201 }
202 
206 static void
208 {
209  const char tmpl[] = "{\"type\":\"LineString\",";
210  stringbuffer_append_len(sb, tmpl, sizeof(tmpl)-1);
211  asgeojson_srs(sb, opts);
212  asgeojson_bbox(sb, opts);
214  stringbuffer_append_char(sb, '}');
215  return;
216 }
217 
221 static void
223 {
224  stringbuffer_append_len(sb, "{\"type\":\"Polygon\",", 18);
225  asgeojson_srs(sb, opts);
226  asgeojson_bbox(sb, opts);
228  stringbuffer_append_char(sb, '}');
229  return;
230 }
231 
235 static void
237 {
238  uint32_t i, ngeoms = mpoint->ngeoms;
239  stringbuffer_append_len(sb, "{\"type\":\"MultiPoint\",", 21);
240  asgeojson_srs(sb, opts);
241  asgeojson_bbox(sb, opts);
242  stringbuffer_append_len(sb, "\"coordinates\":[", 15);
243 
244  if (lwgeom_is_empty((LWGEOM*)mpoint))
245  ngeoms = 0;
246 
247  for (i=0; i < ngeoms; i++)
248  {
249  if (i) stringbuffer_append_char(sb, ',');
251  }
252  stringbuffer_append_len(sb, "]}", 2);
253  return;
254 }
255 
256 
260 static void
262 {
263  uint32_t i, ngeoms = mline->ngeoms;
264  stringbuffer_append_len(sb, "{\"type\":\"MultiLineString\",", 26);
265  asgeojson_srs(sb, opts);
266  asgeojson_bbox(sb, opts);
267  stringbuffer_append_len(sb, "\"coordinates\":[", 15);
268 
269  if (lwgeom_is_empty((LWGEOM*)mline))
270  ngeoms = 0;
271 
272  for (i=0; i < ngeoms; i++)
273  {
274  if (i) stringbuffer_append_char(sb, ',');
276  }
277  stringbuffer_append_len(sb, "]}", 2);
278  return;
279 }
280 
281 
282 static void
284 {
285  uint32_t i, ngeoms = mpoly->ngeoms;
286 
287  stringbuffer_append_len(sb, "{\"type\":\"MultiPolygon\",", 23);
288  asgeojson_srs(sb, opts);
289  asgeojson_bbox(sb, opts);
290  stringbuffer_append_len(sb, "\"coordinates\":[", 15);
291 
292  if (lwgeom_is_empty((LWGEOM*)mpoly))
293  ngeoms = 0;
294 
295  for (i=0; i < ngeoms; i++)
296  {
297  if (i) stringbuffer_append_char(sb, ',');
299  }
300  stringbuffer_append_len(sb, "]}", 2);
301  return;
302 }
303 
307 static void
309 {
310  uint32_t i, ngeoms = col->ngeoms;
311 
312  /* subgeometries don't get boxes or srs */
313  geojson_opts subopts = *opts;
314  subopts.bbox = NULL;
315  subopts.srs = NULL;
316  subopts.isCollectionElement = LW_TRUE;
317 
318  stringbuffer_append_len(sb, "{\"type\":\"GeometryCollection\",", 29);
319  asgeojson_srs(sb, opts);
320  if (col->ngeoms) asgeojson_bbox(sb, opts);
321  stringbuffer_append_len(sb, "\"geometries\":[", 14);
322 
323  if (lwgeom_is_empty((LWGEOM*)col))
324  ngeoms = 0;
325 
326  for (i=0; i<ngeoms; i++)
327  {
328  if (i) stringbuffer_append_char(sb, ',');
329  asgeojson_geometry(sb, col->geoms[i], &subopts);
330  }
331 
332  stringbuffer_append_len(sb, "]}", 2);
333  return;
334 }
335 
336 static void
338 {
339  switch (geom->type)
340  {
341  case POINTTYPE:
342  asgeojson_point(sb, (LWPOINT*)geom, opts);
343  break;
344  case LINETYPE:
345  asgeojson_line(sb, (LWLINE*)geom, opts);
346  break;
347  case POLYGONTYPE:
348  asgeojson_poly(sb, (LWPOLY*)geom, opts);
349  break;
350  case MULTIPOINTTYPE:
351  asgeojson_multipoint(sb, (LWMPOINT*)geom, opts);
352  break;
353  case MULTILINETYPE:
354  asgeojson_multiline(sb, (LWMLINE*)geom, opts);
355  break;
356  case MULTIPOLYGONTYPE:
357  asgeojson_multipolygon(sb, (LWMPOLY*)geom, opts);
358  break;
359  case TRIANGLETYPE:
360  asgeojson_triangle(sb, (LWTRIANGLE *)geom, opts);
361  break;
362  case TINTYPE:
363  case COLLECTIONTYPE:
364  if (opts->isCollectionElement) {
365  lwerror("GeoJson: geometry not supported.");
366  }
368  break;
369  default:
370  lwerror("lwgeom_to_geojson: '%s' geometry type not supported", lwtype_name(geom->type));
371  }
372 }
373 
377 lwvarlena_t *
378 lwgeom_to_geojson(const LWGEOM *geom, const char *srs, int precision, int has_bbox)
379 {
380  GBOX static_bbox = {0};
382  stringbuffer_t sb;
383 
384  memset(&opts, 0, sizeof(opts));
385  opts.precision = precision;
386  opts.hasz = FLAGS_GET_Z(geom->flags);
387  opts.srs = srs;
388 
389  if (has_bbox)
390  {
391  /* Whether these are geography or geometry,
392  the GeoJSON expects a cartesian bounding box */
393  lwgeom_calculate_gbox_cartesian(geom, &static_bbox);
394  opts.bbox = &static_bbox;
395  }
396 
397  /* To avoid taking a copy of the output, we make */
398  /* space for the VARLENA header before starting to */
399  /* serialize the geom */
401  /* Now serialize the geometry */
402  asgeojson_geometry(&sb, geom, &opts);
403  /* Leave the initially allocated buffer in place */
404  /* and write the varlena_t metadata into the slot we */
405  /* left at the start */
406  return stringbuffer_getvarlena(&sb);
407 }
static uint8_t precision
Definition: cu_in_twkb.c:25
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: gbox.c:740
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define LINETYPE
Definition: liblwgeom.h:103
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:165
#define TINTYPE
Definition: liblwgeom.h:116
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
#define POLYGONTYPE
Definition: liblwgeom.h:104
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define TRIANGLETYPE
Definition: liblwgeom.h:115
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
int lwtriangle_is_empty(const LWTRIANGLE *triangle)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:101
static const POINT3D * getPoint3d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT3D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:113
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:203
static void pointArray_to_geojson(stringbuffer_t *sb, const POINTARRAY *pa, const geojson_opts *opts)
Definition: lwout_geojson.c:76
static void asgeojson_point(stringbuffer_t *sb, const LWPOINT *point, const geojson_opts *opts)
Point Geometry.
static void asgeojson_srs(stringbuffer_t *sb, const geojson_opts *opts)
Definition: lwout_geojson.c:95
static void asgeojson_triangle(stringbuffer_t *sb, const LWTRIANGLE *tri, const geojson_opts *opts)
Triangle Geometry.
static void asgeojson_multipoint(stringbuffer_t *sb, const LWMPOINT *mpoint, const geojson_opts *opts)
Multipoint Geometry.
static void asgeojson_geometry(stringbuffer_t *sb, const LWGEOM *geom, const geojson_opts *opts)
static void asgeojson_bbox(stringbuffer_t *sb, const geojson_opts *opts)
static void asgeojson_line(stringbuffer_t *sb, const LWLINE *line, const geojson_opts *opts)
Line Geometry.
static void asgeojson_point_coords(stringbuffer_t *sb, const LWPOINT *point, const geojson_opts *opts, int tagged)
Point Geometry.
static void coordinate_to_geojson(stringbuffer_t *sb, const POINTARRAY *pa, uint32_t i, const geojson_opts *opts)
Definition: lwout_geojson.c:51
static void asgeojson_poly(stringbuffer_t *sb, const LWPOLY *poly, const geojson_opts *opts)
Polygon Geometry.
lwvarlena_t * lwgeom_to_geojson(const LWGEOM *geom, const char *srs, int precision, int has_bbox)
Takes a GEOMETRY and returns a GeoJson representation.
static void asgeojson_multipolygon(stringbuffer_t *sb, const LWMPOLY *mpoly, const geojson_opts *opts)
static void asgeojson_collection(stringbuffer_t *sb, const LWCOLLECTION *col, const geojson_opts *opts)
Collection Geometry.
static void asgeojson_poly_coords(stringbuffer_t *sb, const LWPOLY *poly, const geojson_opts *opts, int tagged)
static void asgeojson_multiline(stringbuffer_t *sb, const LWMLINE *mline, const geojson_opts *opts)
Multipoint Geometry.
@ geojson_untagged
Definition: lwout_geojson.c:43
@ geojson_tagged
Definition: lwout_geojson.c:42
static void asgeojson_line_coords(stringbuffer_t *sb, const LWLINE *line, const geojson_opts *opts, int tagged)
struct geojson_opts geojson_opts
opts
Definition: ovdump.py:45
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
Definition: stringbuffer.c:247
lwvarlena_t * stringbuffer_getvarlena(stringbuffer_t *s)
Definition: stringbuffer.c:143
void stringbuffer_init_varlena(stringbuffer_t *s)
Definition: stringbuffer.c:60
static void stringbuffer_append_double(stringbuffer_t *s, double d, int precision)
Definition: stringbuffer.h:112
static void stringbuffer_append_char(stringbuffer_t *s, char c)
Definition: stringbuffer.h:119
static void stringbuffer_append_len(stringbuffer_t *s, const char *a, size_t alen)
Append the specified string to the stringbuffer_t using known length.
Definition: stringbuffer.h:93
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
uint8_t type
Definition: liblwgeom.h:462
lwflags_t flags
Definition: liblwgeom.h:461
POINTARRAY * points
Definition: liblwgeom.h:483
LWLINE ** geoms
Definition: liblwgeom.h:547
uint32_t ngeoms
Definition: liblwgeom.h:552
uint32_t ngeoms
Definition: liblwgeom.h:538
LWPOINT ** geoms
Definition: liblwgeom.h:533
uint32_t ngeoms
Definition: liblwgeom.h:566
LWPOLY ** geoms
Definition: liblwgeom.h:561
POINTARRAY * point
Definition: liblwgeom.h:471
uint8_t type
Definition: liblwgeom.h:474
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
POINTARRAY * points
Definition: liblwgeom.h:495
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
double z
Definition: liblwgeom.h:402
double x
Definition: liblwgeom.h:402
double y
Definition: liblwgeom.h:402
lwflags_t flags
Definition: liblwgeom.h:431
uint32_t npoints
Definition: liblwgeom.h:427
const char * srs
Definition: lwout_geojson.c:34
int isCollectionElement
Definition: lwout_geojson.c:38