PostGIS  2.4.9dev-r@@SVN_REVISION@@
g_serialized.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 
31 /***********************************************************************
32 * GSERIALIZED metadata utility functions.
33 */
34 /* handle missaligned uint32_t data */
35 static inline uint32_t gserialized_get_uint32_t(const uint8_t *loc)
36 {
37  return *((uint32_t*)loc);
38 }
39 
41 {
42  return FLAGS_GET_BBOX(gser->flags);
43 }
44 
46 {
47  return FLAGS_GET_Z(gser->flags);
48 }
49 
51 {
52  return FLAGS_GET_M(gser->flags);
53 }
54 
56 {
57  return 2 * FLAGS_GET_Z(gser->flags) + FLAGS_GET_M(gser->flags);
58 }
59 
61 {
62  return FLAGS_NDIMS(gser->flags);
63 }
64 
66 {
67  return FLAGS_GET_GEODETIC(gser->flags);
68 }
69 
71 {
72  /* read GSERIALIZED size + max bbox according gbox_serialized_size (2 + Z + M) + 1 int for type */
73  return sizeof(GSERIALIZED) + 8 * sizeof(float) + sizeof(int);
74 }
75 
77 {
78  uint32_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
79 
80  if (gserialized_has_bbox(gser))
81  sz += gbox_serialized_size(gser->flags);
82 
83  return sz;
84 }
85 
87 {
88  uint32_t *ptr;
89  assert(s);
90  ptr = (uint32_t*)(s->data);
91  LWDEBUG(4,"entered");
92  if ( FLAGS_GET_BBOX(s->flags) )
93  {
94  LWDEBUGF(4,"skipping forward past bbox (%d bytes)",gbox_serialized_size(s->flags));
95  ptr += (gbox_serialized_size(s->flags) / sizeof(uint32_t));
96  }
97  return *ptr;
98 }
99 
101 {
102  int32_t srid = 0;
103  srid = srid | (s->srid[0] << 16);
104  srid = srid | (s->srid[1] << 8);
105  srid = srid | s->srid[2];
106  /* Only the first 21 bits are set. Slide up and back to pull
107  the negative bits down, if we need them. */
108  srid = (srid<<11)>>11;
109 
110  /* 0 is our internal unknown value. We'll map back and forth here for now */
111  if ( srid == 0 )
112  return SRID_UNKNOWN;
113  else
114  return srid;
115 }
116 
117 void gserialized_set_srid(GSERIALIZED *s, int32_t srid)
118 {
119  LWDEBUGF(3, "Called with srid = %d", srid);
120 
121  srid = clamp_srid(srid);
122 
123  /* 0 is our internal unknown value.
124  * We'll map back and forth here for now */
125  if ( srid == SRID_UNKNOWN )
126  srid = 0;
127 
128  s->srid[0] = (srid & 0x001F0000) >> 16;
129  s->srid[1] = (srid & 0x0000FF00) >> 8;
130  s->srid[2] = (srid & 0x000000FF);
131 }
132 
133 inline static int gserialized_cmp_srid(const GSERIALIZED *s1, const GSERIALIZED *s2)
134 {
135  return (
136  s1->srid[0] == s2->srid[0] &&
137  s1->srid[1] == s2->srid[1] &&
138  s1->srid[2] == s2->srid[2]
139  ) ? 0 : 1;
140 }
141 
143 {
144  GSERIALIZED *g_out = NULL;
145  assert(g);
146  g_out = (GSERIALIZED*)lwalloc(SIZE_GET(g->size));
147  memcpy((uint8_t*)g_out,(uint8_t*)g,SIZE_GET(g->size));
148  return g_out;
149 }
150 
151 static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty);
152 static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty)
153 {
154  int i;
155  int32_t type, num;
156 
157  memcpy(&type, p, 4);
158  memcpy(&num, p+4, 4);
159 
160  if ( lwtype_is_collection(type) )
161  {
162  size_t lz = 8;
163  for ( i = 0; i < num; i++ )
164  {
165  lz += gserialized_is_empty_recurse(p+lz, isempty);
166  if ( ! *isempty )
167  return lz;
168  }
169  *isempty = LW_TRUE;
170  return lz;
171  }
172  else
173  {
174  *isempty = (num == 0 ? LW_TRUE : LW_FALSE);
175  return 8;
176  }
177 }
178 
180 {
181  uint8_t *p = (uint8_t*)g;
182  int isempty = 0;
183  assert(g);
184 
185  p += 8; /* Skip varhdr and srid/flags */
186  if( FLAGS_GET_BBOX(g->flags) )
187  p += gbox_serialized_size(g->flags); /* Skip the box */
188 
189  gserialized_is_empty_recurse(p, &isempty);
190  return isempty;
191 }
192 
194 {
195  return lwgeom_to_wkt(lwgeom_from_gserialized(g), WKT_ISO, 12, 0);
196 }
197 
198 /* Unfortunately including advanced instructions is something that
199 only helps a small sliver of users who can build their own
200 knowing the target system they will be running on. Packagers
201 have to aim for the lowest common demoninator. So this is
202 dead code for the forseeable future. */
203 #define HAVE_PDEP 0
204 #if HAVE_PDEP
205 /* http://www.joshbarczak.com/blog/?p=454 */
206 static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
207 {
208  uint64_t x = u1;
209  uint64_t y = u2;
210  uint64_t x_mask = 0x5555555555555555;
211  uint64_t y_mask = 0xAAAAAAAAAAAAAAAA;
212  return _pdep_u64(x, x_mask) | _pdep_u64(y, y_mask);
213 }
214 
215 static uint64_t uint32_interleave_3(uint32_t u1, uint32_t u2, uint32_t u3)
216 {
217  /* only look at the first 21 bits */
218  uint64_t x = u1 & 0x1FFFFF;
219  uint64_t y = u2 & 0x1FFFFF;
220  uint64_t z = u3 & 0x1FFFFF;
221  uint64_t x_mask = 0x9249249249249249;
222  uint64_t y_mask = 0x2492492492492492;
223  uint64_t z_mask = 0x4924924924924924;
224  return _pdep_u64(x, x_mask) | _pdep_u64(y, y_mask) | _pdep_u64(z, z_mask);
225 }
226 
227 #else
228 static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
229 {
230  uint64_t x = u1;
231  uint64_t y = u2;
232  int i;
233 
234  static uint64_t B[5] =
235  {
236  0x5555555555555555,
237  0x3333333333333333,
238  0x0F0F0F0F0F0F0F0F,
239  0x00FF00FF00FF00FF,
240  0x0000FFFF0000FFFF
241  };
242  static uint64_t S[5] = { 1, 2, 4, 8, 16 };
243 
244  for ( i = 4; i >= 0; i-- )
245  {
246  x = (x | (x << S[i])) & B[i];
247  y = (y | (y << S[i])) & B[i];
248  }
249 
250  return x | (y << 1);
251 }
252 #endif
253 
254 union floatuint {
256  float f;
257 };
258 
259 uint64_t gbox_get_sortable_hash(const GBOX *g)
260 {
261  union floatuint x, y;
262 
263  /*
264  * Since in theory the bitwise representation of an IEEE
265  * float is sortable (exponents come before mantissa, etc)
266  * we just copy the bits directly into an int and then
267  * interleave those ints.
268  */
269  if ( FLAGS_GET_GEODETIC(g->flags) )
270  {
271  GEOGRAPHIC_POINT gpt;
272  POINT3D p;
273  p.x = (g->xmax + g->xmin) / 2.0;
274  p.y = (g->ymax + g->ymin) / 2.0;
275  p.z = (g->zmax + g->zmin) / 2.0;
276  normalize(&p);
277  cart2geog(&p, &gpt);
278  x.f = gpt.lon;
279  y.f = gpt.lat;
280  }
281  else
282  {
283  /*
284  * Here we'd like to get two ordinates from 4 in the box.
285  * Since it's just a sortable bit representation we can omit division from (A+B)/2.
286  * All it should do is subtract 1 from exponent anyways.
287  */
288  x.f = g->xmax + g->xmin;
289  y.f = g->ymax + g->ymin;
290  }
291  return uint32_interleave_2(x.u, y.u);
292 }
293 
294 int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
295 {
296  int g1_is_empty, g2_is_empty, cmp;
297  GBOX box1, box2;
298  uint64_t hash1, hash2;
299  size_t sz1 = SIZE_GET(g1->size);
300  size_t sz2 = SIZE_GET(g2->size);
301  union floatuint x, y;
302 
303  /*
304  * For two non-same planar points, we can skip a lot of machinery.
305  */
306  if (
307  sz1 > 16 && // 16 is size of EMPTY, if it's larger - it has coordinates
308  sz2 > 16 &&
309  *(uint32_t*)(g1->data) == POINTTYPE &&
310  *(uint32_t*)(g2->data) == POINTTYPE &&
311  !FLAGS_GET_BBOX(g1->flags) &&
312  !FLAGS_GET_GEODETIC(g1->flags) &&
313  !FLAGS_GET_BBOX(g2->flags) &&
315  )
316  {
317  double *dptr = (double*)(g1->data);
318  x.f = 2.0 * dptr[1];
319  y.f = 2.0 * dptr[2];
320  hash1 = uint32_interleave_2(x.u, y.u);
321 
322  dptr = (double*)(g2->data);
323  x.f = 2.0 * dptr[1];
324  y.f = 2.0 * dptr[2];
325  hash2 = uint32_interleave_2(x.u, y.u);
326 
327  if ( hash1 > hash2 )
328  return 1;
329  if ( hash1 < hash2 )
330  return -1;
331 
332  // if hashes happen to be the same, go to full compare.
333  }
334 
335  size_t hsz1 = gserialized_header_size(g1);
336  size_t hsz2 = gserialized_header_size(g2);
337 
338  uint8_t *b1 = (uint8_t*)g1 + hsz1;
339  uint8_t *b2 = (uint8_t*)g2 + hsz2;
340  size_t bsz1 = sz1 - hsz1;
341  size_t bsz2 = sz2 - hsz2;
342  size_t bsz = bsz1 < bsz2 ? bsz1 : bsz2;
343 
344  int cmp_srid = gserialized_cmp_srid(g1, g2);
345 
346  g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
347  g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
348 
349  /* Empty == Empty */
350  if (g1_is_empty && g2_is_empty)
351  {
352  /* POINT EMPTY == POINT EMPTY */
353  /* POINT EMPTY < LINESTRING EMPTY */
356  return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1);
357  }
358 
359  /* Empty < Non-empty */
360  if (g1_is_empty)
361  return -1;
362 
363  /* Non-empty > Empty */
364  if (g2_is_empty)
365  return 1;
366 
367  /* Return equality for perfect equality only */
368  cmp = memcmp(b1, b2, bsz);
369  if ( bsz1 == bsz2 && cmp_srid == 0 && cmp == 0 )
370  return 0;
371 
372  /* Using the centroids, calculate somewhat sortable */
373  /* hash key. The key doesn't provide good locality over */
374  /* the +/- boundary, but otherwise is pretty OK */
375  hash1 = gbox_get_sortable_hash(&box1);
376  hash2 = gbox_get_sortable_hash(&box2);
377 
378  if ( hash1 > hash2 )
379  return 1;
380  else if ( hash1 < hash2 )
381  return -1;
382 
383  /* What, the hashes are equal? OK... sort on the */
384  /* box minima */
385  if (box1.xmin < box2.xmin)
386  return -1;
387  else if (box1.xmin > box2.xmin)
388  return 1;
389 
390  if (box1.ymin < box2.ymin)
391  return -1;
392  else if (box1.ymin > box2.ymin)
393  return 1;
394 
395  /* Still equal? OK... sort on the box maxima */
396  if (box1.xmax < box2.xmax)
397  return -1;
398  else if (box1.xmax > box2.xmax)
399  return 1;
400 
401  if (box1.ymax < box2.ymax)
402  return -1;
403  else if (box1.ymax > box2.ymax)
404  return 1;
405 
406  /* Geeze! How about object size? Sort on that... */
407  if (hsz1 < hsz2)
408  return -1;
409  else if (hsz1 > hsz2)
410  return 1;
411 
412  /* OK fine, we'll sort on the memcmp just to be done with this */
413  return cmp == 0 ? 0 : (cmp > 0 ? 1 : -1);
414 }
415 
417 {
418 
419  /* Null input! */
420  if ( ! ( g && gbox ) ) return LW_FAILURE;
421 
422  /* Initialize the flags on the box */
423  gbox->flags = g->flags;
424 
425  /* Has pre-calculated box */
426  if ( FLAGS_GET_BBOX(g->flags) )
427  {
428  int i = 0;
429  float *fbox = (float*)(g->data);
430  gbox->xmin = fbox[i++];
431  gbox->xmax = fbox[i++];
432  gbox->ymin = fbox[i++];
433  gbox->ymax = fbox[i++];
434 
435  /* Geodetic? Read next dimension (geocentric Z) and return */
436  if ( FLAGS_GET_GEODETIC(g->flags) )
437  {
438  gbox->zmin = fbox[i++];
439  gbox->zmax = fbox[i++];
440  return LW_SUCCESS;
441  }
442  /* Cartesian? Read extra dimensions (if there) and return */
443  if ( FLAGS_GET_Z(g->flags) )
444  {
445  gbox->zmin = fbox[i++];
446  gbox->zmax = fbox[i++];
447  }
448  if ( FLAGS_GET_M(g->flags) )
449  {
450  gbox->mmin = fbox[i++];
451  gbox->mmax = fbox[i++];
452  }
453  return LW_SUCCESS;
454  }
455 
456  return LW_FAILURE;
457 }
458 
459 /*
460 * Populate a bounding box *without* allocating an LWGEOM. Useful
461 * for some performance purposes.
462 */
463 static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
464 {
466 
467  /* Peeking doesn't help if you already have a box or are geodetic */
468  if ( FLAGS_GET_GEODETIC(g->flags) || FLAGS_GET_BBOX(g->flags) )
469  {
470  return LW_FAILURE;
471  }
472 
473  /* Boxes of points are easy peasy */
474  if ( type == POINTTYPE )
475  {
476  int i = 1; /* Start past <pointtype><padding> */
477  double *dptr = (double*)(g->data);
478 
479  /* Read the empty flag */
480  int *iptr = (int*)(g->data);
481  int isempty = (iptr[1] == 0);
482 
483  /* EMPTY point has no box */
484  if ( isempty ) return LW_FAILURE;
485 
486  gbox->xmin = gbox->xmax = dptr[i++];
487  gbox->ymin = gbox->ymax = dptr[i++];
488  gbox->flags = g->flags;
489  if ( FLAGS_GET_Z(g->flags) )
490  {
491  gbox->zmin = gbox->zmax = dptr[i++];
492  }
493  if ( FLAGS_GET_M(g->flags) )
494  {
495  gbox->mmin = gbox->mmax = dptr[i++];
496  }
497  gbox_float_round(gbox);
498  return LW_SUCCESS;
499  }
500  /* We can calculate the box of a two-point cartesian line trivially */
501  else if ( type == LINETYPE )
502  {
503  int ndims = FLAGS_NDIMS(g->flags);
504  int i = 0; /* Start at <linetype><npoints> */
505  double *dptr = (double*)(g->data);
506  int *iptr = (int*)(g->data);
507  int npoints = iptr[1]; /* Read the npoints */
508 
509  /* This only works with 2-point lines */
510  if ( npoints != 2 )
511  return LW_FAILURE;
512 
513  /* Advance to X */
514  /* Past <linetype><npoints> */
515  i++;
516  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
517  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
518 
519  /* Advance to Y */
520  i++;
521  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
522  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
523 
524  gbox->flags = g->flags;
525  if ( FLAGS_GET_Z(g->flags) )
526  {
527  /* Advance to Z */
528  i++;
529  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
530  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
531  }
532  if ( FLAGS_GET_M(g->flags) )
533  {
534  /* Advance to M */
535  i++;
536  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
537  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
538  }
539  gbox_float_round(gbox);
540  return LW_SUCCESS;
541  }
542  /* We can also do single-entry multi-points */
543  else if ( type == MULTIPOINTTYPE )
544  {
545  int i = 0; /* Start at <multipointtype><ngeoms> */
546  double *dptr = (double*)(g->data);
547  int *iptr = (int*)(g->data);
548  int ngeoms = iptr[1]; /* Read the ngeoms */
549  int npoints;
550 
551  /* This only works with single-entry multipoints */
552  if ( ngeoms != 1 )
553  return LW_FAILURE;
554 
555  /* Npoints is at <multipointtype><ngeoms><pointtype><npoints> */
556  npoints = iptr[3];
557 
558  /* The check below is necessary because we can have a MULTIPOINT
559  * that contains a single, empty POINT (ngeoms = 1, npoints = 0) */
560  if ( npoints != 1 )
561  return LW_FAILURE;
562 
563  /* Move forward two doubles (four ints) */
564  /* Past <multipointtype><ngeoms> */
565  /* Past <pointtype><npoints> */
566  i += 2;
567 
568  /* Read the doubles from the one point */
569  gbox->xmin = gbox->xmax = dptr[i++];
570  gbox->ymin = gbox->ymax = dptr[i++];
571  gbox->flags = g->flags;
572  if ( FLAGS_GET_Z(g->flags) )
573  {
574  gbox->zmin = gbox->zmax = dptr[i++];
575  }
576  if ( FLAGS_GET_M(g->flags) )
577  {
578  gbox->mmin = gbox->mmax = dptr[i++];
579  }
580  gbox_float_round(gbox);
581  return LW_SUCCESS;
582  }
583  /* And we can do single-entry multi-lines with two vertices (!!!) */
584  else if ( type == MULTILINETYPE )
585  {
586  int ndims = FLAGS_NDIMS(g->flags);
587  int i = 0; /* Start at <multilinetype><ngeoms> */
588  double *dptr = (double*)(g->data);
589  int *iptr = (int*)(g->data);
590  int ngeoms = iptr[1]; /* Read the ngeoms */
591  int npoints;
592 
593  /* This only works with 1-line multilines */
594  if ( ngeoms != 1 )
595  return LW_FAILURE;
596 
597  /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
598  npoints = iptr[3];
599 
600  if ( npoints != 2 )
601  return LW_FAILURE;
602 
603  /* Advance to X */
604  /* Move forward two doubles (four ints) */
605  /* Past <multilinetype><ngeoms> */
606  /* Past <linetype><npoints> */
607  i += 2;
608  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
609  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
610 
611  /* Advance to Y */
612  i++;
613  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
614  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
615 
616  gbox->flags = g->flags;
617  if ( FLAGS_GET_Z(g->flags) )
618  {
619  /* Advance to Z */
620  i++;
621  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
622  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
623  }
624  if ( FLAGS_GET_M(g->flags) )
625  {
626  /* Advance to M */
627  i++;
628  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
629  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
630  }
631  gbox_float_round(gbox);
632  return LW_SUCCESS;
633  }
634 
635  return LW_FAILURE;
636 }
637 
643 {
644  /* Try to just read the serialized box. */
645  if ( gserialized_read_gbox_p(g, box) == LW_SUCCESS )
646  {
647  return LW_SUCCESS;
648  }
649  /* No box? Try to peek into simpler geometries and */
650  /* derive a box without creating an lwgeom */
651  else if ( gserialized_peek_gbox_p(g, box) == LW_SUCCESS )
652  {
653  return LW_SUCCESS;
654  }
655  /* Damn! Nothing for it but to create an lwgeom... */
656  /* See http://trac.osgeo.org/postgis/ticket/1023 */
657  else
658  {
659  LWGEOM *lwgeom = lwgeom_from_gserialized(g);
660  int ret = lwgeom_calculate_gbox(lwgeom, box);
661  gbox_float_round(box);
662  lwgeom_free(lwgeom);
663  return ret;
664  }
665 }
666 
667 
668 /***********************************************************************
669 * Calculate the GSERIALIZED size for an LWGEOM.
670 */
671 
672 /* Private functions */
673 
674 static size_t gserialized_from_any_size(const LWGEOM *geom); /* Local prototype */
675 
676 static size_t gserialized_from_lwpoint_size(const LWPOINT *point)
677 {
678  size_t size = 4; /* Type number. */
679 
680  assert(point);
681 
682  size += 4; /* Number of points (one or zero (empty)). */
683  size += point->point->npoints * FLAGS_NDIMS(point->flags) * sizeof(double);
684 
685  LWDEBUGF(3, "point size = %d", size);
686 
687  return size;
688 }
689 
690 static size_t gserialized_from_lwline_size(const LWLINE *line)
691 {
692  size_t size = 4; /* Type number. */
693 
694  assert(line);
695 
696  size += 4; /* Number of points (zero => empty). */
697  size += line->points->npoints * FLAGS_NDIMS(line->flags) * sizeof(double);
698 
699  LWDEBUGF(3, "linestring size = %d", size);
700 
701  return size;
702 }
703 
704 static size_t gserialized_from_lwtriangle_size(const LWTRIANGLE *triangle)
705 {
706  size_t size = 4; /* Type number. */
707 
708  assert(triangle);
709 
710  size += 4; /* Number of points (zero => empty). */
711  size += triangle->points->npoints * FLAGS_NDIMS(triangle->flags) * sizeof(double);
712 
713  LWDEBUGF(3, "triangle size = %d", size);
714 
715  return size;
716 }
717 
718 static size_t gserialized_from_lwpoly_size(const LWPOLY *poly)
719 {
720  size_t size = 4; /* Type number. */
721  int i = 0;
722 
723  assert(poly);
724 
725  size += 4; /* Number of rings (zero => empty). */
726  if ( poly->nrings % 2 )
727  size += 4; /* Padding to double alignment. */
728 
729  for ( i = 0; i < poly->nrings; i++ )
730  {
731  size += 4; /* Number of points in ring. */
732  size += poly->rings[i]->npoints * FLAGS_NDIMS(poly->flags) * sizeof(double);
733  }
734 
735  LWDEBUGF(3, "polygon size = %d", size);
736 
737  return size;
738 }
739 
741 {
742  size_t size = 4; /* Type number. */
743 
744  assert(curve);
745 
746  size += 4; /* Number of points (zero => empty). */
747  size += curve->points->npoints * FLAGS_NDIMS(curve->flags) * sizeof(double);
748 
749  LWDEBUGF(3, "circstring size = %d", size);
750 
751  return size;
752 }
753 
755 {
756  size_t size = 4; /* Type number. */
757  int i = 0;
758 
759  assert(col);
760 
761  size += 4; /* Number of sub-geometries (zero => empty). */
762 
763  for ( i = 0; i < col->ngeoms; i++ )
764  {
765  size_t subsize = gserialized_from_any_size(col->geoms[i]);
766  size += subsize;
767  LWDEBUGF(3, "lwcollection subgeom(%d) size = %d", i, subsize);
768  }
769 
770  LWDEBUGF(3, "lwcollection size = %d", size);
771 
772  return size;
773 }
774 
775 static size_t gserialized_from_any_size(const LWGEOM *geom)
776 {
777  LWDEBUGF(2, "Input type: %s", lwtype_name(geom->type));
778 
779  switch (geom->type)
780  {
781  case POINTTYPE:
782  return gserialized_from_lwpoint_size((LWPOINT *)geom);
783  case LINETYPE:
784  return gserialized_from_lwline_size((LWLINE *)geom);
785  case POLYGONTYPE:
786  return gserialized_from_lwpoly_size((LWPOLY *)geom);
787  case TRIANGLETYPE:
789  case CIRCSTRINGTYPE:
791  case CURVEPOLYTYPE:
792  case COMPOUNDTYPE:
793  case MULTIPOINTTYPE:
794  case MULTILINETYPE:
795  case MULTICURVETYPE:
796  case MULTIPOLYGONTYPE:
797  case MULTISURFACETYPE:
799  case TINTYPE:
800  case COLLECTIONTYPE:
802  default:
803  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
804  return 0;
805  }
806 }
807 
808 /* Public function */
809 
811 {
812  size_t size = 8; /* Header overhead. */
813  assert(geom);
814 
815  if ( geom->bbox )
816  size += gbox_serialized_size(geom->flags);
817 
818  size += gserialized_from_any_size(geom);
819  LWDEBUGF(3, "g_serialize size = %d", size);
820 
821  return size;
822 }
823 
824 /***********************************************************************
825 * Serialize an LWGEOM into GSERIALIZED.
826 */
827 
828 /* Private functions */
829 
830 static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf);
831 
832 static size_t gserialized_from_lwpoint(const LWPOINT *point, uint8_t *buf)
833 {
834  uint8_t *loc;
835  int ptsize = ptarray_point_size(point->point);
836  int type = POINTTYPE;
837 
838  assert(point);
839  assert(buf);
840 
841  if ( FLAGS_GET_ZM(point->flags) != FLAGS_GET_ZM(point->point->flags) )
842  lwerror("Dimensions mismatch in lwpoint");
843 
844  LWDEBUGF(2, "lwpoint_to_gserialized(%p, %p) called", point, buf);
845 
846  loc = buf;
847 
848  /* Write in the type. */
849  memcpy(loc, &type, sizeof(uint32_t));
850  loc += sizeof(uint32_t);
851  /* Write in the number of points (0 => empty). */
852  memcpy(loc, &(point->point->npoints), sizeof(uint32_t));
853  loc += sizeof(uint32_t);
854 
855  /* Copy in the ordinates. */
856  if ( point->point->npoints > 0 )
857  {
858  memcpy(loc, getPoint_internal(point->point, 0), ptsize);
859  loc += ptsize;
860  }
861 
862  return (size_t)(loc - buf);
863 }
864 
865 static size_t gserialized_from_lwline(const LWLINE *line, uint8_t *buf)
866 {
867  uint8_t *loc;
868  int ptsize;
869  size_t size;
870  int type = LINETYPE;
871 
872  assert(line);
873  assert(buf);
874 
875  LWDEBUGF(2, "lwline_to_gserialized(%p, %p) called", line, buf);
876 
877  if ( FLAGS_GET_Z(line->flags) != FLAGS_GET_Z(line->points->flags) )
878  lwerror("Dimensions mismatch in lwline");
879 
880  ptsize = ptarray_point_size(line->points);
881 
882  loc = buf;
883 
884  /* Write in the type. */
885  memcpy(loc, &type, sizeof(uint32_t));
886  loc += sizeof(uint32_t);
887 
888  /* Write in the npoints. */
889  memcpy(loc, &(line->points->npoints), sizeof(uint32_t));
890  loc += sizeof(uint32_t);
891 
892  LWDEBUGF(3, "lwline_to_gserialized added npoints (%d)", line->points->npoints);
893 
894  /* Copy in the ordinates. */
895  if ( line->points->npoints > 0 )
896  {
897  size = line->points->npoints * ptsize;
898  memcpy(loc, getPoint_internal(line->points, 0), size);
899  loc += size;
900  }
901  LWDEBUGF(3, "lwline_to_gserialized copied serialized_pointlist (%d bytes)", ptsize * line->points->npoints);
902 
903  return (size_t)(loc - buf);
904 }
905 
906 static size_t gserialized_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
907 {
908  int i;
909  uint8_t *loc;
910  int ptsize;
911  int type = POLYGONTYPE;
912 
913  assert(poly);
914  assert(buf);
915 
916  LWDEBUG(2, "lwpoly_to_gserialized called");
917 
918  ptsize = sizeof(double) * FLAGS_NDIMS(poly->flags);
919  loc = buf;
920 
921  /* Write in the type. */
922  memcpy(loc, &type, sizeof(uint32_t));
923  loc += sizeof(uint32_t);
924 
925  /* Write in the nrings. */
926  memcpy(loc, &(poly->nrings), sizeof(uint32_t));
927  loc += sizeof(uint32_t);
928 
929  /* Write in the npoints per ring. */
930  for ( i = 0; i < poly->nrings; i++ )
931  {
932  memcpy(loc, &(poly->rings[i]->npoints), sizeof(uint32_t));
933  loc += sizeof(uint32_t);
934  }
935 
936  /* Add in padding if necessary to remain double aligned. */
937  if ( poly->nrings % 2 )
938  {
939  memset(loc, 0, sizeof(uint32_t));
940  loc += sizeof(uint32_t);
941  }
942 
943  /* Copy in the ordinates. */
944  for ( i = 0; i < poly->nrings; i++ )
945  {
946  POINTARRAY *pa = poly->rings[i];
947  size_t pasize;
948 
949  if ( FLAGS_GET_ZM(poly->flags) != FLAGS_GET_ZM(pa->flags) )
950  lwerror("Dimensions mismatch in lwpoly");
951 
952  pasize = pa->npoints * ptsize;
953  if ( pasize )
954  memcpy(loc, getPoint_internal(pa, 0), pasize);
955  loc += pasize;
956  }
957  return (size_t)(loc - buf);
958 }
959 
960 static size_t gserialized_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
961 {
962  uint8_t *loc;
963  int ptsize;
964  size_t size;
965  int type = TRIANGLETYPE;
966 
967  assert(triangle);
968  assert(buf);
969 
970  LWDEBUGF(2, "lwtriangle_to_gserialized(%p, %p) called", triangle, buf);
971 
972  if ( FLAGS_GET_ZM(triangle->flags) != FLAGS_GET_ZM(triangle->points->flags) )
973  lwerror("Dimensions mismatch in lwtriangle");
974 
975  ptsize = ptarray_point_size(triangle->points);
976 
977  loc = buf;
978 
979  /* Write in the type. */
980  memcpy(loc, &type, sizeof(uint32_t));
981  loc += sizeof(uint32_t);
982 
983  /* Write in the npoints. */
984  memcpy(loc, &(triangle->points->npoints), sizeof(uint32_t));
985  loc += sizeof(uint32_t);
986 
987  LWDEBUGF(3, "lwtriangle_to_gserialized added npoints (%d)", triangle->points->npoints);
988 
989  /* Copy in the ordinates. */
990  if ( triangle->points->npoints > 0 )
991  {
992  size = triangle->points->npoints * ptsize;
993  memcpy(loc, getPoint_internal(triangle->points, 0), size);
994  loc += size;
995  }
996  LWDEBUGF(3, "lwtriangle_to_gserialized copied serialized_pointlist (%d bytes)", ptsize * triangle->points->npoints);
997 
998  return (size_t)(loc - buf);
999 }
1000 
1001 static size_t gserialized_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
1002 {
1003  uint8_t *loc;
1004  int ptsize;
1005  size_t size;
1006  int type = CIRCSTRINGTYPE;
1007 
1008  assert(curve);
1009  assert(buf);
1010 
1011  if (FLAGS_GET_ZM(curve->flags) != FLAGS_GET_ZM(curve->points->flags))
1012  lwerror("Dimensions mismatch in lwcircstring");
1013 
1014 
1015  ptsize = ptarray_point_size(curve->points);
1016  loc = buf;
1017 
1018  /* Write in the type. */
1019  memcpy(loc, &type, sizeof(uint32_t));
1020  loc += sizeof(uint32_t);
1021 
1022  /* Write in the npoints. */
1023  memcpy(loc, &curve->points->npoints, sizeof(uint32_t));
1024  loc += sizeof(uint32_t);
1025 
1026  /* Copy in the ordinates. */
1027  if ( curve->points->npoints > 0 )
1028  {
1029  size = curve->points->npoints * ptsize;
1030  memcpy(loc, getPoint_internal(curve->points, 0), size);
1031  loc += size;
1032  }
1033 
1034  return (size_t)(loc - buf);
1035 }
1036 
1037 static size_t gserialized_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
1038 {
1039  size_t subsize = 0;
1040  uint8_t *loc;
1041  int i;
1042  int type;
1043 
1044  assert(coll);
1045  assert(buf);
1046 
1047  type = coll->type;
1048  loc = buf;
1049 
1050  /* Write in the type. */
1051  memcpy(loc, &type, sizeof(uint32_t));
1052  loc += sizeof(uint32_t);
1053 
1054  /* Write in the number of subgeoms. */
1055  memcpy(loc, &coll->ngeoms, sizeof(uint32_t));
1056  loc += sizeof(uint32_t);
1057 
1058  /* Serialize subgeoms. */
1059  for ( i=0; i<coll->ngeoms; i++ )
1060  {
1061  if (FLAGS_GET_ZM(coll->flags) != FLAGS_GET_ZM(coll->geoms[i]->flags))
1062  lwerror("Dimensions mismatch in lwcollection");
1063  subsize = gserialized_from_lwgeom_any(coll->geoms[i], loc);
1064  loc += subsize;
1065  }
1066 
1067  return (size_t)(loc - buf);
1068 }
1069 
1070 static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
1071 {
1072  assert(geom);
1073  assert(buf);
1074 
1075  LWDEBUGF(2, "Input type (%d) %s, hasz: %d hasm: %d",
1076  geom->type, lwtype_name(geom->type),
1077  FLAGS_GET_Z(geom->flags), FLAGS_GET_M(geom->flags));
1078  LWDEBUGF(2, "LWGEOM(%p) uint8_t(%p)", geom, buf);
1079 
1080  switch (geom->type)
1081  {
1082  case POINTTYPE:
1083  return gserialized_from_lwpoint((LWPOINT *)geom, buf);
1084  case LINETYPE:
1085  return gserialized_from_lwline((LWLINE *)geom, buf);
1086  case POLYGONTYPE:
1087  return gserialized_from_lwpoly((LWPOLY *)geom, buf);
1088  case TRIANGLETYPE:
1089  return gserialized_from_lwtriangle((LWTRIANGLE *)geom, buf);
1090  case CIRCSTRINGTYPE:
1091  return gserialized_from_lwcircstring((LWCIRCSTRING *)geom, buf);
1092  case CURVEPOLYTYPE:
1093  case COMPOUNDTYPE:
1094  case MULTIPOINTTYPE:
1095  case MULTILINETYPE:
1096  case MULTICURVETYPE:
1097  case MULTIPOLYGONTYPE:
1098  case MULTISURFACETYPE:
1099  case POLYHEDRALSURFACETYPE:
1100  case TINTYPE:
1101  case COLLECTIONTYPE:
1102  return gserialized_from_lwcollection((LWCOLLECTION *)geom, buf);
1103  default:
1104  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
1105  return 0;
1106  }
1107  return 0;
1108 }
1109 
1110 static size_t gserialized_from_gbox(const GBOX *gbox, uint8_t *buf)
1111 {
1112  uint8_t *loc = buf;
1113  float f;
1114  size_t return_size;
1115 
1116  assert(buf);
1117 
1118  f = next_float_down(gbox->xmin);
1119  memcpy(loc, &f, sizeof(float));
1120  loc += sizeof(float);
1121 
1122  f = next_float_up(gbox->xmax);
1123  memcpy(loc, &f, sizeof(float));
1124  loc += sizeof(float);
1125 
1126  f = next_float_down(gbox->ymin);
1127  memcpy(loc, &f, sizeof(float));
1128  loc += sizeof(float);
1129 
1130  f = next_float_up(gbox->ymax);
1131  memcpy(loc, &f, sizeof(float));
1132  loc += sizeof(float);
1133 
1134  if ( FLAGS_GET_GEODETIC(gbox->flags) )
1135  {
1136  f = next_float_down(gbox->zmin);
1137  memcpy(loc, &f, sizeof(float));
1138  loc += sizeof(float);
1139 
1140  f = next_float_up(gbox->zmax);
1141  memcpy(loc, &f, sizeof(float));
1142  loc += sizeof(float);
1143 
1144  return_size = (size_t)(loc - buf);
1145  LWDEBUGF(4, "returning size %d", return_size);
1146  return return_size;
1147  }
1148 
1149  if ( FLAGS_GET_Z(gbox->flags) )
1150  {
1151  f = next_float_down(gbox->zmin);
1152  memcpy(loc, &f, sizeof(float));
1153  loc += sizeof(float);
1154 
1155  f = next_float_up(gbox->zmax);
1156  memcpy(loc, &f, sizeof(float));
1157  loc += sizeof(float);
1158 
1159  }
1160 
1161  if ( FLAGS_GET_M(gbox->flags) )
1162  {
1163  f = next_float_down(gbox->mmin);
1164  memcpy(loc, &f, sizeof(float));
1165  loc += sizeof(float);
1166 
1167  f = next_float_up(gbox->mmax);
1168  memcpy(loc, &f, sizeof(float));
1169  loc += sizeof(float);
1170  }
1171  return_size = (size_t)(loc - buf);
1172  LWDEBUGF(4, "returning size %d", return_size);
1173  return return_size;
1174 }
1175 
1176 /* Public function */
1177 
1179 {
1180  size_t expected_size = 0;
1181  size_t return_size = 0;
1182  uint8_t *serialized = NULL;
1183  uint8_t *ptr = NULL;
1184  GSERIALIZED *g = NULL;
1185  assert(geom);
1186 
1187  /*
1188  ** See if we need a bounding box, add one if we don't have one.
1189  */
1190  if ( (! geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)) )
1191  {
1192  lwgeom_add_bbox(geom);
1193  }
1194 
1195  /*
1196  ** Harmonize the flags to the state of the lwgeom
1197  */
1198  if ( geom->bbox )
1199  FLAGS_SET_BBOX(geom->flags, 1);
1200  else
1201  FLAGS_SET_BBOX(geom->flags, 0);
1202 
1203  /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1204  expected_size = gserialized_from_lwgeom_size(geom);
1205  serialized = lwalloc(expected_size);
1206  ptr = serialized;
1207 
1208  /* Move past size, srid and flags. */
1209  ptr += 8;
1210 
1211  /* Write in the serialized form of the gbox, if necessary. */
1212  if ( geom->bbox )
1213  ptr += gserialized_from_gbox(geom->bbox, ptr);
1214 
1215  /* Write in the serialized form of the geometry. */
1216  ptr += gserialized_from_lwgeom_any(geom, ptr);
1217 
1218  /* Calculate size as returned by data processing functions. */
1219  return_size = ptr - serialized;
1220 
1221  if ( expected_size != return_size ) /* Uh oh! */
1222  {
1223  lwerror("Return size (%d) not equal to expected size (%d)!", return_size, expected_size);
1224  return NULL;
1225  }
1226 
1227  if ( size ) /* Return the output size to the caller if necessary. */
1228  *size = return_size;
1229 
1230  g = (GSERIALIZED*)serialized;
1231 
1232  /*
1233  ** We are aping PgSQL code here, PostGIS code should use
1234  ** VARSIZE to set this for real.
1235  */
1236  g->size = return_size << 2;
1237 
1238  /* Set the SRID! */
1239  gserialized_set_srid(g, geom->srid);
1240 
1241  g->flags = geom->flags;
1242 
1243  return g;
1244 }
1245 
1246 /***********************************************************************
1247 * De-serialize GSERIALIZED into an LWGEOM.
1248 */
1249 
1250 static LWGEOM* lwgeom_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size);
1251 
1252 static LWPOINT* lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1253 {
1254  uint8_t *start_ptr = data_ptr;
1255  LWPOINT *point;
1256  uint32_t npoints = 0;
1257 
1258  assert(data_ptr);
1259 
1260  point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1261  point->srid = SRID_UNKNOWN; /* Default */
1262  point->bbox = NULL;
1263  point->type = POINTTYPE;
1264  point->flags = g_flags;
1265 
1266  data_ptr += 4; /* Skip past the type. */
1267  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1268  data_ptr += 4; /* Skip past the npoints. */
1269 
1270  if ( npoints > 0 )
1271  point->point = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 1, data_ptr);
1272  else
1273  point->point = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty point */
1274 
1275  data_ptr += npoints * FLAGS_NDIMS(g_flags) * sizeof(double);
1276 
1277  if ( g_size )
1278  *g_size = data_ptr - start_ptr;
1279 
1280  return point;
1281 }
1282 
1283 static LWLINE* lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1284 {
1285  uint8_t *start_ptr = data_ptr;
1286  LWLINE *line;
1287  uint32_t npoints = 0;
1288 
1289  assert(data_ptr);
1290 
1291  line = (LWLINE*)lwalloc(sizeof(LWLINE));
1292  line->srid = SRID_UNKNOWN; /* Default */
1293  line->bbox = NULL;
1294  line->type = LINETYPE;
1295  line->flags = g_flags;
1296 
1297  data_ptr += 4; /* Skip past the type. */
1298  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1299  data_ptr += 4; /* Skip past the npoints. */
1300 
1301  if ( npoints > 0 )
1302  line->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1303 
1304  else
1305  line->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty linestring */
1306 
1307  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1308 
1309  if ( g_size )
1310  *g_size = data_ptr - start_ptr;
1311 
1312  return line;
1313 }
1314 
1315 static LWPOLY* lwpoly_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1316 {
1317  uint8_t *start_ptr = data_ptr;
1318  LWPOLY *poly;
1319  uint8_t *ordinate_ptr;
1320  uint32_t nrings = 0;
1321  int i = 0;
1322 
1323  assert(data_ptr);
1324 
1325  poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1326  poly->srid = SRID_UNKNOWN; /* Default */
1327  poly->bbox = NULL;
1328  poly->type = POLYGONTYPE;
1329  poly->flags = g_flags;
1330 
1331  data_ptr += 4; /* Skip past the polygontype. */
1332  nrings = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1333  poly->nrings = nrings;
1334  LWDEBUGF(4, "nrings = %d", nrings);
1335  data_ptr += 4; /* Skip past the nrings. */
1336 
1337  ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1338  if ( nrings > 0)
1339  {
1340  poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1341  ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1342  if ( nrings % 2 ) /* If there is padding, move past that too. */
1343  ordinate_ptr += 4;
1344  }
1345  else /* Empty polygon */
1346  {
1347  poly->rings = NULL;
1348  }
1349 
1350  for ( i = 0; i < nrings; i++ )
1351  {
1352  uint32_t npoints = 0;
1353 
1354  /* Read in the number of points. */
1355  npoints = gserialized_get_uint32_t(data_ptr);
1356  data_ptr += 4;
1357 
1358  /* Make a point array for the ring, and move the ordinate pointer past the ring ordinates. */
1359  poly->rings[i] = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, ordinate_ptr);
1360 
1361  ordinate_ptr += sizeof(double) * FLAGS_NDIMS(g_flags) * npoints;
1362  }
1363 
1364  if ( g_size )
1365  *g_size = ordinate_ptr - start_ptr;
1366 
1367  return poly;
1368 }
1369 
1371 {
1372  uint8_t *start_ptr = data_ptr;
1373  LWTRIANGLE *triangle;
1374  uint32_t npoints = 0;
1375 
1376  assert(data_ptr);
1377 
1378  triangle = (LWTRIANGLE*)lwalloc(sizeof(LWTRIANGLE));
1379  triangle->srid = SRID_UNKNOWN; /* Default */
1380  triangle->bbox = NULL;
1381  triangle->type = TRIANGLETYPE;
1382  triangle->flags = g_flags;
1383 
1384  data_ptr += 4; /* Skip past the type. */
1385  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1386  data_ptr += 4; /* Skip past the npoints. */
1387 
1388  if ( npoints > 0 )
1389  triangle->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1390  else
1391  triangle->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty triangle */
1392 
1393  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1394 
1395  if ( g_size )
1396  *g_size = data_ptr - start_ptr;
1397 
1398  return triangle;
1399 }
1400 
1402 {
1403  uint8_t *start_ptr = data_ptr;
1404  LWCIRCSTRING *circstring;
1405  uint32_t npoints = 0;
1406 
1407  assert(data_ptr);
1408 
1409  circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING));
1410  circstring->srid = SRID_UNKNOWN; /* Default */
1411  circstring->bbox = NULL;
1412  circstring->type = CIRCSTRINGTYPE;
1413  circstring->flags = g_flags;
1414 
1415  data_ptr += 4; /* Skip past the circstringtype. */
1416  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1417  data_ptr += 4; /* Skip past the npoints. */
1418 
1419  if ( npoints > 0 )
1420  circstring->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1421  else
1422  circstring->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty circularstring */
1423 
1424  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1425 
1426  if ( g_size )
1427  *g_size = data_ptr - start_ptr;
1428 
1429  return circstring;
1430 }
1431 
1433 {
1434  uint32_t type;
1435  uint8_t *start_ptr = data_ptr;
1436  LWCOLLECTION *collection;
1437  uint32_t ngeoms = 0;
1438  int i = 0;
1439 
1440  assert(data_ptr);
1441 
1442  type = gserialized_get_uint32_t(data_ptr);
1443  data_ptr += 4; /* Skip past the type. */
1444 
1445  collection = (LWCOLLECTION*)lwalloc(sizeof(LWCOLLECTION));
1446  collection->srid = SRID_UNKNOWN; /* Default */
1447  collection->bbox = NULL;
1448  collection->type = type;
1449  collection->flags = g_flags;
1450 
1451  ngeoms = gserialized_get_uint32_t(data_ptr);
1452  collection->ngeoms = ngeoms; /* Zero => empty geometry */
1453  data_ptr += 4; /* Skip past the ngeoms. */
1454 
1455  if ( ngeoms > 0 )
1456  collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1457  else
1458  collection->geoms = NULL;
1459 
1460  /* Sub-geometries are never de-serialized with boxes (#1254) */
1461  FLAGS_SET_BBOX(g_flags, 0);
1462 
1463  for ( i = 0; i < ngeoms; i++ )
1464  {
1465  uint32_t subtype = gserialized_get_uint32_t(data_ptr);
1466  size_t subsize = 0;
1467 
1468  if ( ! lwcollection_allows_subtype(type, subtype) )
1469  {
1470  lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1471  lwfree(collection);
1472  return NULL;
1473  }
1474  collection->geoms[i] = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &subsize);
1475  data_ptr += subsize;
1476  }
1477 
1478  if ( g_size )
1479  *g_size = data_ptr - start_ptr;
1480 
1481  return collection;
1482 }
1483 
1485 {
1486  uint32_t type;
1487 
1488  assert(data_ptr);
1489 
1490  type = gserialized_get_uint32_t(data_ptr);
1491 
1492  LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1493  FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), FLAGS_GET_GEODETIC(g_flags), FLAGS_GET_BBOX(g_flags));
1494 
1495  switch (type)
1496  {
1497  case POINTTYPE:
1498  return (LWGEOM *)lwpoint_from_gserialized_buffer(data_ptr, g_flags, g_size);
1499  case LINETYPE:
1500  return (LWGEOM *)lwline_from_gserialized_buffer(data_ptr, g_flags, g_size);
1501  case CIRCSTRINGTYPE:
1502  return (LWGEOM *)lwcircstring_from_gserialized_buffer(data_ptr, g_flags, g_size);
1503  case POLYGONTYPE:
1504  return (LWGEOM *)lwpoly_from_gserialized_buffer(data_ptr, g_flags, g_size);
1505  case TRIANGLETYPE:
1506  return (LWGEOM *)lwtriangle_from_gserialized_buffer(data_ptr, g_flags, g_size);
1507  case MULTIPOINTTYPE:
1508  case MULTILINETYPE:
1509  case MULTIPOLYGONTYPE:
1510  case COMPOUNDTYPE:
1511  case CURVEPOLYTYPE:
1512  case MULTICURVETYPE:
1513  case MULTISURFACETYPE:
1514  case POLYHEDRALSURFACETYPE:
1515  case TINTYPE:
1516  case COLLECTIONTYPE:
1517  return (LWGEOM *)lwcollection_from_gserialized_buffer(data_ptr, g_flags, g_size);
1518  default:
1519  lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1520  return NULL;
1521  }
1522 }
1523 
1525 {
1526  uint8_t g_flags = 0;
1527  int32_t g_srid = 0;
1528  uint32_t g_type = 0;
1529  uint8_t *data_ptr = NULL;
1530  LWGEOM *lwgeom = NULL;
1531  GBOX bbox;
1532  size_t g_size = 0;
1533 
1534  assert(g);
1535 
1536  g_srid = gserialized_get_srid(g);
1537  g_flags = g->flags;
1538  g_type = gserialized_get_type(g);
1539  LWDEBUGF(4, "Got type %d (%s), srid=%d", g_type, lwtype_name(g_type), g_srid);
1540 
1541  data_ptr = (uint8_t*)g->data;
1542  if ( FLAGS_GET_BBOX(g_flags) )
1543  data_ptr += gbox_serialized_size(g_flags);
1544 
1545  lwgeom = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &g_size);
1546 
1547  if ( ! lwgeom )
1548  lwerror("lwgeom_from_gserialized: unable create geometry"); /* Ooops! */
1549 
1550  lwgeom->type = g_type;
1551  lwgeom->flags = g_flags;
1552 
1553  if ( gserialized_read_gbox_p(g, &bbox) == LW_SUCCESS )
1554  {
1555  lwgeom->bbox = gbox_copy(&bbox);
1556  }
1557  else if ( lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS) )
1558  {
1559  lwgeom->bbox = gbox_copy(&bbox);
1560  }
1561  else
1562  {
1563  lwgeom->bbox = NULL;
1564  }
1565 
1566  lwgeom_set_srid(lwgeom, g_srid);
1567 
1568  return lwgeom;
1569 }
1570 
int gserialized_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: g_serialized.c:642
int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
Return -1 if g1 is "less than" g2, 1 if g1 is "greater than" g2 and 0 if g1 and g2 are the "same"...
Definition: g_serialized.c:294
#define LINETYPE
Definition: liblwgeom.h:86
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:438
static LWLINE * lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:86
uint8_t type
Definition: liblwgeom.h:418
int clamp_srid(int srid)
Return a valid SRID from an arbitrary integer Raises a notice if what comes out is different from wha...
Definition: lwutil.c:380
int gserialized_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Pull a GBOX from the header of a GSERIALIZED, if one is available.
Definition: g_serialized.c:416
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:62
static LWTRIANGLE * lwtriangle_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
static LWCIRCSTRING * lwcircstring_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
GBOX * bbox
Definition: liblwgeom.h:398
uint8_t flags
Definition: liblwgeom.h:441
POINTARRAY * points
Definition: liblwgeom.h:433
uint8_t data[1]
Definition: liblwgeom.h:384
#define MULTICURVETYPE
Definition: liblwgeom.h:95
static LWCOLLECTION * lwcollection_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
static int gserialized_cmp_srid(const GSERIALIZED *s1, const GSERIALIZED *s2)
Definition: g_serialized.c:133
GBOX * bbox
Definition: liblwgeom.h:420
void normalize(POINT3D *p)
Normalize to a unit vector.
Definition: lwgeodetic.c:611
uint8_t type
Definition: liblwgeom.h:407
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:669
static size_t gserialized_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
void lwfree(void *mem)
Definition: lwutil.c:244
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
double y
Definition: liblwgeom.h:340
int npoints
Definition: liblwgeom.h:371
uint8_t type
Definition: liblwgeom.h:503
int gserialized_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
Definition: g_serialized.c:50
static LWPOLY * lwpoly_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
static size_t gserialized_from_lwcircstring_size(const LWCIRCSTRING *curve)
Definition: g_serialized.c:740
int32_t srid
Definition: liblwgeom.h:443
static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Definition: g_serialized.c:463
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:143
static size_t gserialized_from_lwpoint_size(const LWPOINT *point)
Definition: g_serialized.c:676
#define POLYGONTYPE
Definition: liblwgeom.h:87
uint8_t flags
Definition: liblwgeom.h:397
double xmax
Definition: liblwgeom.h:293
#define CURVEPOLYTYPE
Definition: liblwgeom.h:94
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
#define COMPOUNDTYPE
Definition: liblwgeom.h:93
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
#define LW_SUCCESS
Definition: liblwgeom.h:80
void cart2geog(const POINT3D *p, GEOGRAPHIC_POINT *g)
Convert cartesion coordinates on unit sphere to spherical coordinates.
Definition: lwgeodetic.c:410
static size_t gserialized_from_gbox(const GBOX *gbox, uint8_t *buf)
GBOX * bbox
Definition: liblwgeom.h:505
int gserialized_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: g_serialized.c:60
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:153
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
void gserialized_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: g_serialized.c:117
#define TRIANGLETYPE
Definition: liblwgeom.h:98
double x
Definition: liblwgeom.h:340
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:97
GBOX * bbox
Definition: liblwgeom.h:431
float next_float_down(double d)
Definition: lwgeom_api.c:51
GBOX * bbox
Definition: liblwgeom.h:453
GSERIALIZED * gserialized_copy(const GSERIALIZED *g)
Return a copy of the input serialized geometry.
Definition: g_serialized.c:142
int32_t srid
Definition: liblwgeom.h:421
#define FP_MIN(A, B)
int gserialized_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: g_serialized.c:40
Point in spherical coordinates on the world.
Definition: lwgeodetic.h:52
POINTARRAY * point
Definition: liblwgeom.h:411
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:45
int32_t srid
Definition: liblwgeom.h:399
static size_t gserialized_from_lwline_size(const LWLINE *line)
Definition: g_serialized.c:690
uint8_t type
Definition: liblwgeom.h:429
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:179
#define LW_FAILURE
Definition: liblwgeom.h:79
static size_t gserialized_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
Definition: g_serialized.c:960
uint64_t gbox_get_sortable_hash(const GBOX *g)
Return a sortable key based on the center point of the GBOX.
Definition: g_serialized.c:259
float next_float_up(double d)
Definition: lwgeom_api.c:72
double z
Definition: liblwgeom.h:340
unsigned int uint32_t
Definition: uthash.h:78
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:701
uint8_t flags
Definition: liblwgeom.h:504
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition: g_box.c:717
double zmax
Definition: liblwgeom.h:297
double ymin
Definition: liblwgeom.h:294
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
uint32_t u
Definition: g_serialized.c:255
static size_t gserialized_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
Definition: g_serialized.c:906
static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty)
Definition: g_serialized.c:152
static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
Definition: g_serialized.c:228
#define WKT_ISO
Definition: liblwgeom.h:2083
static size_t gserialized_from_lwpoint(const LWPOINT *point, uint8_t *buf)
Definition: g_serialized.c:832
double xmin
Definition: liblwgeom.h:292
#define FLAGS_GET_BBOX(flags)
Definition: liblwgeom.h:142
#define LW_FALSE
Definition: liblwgeom.h:77
uint8_t type
Definition: liblwgeom.h:451
uint8_t flags
Definition: liblwgeom.h:369
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
LWGEOM ** geoms
Definition: liblwgeom.h:509
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
#define TINTYPE
Definition: liblwgeom.h:99
uint8_t type
Definition: liblwgeom.h:440
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
Definition: ptarray.c:1753
int ptarray_point_size(const POINTARRAY *pa)
Definition: ptarray.c:54
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:295
static size_t gserialized_from_any_size(const LWGEOM *geom)
Definition: g_serialized.c:775
POINTARRAY ** rings
Definition: liblwgeom.h:457
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1048
int nrings
Definition: liblwgeom.h:455
int32_t srid
Definition: liblwgeom.h:506
double ymax
Definition: liblwgeom.h:295
char * s
Definition: cu_in_wkt.c:23
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:140
int32_t srid
Definition: liblwgeom.h:410
uint8_t flags
Definition: liblwgeom.h:291
static LWGEOM * lwgeom_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
GBOX * bbox
Definition: liblwgeom.h:442
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
uint8_t flags
Definition: liblwgeom.h:408
int gserialized_get_zm(const GSERIALIZED *gser)
Return a number indicating presence of Z and M coordinates.
Definition: g_serialized.c:55
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:148
GBOX * bbox
Definition: liblwgeom.h:409
#define SIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
static size_t gserialized_from_lwcollection_size(const LWCOLLECTION *col)
Definition: g_serialized.c:754
size_t gserialized_from_lwgeom_size(const LWGEOM *geom)
Calculate required memory segment to contain a serialized form of the LWGEOM.
Definition: g_serialized.c:810
#define MULTISURFACETYPE
Definition: liblwgeom.h:96
static size_t gserialized_from_lwpoly_size(const LWPOLY *poly)
Definition: g_serialized.c:718
int32_t srid
Definition: liblwgeom.h:454
uint32_t size
Definition: liblwgeom.h:381
uint8_t srid[3]
Definition: liblwgeom.h:382
double mmin
Definition: liblwgeom.h:298
double zmin
Definition: liblwgeom.h:296
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
char * gserialized_to_string(const GSERIALIZED *g)
Return a WKT representation of the gserialized geometry.
Definition: g_serialized.c:193
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:648
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:141
uint8_t type
Definition: liblwgeom.h:396
type
Definition: ovdump.py:41
static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
double mmax
Definition: liblwgeom.h:299
tuple g_size
Definition: genraster.py:41
POINTARRAY * points
Definition: liblwgeom.h:444
int gserialized_is_geodetic(const GSERIALIZED *gser)
Check if a GSERIALIZED is a geography.
Definition: g_serialized.c:65
void lwgeom_set_srid(LWGEOM *geom, int srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
uint32_t gserialized_header_size(const GSERIALIZED *gser)
Returns the size in bytes of the header, from the start of the object up to the type number...
Definition: g_serialized.c:76
int lwcollection_allows_subtype(int collectiontype, int subtype)
Check if subtype is allowed in collectiontype.
Definition: lwcollection.c:543
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:92
uint8_t flags
Definition: liblwgeom.h:452
void * lwalloc(size_t size)
Definition: lwutil.c:229
static size_t gserialized_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1346
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
#define MULTILINETYPE
Definition: liblwgeom.h:89
static uint32_t gserialized_get_uint32_t(const uint8_t *loc)
Definition: g_serialized.c:35
uint8_t flags
Definition: liblwgeom.h:419
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:152
static size_t gserialized_from_lwline(const LWLINE *line, uint8_t *buf)
Definition: g_serialized.c:865
unsigned char uint8_t
Definition: uthash.h:79
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1152
static LWPOINT * lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
int32_t gserialized_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: g_serialized.c:100
if(!(yy_init))
int32_t srid
Definition: liblwgeom.h:432
static size_t gserialized_from_lwtriangle_size(const LWTRIANGLE *triangle)
Definition: g_serialized.c:704
size_t gbox_serialized_size(uint8_t flags)
Return the number of bytes necessary to hold a GBOX of this dimension in serialized form...
Definition: g_box.c:451
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
uint32_t gserialized_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: g_serialized.c:70
uint8_t flags
Definition: liblwgeom.h:383
#define FP_MAX(A, B)
uint8_t flags
Definition: liblwgeom.h:430
POINTARRAY * points
Definition: liblwgeom.h:422