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