PostGIS  2.5.2dev-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, __attribute__((__unused__)) 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  if (LW_FAILURE == parse_geojson_coord(coords, hasz, ppa[i]))
277  {
278  int k;
279  for (k = 0; k <= i; k++)
280  {
281  ptarray_free(ppa[k]);
282  }
283  lwfree(ppa);
284  geojson_lwerror("The 'coordinates' in GeoJSON polygon are not sufficiently nested", 4);
285  return NULL;
286  }
287  }
288  }
289 
290  /* All the rings were empty! */
291  if ( ! ppa )
292  return (LWGEOM *)lwpoly_construct_empty(root_srid, 0, 0);
293 
294  return (LWGEOM *) lwpoly_construct(root_srid, NULL, nRings, ppa);
295 }
296 
297 static LWGEOM*
298 parse_geojson_multipoint(json_object *geojson, int *hasz, int root_srid)
299 {
300  LWGEOM *geom;
301  int i = 0;
302  json_object* poObjPoints = NULL;
303 
304  if (!root_srid)
305  {
306  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, root_srid, 1, 0);
307  }
308  else
309  {
311  }
312 
313  poObjPoints = findMemberByName( geojson, "coordinates" );
314  if ( ! poObjPoints )
315  {
316  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
317  return NULL;
318  }
319 
320  if( json_type_array == json_object_get_type( poObjPoints ) )
321  {
322  const int nPoints = json_object_array_length( poObjPoints );
323  for( i = 0; i < nPoints; ++i)
324  {
325  POINTARRAY *pa;
326  json_object* poObjCoords = NULL;
327  poObjCoords = json_object_array_get_idx( poObjPoints, i );
328 
329  pa = ptarray_construct_empty(1, 0, 1);
330  parse_geojson_coord(poObjCoords, hasz, pa);
331 
332  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
333  (LWPOINT*)lwpoint_construct(root_srid, NULL, pa));
334  }
335  }
336 
337  return geom;
338 }
339 
340 static LWGEOM*
341 parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid)
342 {
343  LWGEOM *geom = NULL;
344  int i, j;
345  json_object* poObjLines = NULL;
346 
347  if (!root_srid)
348  {
349  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, root_srid, 1, 0);
350  }
351  else
352  {
354  }
355 
356  poObjLines = findMemberByName( geojson, "coordinates" );
357  if ( ! poObjLines )
358  {
359  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
360  return NULL;
361  }
362 
363  if( json_type_array == json_object_get_type( poObjLines ) )
364  {
365  const int nLines = json_object_array_length( poObjLines );
366  for( i = 0; i < nLines; ++i)
367  {
368  POINTARRAY *pa = NULL;
369  json_object* poObjLine = NULL;
370  poObjLine = json_object_array_get_idx( poObjLines, i );
371  pa = ptarray_construct_empty(1, 0, 1);
372 
373  if( json_type_array == json_object_get_type( poObjLine ) )
374  {
375  const int nPoints = json_object_array_length( poObjLine );
376  for(j = 0; j < nPoints; ++j)
377  {
378  json_object* coords = NULL;
379  coords = json_object_array_get_idx( poObjLine, j );
380  parse_geojson_coord(coords, hasz, pa);
381  }
382 
383  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
384  (LWLINE*)lwline_construct(root_srid, NULL, pa));
385  }
386  }
387  }
388 
389  return geom;
390 }
391 
392 static LWGEOM*
393 parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid)
394 {
395  LWGEOM *geom = NULL;
396  int i, j, k;
397  json_object* poObjPolys = NULL;
398 
399  if (!root_srid)
400  {
401  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, root_srid, 1, 0);
402  }
403  else
404  {
406  }
407 
408  poObjPolys = findMemberByName( geojson, "coordinates" );
409  if ( ! poObjPolys )
410  {
411  geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
412  return NULL;
413  }
414 
415  if( json_type_array == json_object_get_type( poObjPolys ) )
416  {
417  const int nPolys = json_object_array_length( poObjPolys );
418 
419  for(i = 0; i < nPolys; ++i)
420  {
421  json_object* poObjPoly = json_object_array_get_idx( poObjPolys, i );
422 
423  if( json_type_array == json_object_get_type( poObjPoly ) )
424  {
425  LWPOLY *lwpoly = lwpoly_construct_empty(geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom));
426  int nRings = json_object_array_length( poObjPoly );
427 
428  for(j = 0; j < nRings; ++j)
429  {
430  json_object* points = json_object_array_get_idx( poObjPoly, j );
431 
432  if( json_type_array == json_object_get_type( points ) )
433  {
434 
435  POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
436 
437  int nPoints = json_object_array_length( points );
438  for ( k=0; k < nPoints; k++ )
439  {
440  json_object* coords = json_object_array_get_idx( points, k );
441  parse_geojson_coord(coords, hasz, pa);
442  }
443 
444  lwpoly_add_ring(lwpoly, pa);
445  }
446  }
447  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, lwpoly);
448  }
449  }
450  }
451 
452  return geom;
453 }
454 
455 static LWGEOM*
456 parse_geojson_geometrycollection(json_object *geojson, int *hasz, int root_srid)
457 {
458  LWGEOM *geom = NULL;
459  int i;
460  json_object* poObjGeoms = NULL;
461 
462  if (!root_srid)
463  {
464  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, root_srid, 1, 0);
465  }
466  else
467  {
469  }
470 
471  poObjGeoms = findMemberByName( geojson, "geometries" );
472  if ( ! poObjGeoms )
473  {
474  geojson_lwerror("Unable to find 'geometries' in GeoJSON string", 4);
475  return NULL;
476  }
477 
478  if( json_type_array == json_object_get_type( poObjGeoms ) )
479  {
480  const int nGeoms = json_object_array_length( poObjGeoms );
481  json_object* poObjGeom = NULL;
482  for(i = 0; i < nGeoms; ++i )
483  {
484  poObjGeom = json_object_array_get_idx( poObjGeoms, i );
486  parse_geojson(poObjGeom, hasz, root_srid));
487  }
488  }
489 
490  return geom;
491 }
492 
493 static LWGEOM*
494 parse_geojson(json_object *geojson, int *hasz, int root_srid)
495 {
496  json_object* type = NULL;
497  const char* name;
498 
499  if( NULL == geojson )
500  {
501  geojson_lwerror("invalid GeoJSON representation", 2);
502  return NULL;
503  }
504 
505  type = findMemberByName( geojson, "type" );
506  if( NULL == type )
507  {
508  geojson_lwerror("unknown GeoJSON type", 3);
509  return NULL;
510  }
511 
512  name = json_object_get_string( type );
513 
514  if( strcasecmp( name, "Point" )==0 )
515  return parse_geojson_point(geojson, hasz, root_srid);
516 
517  if( strcasecmp( name, "LineString" )==0 )
518  return parse_geojson_linestring(geojson, hasz, root_srid);
519 
520  if( strcasecmp( name, "Polygon" )==0 )
521  return parse_geojson_polygon(geojson, hasz, root_srid);
522 
523  if( strcasecmp( name, "MultiPoint" )==0 )
524  return parse_geojson_multipoint(geojson, hasz, root_srid);
525 
526  if( strcasecmp( name, "MultiLineString" )==0 )
527  return parse_geojson_multilinestring(geojson, hasz, root_srid);
528 
529  if( strcasecmp( name, "MultiPolygon" )==0 )
530  return parse_geojson_multipolygon(geojson, hasz, root_srid);
531 
532  if( strcasecmp( name, "GeometryCollection" )==0 )
533  return parse_geojson_geometrycollection(geojson, hasz, root_srid);
534 
535  lwerror("invalid GeoJson representation");
536  return NULL; /* Never reach */
537 }
538 
539 #endif /* HAVE_LIBJSON or HAVE_LIBJSON_C --} */
540 
541 LWGEOM*
542 lwgeom_from_geojson(const char *geojson, char **srs)
543 {
544 #ifndef HAVE_LIBJSON
545  *srs = NULL;
546  lwerror("You need JSON-C for lwgeom_from_geojson");
547  return NULL;
548 #else /* HAVE_LIBJSON */
549 
550  /* size_t geojson_size = strlen(geojson); */
551 
552  LWGEOM *lwgeom;
553  int hasz=LW_TRUE;
554  json_tokener* jstok = NULL;
555  json_object* poObj = NULL;
556  json_object* poObjSrs = NULL;
557  *srs = NULL;
558 
559  /* Begin to Parse json */
560  jstok = json_tokener_new();
561  poObj = json_tokener_parse_ex(jstok, geojson, -1);
562  if( jstok->err != json_tokener_success)
563  {
564  char err[256];
565  snprintf(err, 256, "%s (at offset %d)", json_tokener_error_desc(jstok->err), jstok->char_offset);
566  json_tokener_free(jstok);
567  json_object_put(poObj);
568  geojson_lwerror(err, 1);
569  return NULL;
570  }
571  json_tokener_free(jstok);
572 
573  poObjSrs = findMemberByName( poObj, "crs" );
574  if (poObjSrs != NULL)
575  {
576  json_object* poObjSrsType = findMemberByName( poObjSrs, "type" );
577  if (poObjSrsType != NULL)
578  {
579  json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" );
580  if ( poObjSrsProps )
581  {
582  json_object* poNameURL = findMemberByName( poObjSrsProps, "name" );
583  if ( poNameURL )
584  {
585  const char* pszName = json_object_get_string( poNameURL );
586  if ( pszName )
587  {
588  *srs = lwalloc(strlen(pszName) + 1);
589  strcpy(*srs, pszName);
590  }
591  }
592  }
593  }
594  }
595 
596  lwgeom = parse_geojson(poObj, &hasz, 0);
597  json_object_put(poObj);
598 
599  lwgeom_add_bbox(lwgeom);
600 
601  if (!hasz)
602  {
603  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
604  lwgeom_free(lwgeom);
605  lwgeom = tmp;
606 
607  LWDEBUG(2, "geom_from_geojson called.");
608  }
609 
610  return lwgeom;
611 #endif /* HAVE_LIBJSON } */
612 }
613 
614 
double x
Definition: liblwgeom.h:355
double m
Definition: liblwgeom.h:355
static LWGEOM * parse_geojson(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:494
static void geojson_lwerror(char *msg, __attribute__((__unused__)) int error_code)
Definition: lwin_geojson.c:55
void lwfree(void *mem)
Definition: lwutil.c:244
#define __attribute__(x)
Definition: liblwgeom.h:201
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:1144
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:328
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
static LWGEOM * parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:393
#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:930
int32_t srid
Definition: liblwgeom.h:402
#define LW_FAILURE
Definition: liblwgeom.h:79
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:77
uint8_t flags
Definition: liblwgeom.h:372
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:76
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:784
static LWGEOM * parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid)
Definition: lwin_geojson.c:341
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:140
double z
Definition: liblwgeom.h:355
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
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:456
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:161
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:686
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:141
type
Definition: ovdump.py:41
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring, allocating extra space if necessary.
Definition: lwpoly.c:247
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:298
double y
Definition: liblwgeom.h:355
#define MULTILINETYPE
Definition: liblwgeom.h:89
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:937
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:91
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:542