PostGIS  2.3.8dev-r@@SVN_REVISION@@
lwin_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 2013 Sandro Santilli <strk@kbt.io>
22  * Copyright 2011 Kashif Rasul <kashif.rasul@gmail.com>
23  *
24  **********************************************************************/
25 
26 
27 #include <assert.h>
28 #include "liblwgeom.h"
29 #include "lwgeom_log.h"
30 #include "../postgis_config.h"
31 
32 #if defined(HAVE_LIBJSON) || defined(HAVE_LIBJSON_C) /* --{ */
33 
34 #ifdef HAVE_LIBJSON_C
35 #include <json-c/json.h>
36 #include <json-c/json_object_private.h>
37 #else
38 #include <json/json.h>
39 #include <json/json_object_private.h>
40 #endif
41 
42 #ifndef JSON_C_VERSION
43 /* Adds support for libjson < 0.10 */
44 # define json_tokener_error_desc(x) json_tokener_errors[(x)]
45 #endif
46 
47 #include <string.h>
48 
49 static void geojson_lwerror(char *msg, int error_code)
50 {
51  LWDEBUGF(3, "lwgeom_from_geojson ERROR %i", error_code);
52  lwerror("%s", msg);
53 }
54 
55 /* Prototype */
56 static LWGEOM* parse_geojson(json_object *geojson, int *hasz, int root_srid);
57 
58 static json_object*
59 findMemberByName(json_object* poObj, const char* pszName )
60 {
61  json_object* poTmp;
62  json_object_iter it;
63 
64  poTmp = poObj;
65 
66  if( NULL == pszName || NULL == poObj)
67  return NULL;
68 
69  it.key = NULL;
70  it.val = NULL;
71  it.entry = NULL;
72 
73  if( NULL != json_object_get_object(poTmp) )
74  {
75  if( NULL == json_object_get_object(poTmp)->head )
76  {
77  geojson_lwerror("invalid GeoJSON representation", 2);
78  return NULL;
79  }
80 
81  for( it.entry = json_object_get_object(poTmp)->head;
82  ( it.entry ?
83  ( it.key = (char*)it.entry->k,
84  it.val = (json_object*)it.entry->v, it.entry) : 0);
85  it.entry = it.entry->next)
86  {
87  if( strcasecmp((char *)it.key, pszName )==0 )
88  return it.val;
89  }
90  }
91 
92  return NULL;
93 }
94 
95 
96 static int
97 parse_geojson_coord(json_object *poObj, int *hasz, POINTARRAY *pa)
98 {
99  POINT4D pt;
100 
101  LWDEBUGF(3, "parse_geojson_coord called for object %s.", json_object_to_json_string( poObj ) );
102 
103  if( json_type_array == json_object_get_type( poObj ) )
104  {
105 
106  json_object* poObjCoord = NULL;
107  const int nSize = json_object_array_length( poObj );
108  LWDEBUGF(3, "parse_geojson_coord called for array size %d.", nSize );
109 
110  if ( nSize < 2 )
111  {
112  geojson_lwerror("Too few ordinates in GeoJSON", 4);
113  return LW_FAILURE;
114  }
115 
116  /* Read X coordinate */
117  poObjCoord = json_object_array_get_idx( poObj, 0 );
118  pt.x = json_object_get_double( poObjCoord );
119  LWDEBUGF(3, "parse_geojson_coord pt.x = %f.", pt.x );
120 
121  /* Read Y coordinate */
122  poObjCoord = json_object_array_get_idx( poObj, 1 );
123  pt.y = json_object_get_double( poObjCoord );
124  LWDEBUGF(3, "parse_geojson_coord pt.y = %f.", pt.y );
125 
126  if( nSize > 2 ) /* should this be >= 3 ? */
127  {
128  /* Read Z coordinate */
129  poObjCoord = json_object_array_get_idx( poObj, 2 );
130  pt.z = json_object_get_double( poObjCoord );
131  LWDEBUGF(3, "parse_geojson_coord pt.z = %f.", pt.z );
132  *hasz = LW_TRUE;
133  }
134  else if ( nSize == 2 )
135  {
136  *hasz = LW_FALSE;
137  /* Initialize Z coordinate, if required */
138  if ( FLAGS_GET_Z(pa->flags) ) pt.z = 0.0;
139  }
140  else
141  {
142  /* TODO: should we account for nSize > 3 ? */
143  /* more than 3 coordinates, we're just dropping dimensions here... */
144  }
145 
146  /* Initialize M coordinate, if required */
147  if ( FLAGS_GET_M(pa->flags) ) pt.m = 0.0;
148 
149  }
150  else
151  {
152  /* If it's not an array, just don't handle it */
153  return LW_FAILURE;
154  }
155 
156  return ptarray_append_point(pa, &pt, LW_TRUE);
157 }
158 
159 static LWGEOM*
160 parse_geojson_point(json_object *geojson, int *hasz, int root_srid)
161 {
162  LWGEOM *geom;
163  POINTARRAY *pa;
164  json_object* coords = NULL;
165 
166  LWDEBUGF(3, "parse_geojson_point called with root_srid = %d.", root_srid );
167 
168  coords = findMemberByName( geojson, "coordinates" );
169  if ( ! coords )
170  {
171  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
172  return NULL;
173  }
174 
175  pa = ptarray_construct_empty(1, 0, 1);
176  parse_geojson_coord(coords, hasz, pa);
177 
178  geom = (LWGEOM *) lwpoint_construct(root_srid, NULL, pa);
179  LWDEBUG(2, "parse_geojson_point finished.");
180  return geom;
181 }
182 
183 static LWGEOM*
184 parse_geojson_linestring(json_object *geojson, int *hasz, int root_srid)
185 {
186  LWGEOM *geom;
187  POINTARRAY *pa;
188  json_object* points = NULL;
189  int i = 0;
190 
191  LWDEBUG(2, "parse_geojson_linestring called.");
192 
193  points = findMemberByName( geojson, "coordinates" );
194  if ( ! points )
195  {
196  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
197  return NULL;
198  }
199 
200  pa = ptarray_construct_empty(1, 0, 1);
201 
202  if( json_type_array == json_object_get_type( points ) )
203  {
204  const int nPoints = json_object_array_length( points );
205  for(i = 0; i < nPoints; ++i)
206  {
207  json_object* coords = NULL;
208  coords = json_object_array_get_idx( points, i );
209  parse_geojson_coord(coords, hasz, pa);
210  }
211  }
212 
213  geom = (LWGEOM *) lwline_construct(root_srid, NULL, pa);
214 
215  LWDEBUG(2, "parse_geojson_linestring finished.");
216  return geom;
217 }
218 
219 static LWGEOM*
220 parse_geojson_polygon(json_object *geojson, int *hasz, int root_srid)
221 {
222  POINTARRAY **ppa = NULL;
223  json_object* rings = NULL;
224  json_object* points = NULL;
225  int i = 0, j = 0;
226  int nRings = 0, nPoints = 0;
227 
228  rings = findMemberByName( geojson, "coordinates" );
229  if ( ! rings )
230  {
231  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
232  return NULL;
233  }
234 
235  if ( json_type_array != json_object_get_type(rings) )
236  {
237  geojson_lwerror("The 'coordinates' in GeoJSON are not an array", 4);
238  return NULL;
239  }
240 
241  nRings = json_object_array_length( rings );
242 
243  /* No rings => POLYGON EMPTY */
244  if ( ! nRings )
245  {
246  return (LWGEOM *)lwpoly_construct_empty(root_srid, 0, 0);
247  }
248 
249  for ( i = 0; i < nRings; i++ )
250  {
251  points = json_object_array_get_idx(rings, i);
252  if ( ! points || json_object_get_type(points) != json_type_array )
253  {
254  geojson_lwerror("The 'coordinates' in GeoJSON ring are not an array", 4);
255  return NULL;
256  }
257  nPoints = json_object_array_length(points);
258 
259  /* Skip empty rings */
260  if ( nPoints == 0 ) continue;
261 
262  if ( ! ppa )
263  ppa = (POINTARRAY**)lwalloc(sizeof(POINTARRAY*) * nRings);
264 
265  ppa[i] = ptarray_construct_empty(1, 0, 1);
266  for ( j = 0; j < nPoints; j++ )
267  {
268  json_object* coords = NULL;
269  coords = json_object_array_get_idx( points, j );
270  parse_geojson_coord(coords, hasz, ppa[i]);
271  }
272  }
273 
274  /* All the rings were empty! */
275  if ( ! ppa )
276  return (LWGEOM *)lwpoly_construct_empty(root_srid, 0, 0);
277 
278  return (LWGEOM *) lwpoly_construct(root_srid, NULL, nRings, ppa);
279 }
280 
281 static LWGEOM*
282 parse_geojson_multipoint(json_object *geojson, int *hasz, int root_srid)
283 {
284  LWGEOM *geom;
285  int i = 0;
286  json_object* poObjPoints = NULL;
287 
288  if (!root_srid)
289  {
290  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, root_srid, 1, 0);
291  }
292  else
293  {
295  }
296 
297  poObjPoints = findMemberByName( geojson, "coordinates" );
298  if ( ! poObjPoints )
299  {
300  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
301  return NULL;
302  }
303 
304  if( json_type_array == json_object_get_type( poObjPoints ) )
305  {
306  const int nPoints = json_object_array_length( poObjPoints );
307  for( i = 0; i < nPoints; ++i)
308  {
309  POINTARRAY *pa;
310  json_object* poObjCoords = NULL;
311  poObjCoords = json_object_array_get_idx( poObjPoints, i );
312 
313  pa = ptarray_construct_empty(1, 0, 1);
314  parse_geojson_coord(poObjCoords, hasz, pa);
315 
316  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
317  (LWPOINT*)lwpoint_construct(root_srid, NULL, pa));
318  }
319  }
320 
321  return geom;
322 }
323 
324 static LWGEOM*
325 parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid)
326 {
327  LWGEOM *geom = NULL;
328  int i, j;
329  json_object* poObjLines = NULL;
330 
331  if (!root_srid)
332  {
333  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, root_srid, 1, 0);
334  }
335  else
336  {
338  }
339 
340  poObjLines = findMemberByName( geojson, "coordinates" );
341  if ( ! poObjLines )
342  {
343  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
344  return NULL;
345  }
346 
347  if( json_type_array == json_object_get_type( poObjLines ) )
348  {
349  const int nLines = json_object_array_length( poObjLines );
350  for( i = 0; i < nLines; ++i)
351  {
352  POINTARRAY *pa = NULL;
353  json_object* poObjLine = NULL;
354  poObjLine = json_object_array_get_idx( poObjLines, i );
355  pa = ptarray_construct_empty(1, 0, 1);
356 
357  if( json_type_array == json_object_get_type( poObjLine ) )
358  {
359  const int nPoints = json_object_array_length( poObjLine );
360  for(j = 0; j < nPoints; ++j)
361  {
362  json_object* coords = NULL;
363  coords = json_object_array_get_idx( poObjLine, j );
364  parse_geojson_coord(coords, hasz, pa);
365  }
366 
367  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
368  (LWLINE*)lwline_construct(root_srid, NULL, pa));
369  }
370  }
371  }
372 
373  return geom;
374 }
375 
376 static LWGEOM*
377 parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid)
378 {
379  LWGEOM *geom = NULL;
380  int i, j, k;
381  json_object* poObjPolys = NULL;
382 
383  if (!root_srid)
384  {
385  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, root_srid, 1, 0);
386  }
387  else
388  {
390  }
391 
392  poObjPolys = findMemberByName( geojson, "coordinates" );
393  if ( ! poObjPolys )
394  {
395  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
396  return NULL;
397  }
398 
399  if( json_type_array == json_object_get_type( poObjPolys ) )
400  {
401  const int nPolys = json_object_array_length( poObjPolys );
402 
403  for(i = 0; i < nPolys; ++i)
404  {
405  json_object* poObjPoly = json_object_array_get_idx( poObjPolys, i );
406 
407  if( json_type_array == json_object_get_type( poObjPoly ) )
408  {
409  LWPOLY *lwpoly = lwpoly_construct_empty(geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom));
410  int nRings = json_object_array_length( poObjPoly );
411 
412  for(j = 0; j < nRings; ++j)
413  {
414  json_object* points = json_object_array_get_idx( poObjPoly, j );
415 
416  if( json_type_array == json_object_get_type( points ) )
417  {
418 
419  POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
420 
421  int nPoints = json_object_array_length( points );
422  for ( k=0; k < nPoints; k++ )
423  {
424  json_object* coords = json_object_array_get_idx( points, k );
425  parse_geojson_coord(coords, hasz, pa);
426  }
427 
428  lwpoly_add_ring(lwpoly, pa);
429  }
430  }
431  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, lwpoly);
432  }
433  }
434  }
435 
436  return geom;
437 }
438 
439 static LWGEOM*
440 parse_geojson_geometrycollection(json_object *geojson, int *hasz, int root_srid)
441 {
442  LWGEOM *geom = NULL;
443  int i;
444  json_object* poObjGeoms = NULL;
445 
446  if (!root_srid)
447  {
448  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, root_srid, 1, 0);
449  }
450  else
451  {
453  }
454 
455  poObjGeoms = findMemberByName( geojson, "geometries" );
456  if ( ! poObjGeoms )
457  {
458  geojson_lwerror("Unable to find 'geometries' in GeoJSON string", 4);
459  return NULL;
460  }
461 
462  if( json_type_array == json_object_get_type( poObjGeoms ) )
463  {
464  const int nGeoms = json_object_array_length( poObjGeoms );
465  json_object* poObjGeom = NULL;
466  for(i = 0; i < nGeoms; ++i )
467  {
468  poObjGeom = json_object_array_get_idx( poObjGeoms, i );
470  parse_geojson(poObjGeom, hasz, root_srid));
471  }
472  }
473 
474  return geom;
475 }
476 
477 static LWGEOM*
478 parse_geojson(json_object *geojson, int *hasz, int root_srid)
479 {
480  json_object* type = NULL;
481  const char* name;
482 
483  if( NULL == geojson )
484  {
485  geojson_lwerror("invalid GeoJSON representation", 2);
486  return NULL;
487  }
488 
489  type = findMemberByName( geojson, "type" );
490  if( NULL == type )
491  {
492  geojson_lwerror("unknown GeoJSON type", 3);
493  return NULL;
494  }
495 
496  name = json_object_get_string( type );
497 
498  if( strcasecmp( name, "Point" )==0 )
499  return parse_geojson_point(geojson, hasz, root_srid);
500 
501  if( strcasecmp( name, "LineString" )==0 )
502  return parse_geojson_linestring(geojson, hasz, root_srid);
503 
504  if( strcasecmp( name, "Polygon" )==0 )
505  return parse_geojson_polygon(geojson, hasz, root_srid);
506 
507  if( strcasecmp( name, "MultiPoint" )==0 )
508  return parse_geojson_multipoint(geojson, hasz, root_srid);
509 
510  if( strcasecmp( name, "MultiLineString" )==0 )
511  return parse_geojson_multilinestring(geojson, hasz, root_srid);
512 
513  if( strcasecmp( name, "MultiPolygon" )==0 )
514  return parse_geojson_multipolygon(geojson, hasz, root_srid);
515 
516  if( strcasecmp( name, "GeometryCollection" )==0 )
517  return parse_geojson_geometrycollection(geojson, hasz, root_srid);
518 
519  lwerror("invalid GeoJson representation");
520  return NULL; /* Never reach */
521 }
522 
523 #endif /* HAVE_LIBJSON or HAVE_LIBJSON_C --} */
524 
525 LWGEOM*
526 lwgeom_from_geojson(const char *geojson, char **srs)
527 {
528 #ifndef HAVE_LIBJSON
529  *srs = NULL;
530  lwerror("You need JSON-C for lwgeom_from_geojson");
531  return NULL;
532 #else /* HAVE_LIBJSON */
533 
534  /* size_t geojson_size = strlen(geojson); */
535 
536  LWGEOM *lwgeom;
537  int hasz=LW_TRUE;
538  json_tokener* jstok = NULL;
539  json_object* poObj = NULL;
540  json_object* poObjSrs = NULL;
541  *srs = NULL;
542 
543  /* Begin to Parse json */
544  jstok = json_tokener_new();
545  poObj = json_tokener_parse_ex(jstok, geojson, -1);
546  if( jstok->err != json_tokener_success)
547  {
548  char err[256];
549  snprintf(err, 256, "%s (at offset %d)", json_tokener_error_desc(jstok->err), jstok->char_offset);
550  json_tokener_free(jstok);
551  json_object_put(poObj);
552  geojson_lwerror(err, 1);
553  return NULL;
554  }
555  json_tokener_free(jstok);
556 
557  poObjSrs = findMemberByName( poObj, "crs" );
558  if (poObjSrs != NULL)
559  {
560  json_object* poObjSrsType = findMemberByName( poObjSrs, "type" );
561  if (poObjSrsType != NULL)
562  {
563  json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" );
564  if ( poObjSrsProps )
565  {
566  json_object* poNameURL = findMemberByName( poObjSrsProps, "name" );
567  if ( poNameURL )
568  {
569  const char* pszName = json_object_get_string( poNameURL );
570  if ( pszName )
571  {
572  *srs = lwalloc(strlen(pszName) + 1);
573  strcpy(*srs, pszName);
574  }
575  }
576  }
577  }
578  }
579 
580  lwgeom = parse_geojson(poObj, &hasz, 0);
581  json_object_put(poObj);
582 
583  lwgeom_add_bbox(lwgeom);
584 
585  if (!hasz)
586  {
587  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
588  lwgeom_free(lwgeom);
589  lwgeom = tmp;
590 
591  LWDEBUG(2, "geom_from_geojson called.");
592  }
593 
594  return lwgeom;
595 #endif /* HAVE_LIBJSON } */
596 }
597 
598 
double x
Definition: liblwgeom.h:351
double m
Definition: liblwgeom.h:351
static LWGEOM * parse_geojson(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:478
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:70
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1063
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
static LWGEOM * parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:377
static void geojson_lwerror(char *msg, int error_code)
Definition: lwin_geojson.c:49
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
static int parse_geojson_coord(json_object *poObj, int *hasz, POINTARRAY *pa)
Definition: lwin_geojson.c:97
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:849
int32_t srid
Definition: liblwgeom.h:398
#define LW_FAILURE
Definition: liblwgeom.h:78
static LWGEOM * parse_geojson_polygon(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:220
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE, then a duplicate point will not be added.
Definition: ptarray.c:156
#define LW_FALSE
Definition: liblwgeom.h:76
uint8_t flags
Definition: liblwgeom.h:368
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:43
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
#define json_tokener_error_desc(x)
Definition: lwin_geojson.c:44
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:703
static LWGEOM * parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:325
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:139
double z
Definition: liblwgeom.h:351
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
static LWGEOM * parse_geojson_linestring(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:184
static LWGEOM * parse_geojson_point(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:160
static LWGEOM * parse_geojson_geometrycollection(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:440
static json_object * findMemberByName(json_object *poObj, const char *pszName)
Definition: lwin_geojson.c:59
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:45
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:139
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:612
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
type
Definition: ovdump.py:41
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring, allocating extra space if necessary.
Definition: lwpoly.c:227
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:111
void * lwalloc(size_t size)
Definition: lwutil.c:227
static LWGEOM * parse_geojson_multipoint(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:282
double y
Definition: liblwgeom.h:351
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:856
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:187
LWMPOLY * lwmpoly_add_lwpoly(LWMPOLY *mobj, const LWPOLY *obj)
Definition: lwmpoly.c:47
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:102
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
This library is the generic geometry handling section of PostGIS.
LWGEOM * lwgeom_from_geojson(const char *geojson, char **srs)
Create an LWGEOM object from a GeoJSON representation.
Definition: lwin_geojson.c:526