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