PostGIS  3.4.0dev-r@@SVN_REVISION@@
gserialized2.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 2009 Paul Ramsey <pramsey@cleverelephant.ca>
22  * Copyright 2017 Darafei Praliaskouski <me@komzpa.net>
23  *
24  **********************************************************************/
25 
26 /*
27 * GSERIALIZED verison 2 includes an optional extended flags uint64_t
28 * before the optional bounding box. There may be other optional
29 * components before the data area, but they all must be double
30 * aligned to that the ordinates remain double aligned.
31 *
32 * <size> size Used by PgSQL VARSIZE g->size
33 * <srid 3 bytes g->srid
34 * gflags> 1 byte g->gflags
35 * [<extendedflags> Optional extended flags (check flags for cue)
36 * <extendedflags>]
37 * [<bbox-xmin> Optional bounding box (check flags for cue)
38 * <bbox-xmax> Number of dimensions is variable
39 * <bbox-ymin> and also indicated in the flags
40 * <bbox-ymax>]
41 * ...
42 * data area
43 */
44 
45 #include "liblwgeom_internal.h"
46 #include "lwgeom_log.h"
47 #include "lwgeodetic.h"
48 #include "gserialized2.h"
49 
50 #include <stddef.h>
51 
52 /***********************************************************************
53 * GSERIALIZED metadata utility functions.
54 */
55 
56 static int gserialized2_read_gbox_p(const GSERIALIZED *g, GBOX *gbox);
57 
58 
60 {
61  lwflags_t lwflags = 0;
62  uint8_t gflags = g->gflags;
67  if (G2FLAGS_GET_EXTENDED(gflags))
68  {
69  uint64_t xflags = 0;
70  memcpy(&xflags, g->data, sizeof(uint64_t));
72  }
73  return lwflags;
74 }
75 
77 {
79  return (lwflags & (~core_lwflags)) != 0;
80 }
81 
82 
83 static inline size_t gserialized2_box_size(const GSERIALIZED *g)
84 {
86  return 6 * sizeof(float);
87  else
88  return 2 * G2FLAGS_NDIMS(g->gflags) * sizeof(float);
89 }
90 
91 static inline size_t gserialized2_header_size(const GSERIALIZED *g)
92 {
93  uint32_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
94 
96  sz += 8;
97 
98  if (gserialized2_has_bbox(g))
99  sz += gserialized2_box_size(g);
100 
101  return sz;
102 }
103 
104 /* Returns a pointer to the start of the geometry data */
105 static inline uint8_t *
107 {
108  uint32_t extra_data_bytes = 0;
110  extra_data_bytes += sizeof(uint64_t);
111 
112  if (gserialized2_has_bbox(g))
113  extra_data_bytes += gserialized2_box_size(g);
114 
115  return ((uint8_t *)g->data) + extra_data_bytes;
116 }
117 
119 {
120  uint8_t gflags = 0;
126  G2FLAGS_SET_VERSION(gflags, 1);
127  return gflags;
128 }
129 
130 /* handle missaligned uint32_t data */
131 static inline uint32_t gserialized2_get_uint32_t(const uint8_t *loc)
132 {
133  return *((uint32_t*)loc);
134 }
135 
136 uint8_t g2flags(int has_z, int has_m, int is_geodetic)
137 {
138  uint8_t gflags = 0;
139  if (has_z)
140  G2FLAGS_SET_Z(gflags, 1);
141  if (has_m)
142  G2FLAGS_SET_M(gflags, 1);
143  if (is_geodetic)
144  G2FLAGS_SET_GEODETIC(gflags, 1);
145  return gflags;
146 }
147 
149 {
150  return G2FLAGS_GET_BBOX(g->gflags);
151 }
152 
154 {
155  return G2FLAGS_GET_EXTENDED(g->gflags);
156 }
157 
159 {
160  return G2FLAGS_GET_Z(g->gflags);
161 }
162 
164 {
165  return G2FLAGS_GET_M(g->gflags);
166 }
167 
169 {
170  return G2FLAGS_NDIMS(g->gflags);
171 }
172 
174 {
175  return G2FLAGS_GET_GEODETIC(g->gflags);
176 }
177 
179 {
180  /* GSERIALIZED size + max bbox according gbox_serialized_size (XYZM*2) + extended flags + type */
181  return offsetof(GSERIALIZED, data) + 8 * sizeof(float) + sizeof(uint64_t) + sizeof(uint32_t);
182 }
183 
184 
186 {
187  uint8_t *ptr = gserialized2_get_geometry_p(g);
188  return *((uint32_t*)(ptr));
189 }
190 
192 {
193  int32_t srid = 0;
194  srid = srid | (g->srid[0] << 16);
195  srid = srid | (g->srid[1] << 8);
196  srid = srid | (g->srid[2]);
197  /* Only the first 21 bits are set. Slide up and back to pull
198  the negative bits down, if we need them. */
199  srid = (srid<<11)>>11;
200 
201  /* 0 is our internal unknown value. We'll map back and forth here for now */
202  if (srid == 0)
203  return SRID_UNKNOWN;
204  else
205  return srid;
206 }
207 
208 void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
209 {
210  LWDEBUGF(3, "%s called with srid = %d", __func__, srid);
211 
212  srid = clamp_srid(srid);
213 
214  /* 0 is our internal unknown value.
215  * We'll map back and forth here for now */
216  if (srid == SRID_UNKNOWN)
217  srid = 0;
218 
219  g->srid[0] = (srid & 0x001F0000) >> 16;
220  g->srid[1] = (srid & 0x0000FF00) >> 8;
221  g->srid[2] = (srid & 0x000000FF);
222 }
223 
224 static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty);
225 static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
226 {
227  int i;
228  int32_t type, num;
229 
230  memcpy(&type, p, 4);
231  memcpy(&num, p+4, 4);
232 
234  {
235  size_t lz = 8;
236  for ( i = 0; i < num; i++ )
237  {
238  lz += gserialized2_is_empty_recurse(p+lz, isempty);
239  if (!*isempty)
240  return lz;
241  }
242  *isempty = LW_TRUE;
243  return lz;
244  }
245  else
246  {
247  *isempty = (num == 0 ? LW_TRUE : LW_FALSE);
248  return 8;
249  }
250 }
251 
253 {
254  int isempty = 0;
255  uint8_t *p = gserialized2_get_geometry_p(g);
256  gserialized2_is_empty_recurse(p, &isempty);
257  return isempty;
258 }
259 
260 
261 /* Prototype for lookup3.c */
262 /* key = the key to hash */
263 /* length = length of the key */
264 /* pc = IN: primary initval, OUT: primary hash */
265 /* pb = IN: secondary initval, OUT: secondary hash */
266 void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);
267 
268 int32_t
270 {
271  int32_t hval;
272  int32_t pb = 0, pc = 0;
273  /* Point to just the type/coordinate part of buffer */
274  size_t hsz1 = gserialized2_header_size(g1);
275  uint8_t *b1 = (uint8_t *)g1 + hsz1;
276  /* Calculate size of type/coordinate buffer */
277  size_t sz1 = LWSIZE_GET(g1->size);
278  size_t bsz1 = sz1 - hsz1;
279  /* Calculate size of srid/type/coordinate buffer */
280  int32_t srid = gserialized2_get_srid(g1);
281  size_t bsz2 = bsz1 + sizeof(int);
282  uint8_t *b2 = lwalloc(bsz2);
283  /* Copy srid into front of combined buffer */
284  memcpy(b2, &srid, sizeof(int));
285  /* Copy type/coordinates into rest of combined buffer */
286  memcpy(b2+sizeof(int), b1, bsz1);
287  /* Hash combined buffer */
288  hashlittle2(b2, bsz2, (uint32_t *)&pb, (uint32_t *)&pc);
289  lwfree(b2);
290  hval = pb ^ pc;
291  return hval;
292 }
293 
294 
295 const float * gserialized2_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
296 {
297  uint8_t *ptr = (uint8_t*)(g->data);
298  size_t bndims = G2FLAGS_NDIMS_BOX(g->gflags);
299 
300  if (ndims)
301  *ndims = bndims;
302 
303  /* Cannot do anything if there's no box */
304  if (!(g && gserialized_has_bbox(g)))
305  return NULL;
306 
307  /* Advance past optional extended flags */
309  ptr += 8;
310 
311  return (const float *)(ptr);
312 }
313 
315 {
316  uint8_t gflags = g->gflags;
317  /* Null input! */
318  if (!(g && gbox)) return LW_FAILURE;
319 
320  /* Initialize the flags on the box */
321  gbox->flags = gserialized2_get_lwflags(g);
322 
323  /* Has pre-calculated box */
324  if (G2FLAGS_GET_BBOX(gflags))
325  {
326  int i = 0;
327  const float *fbox = gserialized2_get_float_box_p(g, NULL);
328  gbox->xmin = fbox[i++];
329  gbox->xmax = fbox[i++];
330  gbox->ymin = fbox[i++];
331  gbox->ymax = fbox[i++];
332 
333  /* Geodetic? Read next dimension (geocentric Z) and return */
334  if (G2FLAGS_GET_GEODETIC(gflags))
335  {
336  gbox->zmin = fbox[i++];
337  gbox->zmax = fbox[i++];
338  return LW_SUCCESS;
339  }
340  /* Cartesian? Read extra dimensions (if there) and return */
341  if (G2FLAGS_GET_Z(gflags))
342  {
343  gbox->zmin = fbox[i++];
344  gbox->zmax = fbox[i++];
345  }
346  if (G2FLAGS_GET_M(gflags))
347  {
348  gbox->mmin = fbox[i++];
349  gbox->mmax = fbox[i++];
350  }
351  return LW_SUCCESS;
352  }
353  return LW_FAILURE;
354 }
355 
356 /*
357 * Populate a bounding box *without* allocating an LWGEOM. Useful
358 * for some performance purposes.
359 */
360 int
362 {
363  uint32_t type = gserialized2_get_type(g);
364  uint8_t *geometry_start = gserialized2_get_geometry_p(g);
365  double *dptr = (double *)(geometry_start);
366  int32_t *iptr = (int32_t *)(geometry_start);
367 
368  /* Peeking doesn't help if you already have a box or are geodetic */
370  {
371  return LW_FAILURE;
372  }
373 
374  /* Boxes of points are easy peasy */
375  if (type == POINTTYPE)
376  {
377  int i = 1; /* Start past <pointtype><padding> */
378 
379  /* Read the npoints flag */
380  int isempty = (iptr[1] == 0);
381 
382  /* EMPTY point has no box */
383  if (isempty) return LW_FAILURE;
384 
385  gbox->xmin = gbox->xmax = dptr[i++];
386  gbox->ymin = gbox->ymax = dptr[i++];
387  gbox->flags = gserialized2_get_lwflags(g);
388  if (G2FLAGS_GET_Z(g->gflags))
389  {
390  gbox->zmin = gbox->zmax = dptr[i++];
391  }
392  if (G2FLAGS_GET_M(g->gflags))
393  {
394  gbox->mmin = gbox->mmax = dptr[i++];
395  }
396  gbox_float_round(gbox);
397  return LW_SUCCESS;
398  }
399  /* We can calculate the box of a two-point cartesian line trivially */
400  else if (type == LINETYPE)
401  {
402  int ndims = G2FLAGS_NDIMS(g->gflags);
403  int i = 0; /* Start at <linetype><npoints> */
404  int npoints = iptr[1]; /* Read the npoints */
405 
406  /* This only works with 2-point lines */
407  if (npoints != 2)
408  return LW_FAILURE;
409 
410  /* Advance to X */
411  /* Past <linetype><npoints> */
412  i++;
413  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
414  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
415 
416  /* Advance to Y */
417  i++;
418  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
419  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
420 
421  gbox->flags = gserialized2_get_lwflags(g);
422  if (G2FLAGS_GET_Z(g->gflags))
423  {
424  /* Advance to Z */
425  i++;
426  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
427  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
428  }
429  if (G2FLAGS_GET_M(g->gflags))
430  {
431  /* Advance to M */
432  i++;
433  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
434  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
435  }
436  gbox_float_round(gbox);
437  return LW_SUCCESS;
438  }
439  /* We can also do single-entry multi-points */
440  else if (type == MULTIPOINTTYPE)
441  {
442  int i = 0; /* Start at <multipointtype><ngeoms> */
443  int ngeoms = iptr[1]; /* Read the ngeoms */
444  int npoints;
445 
446  /* This only works with single-entry multipoints */
447  if (ngeoms != 1)
448  return LW_FAILURE;
449 
450  /* Npoints is at <multipointtype><ngeoms><pointtype><npoints> */
451  npoints = iptr[3];
452 
453  /* The check below is necessary because we can have a MULTIPOINT
454  * that contains a single, empty POINT (ngeoms = 1, npoints = 0) */
455  if (npoints != 1)
456  return LW_FAILURE;
457 
458  /* Move forward two doubles (four ints) */
459  /* Past <multipointtype><ngeoms> */
460  /* Past <pointtype><npoints> */
461  i += 2;
462 
463  /* Read the doubles from the one point */
464  gbox->xmin = gbox->xmax = dptr[i++];
465  gbox->ymin = gbox->ymax = dptr[i++];
466  gbox->flags = gserialized2_get_lwflags(g);
467  if (G2FLAGS_GET_Z(g->gflags))
468  {
469  gbox->zmin = gbox->zmax = dptr[i++];
470  }
471  if (G2FLAGS_GET_M(g->gflags))
472  {
473  gbox->mmin = gbox->mmax = dptr[i++];
474  }
475  gbox_float_round(gbox);
476  return LW_SUCCESS;
477  }
478  /* And we can do single-entry multi-lines with two vertices (!!!) */
479  else if (type == MULTILINETYPE)
480  {
481  int ndims = G2FLAGS_NDIMS(g->gflags);
482  int i = 0; /* Start at <multilinetype><ngeoms> */
483  int ngeoms = iptr[1]; /* Read the ngeoms */
484  int npoints;
485 
486  /* This only works with 1-line multilines */
487  if (ngeoms != 1)
488  return LW_FAILURE;
489 
490  /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
491  npoints = iptr[3];
492 
493  if (npoints != 2)
494  return LW_FAILURE;
495 
496  /* Advance to X */
497  /* Move forward two doubles (four ints) */
498  /* Past <multilinetype><ngeoms> */
499  /* Past <linetype><npoints> */
500  i += 2;
501  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
502  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
503 
504  /* Advance to Y */
505  i++;
506  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
507  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
508 
509  gbox->flags = gserialized2_get_lwflags(g);
510  if (G2FLAGS_GET_Z(g->gflags))
511  {
512  /* Advance to Z */
513  i++;
514  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
515  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
516  }
517  if (G2FLAGS_GET_M(g->gflags))
518  {
519  /* Advance to M */
520  i++;
521  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
522  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
523  }
524  gbox_float_round(gbox);
525  return LW_SUCCESS;
526  }
527 
528  return LW_FAILURE;
529 }
530 
531 static inline void
532 gserialized2_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
533 {
534  uint8_t dim = 0;
535  out_point->x = dptr[dim++];
536  out_point->y = dptr[dim++];
537 
538  if (G2FLAGS_GET_Z(flags))
539  {
540  out_point->z = dptr[dim++];
541  }
542  if (G2FLAGS_GET_M(flags))
543  {
544  out_point->m = dptr[dim];
545  }
546 }
547 
548 int
550 {
551  uint8_t *geometry_start = gserialized2_get_geometry_p(g);
552 
553  uint32_t isEmpty = (((uint32_t *)geometry_start)[1]) == 0;
554  if (isEmpty)
555  {
556  return LW_FAILURE;
557  }
558 
559  uint32_t type = (((uint32_t *)geometry_start)[0]);
560  /* Setup double_array_start depending on the geometry type */
561  double *double_array_start = NULL;
562  switch (type)
563  {
564  case (POINTTYPE):
565  /* For points we only need to jump over the type and npoints 32b ints */
566  double_array_start = (double *)(geometry_start + 2 * sizeof(uint32_t));
567  break;
568 
569  default:
570  lwerror("%s is currently not implemented for type %d", __func__, type);
571  return LW_FAILURE;
572  }
573 
574  gserialized2_copy_point(double_array_start, g->gflags, out_point);
575  return LW_SUCCESS;
576 }
577 
583 {
584  /* Try to just read the serialized box. */
585  if (gserialized2_read_gbox_p(g, box) == LW_SUCCESS)
586  {
587  return LW_SUCCESS;
588  }
589  /* No box? Try to peek into simpler geometries and */
590  /* derive a box without creating an lwgeom */
591  else if (gserialized2_peek_gbox_p(g, box) == LW_SUCCESS)
592  {
593  return LW_SUCCESS;
594  }
595  /* Damn! Nothing for it but to create an lwgeom... */
596  /* See http://trac.osgeo.org/postgis/ticket/1023 */
597  else
598  {
599  LWGEOM *lwgeom = lwgeom_from_gserialized(g);
600  int ret = lwgeom_calculate_gbox(lwgeom, box);
601  gbox_float_round(box);
602  lwgeom_free(lwgeom);
603  return ret;
604  }
605 }
606 
612 {
613  /* Try to just read the serialized box. */
614  if (gserialized2_read_gbox_p(g, box) == LW_SUCCESS)
615  {
616  return LW_SUCCESS;
617  }
618  /* No box? Try to peek into simpler geometries and */
619  /* derive a box without creating an lwgeom */
620  else if (gserialized2_peek_gbox_p(g, box) == LW_SUCCESS)
621  {
622  return LW_SUCCESS;
623  }
624  else
625  {
626  return LW_FAILURE;
627  }
628 }
629 
630 
631 
632 
633 /***********************************************************************
634 * Calculate the GSERIALIZED size for an LWGEOM.
635 */
636 
637 /* Private functions */
638 
639 static size_t gserialized2_from_any_size(const LWGEOM *geom); /* Local prototype */
640 
641 static size_t gserialized2_from_lwpoint_size(const LWPOINT *point)
642 {
643  size_t size = 4; /* Type number. */
644 
645  assert(point);
646 
647  size += 4; /* Number of points (one or zero (empty)). */
648  size += point->point->npoints * FLAGS_NDIMS(point->flags) * sizeof(double);
649 
650  LWDEBUGF(3, "point size = %d", size);
651 
652  return size;
653 }
654 
655 static size_t gserialized2_from_lwline_size(const LWLINE *line)
656 {
657  size_t size = 4; /* Type number. */
658 
659  assert(line);
660 
661  size += 4; /* Number of points (zero => empty). */
662  size += line->points->npoints * FLAGS_NDIMS(line->flags) * sizeof(double);
663 
664  LWDEBUGF(3, "linestring size = %d", size);
665 
666  return size;
667 }
668 
669 static size_t gserialized2_from_lwtriangle_size(const LWTRIANGLE *triangle)
670 {
671  size_t size = 4; /* Type number. */
672 
673  assert(triangle);
674 
675  size += 4; /* Number of points (zero => empty). */
676  size += triangle->points->npoints * FLAGS_NDIMS(triangle->flags) * sizeof(double);
677 
678  LWDEBUGF(3, "triangle size = %d", size);
679 
680  return size;
681 }
682 
683 static size_t gserialized2_from_lwpoly_size(const LWPOLY *poly)
684 {
685  size_t size = 4; /* Type number. */
686  uint32_t i = 0;
687  const size_t point_size = FLAGS_NDIMS(poly->flags) * sizeof(double);
688 
689  assert(poly);
690 
691  size += 4; /* Number of rings (zero => empty). */
692  if (poly->nrings % 2)
693  size += 4; /* Padding to double alignment. */
694 
695  for (i = 0; i < poly->nrings; i++)
696  {
697  size += 4; /* Number of points in ring. */
698  size += poly->rings[i]->npoints * point_size;
699  }
700 
701  LWDEBUGF(3, "polygon size = %d", size);
702 
703  return size;
704 }
705 
707 {
708  size_t size = 4; /* Type number. */
709 
710  assert(curve);
711 
712  size += 4; /* Number of points (zero => empty). */
713  size += curve->points->npoints * FLAGS_NDIMS(curve->flags) * sizeof(double);
714 
715  LWDEBUGF(3, "circstring size = %d", size);
716 
717  return size;
718 }
719 
721 {
722  size_t size = 4; /* Type number. */
723  uint32_t i = 0;
724 
725  assert(col);
726 
727  size += 4; /* Number of sub-geometries (zero => empty). */
728 
729  for (i = 0; i < col->ngeoms; i++)
730  {
731  size_t subsize = gserialized2_from_any_size(col->geoms[i]);
732  size += subsize;
733  LWDEBUGF(3, "lwcollection subgeom(%d) size = %d", i, subsize);
734  }
735 
736  LWDEBUGF(3, "lwcollection size = %d", size);
737 
738  return size;
739 }
740 
741 static size_t gserialized2_from_any_size(const LWGEOM *geom)
742 {
743  LWDEBUGF(2, "Input type: %s", lwtype_name(geom->type));
744 
745  switch (geom->type)
746  {
747  case POINTTYPE:
748  return gserialized2_from_lwpoint_size((LWPOINT *)geom);
749  case LINETYPE:
750  return gserialized2_from_lwline_size((LWLINE *)geom);
751  case POLYGONTYPE:
752  return gserialized2_from_lwpoly_size((LWPOLY *)geom);
753  case TRIANGLETYPE:
755  case CIRCSTRINGTYPE:
757  case CURVEPOLYTYPE:
758  case COMPOUNDTYPE:
759  case MULTIPOINTTYPE:
760  case MULTILINETYPE:
761  case MULTICURVETYPE:
762  case MULTIPOLYGONTYPE:
763  case MULTISURFACETYPE:
765  case TINTYPE:
766  case COLLECTIONTYPE:
768  default:
769  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
770  return 0;
771  }
772 }
773 
774 /* Public function */
775 
777 {
778  size_t size = 8; /* Header overhead (varsize+flags+srid) */
779  assert(geom);
780 
781  /* Reserve space for extended flags */
783  size += 8;
784 
785  /* Reserve space for bounding box */
786  if (geom->bbox)
787  size += gbox_serialized_size(geom->flags);
788 
789  size += gserialized2_from_any_size(geom);
790  LWDEBUGF(3, "%s size = %d", __func__, size);
791 
792  return size;
793 }
794 
795 /***********************************************************************
796 * Serialize an LWGEOM into GSERIALIZED.
797 */
798 
799 /* Private functions */
800 
801 static size_t gserialized2_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf);
802 
803 static size_t gserialized2_from_lwpoint(const LWPOINT *point, uint8_t *buf)
804 {
805  uint8_t *loc;
806  int ptsize = ptarray_point_size(point->point);
807  int type = POINTTYPE;
808 
809  assert(point);
810  assert(buf);
811 
812  if (FLAGS_GET_ZM(point->flags) != FLAGS_GET_ZM(point->point->flags))
813  lwerror("Dimensions mismatch in lwpoint");
814 
815  LWDEBUGF(2, "%s (%p, %p) called", __func__, point, buf);
816 
817  loc = buf;
818 
819  /* Write in the type. */
820  memcpy(loc, &type, sizeof(uint32_t));
821  loc += sizeof(uint32_t);
822  /* Write in the number of points (0 => empty). */
823  memcpy(loc, &(point->point->npoints), sizeof(uint32_t));
824  loc += sizeof(uint32_t);
825 
826  /* Copy in the ordinates. */
827  if (point->point->npoints > 0)
828  {
829  memcpy(loc, getPoint_internal(point->point, 0), ptsize);
830  loc += ptsize;
831  }
832 
833  return (size_t)(loc - buf);
834 }
835 
836 static size_t gserialized2_from_lwline(const LWLINE *line, uint8_t *buf)
837 {
838  uint8_t *loc;
839  int ptsize;
840  size_t size;
841  int type = LINETYPE;
842 
843  assert(line);
844  assert(buf);
845 
846  LWDEBUGF(2, "%s (%p, %p) called", __func__, line, buf);
847 
848  if (FLAGS_GET_Z(line->flags) != FLAGS_GET_Z(line->points->flags))
849  lwerror("Dimensions mismatch in lwline");
850 
851  ptsize = ptarray_point_size(line->points);
852 
853  loc = buf;
854 
855  /* Write in the type. */
856  memcpy(loc, &type, sizeof(uint32_t));
857  loc += sizeof(uint32_t);
858 
859  /* Write in the npoints. */
860  memcpy(loc, &(line->points->npoints), sizeof(uint32_t));
861  loc += sizeof(uint32_t);
862 
863  LWDEBUGF(3, "%s added npoints (%d)", __func__, line->points->npoints);
864 
865  /* Copy in the ordinates. */
866  if (line->points->npoints > 0)
867  {
868  size = line->points->npoints * ptsize;
869  memcpy(loc, getPoint_internal(line->points, 0), size);
870  loc += size;
871  }
872  LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * line->points->npoints);
873 
874  return (size_t)(loc - buf);
875 }
876 
877 static size_t gserialized2_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
878 {
879  uint32_t i;
880  uint8_t *loc;
881  int ptsize;
882  int type = POLYGONTYPE;
883 
884  assert(poly);
885  assert(buf);
886 
887  LWDEBUGF(2, "%s called", __func__);
888 
889  ptsize = sizeof(double) * FLAGS_NDIMS(poly->flags);
890  loc = buf;
891 
892  /* Write in the type. */
893  memcpy(loc, &type, sizeof(uint32_t));
894  loc += sizeof(uint32_t);
895 
896  /* Write in the nrings. */
897  memcpy(loc, &(poly->nrings), sizeof(uint32_t));
898  loc += sizeof(uint32_t);
899 
900  /* Write in the npoints per ring. */
901  for (i = 0; i < poly->nrings; i++)
902  {
903  memcpy(loc, &(poly->rings[i]->npoints), sizeof(uint32_t));
904  loc += sizeof(uint32_t);
905  }
906 
907  /* Add in padding if necessary to remain double aligned. */
908  if (poly->nrings % 2)
909  {
910  memset(loc, 0, sizeof(uint32_t));
911  loc += sizeof(uint32_t);
912  }
913 
914  /* Copy in the ordinates. */
915  for (i = 0; i < poly->nrings; i++)
916  {
917  POINTARRAY *pa = poly->rings[i];
918  size_t pasize;
919 
920  if (FLAGS_GET_ZM(poly->flags) != FLAGS_GET_ZM(pa->flags))
921  lwerror("Dimensions mismatch in lwpoly");
922 
923  pasize = pa->npoints * ptsize;
924  if ( pa->npoints > 0 )
925  memcpy(loc, getPoint_internal(pa, 0), pasize);
926  loc += pasize;
927  }
928  return (size_t)(loc - buf);
929 }
930 
931 static size_t gserialized2_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
932 {
933  uint8_t *loc;
934  int ptsize;
935  size_t size;
936  int type = TRIANGLETYPE;
937 
938  assert(triangle);
939  assert(buf);
940 
941  LWDEBUGF(2, "%s (%p, %p) called", __func__, triangle, buf);
942 
943  if (FLAGS_GET_ZM(triangle->flags) != FLAGS_GET_ZM(triangle->points->flags))
944  lwerror("Dimensions mismatch in lwtriangle");
945 
946  ptsize = ptarray_point_size(triangle->points);
947 
948  loc = buf;
949 
950  /* Write in the type. */
951  memcpy(loc, &type, sizeof(uint32_t));
952  loc += sizeof(uint32_t);
953 
954  /* Write in the npoints. */
955  memcpy(loc, &(triangle->points->npoints), sizeof(uint32_t));
956  loc += sizeof(uint32_t);
957 
958  LWDEBUGF(3, "%s added npoints (%d)", __func__, triangle->points->npoints);
959 
960  /* Copy in the ordinates. */
961  if (triangle->points->npoints > 0)
962  {
963  size = triangle->points->npoints * ptsize;
964  memcpy(loc, getPoint_internal(triangle->points, 0), size);
965  loc += size;
966  }
967  LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * triangle->points->npoints);
968 
969  return (size_t)(loc - buf);
970 }
971 
972 static size_t gserialized2_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
973 {
974  uint8_t *loc;
975  int ptsize;
976  size_t size;
977  int type = CIRCSTRINGTYPE;
978 
979  assert(curve);
980  assert(buf);
981 
982  if (FLAGS_GET_ZM(curve->flags) != FLAGS_GET_ZM(curve->points->flags))
983  lwerror("Dimensions mismatch in lwcircstring");
984 
985 
986  ptsize = ptarray_point_size(curve->points);
987  loc = buf;
988 
989  /* Write in the type. */
990  memcpy(loc, &type, sizeof(uint32_t));
991  loc += sizeof(uint32_t);
992 
993  /* Write in the npoints. */
994  memcpy(loc, &curve->points->npoints, sizeof(uint32_t));
995  loc += sizeof(uint32_t);
996 
997  /* Copy in the ordinates. */
998  if (curve->points->npoints > 0)
999  {
1000  size = curve->points->npoints * ptsize;
1001  memcpy(loc, getPoint_internal(curve->points, 0), size);
1002  loc += size;
1003  }
1004 
1005  return (size_t)(loc - buf);
1006 }
1007 
1008 static size_t gserialized2_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
1009 {
1010  size_t subsize = 0;
1011  uint8_t *loc;
1012  uint32_t i;
1013  int type;
1014 
1015  assert(coll);
1016  assert(buf);
1017 
1018  type = coll->type;
1019  loc = buf;
1020 
1021  /* Write in the type. */
1022  memcpy(loc, &type, sizeof(uint32_t));
1023  loc += sizeof(uint32_t);
1024 
1025  /* Write in the number of subgeoms. */
1026  memcpy(loc, &coll->ngeoms, sizeof(uint32_t));
1027  loc += sizeof(uint32_t);
1028 
1029  /* Serialize subgeoms. */
1030  for (i = 0; i < coll->ngeoms; i++)
1031  {
1032  if (FLAGS_GET_ZM(coll->flags) != FLAGS_GET_ZM(coll->geoms[i]->flags))
1033  lwerror("Dimensions mismatch in lwcollection");
1034  subsize = gserialized2_from_lwgeom_any(coll->geoms[i], loc);
1035  loc += subsize;
1036  }
1037 
1038  return (size_t)(loc - buf);
1039 }
1040 
1041 static size_t gserialized2_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
1042 {
1043  assert(geom);
1044  assert(buf);
1045 
1046  LWDEBUGF(2, "Input type (%d) %s, hasz: %d hasm: %d",
1047  geom->type, lwtype_name(geom->type),
1048  FLAGS_GET_Z(geom->flags), FLAGS_GET_M(geom->flags));
1049  LWDEBUGF(2, "LWGEOM(%p) uint8_t(%p)", geom, buf);
1050 
1051  switch (geom->type)
1052  {
1053  case POINTTYPE:
1054  return gserialized2_from_lwpoint((LWPOINT *)geom, buf);
1055  case LINETYPE:
1056  return gserialized2_from_lwline((LWLINE *)geom, buf);
1057  case POLYGONTYPE:
1058  return gserialized2_from_lwpoly((LWPOLY *)geom, buf);
1059  case TRIANGLETYPE:
1060  return gserialized2_from_lwtriangle((LWTRIANGLE *)geom, buf);
1061  case CIRCSTRINGTYPE:
1062  return gserialized2_from_lwcircstring((LWCIRCSTRING *)geom, buf);
1063  case CURVEPOLYTYPE:
1064  case COMPOUNDTYPE:
1065  case MULTIPOINTTYPE:
1066  case MULTILINETYPE:
1067  case MULTICURVETYPE:
1068  case MULTIPOLYGONTYPE:
1069  case MULTISURFACETYPE:
1070  case POLYHEDRALSURFACETYPE:
1071  case TINTYPE:
1072  case COLLECTIONTYPE:
1073  return gserialized2_from_lwcollection((LWCOLLECTION *)geom, buf);
1074  default:
1075  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
1076  return 0;
1077  }
1078  return 0;
1079 }
1080 
1082 {
1084  {
1085  uint64_t xflags = 0;
1086  if (FLAGS_GET_SOLID(lwflags))
1087  xflags |= G2FLAG_X_SOLID;
1088 
1089  // G2FLAG_X_CHECKED_VALID
1090  // G2FLAG_X_IS_VALID
1091  // G2FLAG_X_HAS_HASH
1092 
1093  memcpy(buf, &xflags, sizeof(uint64_t));
1094  return sizeof(uint64_t);
1095  }
1096  return 0;
1097 }
1098 
1099 static size_t gserialized2_from_gbox(const GBOX *gbox, uint8_t *buf)
1100 {
1101  uint8_t *loc = buf;
1102  float *f;
1103  uint8_t i = 0;
1104  size_t return_size;
1105 
1106  assert(buf);
1107 
1108  f = (float *)buf;
1109  f[i++] = next_float_down(gbox->xmin);
1110  f[i++] = next_float_up(gbox->xmax);
1111  f[i++] = next_float_down(gbox->ymin);
1112  f[i++] = next_float_up(gbox->ymax);
1113  loc += 4 * sizeof(float);
1114 
1115  if (FLAGS_GET_GEODETIC(gbox->flags))
1116  {
1117  f[i++] = next_float_down(gbox->zmin);
1118  f[i++] = next_float_up(gbox->zmax);
1119  loc += 2 * sizeof(float);
1120 
1121  return_size = (size_t)(loc - buf);
1122  LWDEBUGF(4, "returning size %d", return_size);
1123  return return_size;
1124  }
1125 
1126  if (FLAGS_GET_Z(gbox->flags))
1127  {
1128  f[i++] = next_float_down(gbox->zmin);
1129  f[i++] = next_float_up(gbox->zmax);
1130  loc += 2 * sizeof(float);
1131  }
1132 
1133  if (FLAGS_GET_M(gbox->flags))
1134  {
1135  f[i++] = next_float_down(gbox->mmin);
1136  f[i++] = next_float_up(gbox->mmax);
1137  loc += 2 * sizeof(float);
1138  }
1139  return_size = (size_t)(loc - buf);
1140  LWDEBUGF(4, "returning size %d", return_size);
1141  return return_size;
1142 }
1143 
1144 /* Public function */
1145 
1147 {
1148  size_t expected_size = 0;
1149  size_t return_size = 0;
1150  uint8_t *ptr = NULL;
1151  GSERIALIZED *g = NULL;
1152  assert(geom);
1153 
1154  /*
1155  ** See if we need a bounding box, add one if we don't have one.
1156  */
1157  if ((!geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)))
1158  {
1159  lwgeom_add_bbox(geom);
1160  }
1161 
1162  /*
1163  ** Harmonize the flags to the state of the lwgeom
1164  */
1165  FLAGS_SET_BBOX(geom->flags, (geom->bbox ? 1 : 0));
1166 
1167  /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1168  expected_size = gserialized2_from_lwgeom_size(geom);
1169  ptr = lwalloc(expected_size);
1170  g = (GSERIALIZED*)(ptr);
1171 
1172  /* Set the SRID! */
1173  gserialized2_set_srid(g, geom->srid);
1174  /*
1175  ** We are aping PgSQL code here, PostGIS code should use
1176  ** VARSIZE to set this for real.
1177  */
1178  LWSIZE_SET(g->size, expected_size);
1179  g->gflags = lwflags_get_g2flags(geom->flags);
1180 
1181  /* Move write head past size, srid and flags. */
1182  ptr += 8;
1183 
1184  /* Write in the extended flags if necessary */
1185  ptr += gserialized2_from_extended_flags(geom->flags, ptr);
1186 
1187  /* Write in the serialized form of the gbox, if necessary. */
1188  if (geom->bbox)
1189  ptr += gserialized2_from_gbox(geom->bbox, ptr);
1190 
1191  /* Write in the serialized form of the geometry. */
1192  ptr += gserialized2_from_lwgeom_any(geom, ptr);
1193 
1194  /* Calculate size as returned by data processing functions. */
1195  return_size = ptr - (uint8_t*)g;
1196 
1197  assert(expected_size == return_size);
1198  if (size) /* Return the output size to the caller if necessary. */
1199  *size = return_size;
1200 
1201  return g;
1202 }
1203 
1204 /***********************************************************************
1205 * De-serialize GSERIALIZED into an LWGEOM.
1206 */
1207 
1208 static LWGEOM *lwgeom_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid);
1209 
1210 static LWPOINT *
1211 lwpoint_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1212 {
1213  uint8_t *start_ptr = data_ptr;
1214  LWPOINT *point;
1215  uint32_t npoints = 0;
1216 
1217  assert(data_ptr);
1218 
1219  point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1220  point->srid = srid;
1221  point->bbox = NULL;
1222  point->type = POINTTYPE;
1223  point->flags = lwflags;
1224 
1225  data_ptr += 4; /* Skip past the type. */
1226  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1227  data_ptr += 4; /* Skip past the npoints. */
1228 
1229  if (npoints > 0)
1231  else
1232  point->point = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty point */
1233 
1234  data_ptr += npoints * FLAGS_NDIMS(lwflags) * sizeof(double);
1235 
1236  if (size)
1237  *size = data_ptr - start_ptr;
1238 
1239  return point;
1240 }
1241 
1242 static LWLINE *
1243 lwline_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1244 {
1245  uint8_t *start_ptr = data_ptr;
1246  LWLINE *line;
1247  uint32_t npoints = 0;
1248 
1249  assert(data_ptr);
1250 
1251  line = (LWLINE*)lwalloc(sizeof(LWLINE));
1252  line->srid = srid;
1253  line->bbox = NULL;
1254  line->type = LINETYPE;
1255  line->flags = lwflags;
1256 
1257  data_ptr += 4; /* Skip past the type. */
1258  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1259  data_ptr += 4; /* Skip past the npoints. */
1260 
1261  if (npoints > 0)
1263 
1264  else
1265  line->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty linestring */
1266 
1267  data_ptr += FLAGS_NDIMS(lwflags) * npoints * sizeof(double);
1268 
1269  if (size)
1270  *size = data_ptr - start_ptr;
1271 
1272  return line;
1273 }
1274 
1275 static LWPOLY *
1276 lwpoly_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1277 {
1278  uint8_t *start_ptr = data_ptr;
1279  LWPOLY *poly;
1280  uint8_t *ordinate_ptr;
1281  uint32_t nrings = 0;
1282  uint32_t i = 0;
1283 
1284  assert(data_ptr);
1285 
1286  poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1287  poly->srid = srid;
1288  poly->bbox = NULL;
1289  poly->type = POLYGONTYPE;
1290  poly->flags = lwflags;
1291 
1292  data_ptr += 4; /* Skip past the polygontype. */
1293  nrings = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1294  poly->nrings = nrings;
1295  LWDEBUGF(4, "nrings = %d", nrings);
1296  data_ptr += 4; /* Skip past the nrings. */
1297 
1298  ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1299  if (nrings > 0)
1300  {
1301  poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1302  poly->maxrings = nrings;
1303  ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1304  if (nrings % 2) /* If there is padding, move past that too. */
1305  ordinate_ptr += 4;
1306  }
1307  else /* Empty polygon */
1308  {
1309  poly->rings = NULL;
1310  poly->maxrings = 0;
1311  }
1312 
1313  for (i = 0; i < nrings; i++)
1314  {
1315  uint32_t npoints = 0;
1316 
1317  /* Read in the number of points. */
1318  npoints = gserialized2_get_uint32_t(data_ptr);
1319  data_ptr += 4;
1320 
1321  /* Make a point array for the ring, and move the ordinate pointer past the ring ordinates. */
1322  poly->rings[i] = ptarray_construct_reference_data(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), npoints, ordinate_ptr);
1323 
1324  ordinate_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1325  }
1326 
1327  if (size)
1328  *size = ordinate_ptr - start_ptr;
1329 
1330  return poly;
1331 }
1332 
1333 static LWTRIANGLE *
1334 lwtriangle_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1335 {
1336  uint8_t *start_ptr = data_ptr;
1337  LWTRIANGLE *triangle;
1338  uint32_t npoints = 0;
1339 
1340  assert(data_ptr);
1341 
1342  triangle = (LWTRIANGLE*)lwalloc(sizeof(LWTRIANGLE));
1343  triangle->srid = srid; /* Default */
1344  triangle->bbox = NULL;
1345  triangle->type = TRIANGLETYPE;
1346  triangle->flags = lwflags;
1347 
1348  data_ptr += 4; /* Skip past the type. */
1349  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1350  data_ptr += 4; /* Skip past the npoints. */
1351 
1352  if (npoints > 0)
1354  else
1355  triangle->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty triangle */
1356 
1357  data_ptr += FLAGS_NDIMS(lwflags) * npoints * sizeof(double);
1358 
1359  if (size)
1360  *size = data_ptr - start_ptr;
1361 
1362  return triangle;
1363 }
1364 
1365 static LWCIRCSTRING *
1366 lwcircstring_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1367 {
1368  uint8_t *start_ptr = data_ptr;
1369  LWCIRCSTRING *circstring;
1370  uint32_t npoints = 0;
1371 
1372  assert(data_ptr);
1373 
1374  circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING));
1375  circstring->srid = srid;
1376  circstring->bbox = NULL;
1377  circstring->type = CIRCSTRINGTYPE;
1378  circstring->flags = lwflags;
1379 
1380  data_ptr += 4; /* Skip past the circstringtype. */
1381  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1382  data_ptr += 4; /* Skip past the npoints. */
1383 
1384  if (npoints > 0)
1385  circstring->points = ptarray_construct_reference_data(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), npoints, data_ptr);
1386  else
1387  circstring->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty circularstring */
1388 
1389  data_ptr += FLAGS_NDIMS(lwflags) * npoints * sizeof(double);
1390 
1391  if (size)
1392  *size = data_ptr - start_ptr;
1393 
1394  return circstring;
1395 }
1396 
1397 static LWCOLLECTION *
1398 lwcollection_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1399 {
1400  uint32_t type;
1401  uint8_t *start_ptr = data_ptr;
1402  LWCOLLECTION *collection;
1403  uint32_t ngeoms = 0;
1404  uint32_t i = 0;
1405 
1406  assert(data_ptr);
1407 
1408  type = gserialized2_get_uint32_t(data_ptr);
1409  data_ptr += 4; /* Skip past the type. */
1410 
1411  collection = (LWCOLLECTION*)lwalloc(sizeof(LWCOLLECTION));
1412  collection->srid = srid;
1413  collection->bbox = NULL;
1414  collection->type = type;
1415  collection->flags = lwflags;
1416 
1417  ngeoms = gserialized2_get_uint32_t(data_ptr);
1418  collection->ngeoms = ngeoms; /* Zero => empty geometry */
1419  data_ptr += 4; /* Skip past the ngeoms. */
1420 
1421  if (ngeoms > 0)
1422  {
1423  collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1424  collection->maxgeoms = ngeoms;
1425  }
1426  else
1427  {
1428  collection->geoms = NULL;
1429  collection->maxgeoms = 0;
1430  }
1431 
1432  /* Sub-geometries are never de-serialized with boxes (#1254) */
1433  FLAGS_SET_BBOX(lwflags, 0);
1434 
1435  for (i = 0; i < ngeoms; i++)
1436  {
1437  uint32_t subtype = gserialized2_get_uint32_t(data_ptr);
1438  size_t subsize = 0;
1439 
1440  if (!lwcollection_allows_subtype(type, subtype))
1441  {
1442  lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1443  lwfree(collection);
1444  return NULL;
1445  }
1446  collection->geoms[i] = lwgeom_from_gserialized2_buffer(data_ptr, lwflags, &subsize, srid);
1447  data_ptr += subsize;
1448  }
1449 
1450  if (size)
1451  *size = data_ptr - start_ptr;
1452 
1453  return collection;
1454 }
1455 
1456 LWGEOM *
1457 lwgeom_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *g_size, int32_t srid)
1458 {
1459  uint32_t type;
1460 
1461  assert(data_ptr);
1462 
1463  type = gserialized2_get_uint32_t(data_ptr);
1464 
1465  LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1467 
1468  switch (type)
1469  {
1470  case POINTTYPE:
1471  return (LWGEOM *)lwpoint_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1472  case LINETYPE:
1473  return (LWGEOM *)lwline_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1474  case CIRCSTRINGTYPE:
1475  return (LWGEOM *)lwcircstring_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1476  case POLYGONTYPE:
1477  return (LWGEOM *)lwpoly_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1478  case TRIANGLETYPE:
1479  return (LWGEOM *)lwtriangle_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1480  case MULTIPOINTTYPE:
1481  case MULTILINETYPE:
1482  case MULTIPOLYGONTYPE:
1483  case COMPOUNDTYPE:
1484  case CURVEPOLYTYPE:
1485  case MULTICURVETYPE:
1486  case MULTISURFACETYPE:
1487  case POLYHEDRALSURFACETYPE:
1488  case TINTYPE:
1489  case COLLECTIONTYPE:
1490  return (LWGEOM *)lwcollection_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1491  default:
1492  lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1493  return NULL;
1494  }
1495 }
1496 
1498 {
1499  lwflags_t lwflags = 0;
1500  int32_t srid = 0;
1501  uint32_t lwtype = 0;
1502  uint8_t *data_ptr = NULL;
1503  LWGEOM *lwgeom = NULL;
1504  GBOX bbox;
1505  size_t size = 0;
1506 
1507  assert(g);
1508 
1509  srid = gserialized2_get_srid(g);
1510  lwtype = gserialized2_get_type(g);
1512 
1513  LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
1514 
1515  data_ptr = (uint8_t*)g->data;
1516 
1517  /* Skip optional flags */
1519  {
1520  data_ptr += sizeof(uint64_t);
1521  }
1522 
1523  /* Skip over optional bounding box */
1524  if (FLAGS_GET_BBOX(lwflags))
1525  data_ptr += gbox_serialized_size(lwflags);
1526 
1527  lwgeom = lwgeom_from_gserialized2_buffer(data_ptr, lwflags, &size, srid);
1528 
1529  if (!lwgeom)
1530  lwerror("%s: unable create geometry", __func__); /* Ooops! */
1531 
1532  lwgeom->type = lwtype;
1533  lwgeom->flags = lwflags;
1534 
1535  if (gserialized2_read_gbox_p(g, &bbox) == LW_SUCCESS)
1536  {
1537  lwgeom->bbox = gbox_copy(&bbox);
1538  }
1539  else if (lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS))
1540  {
1541  lwgeom->bbox = gbox_copy(&bbox);
1542  }
1543  else
1544  {
1545  lwgeom->bbox = NULL;
1546  }
1547 
1548  return lwgeom;
1549 }
1550 
1560 {
1561 
1562  int g_ndims = G2FLAGS_NDIMS_BOX(g->gflags);
1563  int box_ndims = FLAGS_NDIMS_BOX(gbox->flags);
1564  GSERIALIZED *g_out = NULL;
1565  size_t box_size = 2 * g_ndims * sizeof(float);
1566  float *fbox;
1567  int fbox_pos = 0;
1568 
1569  /* The dimensionality of the inputs has to match or we are SOL. */
1570  if (g_ndims != box_ndims)
1571  {
1572  return NULL;
1573  }
1574 
1575  /* Serialized already has room for a box. */
1576  if (G2FLAGS_GET_BBOX(g->gflags))
1577  {
1578  g_out = g;
1579  }
1580  /* Serialized has no box. We need to allocate enough space for the old
1581  data plus the box, and leave a gap in the memory segment to write
1582  the new values into.
1583  */
1584  else
1585  {
1586  size_t varsize_in = LWSIZE_GET(g->size);
1587  size_t varsize_out = varsize_in + box_size;
1588  uint8_t *ptr_out, *ptr_in, *ptr;
1589  g_out = lwalloc(varsize_out);
1590  ptr_out = (uint8_t*)g_out;
1591  ptr = ptr_in = (uint8_t*)g;
1592  /* Copy the head of g into place */
1593  memcpy(ptr_out, ptr_in, 8); ptr_out += 8; ptr_in += 8;
1594  /* Optionally copy extended bit into place */
1595  if (G2FLAGS_GET_EXTENDED(g->gflags))
1596  {
1597  memcpy(ptr_out, ptr_in, 8); ptr_out += 8; ptr_in += 8;
1598  }
1599  /* Copy the body of g into place after leaving space for the box */
1600  ptr_out += box_size;
1601  memcpy(ptr_out, ptr_in, varsize_in - (ptr_in - ptr));
1602  G2FLAGS_SET_BBOX(g_out->gflags, 1);
1603  LWSIZE_SET(g_out->size, varsize_out);
1604  }
1605 
1606  /* Move bounds to nearest float values */
1607  gbox_float_round(gbox);
1608  /* Now write the float box values into the memory segement */
1609  fbox = (float*)(g_out->data);
1610  /* Copy in X/Y */
1611  fbox[fbox_pos++] = gbox->xmin;
1612  fbox[fbox_pos++] = gbox->xmax;
1613  fbox[fbox_pos++] = gbox->ymin;
1614  fbox[fbox_pos++] = gbox->ymax;
1615  /* Optionally copy in higher dims */
1617  {
1618  fbox[fbox_pos++] = gbox->zmin;
1619  fbox[fbox_pos++] = gbox->zmax;
1620  }
1622  {
1623  fbox[fbox_pos++] = gbox->mmin;
1624  fbox[fbox_pos++] = gbox->mmax;
1625  }
1626 
1627  return g_out;
1628 }
1629 
1630 
1636 {
1637  int g_ndims = G2FLAGS_NDIMS_BOX(g->gflags);
1638  size_t box_size = 2 * g_ndims * sizeof(float);
1639  size_t g_out_size = LWSIZE_GET(g->size) - box_size;
1640  GSERIALIZED *g_out = lwalloc(g_out_size);
1641 
1642  /* Copy the contents while omitting the box */
1643  if (G2FLAGS_GET_BBOX(g->gflags))
1644  {
1645  uint8_t *outptr = (uint8_t*)g_out;
1646  uint8_t *inptr = (uint8_t*)g;
1647  /* Copy the header (size+type) of g into place */
1648  memcpy(outptr, inptr, 8); outptr += 8; inptr += 8;
1649  /* Copy extended flags, if there are any */
1650  if (G2FLAGS_GET_EXTENDED(g->gflags))
1651  {
1652  memcpy(outptr, inptr, 8); outptr += 8; inptr += 8;
1653  }
1654  /* Advance past box */
1655  inptr += box_size;
1656  /* Copy parts after the box into place */
1657  memcpy(outptr, inptr, g_out_size - 8);
1658  G2FLAGS_SET_BBOX(g_out->gflags, 0);
1659  LWSIZE_SET(g_out->size, g_out_size);
1660  }
1661  /* No box? Nothing to do but copy and return. */
1662  else
1663  {
1664  memcpy(g_out, g, g_out_size);
1665  }
1666 
1667  return g_out;
1668 }
size_t gbox_serialized_size(lwflags_t flags)
Return the number of bytes necessary to hold a GBOX of this dimension in serialized form.
Definition: gbox.c:440
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition: gbox.c:774
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: gbox.c:426
static size_t gserialized2_header_size(const GSERIALIZED *g)
Definition: gserialized2.c:91
static size_t gserialized2_box_size(const GSERIALIZED *g)
Definition: gserialized2.c:83
static int gserialized2_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Definition: gserialized2.c:314
int gserialized2_fast_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and fail if it is not already there.
Definition: gserialized2.c:611
int32_t gserialized2_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized2.c:191
int gserialized2_is_geodetic(const GSERIALIZED *g)
Check if a GSERIALIZED is a geography.
Definition: gserialized2.c:173
void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized2.c:208
int gserialized2_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized2.c:158
void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb)
Definition: lookup3.c:479
static uint32_t gserialized2_get_uint32_t(const uint8_t *loc)
Definition: gserialized2.c:131
int32_t gserialized2_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized2.c:269
const float * gserialized2_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
Point into the float box area of the serialization.
Definition: gserialized2.c:295
static size_t gserialized2_from_gbox(const GBOX *gbox, uint8_t *buf)
static size_t gserialized2_from_lwcircstring_size(const LWCIRCSTRING *curve)
Definition: gserialized2.c:706
static size_t gserialized2_from_lwpoly_size(const LWPOLY *poly)
Definition: gserialized2.c:683
uint32_t gserialized2_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized2.c:185
int gserialized2_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized2.c:252
int gserialized2_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Definition: gserialized2.c:549
static LWGEOM * lwgeom_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
static int lwflags_uses_extended_flags(lwflags_t lwflags)
Definition: gserialized2.c:76
int gserialized2_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized2.c:168
LWGEOM * lwgeom_from_gserialized2(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized2_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Definition: gserialized2.c:361
uint8_t lwflags_get_g2flags(lwflags_t lwflags)
Definition: gserialized2.c:118
static LWTRIANGLE * lwtriangle_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
static size_t gserialized2_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
static size_t gserialized2_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
int gserialized2_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
Definition: gserialized2.c:582
static size_t gserialized2_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
Definition: gserialized2.c:972
static LWCIRCSTRING * lwcircstring_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
Definition: gserialized2.c:225
static size_t gserialized2_from_lwpoint_size(const LWPOINT *point)
Definition: gserialized2.c:641
size_t gserialized2_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized2.c:776
static size_t gserialized2_from_lwtriangle_size(const LWTRIANGLE *triangle)
Definition: gserialized2.c:669
static size_t gserialized2_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
Definition: gserialized2.c:877
static size_t gserialized2_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
Definition: gserialized2.c:931
static uint8_t * gserialized2_get_geometry_p(const GSERIALIZED *g)
Definition: gserialized2.c:106
static size_t gserialized2_from_lwcollection_size(const LWCOLLECTION *col)
Definition: gserialized2.c:720
static size_t gserialized2_from_lwline(const LWLINE *line, uint8_t *buf)
Definition: gserialized2.c:836
int gserialized2_has_extended(const GSERIALIZED *g)
Check if a GSERIALIZED has an extended flags section.
Definition: gserialized2.c:153
static size_t gserialized2_from_lwpoint(const LWPOINT *point, uint8_t *buf)
Definition: gserialized2.c:803
GSERIALIZED * gserialized2_set_gbox(GSERIALIZED *g, GBOX *gbox)
Update the bounding box of a GSERIALIZED, allocating a fresh one if there is not enough space to just...
static void gserialized2_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
Definition: gserialized2.c:532
static LWLINE * lwline_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
int gserialized2_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized2.c:163
GSERIALIZED * gserialized2_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
GSERIALIZED * gserialized2_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
static LWPOINT * lwpoint_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
uint32_t gserialized2_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: gserialized2.c:178
static LWPOLY * lwpoly_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
static size_t gserialized2_from_extended_flags(lwflags_t lwflags, uint8_t *buf)
static size_t gserialized2_from_any_size(const LWGEOM *geom)
Definition: gserialized2.c:741
lwflags_t gserialized2_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized2.c:59
uint8_t g2flags(int has_z, int has_m, int is_geodetic)
Definition: gserialized2.c:136
static size_t gserialized2_from_lwline_size(const LWLINE *line)
Definition: gserialized2.c:655
int gserialized2_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized2.c:148
static LWCOLLECTION * lwcollection_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
#define G2FLAGS_SET_Z(gflags, value)
Definition: gserialized2.h:29
#define G2FLAGS_SET_EXTENDED(gflags, value)
Definition: gserialized2.h:33
#define G2FLAGS_SET_VERSION(gflags, value)
Definition: gserialized2.h:34
#define G2FLAGS_NDIMS_BOX(gflags)
Definition: gserialized2.h:38
#define G2FLAGS_GET_BBOX(gflags)
Definition: gserialized2.h:24
#define G2FLAG_X_SOLID
Macros for the extended 'flags' uint64_t.
Definition: gserialized2.h:16
#define G2FLAGS_SET_M(gflags, value)
Definition: gserialized2.h:30
#define G2FLAGS_GET_GEODETIC(gflags)
Definition: gserialized2.h:25
#define G2FLAGS_GET_Z(gflags)
Definition: gserialized2.h:22
#define G2FLAGS_GET_EXTENDED(gflags)
Definition: gserialized2.h:26
#define G2FLAGS_SET_GEODETIC(gflags, value)
Definition: gserialized2.h:32
#define G2FLAGS_GET_M(gflags)
Definition: gserialized2.h:23
#define G2FLAGS_SET_BBOX(gflags, value)
Definition: gserialized2.h:31
#define G2FLAGS_NDIMS(gflags)
Definition: gserialized2.h:36
int gserialized_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized.c:163
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
POINTARRAY * ptarray_construct_reference_data(char hasz, char hasm, uint32_t npoints, uint8_t *ptlist)
Construct a new POINTARRAY, referencing to the data from ptlist.
Definition: ptarray.c:283
#define LW_FALSE
Definition: liblwgeom.h:94
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define COMPOUNDTYPE
Definition: liblwgeom.h:110
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define CURVEPOLYTYPE
Definition: liblwgeom.h:111
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define FLAGS_NDIMS_BOX(flags)
Definition: liblwgeom.h:181
#define MULTISURFACETYPE
Definition: liblwgeom.h:113
#define LINETYPE
Definition: liblwgeom.h:103
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition: liblwgeom.h:324
#define LWFLAG_M
Definition: liblwgeom.h:159
#define LW_SUCCESS
Definition: liblwgeom.h:97
uint16_t lwflags_t
Definition: liblwgeom.h:299
#define FLAGS_GET_BBOX(flags)
Definition: liblwgeom.h:167
#define LWFLAG_Z
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:158
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:174
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
#define LWFLAG_BBOX
Definition: liblwgeom.h:160
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1208
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1105
#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
void lwfree(void *mem)
Definition: lwutil.c:242
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:179
#define POLYGONTYPE
Definition: liblwgeom.h:104
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:109
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:166
#define FLAGS_GET_SOLID(flags)
Definition: liblwgeom.h:170
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:180
#define LWFLAG_GEODETIC
Definition: liblwgeom.h:161
#define LWSIZE_SET(varsize, len)
Definition: liblwgeom.h:325
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition: lwgeom.c:755
#define MULTICURVETYPE
Definition: liblwgeom.h:112
#define TRIANGLETYPE
Definition: liblwgeom.h:115
#define FLAGS_SET_GEODETIC(flags, value)
Definition: liblwgeom.h:175
void * lwalloc(size_t size)
Definition: lwutil.c:227
float next_float_up(double d)
Definition: lwgeom_api.c:75
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition: lwutil.c:471
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define FLAGS_SET_M(flags, value)
Definition: liblwgeom.h:173
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
#define FLAGS_SET_Z(flags, value)
Definition: liblwgeom.h:172
#define FLAGS_SET_SOLID(flags, value)
Definition: liblwgeom.h:177
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
float next_float_down(double d)
Definition: lwgeom_api.c:54
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:168
int32_t clamp_srid(int32_t srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:333
#define FP_MAX(A, B)
#define FP_MIN(A, B)
int lwcollection_allows_subtype(int collectiontype, int subtype)
Check if subtype is allowed in collectiontype.
Definition: lwcollection.c:513
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
if(!(yy_init))
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:58
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:77
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
tuple g_size
Definition: genraster.py:42
type
Definition: ovdump.py:42
data
Definition: ovdump.py:104
double ymax
Definition: liblwgeom.h:357
double zmax
Definition: liblwgeom.h:359
double xmax
Definition: liblwgeom.h:355
double zmin
Definition: liblwgeom.h:358
double mmax
Definition: liblwgeom.h:361
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
double mmin
Definition: liblwgeom.h:360
lwflags_t flags
Definition: liblwgeom.h:353
uint8_t srid[3]
Definition: liblwgeom.h:445
uint32_t size
Definition: liblwgeom.h:444
uint8_t data[1]
Definition: liblwgeom.h:447
uint8_t gflags
Definition: liblwgeom.h:446
uint8_t type
Definition: liblwgeom.h:510
int32_t srid
Definition: liblwgeom.h:508
lwflags_t flags
Definition: liblwgeom.h:509
POINTARRAY * points
Definition: liblwgeom.h:507
GBOX * bbox
Definition: liblwgeom.h:506
lwflags_t flags
Definition: liblwgeom.h:577
uint32_t ngeoms
Definition: liblwgeom.h:580
uint32_t maxgeoms
Definition: liblwgeom.h:581
uint8_t type
Definition: liblwgeom.h:578
GBOX * bbox
Definition: liblwgeom.h:574
LWGEOM ** geoms
Definition: liblwgeom.h:575
int32_t srid
Definition: liblwgeom.h:576
uint8_t type
Definition: liblwgeom.h:462
GBOX * bbox
Definition: liblwgeom.h:458
int32_t srid
Definition: liblwgeom.h:460
lwflags_t flags
Definition: liblwgeom.h:461
lwflags_t flags
Definition: liblwgeom.h:485
GBOX * bbox
Definition: liblwgeom.h:482
POINTARRAY * points
Definition: liblwgeom.h:483
uint8_t type
Definition: liblwgeom.h:486
int32_t srid
Definition: liblwgeom.h:484
POINTARRAY * point
Definition: liblwgeom.h:471
uint8_t type
Definition: liblwgeom.h:474
lwflags_t flags
Definition: liblwgeom.h:473
GBOX * bbox
Definition: liblwgeom.h:470
int32_t srid
Definition: liblwgeom.h:472
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint8_t type
Definition: liblwgeom.h:522
uint32_t maxrings
Definition: liblwgeom.h:525
uint32_t nrings
Definition: liblwgeom.h:524
GBOX * bbox
Definition: liblwgeom.h:518
lwflags_t flags
Definition: liblwgeom.h:521
int32_t srid
Definition: liblwgeom.h:520
int32_t srid
Definition: liblwgeom.h:496
uint8_t type
Definition: liblwgeom.h:498
GBOX * bbox
Definition: liblwgeom.h:494
lwflags_t flags
Definition: liblwgeom.h:497
POINTARRAY * points
Definition: liblwgeom.h:495
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
lwflags_t flags
Definition: liblwgeom.h:431
uint32_t npoints
Definition: liblwgeom.h:427