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