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