PostGIS  3.7.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 version 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  /* Cannot do anything if there's no box */
298  if (!(g && gserialized_has_bbox(g)))
299  return NULL;
300 
301  uint8_t *ptr = (uint8_t*)(g->data);
302  size_t bndims = G2FLAGS_NDIMS_BOX(g->gflags);
303 
304  if (ndims)
305  *ndims = bndims;
306 
307  /* Advance past optional extended flags */
309  ptr += 8;
310 
311  return (const float *)(ptr);
312 }
313 
315 {
316  /* Null input! */
317  if (!(g && gbox)) return LW_FAILURE;
318 
319  uint8_t gflags = g->gflags;
320 
321  /* Initialize the flags on the box */
322  gbox->flags = gserialized2_get_lwflags(g);
323 
324  /* Has pre-calculated box */
325  if (G2FLAGS_GET_BBOX(gflags))
326  {
327  int i = 0;
328  const float *fbox = gserialized2_get_float_box_p(g, NULL);
329  gbox->xmin = fbox[i++];
330  gbox->xmax = fbox[i++];
331  gbox->ymin = fbox[i++];
332  gbox->ymax = fbox[i++];
333 
334  /* Geodetic? Read next dimension (geocentric Z) and return */
335  if (G2FLAGS_GET_GEODETIC(gflags))
336  {
337  gbox->zmin = fbox[i++];
338  gbox->zmax = fbox[i++];
339  return LW_SUCCESS;
340  }
341  /* Cartesian? Read extra dimensions (if there) and return */
342  if (G2FLAGS_GET_Z(gflags))
343  {
344  gbox->zmin = fbox[i++];
345  gbox->zmax = fbox[i++];
346  }
347  if (G2FLAGS_GET_M(gflags))
348  {
349  gbox->mmin = fbox[i++];
350  gbox->mmax = fbox[i++];
351  }
352  return LW_SUCCESS;
353  }
354  return LW_FAILURE;
355 }
356 
357 /*
358 * Populate a bounding box *without* allocating an LWGEOM. Useful
359 * for some performance purposes.
360 */
361 int
363 {
364  uint32_t type = gserialized2_get_type(g);
365  uint8_t *geometry_start = gserialized2_get_geometry_p(g);
366  double *dptr = (double *)(geometry_start);
367  int32_t *iptr = (int32_t *)(geometry_start);
368 
369  /* Peeking doesn't help if you already have a box or are geodetic */
371  {
372  return LW_FAILURE;
373  }
374 
375  /* Boxes of points are easy peasy */
376  if (type == POINTTYPE)
377  {
378  int i = 1; /* Start past <pointtype><padding> */
379 
380  /* Read the npoints flag */
381  int isempty = (iptr[1] == 0);
382 
383  /* EMPTY point has no box */
384  if (isempty) return LW_FAILURE;
385 
386  gbox->xmin = gbox->xmax = dptr[i++];
387  gbox->ymin = gbox->ymax = dptr[i++];
388  gbox->flags = gserialized2_get_lwflags(g);
389  if (G2FLAGS_GET_Z(g->gflags))
390  {
391  gbox->zmin = gbox->zmax = dptr[i++];
392  }
393  if (G2FLAGS_GET_M(g->gflags))
394  {
395  gbox->mmin = gbox->mmax = dptr[i++];
396  }
397  gbox_float_round(gbox);
398  return LW_SUCCESS;
399  }
400  /* We can calculate the box of a two-point cartesian line trivially */
401  else if (type == LINETYPE)
402  {
403  int ndims = G2FLAGS_NDIMS(g->gflags);
404  int i = 0; /* Start at <linetype><npoints> */
405  int npoints = iptr[1]; /* Read the npoints */
406 
407  /* This only works with 2-point lines */
408  if (npoints != 2)
409  return LW_FAILURE;
410 
411  /* Advance to X */
412  /* Past <linetype><npoints> */
413  i++;
414  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
415  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
416 
417  /* Advance to Y */
418  i++;
419  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
420  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
421 
422  gbox->flags = gserialized2_get_lwflags(g);
423  if (G2FLAGS_GET_Z(g->gflags))
424  {
425  /* Advance to Z */
426  i++;
427  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
428  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
429  }
430  if (G2FLAGS_GET_M(g->gflags))
431  {
432  /* Advance to M */
433  i++;
434  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
435  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
436  }
437  gbox_float_round(gbox);
438  return LW_SUCCESS;
439  }
440  /* We can also do single-entry multi-points */
441  else if (type == MULTIPOINTTYPE)
442  {
443  int i = 0; /* Start at <multipointtype><ngeoms> */
444  int ngeoms = iptr[1]; /* Read the ngeoms */
445  int npoints;
446 
447  /* This only works with single-entry multipoints */
448  if (ngeoms != 1)
449  return LW_FAILURE;
450 
451  /* Npoints is at <multipointtype><ngeoms><pointtype><npoints> */
452  npoints = iptr[3];
453 
454  /* The check below is necessary because we can have a MULTIPOINT
455  * that contains a single, empty POINT (ngeoms = 1, npoints = 0) */
456  if (npoints != 1)
457  return LW_FAILURE;
458 
459  /* Move forward two doubles (four ints) */
460  /* Past <multipointtype><ngeoms> */
461  /* Past <pointtype><npoints> */
462  i += 2;
463 
464  /* Read the doubles from the one point */
465  gbox->xmin = gbox->xmax = dptr[i++];
466  gbox->ymin = gbox->ymax = dptr[i++];
467  gbox->flags = gserialized2_get_lwflags(g);
468  if (G2FLAGS_GET_Z(g->gflags))
469  {
470  gbox->zmin = gbox->zmax = dptr[i++];
471  }
472  if (G2FLAGS_GET_M(g->gflags))
473  {
474  gbox->mmin = gbox->mmax = dptr[i++];
475  }
476  gbox_float_round(gbox);
477  return LW_SUCCESS;
478  }
479  /* And we can do single-entry multi-lines with two vertices (!!!) */
480  else if (type == MULTILINETYPE)
481  {
482  int ndims = G2FLAGS_NDIMS(g->gflags);
483  int i = 0; /* Start at <multilinetype><ngeoms> */
484  int ngeoms = iptr[1]; /* Read the ngeoms */
485  int npoints;
486 
487  /* This only works with 1-line multilines */
488  if (ngeoms != 1)
489  return LW_FAILURE;
490 
491  /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
492  npoints = iptr[3];
493 
494  if (npoints != 2)
495  return LW_FAILURE;
496 
497  /* Advance to X */
498  /* Move forward two doubles (four ints) */
499  /* Past <multilinetype><ngeoms> */
500  /* Past <linetype><npoints> */
501  i += 2;
502  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
503  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
504 
505  /* Advance to Y */
506  i++;
507  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
508  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
509 
510  gbox->flags = gserialized2_get_lwflags(g);
511  if (G2FLAGS_GET_Z(g->gflags))
512  {
513  /* Advance to Z */
514  i++;
515  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
516  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
517  }
518  if (G2FLAGS_GET_M(g->gflags))
519  {
520  /* Advance to M */
521  i++;
522  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
523  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
524  }
525  gbox_float_round(gbox);
526  return LW_SUCCESS;
527  }
528 
529  return LW_FAILURE;
530 }
531 
532 static inline void
533 gserialized2_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
534 {
535  uint8_t dim = 0;
536  out_point->x = dptr[dim++];
537  out_point->y = dptr[dim++];
538 
539  if (G2FLAGS_GET_Z(flags))
540  {
541  out_point->z = dptr[dim++];
542  }
543  if (G2FLAGS_GET_M(flags))
544  {
545  out_point->m = dptr[dim];
546  }
547 }
548 
549 int
551 {
552  uint8_t *geometry_start = gserialized2_get_geometry_p(g);
553 
554  uint32_t isEmpty = (((uint32_t *)geometry_start)[1]) == 0;
555  if (isEmpty)
556  {
557  return LW_FAILURE;
558  }
559 
560  uint32_t type = (((uint32_t *)geometry_start)[0]);
561  /* Setup double_array_start depending on the geometry type */
562  double *double_array_start = NULL;
563  switch (type)
564  {
565  case (POINTTYPE):
566  /* For points we only need to jump over the type and npoints 32b ints */
567  double_array_start = (double *)(geometry_start + 2 * sizeof(uint32_t));
568  break;
569 
570  default:
571  lwerror("%s is currently not implemented for type %d", __func__, type);
572  return LW_FAILURE;
573  }
574 
575  gserialized2_copy_point(double_array_start, g->gflags, out_point);
576  return LW_SUCCESS;
577 }
578 
584 {
585  /* Try to just read the serialized box. */
586  if (gserialized2_read_gbox_p(g, box) == LW_SUCCESS)
587  {
588  return LW_SUCCESS;
589  }
590  /* No box? Try to peek into simpler geometries and */
591  /* derive a box without creating an lwgeom */
592  else if (gserialized2_peek_gbox_p(g, box) == LW_SUCCESS)
593  {
594  return LW_SUCCESS;
595  }
596  /* Damn! Nothing for it but to create an lwgeom... */
597  /* See http://trac.osgeo.org/postgis/ticket/1023 */
598  else
599  {
600  LWGEOM *lwgeom = lwgeom_from_gserialized(g);
601  int ret = lwgeom_calculate_gbox(lwgeom, box);
602  gbox_float_round(box);
603  lwgeom_free(lwgeom);
604  return ret;
605  }
606 }
607 
613 {
614  /* Try to just read the serialized box. */
615  if (gserialized2_read_gbox_p(g, box) == LW_SUCCESS)
616  {
617  return LW_SUCCESS;
618  }
619  /* No box? Try to peek into simpler geometries and */
620  /* derive a box without creating an lwgeom */
621  else if (gserialized2_peek_gbox_p(g, box) == LW_SUCCESS)
622  {
623  return LW_SUCCESS;
624  }
625  else
626  {
627  return LW_FAILURE;
628  }
629 }
630 
631 
632 
633 
634 /***********************************************************************
635 * Calculate the GSERIALIZED size for an LWGEOM.
636 */
637 
638 /* Private functions */
639 
640 static size_t gserialized2_from_any_size(const LWGEOM *geom); /* Local prototype */
641 
642 static size_t gserialized2_from_lwpoint_size(const LWPOINT *point)
643 {
644  size_t size = 4; /* Type number. */
645 
646  assert(point);
647 
648  size += 4; /* Number of points (one or zero (empty)). */
649  size += sizeof(double) * point->point->npoints * FLAGS_NDIMS(point->flags);
650 
651  LWDEBUGF(3, "point size = %zu", size);
652 
653  return size;
654 }
655 
656 static size_t gserialized2_from_lwline_size(const LWLINE *line)
657 {
658  size_t size = 4; /* Type number. */
659 
660  assert(line);
661 
662  size += 4; /* Number of points (zero => empty). */
663  size += sizeof(double) * line->points->npoints * FLAGS_NDIMS(line->flags);
664 
665  LWDEBUGF(3, "linestring size = %zu", size);
666 
667  return size;
668 }
669 
670 static size_t gserialized2_from_lwtriangle_size(const LWTRIANGLE *triangle)
671 {
672  size_t size = 4; /* Type number. */
673 
674  assert(triangle);
675 
676  size += 4; /* Number of points (zero => empty). */
677  size += sizeof(double)* triangle->points->npoints * FLAGS_NDIMS(triangle->flags);
678 
679  LWDEBUGF(3, "triangle size = %zu", size);
680 
681  return size;
682 }
683 
684 static size_t gserialized2_from_lwpoly_size(const LWPOLY *poly)
685 {
686  size_t size = 4; /* Type number. */
687  uint32_t i = 0;
688  const size_t point_size = FLAGS_NDIMS(poly->flags) * sizeof(double);
689 
690  assert(poly);
691 
692  size += 4; /* Number of rings (zero => empty). */
693  if (poly->nrings % 2)
694  size += 4; /* Padding to double alignment. */
695 
696  for (i = 0; i < poly->nrings; i++)
697  {
698  size += 4; /* Number of points in ring. */
699  size += poly->rings[i]->npoints * point_size;
700  }
701 
702  LWDEBUGF(3, "polygon size = %zu", size);
703 
704  return size;
705 }
706 
708 {
709  size_t size = 4; /* Type number. */
710 
711  assert(curve);
712 
713  size += 4; /* Number of points (zero => empty). */
714  size += sizeof(double) * curve->points->npoints * FLAGS_NDIMS(curve->flags);
715 
716  LWDEBUGF(3, "circstring size = %zu", size);
717 
718  return size;
719 }
720 
722 {
723  size_t size = 4; /* Type number. */
724  uint32_t i = 0;
725 
726  assert(col);
727 
728  size += 4; /* Number of sub-geometries (zero => empty). */
729 
730  for (i = 0; i < col->ngeoms; i++)
731  {
732  size_t subsize = gserialized2_from_any_size(col->geoms[i]);
733  size += subsize;
734  LWDEBUGF(3, "lwcollection subgeom(%d) size = %zu", i, subsize);
735  }
736 
737  LWDEBUGF(3, "lwcollection size = %zu", size);
738 
739  return size;
740 }
741 
742 static size_t gserialized2_from_any_size(const LWGEOM *geom)
743 {
744  LWDEBUGF(2, "Input type: %s", lwtype_name(geom->type));
745 
746  switch (geom->type)
747  {
748  case POINTTYPE:
749  return gserialized2_from_lwpoint_size((LWPOINT *)geom);
750  case LINETYPE:
751  return gserialized2_from_lwline_size((LWLINE *)geom);
752  case POLYGONTYPE:
753  return gserialized2_from_lwpoly_size((LWPOLY *)geom);
754  case TRIANGLETYPE:
756  case CIRCSTRINGTYPE:
758  case CURVEPOLYTYPE:
759  case COMPOUNDTYPE:
760  case MULTIPOINTTYPE:
761  case MULTILINETYPE:
762  case MULTICURVETYPE:
763  case MULTIPOLYGONTYPE:
764  case MULTISURFACETYPE:
766  case TINTYPE:
767  case COLLECTIONTYPE:
769  default:
770  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
771  return 0;
772  }
773 }
774 
775 /* Public function */
776 
778 {
779  size_t size = 8; /* Header overhead (varsize+flags+srid) */
780  assert(geom);
781 
782  /* Reserve space for extended flags */
784  size += 8;
785 
786  /* Reserve space for bounding box */
787  if (geom->bbox)
788  size += gbox_serialized_size(geom->flags);
789 
790  size += gserialized2_from_any_size(geom);
791  LWDEBUGF(3, "%s size = %zu", __func__, size);
792 
793  return size;
794 }
795 
796 /***********************************************************************
797 * Serialize an LWGEOM into GSERIALIZED.
798 */
799 
800 /* Private functions */
801 
802 static size_t gserialized2_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf);
803 
804 static size_t gserialized2_from_lwpoint(const LWPOINT *point, uint8_t *buf)
805 {
806  uint8_t *loc;
807  int ptsize = ptarray_point_size(point->point);
808  int type = POINTTYPE;
809 
810  assert(point);
811  assert(buf);
812 
813  if (FLAGS_GET_ZM(point->flags) != FLAGS_GET_ZM(point->point->flags))
814  lwerror("Dimensions mismatch in lwpoint");
815 
816  LWDEBUGF(2, "%s (%p, %p) called", __func__, point, buf);
817 
818  loc = buf;
819 
820  /* Write in the type. */
821  memcpy(loc, &type, sizeof(uint32_t));
822  loc += sizeof(uint32_t);
823  /* Write in the number of points (0 => empty). */
824  memcpy(loc, &(point->point->npoints), sizeof(uint32_t));
825  loc += sizeof(uint32_t);
826 
827  /* Copy in the ordinates. */
828  if (point->point->npoints > 0)
829  {
830  memcpy(loc, getPoint_internal(point->point, 0), ptsize);
831  loc += ptsize;
832  }
833 
834  return (size_t)(loc - buf);
835 }
836 
837 static size_t gserialized2_from_lwline(const LWLINE *line, uint8_t *buf)
838 {
839  uint8_t *loc;
840  int ptsize;
841  size_t size;
842  int type = LINETYPE;
843 
844  assert(line);
845  assert(buf);
846 
847  LWDEBUGF(2, "%s (%p, %p) called", __func__, line, buf);
848 
849  if (FLAGS_GET_Z(line->flags) != FLAGS_GET_Z(line->points->flags))
850  lwerror("Dimensions mismatch in lwline");
851 
852  ptsize = ptarray_point_size(line->points);
853 
854  loc = buf;
855 
856  /* Write in the type. */
857  memcpy(loc, &type, sizeof(uint32_t));
858  loc += sizeof(uint32_t);
859 
860  /* Write in the npoints. */
861  memcpy(loc, &(line->points->npoints), sizeof(uint32_t));
862  loc += sizeof(uint32_t);
863 
864  LWDEBUGF(3, "%s added npoints (%d)", __func__, line->points->npoints);
865 
866  /* Copy in the ordinates. */
867  if (line->points->npoints > 0)
868  {
869  size = (size_t)line->points->npoints * ptsize;
870  memcpy(loc, getPoint_internal(line->points, 0), size);
871  loc += size;
872  }
873  LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * line->points->npoints);
874 
875  return (size_t)(loc - buf);
876 }
877 
878 static size_t gserialized2_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
879 {
880  uint32_t i;
881  uint8_t *loc;
882  int ptsize;
883  int type = POLYGONTYPE;
884 
885  assert(poly);
886  assert(buf);
887 
888  LWDEBUGF(2, "%s called", __func__);
889 
890  ptsize = sizeof(double) * FLAGS_NDIMS(poly->flags);
891  loc = buf;
892 
893  /* Write in the type. */
894  memcpy(loc, &type, sizeof(uint32_t));
895  loc += sizeof(uint32_t);
896 
897  /* Write in the nrings. */
898  memcpy(loc, &(poly->nrings), sizeof(uint32_t));
899  loc += sizeof(uint32_t);
900 
901  /* Write in the npoints per ring. */
902  for (i = 0; i < poly->nrings; i++)
903  {
904  memcpy(loc, &(poly->rings[i]->npoints), sizeof(uint32_t));
905  loc += sizeof(uint32_t);
906  }
907 
908  /* Add in padding if necessary to remain double aligned. */
909  if (poly->nrings % 2)
910  {
911  memset(loc, 0, sizeof(uint32_t));
912  loc += sizeof(uint32_t);
913  }
914 
915  /* Copy in the ordinates. */
916  for (i = 0; i < poly->nrings; i++)
917  {
918  POINTARRAY *pa = poly->rings[i];
919  size_t pasize;
920 
921  if (FLAGS_GET_ZM(poly->flags) != FLAGS_GET_ZM(pa->flags))
922  lwerror("Dimensions mismatch in lwpoly");
923 
924  pasize = (size_t)pa->npoints * ptsize;
925  if ( pa->npoints > 0 )
926  memcpy(loc, getPoint_internal(pa, 0), pasize);
927  loc += pasize;
928  }
929  return (size_t)(loc - buf);
930 }
931 
932 static size_t gserialized2_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
933 {
934  uint8_t *loc;
935  int ptsize;
936  size_t size;
937  int type = TRIANGLETYPE;
938 
939  assert(triangle);
940  assert(buf);
941 
942  LWDEBUGF(2, "%s (%p, %p) called", __func__, triangle, buf);
943 
944  if (FLAGS_GET_ZM(triangle->flags) != FLAGS_GET_ZM(triangle->points->flags))
945  lwerror("Dimensions mismatch in lwtriangle");
946 
947  ptsize = ptarray_point_size(triangle->points);
948 
949  loc = buf;
950 
951  /* Write in the type. */
952  memcpy(loc, &type, sizeof(uint32_t));
953  loc += sizeof(uint32_t);
954 
955  /* Write in the npoints. */
956  memcpy(loc, &(triangle->points->npoints), sizeof(uint32_t));
957  loc += sizeof(uint32_t);
958 
959  LWDEBUGF(3, "%s added npoints (%d)", __func__, triangle->points->npoints);
960 
961  /* Copy in the ordinates. */
962  if (triangle->points->npoints > 0)
963  {
964  size = (size_t)triangle->points->npoints * ptsize;
965  memcpy(loc, getPoint_internal(triangle->points, 0), size);
966  loc += size;
967  }
968  LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * triangle->points->npoints);
969 
970  return (size_t)(loc - buf);
971 }
972 
973 static size_t gserialized2_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
974 {
975  uint8_t *loc;
976  int ptsize;
977  size_t size;
978  int type = CIRCSTRINGTYPE;
979 
980  assert(curve);
981  assert(buf);
982 
983  if (FLAGS_GET_ZM(curve->flags) != FLAGS_GET_ZM(curve->points->flags))
984  lwerror("Dimensions mismatch in lwcircstring");
985 
986 
987  ptsize = ptarray_point_size(curve->points);
988  loc = buf;
989 
990  /* Write in the type. */
991  memcpy(loc, &type, sizeof(uint32_t));
992  loc += sizeof(uint32_t);
993 
994  /* Write in the npoints. */
995  memcpy(loc, &curve->points->npoints, sizeof(uint32_t));
996  loc += sizeof(uint32_t);
997 
998  /* Copy in the ordinates. */
999  if (curve->points->npoints > 0)
1000  {
1001  size = (size_t)curve->points->npoints * ptsize;
1002  memcpy(loc, getPoint_internal(curve->points, 0), size);
1003  loc += size;
1004  }
1005 
1006  return (size_t)(loc - buf);
1007 }
1008 
1009 static size_t gserialized2_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
1010 {
1011  size_t subsize = 0;
1012  uint8_t *loc;
1013  uint32_t i;
1014  int type;
1015 
1016  assert(coll);
1017  assert(buf);
1018 
1019  type = coll->type;
1020  loc = buf;
1021 
1022  /* Write in the type. */
1023  memcpy(loc, &type, sizeof(uint32_t));
1024  loc += sizeof(uint32_t);
1025 
1026  /* Write in the number of subgeoms. */
1027  memcpy(loc, &coll->ngeoms, sizeof(uint32_t));
1028  loc += sizeof(uint32_t);
1029 
1030  /* Serialize subgeoms. */
1031  for (i = 0; i < coll->ngeoms; i++)
1032  {
1033  if (FLAGS_GET_ZM(coll->flags) != FLAGS_GET_ZM(coll->geoms[i]->flags))
1034  lwerror("Dimensions mismatch in lwcollection");
1035  subsize = gserialized2_from_lwgeom_any(coll->geoms[i], loc);
1036  loc += subsize;
1037  }
1038 
1039  return (size_t)(loc - buf);
1040 }
1041 
1042 static size_t gserialized2_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
1043 {
1044  assert(geom);
1045  assert(buf);
1046 
1047  LWDEBUGF(2, "Input type (%d) %s, hasz: %d hasm: %d",
1048  geom->type, lwtype_name(geom->type),
1049  FLAGS_GET_Z(geom->flags), FLAGS_GET_M(geom->flags));
1050  LWDEBUGF(2, "LWGEOM(%p) uint8_t(%p)", geom, buf);
1051 
1052  switch (geom->type)
1053  {
1054  case POINTTYPE:
1055  return gserialized2_from_lwpoint((LWPOINT *)geom, buf);
1056  case LINETYPE:
1057  return gserialized2_from_lwline((LWLINE *)geom, buf);
1058  case POLYGONTYPE:
1059  return gserialized2_from_lwpoly((LWPOLY *)geom, buf);
1060  case TRIANGLETYPE:
1061  return gserialized2_from_lwtriangle((LWTRIANGLE *)geom, buf);
1062  case CIRCSTRINGTYPE:
1063  return gserialized2_from_lwcircstring((LWCIRCSTRING *)geom, buf);
1064  case CURVEPOLYTYPE:
1065  case COMPOUNDTYPE:
1066  case MULTIPOINTTYPE:
1067  case MULTILINETYPE:
1068  case MULTICURVETYPE:
1069  case MULTIPOLYGONTYPE:
1070  case MULTISURFACETYPE:
1071  case POLYHEDRALSURFACETYPE:
1072  case TINTYPE:
1073  case COLLECTIONTYPE:
1074  return gserialized2_from_lwcollection((LWCOLLECTION *)geom, buf);
1075  default:
1076  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
1077  return 0;
1078  }
1079  return 0;
1080 }
1081 
1083 {
1085  {
1086  uint64_t xflags = 0;
1087  if (FLAGS_GET_SOLID(lwflags))
1088  xflags |= G2FLAG_X_SOLID;
1089 
1090  // G2FLAG_X_CHECKED_VALID
1091  // G2FLAG_X_IS_VALID
1092  // G2FLAG_X_HAS_HASH
1093 
1094  memcpy(buf, &xflags, sizeof(uint64_t));
1095  return sizeof(uint64_t);
1096  }
1097  return 0;
1098 }
1099 
1100 static size_t gserialized2_from_gbox(const GBOX *gbox, uint8_t *buf)
1101 {
1102  uint8_t *loc = buf;
1103  float *f;
1104  uint8_t i = 0;
1105  size_t return_size;
1106 
1107  assert(buf);
1108 
1109  f = (float *)buf;
1110  f[i++] = next_float_down(gbox->xmin);
1111  f[i++] = next_float_up(gbox->xmax);
1112  f[i++] = next_float_down(gbox->ymin);
1113  f[i++] = next_float_up(gbox->ymax);
1114  loc += 4 * sizeof(float);
1115 
1116  if (FLAGS_GET_GEODETIC(gbox->flags))
1117  {
1118  f[i++] = next_float_down(gbox->zmin);
1119  f[i++] = next_float_up(gbox->zmax);
1120  loc += 2 * sizeof(float);
1121 
1122  return_size = (size_t)(loc - buf);
1123  LWDEBUGF(4, "returning size %zu", return_size);
1124  return return_size;
1125  }
1126 
1127  if (FLAGS_GET_Z(gbox->flags))
1128  {
1129  f[i++] = next_float_down(gbox->zmin);
1130  f[i++] = next_float_up(gbox->zmax);
1131  loc += 2 * sizeof(float);
1132  }
1133 
1134  if (FLAGS_GET_M(gbox->flags))
1135  {
1136  f[i++] = next_float_down(gbox->mmin);
1137  f[i++] = next_float_up(gbox->mmax);
1138  loc += 2 * sizeof(float);
1139  }
1140  return_size = (size_t)(loc - buf);
1141  LWDEBUGF(4, "returning size %zu", return_size);
1142  return return_size;
1143 }
1144 
1145 /* Public function */
1146 
1148 {
1149  size_t expected_size = 0;
1150  size_t return_size = 0;
1151  uint8_t *ptr = NULL;
1152  GSERIALIZED *g = NULL;
1153  assert(geom);
1154 
1155  /*
1156  ** See if we need a bounding box, add one if we don't have one.
1157  */
1158  if ((!geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)))
1159  {
1160  lwgeom_add_bbox(geom);
1161  }
1162 
1163  /*
1164  ** Harmonize the flags to the state of the lwgeom
1165  */
1166  FLAGS_SET_BBOX(geom->flags, (geom->bbox ? 1 : 0));
1167 
1168  /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1169  expected_size = gserialized2_from_lwgeom_size(geom);
1170  ptr = lwalloc(expected_size);
1171  g = (GSERIALIZED*)(ptr);
1172 
1173  /* Set the SRID! */
1174  gserialized2_set_srid(g, geom->srid);
1175  /*
1176  ** We are aping PgSQL code here, PostGIS code should use
1177  ** VARSIZE to set this for real.
1178  */
1179  LWSIZE_SET(g->size, expected_size);
1180  g->gflags = lwflags_get_g2flags(geom->flags);
1181 
1182  /* Move write head past size, srid and flags. */
1183  ptr += 8;
1184 
1185  /* Write in the extended flags if necessary */
1186  ptr += gserialized2_from_extended_flags(geom->flags, ptr);
1187 
1188  /* Write in the serialized form of the gbox, if necessary. */
1189  if (geom->bbox)
1190  ptr += gserialized2_from_gbox(geom->bbox, ptr);
1191 
1192  /* Write in the serialized form of the geometry. */
1193  ptr += gserialized2_from_lwgeom_any(geom, ptr);
1194 
1195  /* Calculate size as returned by data processing functions. */
1196  return_size = ptr - (uint8_t*)g;
1197 
1198  assert(expected_size == return_size);
1199  if (size) /* Return the output size to the caller if necessary. */
1200  *size = return_size;
1201 
1202  return g;
1203 }
1204 
1205 /***********************************************************************
1206 * De-serialize GSERIALIZED into an LWGEOM.
1207 */
1208 
1209 static LWGEOM *lwgeom_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid);
1210 
1211 static LWPOINT *
1212 lwpoint_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1213 {
1214  uint8_t *start_ptr = data_ptr;
1215  LWPOINT *point;
1216  uint32_t npoints = 0;
1217 
1218  assert(data_ptr);
1219 
1220  point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1221  point->srid = srid;
1222  point->bbox = NULL;
1223  point->type = POINTTYPE;
1224  point->flags = lwflags;
1225 
1226  data_ptr += 4; /* Skip past the type. */
1227  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1228  data_ptr += 4; /* Skip past the npoints. */
1229 
1230  if (npoints > 0)
1232  else
1233  point->point = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty point */
1234 
1235  data_ptr += sizeof(double) * npoints * FLAGS_NDIMS(lwflags);
1236 
1237  if (size)
1238  *size = data_ptr - start_ptr;
1239 
1240  return point;
1241 }
1242 
1243 static LWLINE *
1244 lwline_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1245 {
1246  uint8_t *start_ptr = data_ptr;
1247  LWLINE *line;
1248  uint32_t npoints = 0;
1249 
1250  assert(data_ptr);
1251 
1252  line = (LWLINE*)lwalloc(sizeof(LWLINE));
1253  line->srid = srid;
1254  line->bbox = NULL;
1255  line->type = LINETYPE;
1256  line->flags = lwflags;
1257 
1258  data_ptr += 4; /* Skip past the type. */
1259  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1260  data_ptr += 4; /* Skip past the npoints. */
1261 
1262  if (npoints > 0)
1264 
1265  else
1266  line->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty linestring */
1267 
1268  data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1269 
1270  if (size)
1271  *size = data_ptr - start_ptr;
1272 
1273  return line;
1274 }
1275 
1276 static LWPOLY *
1277 lwpoly_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1278 {
1279  uint8_t *start_ptr = data_ptr;
1280  LWPOLY *poly;
1281  uint8_t *ordinate_ptr;
1282  uint32_t nrings = 0;
1283  uint32_t i = 0;
1284 
1285  assert(data_ptr);
1286 
1287  poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1288  poly->srid = srid;
1289  poly->bbox = NULL;
1290  poly->type = POLYGONTYPE;
1291  poly->flags = lwflags;
1292 
1293  data_ptr += 4; /* Skip past the polygontype. */
1294  nrings = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1295  poly->nrings = nrings;
1296  LWDEBUGF(4, "nrings = %d", nrings);
1297  data_ptr += 4; /* Skip past the nrings. */
1298 
1299  ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1300  if (nrings > 0)
1301  {
1302  poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1303  poly->maxrings = nrings;
1304  ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1305  if (nrings % 2) /* If there is padding, move past that too. */
1306  ordinate_ptr += 4;
1307  }
1308  else /* Empty polygon */
1309  {
1310  poly->rings = NULL;
1311  poly->maxrings = 0;
1312  }
1313 
1314  for (i = 0; i < nrings; i++)
1315  {
1316  uint32_t npoints = 0;
1317 
1318  /* Read in the number of points. */
1319  npoints = gserialized2_get_uint32_t(data_ptr);
1320  data_ptr += 4;
1321 
1322  /* Make a point array for the ring, and move the ordinate pointer past the ring ordinates. */
1323  poly->rings[i] = ptarray_construct_reference_data(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), npoints, ordinate_ptr);
1324 
1325  ordinate_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1326  }
1327 
1328  if (size)
1329  *size = ordinate_ptr - start_ptr;
1330 
1331  return poly;
1332 }
1333 
1334 static LWTRIANGLE *
1335 lwtriangle_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1336 {
1337  uint8_t *start_ptr = data_ptr;
1338  LWTRIANGLE *triangle;
1339  uint32_t npoints = 0;
1340 
1341  assert(data_ptr);
1342 
1343  triangle = (LWTRIANGLE*)lwalloc(sizeof(LWTRIANGLE));
1344  triangle->srid = srid; /* Default */
1345  triangle->bbox = NULL;
1346  triangle->type = TRIANGLETYPE;
1347  triangle->flags = lwflags;
1348 
1349  data_ptr += 4; /* Skip past the type. */
1350  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1351  data_ptr += 4; /* Skip past the npoints. */
1352 
1353  if (npoints > 0)
1355  else
1356  triangle->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty triangle */
1357 
1358  data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1359 
1360  if (size)
1361  *size = data_ptr - start_ptr;
1362 
1363  return triangle;
1364 }
1365 
1366 static LWCIRCSTRING *
1367 lwcircstring_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1368 {
1369  uint8_t *start_ptr = data_ptr;
1370  LWCIRCSTRING *circstring;
1371  uint32_t npoints = 0;
1372 
1373  assert(data_ptr);
1374 
1375  circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING));
1376  circstring->srid = srid;
1377  circstring->bbox = NULL;
1378  circstring->type = CIRCSTRINGTYPE;
1379  circstring->flags = lwflags;
1380 
1381  data_ptr += 4; /* Skip past the circstringtype. */
1382  npoints = gserialized2_get_uint32_t(data_ptr); /* Zero => empty geometry */
1383  data_ptr += 4; /* Skip past the npoints. */
1384 
1385  if (npoints > 0)
1386  circstring->points = ptarray_construct_reference_data(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), npoints, data_ptr);
1387  else
1388  circstring->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty circularstring */
1389 
1390  data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1391 
1392  if (size)
1393  *size = data_ptr - start_ptr;
1394 
1395  return circstring;
1396 }
1397 
1398 static LWCOLLECTION *
1399 lwcollection_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size, int32_t srid)
1400 {
1401  uint32_t type;
1402  uint8_t *start_ptr = data_ptr;
1403  LWCOLLECTION *collection;
1404  uint32_t ngeoms = 0;
1405  uint32_t i = 0;
1406 
1407  assert(data_ptr);
1408 
1409  type = gserialized2_get_uint32_t(data_ptr);
1410  data_ptr += 4; /* Skip past the type. */
1411 
1412  collection = (LWCOLLECTION*)lwalloc(sizeof(LWCOLLECTION));
1413  collection->srid = srid;
1414  collection->bbox = NULL;
1415  collection->type = type;
1416  collection->flags = lwflags;
1417 
1418  ngeoms = gserialized2_get_uint32_t(data_ptr);
1419  collection->ngeoms = ngeoms; /* Zero => empty geometry */
1420  data_ptr += 4; /* Skip past the ngeoms. */
1421 
1422  if (ngeoms > 0)
1423  {
1424  collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1425  collection->maxgeoms = ngeoms;
1426  }
1427  else
1428  {
1429  collection->geoms = NULL;
1430  collection->maxgeoms = 0;
1431  }
1432 
1433  /* Sub-geometries are never de-serialized with boxes (#1254) */
1434  FLAGS_SET_BBOX(lwflags, 0);
1435 
1436  for (i = 0; i < ngeoms; i++)
1437  {
1438  uint32_t subtype = gserialized2_get_uint32_t(data_ptr);
1439  size_t subsize = 0;
1440 
1441  if (!lwcollection_allows_subtype(type, subtype))
1442  {
1443  lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1444  lwfree(collection);
1445  return NULL;
1446  }
1447  collection->geoms[i] = lwgeom_from_gserialized2_buffer(data_ptr, lwflags, &subsize, srid);
1448  data_ptr += subsize;
1449  }
1450 
1451  if (size)
1452  *size = data_ptr - start_ptr;
1453 
1454  return collection;
1455 }
1456 
1457 LWGEOM *
1458 lwgeom_from_gserialized2_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *g_size, int32_t srid)
1459 {
1460  uint32_t type;
1461 
1462  assert(data_ptr);
1463 
1464  type = gserialized2_get_uint32_t(data_ptr);
1465 
1466  LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1468 
1469  switch (type)
1470  {
1471  case POINTTYPE:
1472  return (LWGEOM *)lwpoint_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1473  case LINETYPE:
1474  return (LWGEOM *)lwline_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1475  case CIRCSTRINGTYPE:
1476  return (LWGEOM *)lwcircstring_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1477  case POLYGONTYPE:
1478  return (LWGEOM *)lwpoly_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1479  case TRIANGLETYPE:
1480  return (LWGEOM *)lwtriangle_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1481  case MULTIPOINTTYPE:
1482  case MULTILINETYPE:
1483  case MULTIPOLYGONTYPE:
1484  case COMPOUNDTYPE:
1485  case CURVEPOLYTYPE:
1486  case MULTICURVETYPE:
1487  case MULTISURFACETYPE:
1488  case POLYHEDRALSURFACETYPE:
1489  case TINTYPE:
1490  case COLLECTIONTYPE:
1491  return (LWGEOM *)lwcollection_from_gserialized2_buffer(data_ptr, lwflags, g_size, srid);
1492  default:
1493  lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1494  return NULL;
1495  }
1496 }
1497 
1499 {
1500  lwflags_t lwflags = 0;
1501  int32_t srid = 0;
1502  uint32_t lwtype = 0;
1503  uint8_t *data_ptr = NULL;
1504  LWGEOM *lwgeom = NULL;
1505  GBOX bbox;
1506  size_t size = 0;
1507 
1508  assert(g);
1509 
1510  srid = gserialized2_get_srid(g);
1511  lwtype = gserialized2_get_type(g);
1513 
1514  LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
1515 
1516  data_ptr = (uint8_t*)g->data;
1517 
1518  /* Skip optional flags */
1520  {
1521  data_ptr += sizeof(uint64_t);
1522  }
1523 
1524  /* Skip over optional bounding box */
1525  if (FLAGS_GET_BBOX(lwflags))
1526  data_ptr += gbox_serialized_size(lwflags);
1527 
1528  lwgeom = lwgeom_from_gserialized2_buffer(data_ptr, lwflags, &size, srid);
1529 
1530  if (!lwgeom)
1531  lwerror("%s: unable create geometry", __func__); /* Ooops! */
1532 
1533  lwgeom->type = lwtype;
1534  lwgeom->flags = lwflags;
1535 
1536  if (gserialized2_read_gbox_p(g, &bbox) == LW_SUCCESS)
1537  {
1538  lwgeom->bbox = gbox_copy(&bbox);
1539  }
1540  else if (lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS))
1541  {
1542  lwgeom->bbox = gbox_copy(&bbox);
1543  }
1544  else
1545  {
1546  lwgeom->bbox = NULL;
1547  }
1548 
1549  return lwgeom;
1550 }
1551 
1561 {
1562 
1563  int g_ndims = G2FLAGS_NDIMS_BOX(g->gflags);
1564  int box_ndims = FLAGS_NDIMS_BOX(gbox->flags);
1565  GSERIALIZED *g_out = NULL;
1566  size_t box_size = 2 * g_ndims * sizeof(float);
1567  float *fbox;
1568  int fbox_pos = 0;
1569 
1570  /* The dimensionality of the inputs has to match or we are SOL. */
1571  if (g_ndims != box_ndims)
1572  {
1573  return NULL;
1574  }
1575 
1576  /* Serialized already has room for a box. */
1577  if (G2FLAGS_GET_BBOX(g->gflags))
1578  {
1579  g_out = g;
1580  }
1581  /* Serialized has no box. We need to allocate enough space for the old
1582  data plus the box, and leave a gap in the memory segment to write
1583  the new values into.
1584  */
1585  else
1586  {
1587  size_t varsize_in = LWSIZE_GET(g->size);
1588  size_t varsize_out = varsize_in + box_size;
1589  uint8_t *ptr_out, *ptr_in, *ptr;
1590  g_out = lwalloc(varsize_out);
1591  ptr_out = (uint8_t*)g_out;
1592  ptr = ptr_in = (uint8_t*)g;
1593  /* Copy the head of g into place */
1594  memcpy(ptr_out, ptr_in, 8); ptr_out += 8; ptr_in += 8;
1595  /* Optionally copy extended bit into place */
1596  if (G2FLAGS_GET_EXTENDED(g->gflags))
1597  {
1598  memcpy(ptr_out, ptr_in, 8); ptr_out += 8; ptr_in += 8;
1599  }
1600  /* Copy the body of g into place after leaving space for the box */
1601  ptr_out += box_size;
1602  memcpy(ptr_out, ptr_in, varsize_in - (ptr_in - ptr));
1603  G2FLAGS_SET_BBOX(g_out->gflags, 1);
1604  LWSIZE_SET(g_out->size, varsize_out);
1605  }
1606 
1607  /* Move bounds to nearest float values */
1608  gbox_float_round(gbox);
1609  /* Now write the float box values into the memory segment */
1610  fbox = (float*)(g_out->data);
1611  /* Copy in X/Y */
1612  fbox[fbox_pos++] = gbox->xmin;
1613  fbox[fbox_pos++] = gbox->xmax;
1614  fbox[fbox_pos++] = gbox->ymin;
1615  fbox[fbox_pos++] = gbox->ymax;
1616  /* Optionally copy in higher dims */
1618  {
1619  fbox[fbox_pos++] = gbox->zmin;
1620  fbox[fbox_pos++] = gbox->zmax;
1621  }
1623  {
1624  fbox[fbox_pos++] = gbox->mmin;
1625  fbox[fbox_pos++] = gbox->mmax;
1626  }
1627 
1628  return g_out;
1629 }
1630 
1631 
1637 {
1638  int g_ndims = G2FLAGS_NDIMS_BOX(g->gflags);
1639  size_t box_size = 2 * g_ndims * sizeof(float);
1640  size_t g_out_size = LWSIZE_GET(g->size) - box_size;
1641  GSERIALIZED *g_out = lwalloc(g_out_size);
1642 
1643  /* Copy the contents while omitting the box */
1644  if (G2FLAGS_GET_BBOX(g->gflags))
1645  {
1646  uint8_t *outptr = (uint8_t*)g_out;
1647  uint8_t *inptr = (uint8_t*)g;
1648  /* Copy the header (size+type) of g into place */
1649  memcpy(outptr, inptr, 8); outptr += 8; inptr += 8;
1650  /* Copy extended flags, if there are any */
1651  if (G2FLAGS_GET_EXTENDED(g->gflags))
1652  {
1653  memcpy(outptr, inptr, 8); outptr += 8; inptr += 8;
1654  }
1655  /* Advance past box */
1656  inptr += box_size;
1657  /* Copy parts after the box into place */
1658  memcpy(outptr, inptr, g_out_size - 8);
1659  G2FLAGS_SET_BBOX(g_out->gflags, 0);
1660  LWSIZE_SET(g_out->size, g_out_size);
1661  }
1662  /* No box? Nothing to do but copy and return. */
1663  else
1664  {
1665  memcpy(g_out, g, g_out_size);
1666  }
1667 
1668  return g_out;
1669 }
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:452
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition: gbox.c:786
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: gbox.c:438
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:612
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:707
static size_t gserialized2_from_lwpoly_size(const LWPOLY *poly)
Definition: gserialized2.c:684
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:550
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:362
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:583
static size_t gserialized2_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
Definition: gserialized2.c:973
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:642
size_t gserialized2_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized2.c:777
static size_t gserialized2_from_lwtriangle_size(const LWTRIANGLE *triangle)
Definition: gserialized2.c:670
static size_t gserialized2_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
Definition: gserialized2.c:878
static size_t gserialized2_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
Definition: gserialized2.c:932
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:721
static size_t gserialized2_from_lwline(const LWLINE *line, uint8_t *buf)
Definition: gserialized2.c:837
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:804
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:533
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:742
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:656
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:192
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
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:291
#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:1218
#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:1271
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1168
#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:248
#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:74
lwflags_t lwflags(int hasz, int hasm, int geodetic)
Construct a new flags bitmask.
Definition: lwutil.c:477
#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:53
#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:339
#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:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
if(!(yy_init))
static size_t ptarray_point_size(const POINTARRAY *pa)
Definition: lwinline.h:56
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:75
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:199
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