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