PostGIS  2.5.7dev-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 denominator. 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  0x5555555555555555ULL,
237  0x3333333333333333ULL,
238  0x0F0F0F0F0F0F0F0FULL,
239  0x00FF00FF00FF00FFULL,
240  0x0000FFFF0000FFFFULL
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 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  !FLAGS_GET_BBOX(g1->flags) &&
310  !FLAGS_GET_BBOX(g2->flags) &&
313  )
314  {
315  double *dptr = (double*)(g1->data + sizeof(double));
316  x.f = 2.0 * dptr[0];
317  y.f = 2.0 * dptr[1];
318  hash1 = uint32_interleave_2(x.u, y.u);
319 
320  dptr = (double*)(g2->data + sizeof(double));
321  x.f = 2.0 * dptr[0];
322  y.f = 2.0 * dptr[1];
323  hash2 = uint32_interleave_2(x.u, y.u);
324 
325  /* If the SRIDs are the same, we can use hash inequality */
326  /* to jump us out of this function early. Otherwise we still */
327  /* have to do the full calculation */
328  if ( gserialized_cmp_srid(g1, g2) == 0 )
329  {
330  if ( hash1 > hash2 )
331  return 1;
332  if ( hash1 < hash2 )
333  return -1;
334  }
335 
336  /* if hashes happen to be the same, go to full compare. */
337  }
338 
339  size_t hsz1 = gserialized_header_size(g1);
340  size_t hsz2 = gserialized_header_size(g2);
341 
342  uint8_t *b1 = (uint8_t*)g1 + hsz1;
343  uint8_t *b2 = (uint8_t*)g2 + hsz2;
344  size_t bsz1 = sz1 - hsz1;
345  size_t bsz2 = sz2 - hsz2;
346  size_t bsz = bsz1 < bsz2 ? bsz1 : bsz2;
347 
348  int cmp_srid = gserialized_cmp_srid(g1, g2);
349 
350  g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
351  g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
352 
353  /* Empty < Non-empty */
354  if (g1_is_empty && !g2_is_empty)
355  return -1;
356 
357  /* Non-empty > Empty */
358  if (!g1_is_empty && g2_is_empty)
359  return 1;
360 
361  /* Return equality for perfect equality only */
362  cmp = memcmp(b1, b2, bsz);
363  if ( bsz1 == bsz2 && cmp_srid == 0 && cmp == 0 )
364  return 0;
365 
366  if (!g1_is_empty && !g2_is_empty)
367  {
368  /* Using the centroids, calculate somewhat sortable */
369  /* hash key. The key doesn't provide good locality over */
370  /* the +/- boundary, but otherwise is pretty OK */
371  hash1 = gbox_get_sortable_hash(&box1);
372  hash2 = gbox_get_sortable_hash(&box2);
373 
374  if ( hash1 > hash2 )
375  return 1;
376  else if ( hash1 < hash2 )
377  return -1;
378 
379  /* What, the hashes are equal? OK... sort on the */
380  /* box minima */
381  if (box1.xmin < box2.xmin)
382  return -1;
383  else if (box1.xmin > box2.xmin)
384  return 1;
385 
386  if (box1.ymin < box2.ymin)
387  return -1;
388  else if (box1.ymin > box2.ymin)
389  return 1;
390 
391  /* Still equal? OK... sort on the box maxima */
392  if (box1.xmax < box2.xmax)
393  return -1;
394  else if (box1.xmax > box2.xmax)
395  return 1;
396 
397  if (box1.ymax < box2.ymax)
398  return -1;
399  else if (box1.ymax > box2.ymax)
400  return 1;
401  }
402 
403  /* Prefix comes before longer one. */
404  if (bsz1 != bsz2 && cmp == 0)
405  {
406  if (bsz1 < bsz2)
407  return -1;
408  else if (bsz1 > bsz2)
409  return 1;
410  }
411  return cmp > 0 ? 1 : -1;
412 }
413 
415 {
416 
417  /* Null input! */
418  if ( ! ( g && gbox ) ) return LW_FAILURE;
419 
420  /* Initialize the flags on the box */
421  gbox->flags = g->flags;
422 
423  /* Has pre-calculated box */
424  if ( FLAGS_GET_BBOX(g->flags) )
425  {
426  int i = 0;
427  float *fbox = (float*)(g->data);
428  gbox->xmin = fbox[i++];
429  gbox->xmax = fbox[i++];
430  gbox->ymin = fbox[i++];
431  gbox->ymax = fbox[i++];
432 
433  /* Geodetic? Read next dimension (geocentric Z) and return */
434  if ( FLAGS_GET_GEODETIC(g->flags) )
435  {
436  gbox->zmin = fbox[i++];
437  gbox->zmax = fbox[i++];
438  return LW_SUCCESS;
439  }
440  /* Cartesian? Read extra dimensions (if there) and return */
441  if ( FLAGS_GET_Z(g->flags) )
442  {
443  gbox->zmin = fbox[i++];
444  gbox->zmax = fbox[i++];
445  }
446  if ( FLAGS_GET_M(g->flags) )
447  {
448  gbox->mmin = fbox[i++];
449  gbox->mmax = fbox[i++];
450  }
451  return LW_SUCCESS;
452  }
453 
454  return LW_FAILURE;
455 }
456 
457 /*
458 * Populate a bounding box *without* allocating an LWGEOM. Useful
459 * for some performance purposes.
460 */
461 static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
462 {
464 
465  /* Peeking doesn't help if you already have a box or are geodetic */
466  if ( FLAGS_GET_GEODETIC(g->flags) || FLAGS_GET_BBOX(g->flags) )
467  {
468  return LW_FAILURE;
469  }
470 
471  /* Boxes of points are easy peasy */
472  if ( type == POINTTYPE )
473  {
474  int i = 1; /* Start past <pointtype><padding> */
475  double *dptr = (double*)(g->data);
476 
477  /* Read the empty flag */
478  int *iptr = (int*)(g->data);
479  int isempty = (iptr[1] == 0);
480 
481  /* EMPTY point has no box */
482  if ( isempty ) return LW_FAILURE;
483 
484  gbox->xmin = gbox->xmax = dptr[i++];
485  gbox->ymin = gbox->ymax = dptr[i++];
486  gbox->flags = g->flags;
487  if ( FLAGS_GET_Z(g->flags) )
488  {
489  gbox->zmin = gbox->zmax = dptr[i++];
490  }
491  if ( FLAGS_GET_M(g->flags) )
492  {
493  gbox->mmin = gbox->mmax = dptr[i++];
494  }
495  gbox_float_round(gbox);
496  return LW_SUCCESS;
497  }
498  /* We can calculate the box of a two-point cartesian line trivially */
499  else if ( type == LINETYPE )
500  {
501  int ndims = FLAGS_NDIMS(g->flags);
502  int i = 0; /* Start at <linetype><npoints> */
503  double *dptr = (double*)(g->data);
504  int *iptr = (int*)(g->data);
505  int npoints = iptr[1]; /* Read the npoints */
506 
507  /* This only works with 2-point lines */
508  if ( npoints != 2 )
509  return LW_FAILURE;
510 
511  /* Advance to X */
512  /* Past <linetype><npoints> */
513  i++;
514  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
515  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
516 
517  /* Advance to Y */
518  i++;
519  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
520  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
521 
522  gbox->flags = g->flags;
523  if ( FLAGS_GET_Z(g->flags) )
524  {
525  /* Advance to Z */
526  i++;
527  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
528  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
529  }
530  if ( FLAGS_GET_M(g->flags) )
531  {
532  /* Advance to M */
533  i++;
534  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
535  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
536  }
537  gbox_float_round(gbox);
538  return LW_SUCCESS;
539  }
540  /* We can also do single-entry multi-points */
541  else if ( type == MULTIPOINTTYPE )
542  {
543  int i = 0; /* Start at <multipointtype><ngeoms> */
544  double *dptr = (double*)(g->data);
545  int *iptr = (int*)(g->data);
546  int ngeoms = iptr[1]; /* Read the ngeoms */
547  int npoints;
548 
549  /* This only works with single-entry multipoints */
550  if ( ngeoms != 1 )
551  return LW_FAILURE;
552 
553  /* Npoints is at <multipointtype><ngeoms><pointtype><npoints> */
554  npoints = iptr[3];
555 
556  /* The check below is necessary because we can have a MULTIPOINT
557  * that contains a single, empty POINT (ngeoms = 1, npoints = 0) */
558  if ( npoints != 1 )
559  return LW_FAILURE;
560 
561  /* Move forward two doubles (four ints) */
562  /* Past <multipointtype><ngeoms> */
563  /* Past <pointtype><npoints> */
564  i += 2;
565 
566  /* Read the doubles from the one point */
567  gbox->xmin = gbox->xmax = dptr[i++];
568  gbox->ymin = gbox->ymax = dptr[i++];
569  gbox->flags = g->flags;
570  if ( FLAGS_GET_Z(g->flags) )
571  {
572  gbox->zmin = gbox->zmax = dptr[i++];
573  }
574  if ( FLAGS_GET_M(g->flags) )
575  {
576  gbox->mmin = gbox->mmax = dptr[i++];
577  }
578  gbox_float_round(gbox);
579  return LW_SUCCESS;
580  }
581  /* And we can do single-entry multi-lines with two vertices (!!!) */
582  else if ( type == MULTILINETYPE )
583  {
584  int ndims = FLAGS_NDIMS(g->flags);
585  int i = 0; /* Start at <multilinetype><ngeoms> */
586  double *dptr = (double*)(g->data);
587  int *iptr = (int*)(g->data);
588  int ngeoms = iptr[1]; /* Read the ngeoms */
589  int npoints;
590 
591  /* This only works with 1-line multilines */
592  if ( ngeoms != 1 )
593  return LW_FAILURE;
594 
595  /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
596  npoints = iptr[3];
597 
598  if ( npoints != 2 )
599  return LW_FAILURE;
600 
601  /* Advance to X */
602  /* Move forward two doubles (four ints) */
603  /* Past <multilinetype><ngeoms> */
604  /* Past <linetype><npoints> */
605  i += 2;
606  gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
607  gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
608 
609  /* Advance to Y */
610  i++;
611  gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
612  gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
613 
614  gbox->flags = g->flags;
615  if ( FLAGS_GET_Z(g->flags) )
616  {
617  /* Advance to Z */
618  i++;
619  gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
620  gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
621  }
622  if ( FLAGS_GET_M(g->flags) )
623  {
624  /* Advance to M */
625  i++;
626  gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
627  gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
628  }
629  gbox_float_round(gbox);
630  return LW_SUCCESS;
631  }
632 
633  return LW_FAILURE;
634 }
635 
641 {
642  /* Try to just read the serialized box. */
643  if ( gserialized_read_gbox_p(g, box) == LW_SUCCESS )
644  {
645  return LW_SUCCESS;
646  }
647  /* No box? Try to peek into simpler geometries and */
648  /* derive a box without creating an lwgeom */
649  else if ( gserialized_peek_gbox_p(g, box) == LW_SUCCESS )
650  {
651  return LW_SUCCESS;
652  }
653  /* Damn! Nothing for it but to create an lwgeom... */
654  /* See http://trac.osgeo.org/postgis/ticket/1023 */
655  else
656  {
657  LWGEOM *lwgeom = lwgeom_from_gserialized(g);
658  int ret = lwgeom_calculate_gbox(lwgeom, box);
659  gbox_float_round(box);
660  lwgeom_free(lwgeom);
661  return ret;
662  }
663 }
664 
665 
666 /***********************************************************************
667 * Calculate the GSERIALIZED size for an LWGEOM.
668 */
669 
670 /* Private functions */
671 
672 static size_t gserialized_from_any_size(const LWGEOM *geom); /* Local prototype */
673 
674 static size_t gserialized_from_lwpoint_size(const LWPOINT *point)
675 {
676  size_t size = 4; /* Type number. */
677 
678  assert(point);
679 
680  size += 4; /* Number of points (one or zero (empty)). */
681  size += point->point->npoints * FLAGS_NDIMS(point->flags) * sizeof(double);
682 
683  LWDEBUGF(3, "point size = %d", size);
684 
685  return size;
686 }
687 
688 static size_t gserialized_from_lwline_size(const LWLINE *line)
689 {
690  size_t size = 4; /* Type number. */
691 
692  assert(line);
693 
694  size += 4; /* Number of points (zero => empty). */
695  size += line->points->npoints * FLAGS_NDIMS(line->flags) * sizeof(double);
696 
697  LWDEBUGF(3, "linestring size = %d", size);
698 
699  return size;
700 }
701 
702 static size_t gserialized_from_lwtriangle_size(const LWTRIANGLE *triangle)
703 {
704  size_t size = 4; /* Type number. */
705 
706  assert(triangle);
707 
708  size += 4; /* Number of points (zero => empty). */
709  size += triangle->points->npoints * FLAGS_NDIMS(triangle->flags) * sizeof(double);
710 
711  LWDEBUGF(3, "triangle size = %d", size);
712 
713  return size;
714 }
715 
716 static size_t gserialized_from_lwpoly_size(const LWPOLY *poly)
717 {
718  size_t size = 4; /* Type number. */
719  uint32_t i = 0;
720 
721  assert(poly);
722 
723  size += 4; /* Number of rings (zero => empty). */
724  if ( poly->nrings % 2 )
725  size += 4; /* Padding to double alignment. */
726 
727  for ( i = 0; i < poly->nrings; i++ )
728  {
729  size += 4; /* Number of points in ring. */
730  size += poly->rings[i]->npoints * FLAGS_NDIMS(poly->flags) * sizeof(double);
731  }
732 
733  LWDEBUGF(3, "polygon size = %d", size);
734 
735  return size;
736 }
737 
739 {
740  size_t size = 4; /* Type number. */
741 
742  assert(curve);
743 
744  size += 4; /* Number of points (zero => empty). */
745  size += curve->points->npoints * FLAGS_NDIMS(curve->flags) * sizeof(double);
746 
747  LWDEBUGF(3, "circstring size = %d", size);
748 
749  return size;
750 }
751 
753 {
754  size_t size = 4; /* Type number. */
755  uint32_t i = 0;
756 
757  assert(col);
758 
759  size += 4; /* Number of sub-geometries (zero => empty). */
760 
761  for ( i = 0; i < col->ngeoms; i++ )
762  {
763  size_t subsize = gserialized_from_any_size(col->geoms[i]);
764  size += subsize;
765  LWDEBUGF(3, "lwcollection subgeom(%d) size = %d", i, subsize);
766  }
767 
768  LWDEBUGF(3, "lwcollection size = %d", size);
769 
770  return size;
771 }
772 
773 static size_t gserialized_from_any_size(const LWGEOM *geom)
774 {
775  LWDEBUGF(2, "Input type: %s", lwtype_name(geom->type));
776 
777  switch (geom->type)
778  {
779  case POINTTYPE:
780  return gserialized_from_lwpoint_size((LWPOINT *)geom);
781  case LINETYPE:
782  return gserialized_from_lwline_size((LWLINE *)geom);
783  case POLYGONTYPE:
784  return gserialized_from_lwpoly_size((LWPOLY *)geom);
785  case TRIANGLETYPE:
787  case CIRCSTRINGTYPE:
789  case CURVEPOLYTYPE:
790  case COMPOUNDTYPE:
791  case MULTIPOINTTYPE:
792  case MULTILINETYPE:
793  case MULTICURVETYPE:
794  case MULTIPOLYGONTYPE:
795  case MULTISURFACETYPE:
797  case TINTYPE:
798  case COLLECTIONTYPE:
800  default:
801  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
802  return 0;
803  }
804 }
805 
806 /* Public function */
807 
809 {
810  size_t size = 8; /* Header overhead. */
811  assert(geom);
812 
813  if ( geom->bbox )
814  size += gbox_serialized_size(geom->flags);
815 
816  size += gserialized_from_any_size(geom);
817  LWDEBUGF(3, "g_serialize size = %d", size);
818 
819  return size;
820 }
821 
822 /***********************************************************************
823 * Serialize an LWGEOM into GSERIALIZED.
824 */
825 
826 /* Private functions */
827 
828 static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf);
829 
830 static size_t gserialized_from_lwpoint(const LWPOINT *point, uint8_t *buf)
831 {
832  uint8_t *loc;
833  int ptsize = ptarray_point_size(point->point);
834  int type = POINTTYPE;
835 
836  assert(point);
837  assert(buf);
838 
839  if ( FLAGS_GET_ZM(point->flags) != FLAGS_GET_ZM(point->point->flags) )
840  lwerror("Dimensions mismatch in lwpoint");
841 
842  LWDEBUGF(2, "lwpoint_to_gserialized(%p, %p) called", point, buf);
843 
844  loc = buf;
845 
846  /* Write in the type. */
847  memcpy(loc, &type, sizeof(uint32_t));
848  loc += sizeof(uint32_t);
849  /* Write in the number of points (0 => empty). */
850  memcpy(loc, &(point->point->npoints), sizeof(uint32_t));
851  loc += sizeof(uint32_t);
852 
853  /* Copy in the ordinates. */
854  if ( point->point->npoints > 0 )
855  {
856  memcpy(loc, getPoint_internal(point->point, 0), ptsize);
857  loc += ptsize;
858  }
859 
860  return (size_t)(loc - buf);
861 }
862 
863 static size_t gserialized_from_lwline(const LWLINE *line, uint8_t *buf)
864 {
865  uint8_t *loc;
866  int ptsize;
867  size_t size;
868  int type = LINETYPE;
869 
870  assert(line);
871  assert(buf);
872 
873  LWDEBUGF(2, "lwline_to_gserialized(%p, %p) called", line, buf);
874 
875  if ( FLAGS_GET_Z(line->flags) != FLAGS_GET_Z(line->points->flags) )
876  lwerror("Dimensions mismatch in lwline");
877 
878  ptsize = ptarray_point_size(line->points);
879 
880  loc = buf;
881 
882  /* Write in the type. */
883  memcpy(loc, &type, sizeof(uint32_t));
884  loc += sizeof(uint32_t);
885 
886  /* Write in the npoints. */
887  memcpy(loc, &(line->points->npoints), sizeof(uint32_t));
888  loc += sizeof(uint32_t);
889 
890  LWDEBUGF(3, "lwline_to_gserialized added npoints (%d)", line->points->npoints);
891 
892  /* Copy in the ordinates. */
893  if ( line->points->npoints > 0 )
894  {
895  size = line->points->npoints * ptsize;
896  memcpy(loc, getPoint_internal(line->points, 0), size);
897  loc += size;
898  }
899  LWDEBUGF(3, "lwline_to_gserialized copied serialized_pointlist (%d bytes)", ptsize * line->points->npoints);
900 
901  return (size_t)(loc - buf);
902 }
903 
904 static size_t gserialized_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
905 {
906  uint32_t i;
907  uint8_t *loc;
908  int ptsize;
909  int type = POLYGONTYPE;
910 
911  assert(poly);
912  assert(buf);
913 
914  LWDEBUG(2, "lwpoly_to_gserialized called");
915 
916  ptsize = sizeof(double) * FLAGS_NDIMS(poly->flags);
917  loc = buf;
918 
919  /* Write in the type. */
920  memcpy(loc, &type, sizeof(uint32_t));
921  loc += sizeof(uint32_t);
922 
923  /* Write in the nrings. */
924  memcpy(loc, &(poly->nrings), sizeof(uint32_t));
925  loc += sizeof(uint32_t);
926 
927  /* Write in the npoints per ring. */
928  for ( i = 0; i < poly->nrings; i++ )
929  {
930  memcpy(loc, &(poly->rings[i]->npoints), sizeof(uint32_t));
931  loc += sizeof(uint32_t);
932  }
933 
934  /* Add in padding if necessary to remain double aligned. */
935  if ( poly->nrings % 2 )
936  {
937  memset(loc, 0, sizeof(uint32_t));
938  loc += sizeof(uint32_t);
939  }
940 
941  /* Copy in the ordinates. */
942  for ( i = 0; i < poly->nrings; i++ )
943  {
944  POINTARRAY *pa = poly->rings[i];
945  size_t pasize;
946 
947  if ( FLAGS_GET_ZM(poly->flags) != FLAGS_GET_ZM(pa->flags) )
948  lwerror("Dimensions mismatch in lwpoly");
949 
950  pasize = pa->npoints * ptsize;
951  if ( pa->npoints > 0 )
952  memcpy(loc, getPoint_internal(pa, 0), pasize);
953  loc += pasize;
954  }
955  return (size_t)(loc - buf);
956 }
957 
958 static size_t gserialized_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
959 {
960  uint8_t *loc;
961  int ptsize;
962  size_t size;
963  int type = TRIANGLETYPE;
964 
965  assert(triangle);
966  assert(buf);
967 
968  LWDEBUGF(2, "lwtriangle_to_gserialized(%p, %p) called", triangle, buf);
969 
970  if ( FLAGS_GET_ZM(triangle->flags) != FLAGS_GET_ZM(triangle->points->flags) )
971  lwerror("Dimensions mismatch in lwtriangle");
972 
973  ptsize = ptarray_point_size(triangle->points);
974 
975  loc = buf;
976 
977  /* Write in the type. */
978  memcpy(loc, &type, sizeof(uint32_t));
979  loc += sizeof(uint32_t);
980 
981  /* Write in the npoints. */
982  memcpy(loc, &(triangle->points->npoints), sizeof(uint32_t));
983  loc += sizeof(uint32_t);
984 
985  LWDEBUGF(3, "lwtriangle_to_gserialized added npoints (%d)", triangle->points->npoints);
986 
987  /* Copy in the ordinates. */
988  if ( triangle->points->npoints > 0 )
989  {
990  size = triangle->points->npoints * ptsize;
991  memcpy(loc, getPoint_internal(triangle->points, 0), size);
992  loc += size;
993  }
994  LWDEBUGF(3, "lwtriangle_to_gserialized copied serialized_pointlist (%d bytes)", ptsize * triangle->points->npoints);
995 
996  return (size_t)(loc - buf);
997 }
998 
999 static size_t gserialized_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
1000 {
1001  uint8_t *loc;
1002  int ptsize;
1003  size_t size;
1004  int type = CIRCSTRINGTYPE;
1005 
1006  assert(curve);
1007  assert(buf);
1008 
1009  if (FLAGS_GET_ZM(curve->flags) != FLAGS_GET_ZM(curve->points->flags))
1010  lwerror("Dimensions mismatch in lwcircstring");
1011 
1012 
1013  ptsize = ptarray_point_size(curve->points);
1014  loc = buf;
1015 
1016  /* Write in the type. */
1017  memcpy(loc, &type, sizeof(uint32_t));
1018  loc += sizeof(uint32_t);
1019 
1020  /* Write in the npoints. */
1021  memcpy(loc, &curve->points->npoints, sizeof(uint32_t));
1022  loc += sizeof(uint32_t);
1023 
1024  /* Copy in the ordinates. */
1025  if ( curve->points->npoints > 0 )
1026  {
1027  size = curve->points->npoints * ptsize;
1028  memcpy(loc, getPoint_internal(curve->points, 0), size);
1029  loc += size;
1030  }
1031 
1032  return (size_t)(loc - buf);
1033 }
1034 
1035 static size_t gserialized_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
1036 {
1037  size_t subsize = 0;
1038  uint8_t *loc;
1039  uint32_t i;
1040  int type;
1041 
1042  assert(coll);
1043  assert(buf);
1044 
1045  type = coll->type;
1046  loc = buf;
1047 
1048  /* Write in the type. */
1049  memcpy(loc, &type, sizeof(uint32_t));
1050  loc += sizeof(uint32_t);
1051 
1052  /* Write in the number of subgeoms. */
1053  memcpy(loc, &coll->ngeoms, sizeof(uint32_t));
1054  loc += sizeof(uint32_t);
1055 
1056  /* Serialize subgeoms. */
1057  for ( i=0; i<coll->ngeoms; i++ )
1058  {
1059  if (FLAGS_GET_ZM(coll->flags) != FLAGS_GET_ZM(coll->geoms[i]->flags))
1060  lwerror("Dimensions mismatch in lwcollection");
1061  subsize = gserialized_from_lwgeom_any(coll->geoms[i], loc);
1062  loc += subsize;
1063  }
1064 
1065  return (size_t)(loc - buf);
1066 }
1067 
1068 static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
1069 {
1070  assert(geom);
1071  assert(buf);
1072 
1073  LWDEBUGF(2, "Input type (%d) %s, hasz: %d hasm: %d",
1074  geom->type, lwtype_name(geom->type),
1075  FLAGS_GET_Z(geom->flags), FLAGS_GET_M(geom->flags));
1076  LWDEBUGF(2, "LWGEOM(%p) uint8_t(%p)", geom, buf);
1077 
1078  switch (geom->type)
1079  {
1080  case POINTTYPE:
1081  return gserialized_from_lwpoint((LWPOINT *)geom, buf);
1082  case LINETYPE:
1083  return gserialized_from_lwline((LWLINE *)geom, buf);
1084  case POLYGONTYPE:
1085  return gserialized_from_lwpoly((LWPOLY *)geom, buf);
1086  case TRIANGLETYPE:
1087  return gserialized_from_lwtriangle((LWTRIANGLE *)geom, buf);
1088  case CIRCSTRINGTYPE:
1089  return gserialized_from_lwcircstring((LWCIRCSTRING *)geom, buf);
1090  case CURVEPOLYTYPE:
1091  case COMPOUNDTYPE:
1092  case MULTIPOINTTYPE:
1093  case MULTILINETYPE:
1094  case MULTICURVETYPE:
1095  case MULTIPOLYGONTYPE:
1096  case MULTISURFACETYPE:
1097  case POLYHEDRALSURFACETYPE:
1098  case TINTYPE:
1099  case COLLECTIONTYPE:
1100  return gserialized_from_lwcollection((LWCOLLECTION *)geom, buf);
1101  default:
1102  lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
1103  return 0;
1104  }
1105  return 0;
1106 }
1107 
1108 static size_t gserialized_from_gbox(const GBOX *gbox, uint8_t *buf)
1109 {
1110  uint8_t *loc = buf;
1111  float f;
1112  size_t return_size;
1113 
1114  assert(buf);
1115 
1116  f = next_float_down(gbox->xmin);
1117  memcpy(loc, &f, sizeof(float));
1118  loc += sizeof(float);
1119 
1120  f = next_float_up(gbox->xmax);
1121  memcpy(loc, &f, sizeof(float));
1122  loc += sizeof(float);
1123 
1124  f = next_float_down(gbox->ymin);
1125  memcpy(loc, &f, sizeof(float));
1126  loc += sizeof(float);
1127 
1128  f = next_float_up(gbox->ymax);
1129  memcpy(loc, &f, sizeof(float));
1130  loc += sizeof(float);
1131 
1132  if ( FLAGS_GET_GEODETIC(gbox->flags) )
1133  {
1134  f = next_float_down(gbox->zmin);
1135  memcpy(loc, &f, sizeof(float));
1136  loc += sizeof(float);
1137 
1138  f = next_float_up(gbox->zmax);
1139  memcpy(loc, &f, sizeof(float));
1140  loc += sizeof(float);
1141 
1142  return_size = (size_t)(loc - buf);
1143  LWDEBUGF(4, "returning size %d", return_size);
1144  return return_size;
1145  }
1146 
1147  if ( FLAGS_GET_Z(gbox->flags) )
1148  {
1149  f = next_float_down(gbox->zmin);
1150  memcpy(loc, &f, sizeof(float));
1151  loc += sizeof(float);
1152 
1153  f = next_float_up(gbox->zmax);
1154  memcpy(loc, &f, sizeof(float));
1155  loc += sizeof(float);
1156 
1157  }
1158 
1159  if ( FLAGS_GET_M(gbox->flags) )
1160  {
1161  f = next_float_down(gbox->mmin);
1162  memcpy(loc, &f, sizeof(float));
1163  loc += sizeof(float);
1164 
1165  f = next_float_up(gbox->mmax);
1166  memcpy(loc, &f, sizeof(float));
1167  loc += sizeof(float);
1168  }
1169  return_size = (size_t)(loc - buf);
1170  LWDEBUGF(4, "returning size %d", return_size);
1171  return return_size;
1172 }
1173 
1174 /* Public function */
1175 
1177 {
1178  size_t expected_size = 0;
1179  size_t return_size = 0;
1180  uint8_t *serialized = NULL;
1181  uint8_t *ptr = NULL;
1182  GSERIALIZED *g = NULL;
1183  assert(geom);
1184 
1185  /*
1186  ** See if we need a bounding box, add one if we don't have one.
1187  */
1188  if ( (! geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)) )
1189  {
1190  lwgeom_add_bbox(geom);
1191  }
1192 
1193  /*
1194  ** Harmonize the flags to the state of the lwgeom
1195  */
1196  if ( geom->bbox )
1197  FLAGS_SET_BBOX(geom->flags, 1);
1198  else
1199  FLAGS_SET_BBOX(geom->flags, 0);
1200 
1201  /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1202  expected_size = gserialized_from_lwgeom_size(geom);
1203  serialized = lwalloc(expected_size);
1204  ptr = serialized;
1205 
1206  /* Move past size, srid and flags. */
1207  ptr += 8;
1208 
1209  /* Write in the serialized form of the gbox, if necessary. */
1210  if ( geom->bbox )
1211  ptr += gserialized_from_gbox(geom->bbox, ptr);
1212 
1213  /* Write in the serialized form of the geometry. */
1214  ptr += gserialized_from_lwgeom_any(geom, ptr);
1215 
1216  /* Calculate size as returned by data processing functions. */
1217  return_size = ptr - serialized;
1218 
1219  if ( expected_size != return_size ) /* Uh oh! */
1220  {
1221  lwerror("Return size (%d) not equal to expected size (%d)!", return_size, expected_size);
1222  return NULL;
1223  }
1224 
1225  if ( size ) /* Return the output size to the caller if necessary. */
1226  *size = return_size;
1227 
1228  g = (GSERIALIZED*)serialized;
1229 
1230  /*
1231  ** We are aping PgSQL code here, PostGIS code should use
1232  ** VARSIZE to set this for real.
1233  */
1234  g->size = return_size << 2;
1235 
1236  /* Set the SRID! */
1237  gserialized_set_srid(g, geom->srid);
1238 
1239  g->flags = geom->flags;
1240 
1241  return g;
1242 }
1243 
1244 /***********************************************************************
1245 * De-serialize GSERIALIZED into an LWGEOM.
1246 */
1247 
1248 static LWGEOM* lwgeom_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size);
1249 
1250 static LWPOINT* lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1251 {
1252  uint8_t *start_ptr = data_ptr;
1253  LWPOINT *point;
1254  uint32_t npoints = 0;
1255 
1256  assert(data_ptr);
1257 
1258  point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1259  point->srid = SRID_UNKNOWN; /* Default */
1260  point->bbox = NULL;
1261  point->type = POINTTYPE;
1262  point->flags = g_flags;
1263 
1264  data_ptr += 4; /* Skip past the type. */
1265  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1266  data_ptr += 4; /* Skip past the npoints. */
1267 
1268  if ( npoints > 0 )
1269  point->point = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 1, data_ptr);
1270  else
1271  point->point = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty point */
1272 
1273  data_ptr += npoints * FLAGS_NDIMS(g_flags) * sizeof(double);
1274 
1275  if ( g_size )
1276  *g_size = data_ptr - start_ptr;
1277 
1278  return point;
1279 }
1280 
1281 static LWLINE* lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1282 {
1283  uint8_t *start_ptr = data_ptr;
1284  LWLINE *line;
1285  uint32_t npoints = 0;
1286 
1287  assert(data_ptr);
1288 
1289  line = (LWLINE*)lwalloc(sizeof(LWLINE));
1290  line->srid = SRID_UNKNOWN; /* Default */
1291  line->bbox = NULL;
1292  line->type = LINETYPE;
1293  line->flags = g_flags;
1294 
1295  data_ptr += 4; /* Skip past the type. */
1296  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1297  data_ptr += 4; /* Skip past the npoints. */
1298 
1299  if ( npoints > 0 )
1300  line->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1301 
1302  else
1303  line->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty linestring */
1304 
1305  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1306 
1307  if ( g_size )
1308  *g_size = data_ptr - start_ptr;
1309 
1310  return line;
1311 }
1312 
1313 static LWPOLY* lwpoly_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1314 {
1315  uint8_t *start_ptr = data_ptr;
1316  LWPOLY *poly;
1317  uint8_t *ordinate_ptr;
1318  uint32_t nrings = 0;
1319  uint32_t i = 0;
1320 
1321  assert(data_ptr);
1322 
1323  poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1324  poly->srid = SRID_UNKNOWN; /* Default */
1325  poly->bbox = NULL;
1326  poly->type = POLYGONTYPE;
1327  poly->flags = g_flags;
1328 
1329  data_ptr += 4; /* Skip past the polygontype. */
1330  nrings = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1331  poly->nrings = nrings;
1332  LWDEBUGF(4, "nrings = %d", nrings);
1333  data_ptr += 4; /* Skip past the nrings. */
1334 
1335  ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1336  if ( nrings > 0)
1337  {
1338  poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1339  poly->maxrings = nrings;
1340  ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1341  if ( nrings % 2 ) /* If there is padding, move past that too. */
1342  ordinate_ptr += 4;
1343  }
1344  else /* Empty polygon */
1345  {
1346  poly->rings = NULL;
1347  poly->maxrings = 0;
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  uint32_t 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  {
1457  collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1458  collection->maxgeoms = ngeoms;
1459  }
1460  else
1461  {
1462  collection->geoms = NULL;
1463  collection->maxgeoms = 0;
1464  }
1465 
1466  /* Sub-geometries are never de-serialized with boxes (#1254) */
1467  FLAGS_SET_BBOX(g_flags, 0);
1468 
1469  for ( i = 0; i < ngeoms; i++ )
1470  {
1471  uint32_t subtype = gserialized_get_uint32_t(data_ptr);
1472  size_t subsize = 0;
1473 
1474  if ( ! lwcollection_allows_subtype(type, subtype) )
1475  {
1476  lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1477  lwfree(collection);
1478  return NULL;
1479  }
1480  collection->geoms[i] = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &subsize);
1481  data_ptr += subsize;
1482  }
1483 
1484  if ( g_size )
1485  *g_size = data_ptr - start_ptr;
1486 
1487  return collection;
1488 }
1489 
1491 {
1492  uint32_t type;
1493 
1494  assert(data_ptr);
1495 
1496  type = gserialized_get_uint32_t(data_ptr);
1497 
1498  LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1499  FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), FLAGS_GET_GEODETIC(g_flags), FLAGS_GET_BBOX(g_flags));
1500 
1501  switch (type)
1502  {
1503  case POINTTYPE:
1504  return (LWGEOM *)lwpoint_from_gserialized_buffer(data_ptr, g_flags, g_size);
1505  case LINETYPE:
1506  return (LWGEOM *)lwline_from_gserialized_buffer(data_ptr, g_flags, g_size);
1507  case CIRCSTRINGTYPE:
1508  return (LWGEOM *)lwcircstring_from_gserialized_buffer(data_ptr, g_flags, g_size);
1509  case POLYGONTYPE:
1510  return (LWGEOM *)lwpoly_from_gserialized_buffer(data_ptr, g_flags, g_size);
1511  case TRIANGLETYPE:
1512  return (LWGEOM *)lwtriangle_from_gserialized_buffer(data_ptr, g_flags, g_size);
1513  case MULTIPOINTTYPE:
1514  case MULTILINETYPE:
1515  case MULTIPOLYGONTYPE:
1516  case COMPOUNDTYPE:
1517  case CURVEPOLYTYPE:
1518  case MULTICURVETYPE:
1519  case MULTISURFACETYPE:
1520  case POLYHEDRALSURFACETYPE:
1521  case TINTYPE:
1522  case COLLECTIONTYPE:
1523  return (LWGEOM *)lwcollection_from_gserialized_buffer(data_ptr, g_flags, g_size);
1524  default:
1525  lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1526  return NULL;
1527  }
1528 }
1529 
1531 {
1532  uint8_t g_flags = 0;
1533  int32_t g_srid = 0;
1534  uint32_t g_type = 0;
1535  uint8_t *data_ptr = NULL;
1536  LWGEOM *lwgeom = NULL;
1537  GBOX bbox;
1538  size_t g_size = 0;
1539 
1540  assert(g);
1541 
1542  g_srid = gserialized_get_srid(g);
1543  g_flags = g->flags;
1544  g_type = gserialized_get_type(g);
1545  LWDEBUGF(4, "Got type %d (%s), srid=%d", g_type, lwtype_name(g_type), g_srid);
1546 
1547  data_ptr = (uint8_t*)g->data;
1548  if ( FLAGS_GET_BBOX(g_flags) )
1549  data_ptr += gbox_serialized_size(g_flags);
1550 
1551  lwgeom = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &g_size);
1552 
1553  if ( ! lwgeom )
1554  lwerror("lwgeom_from_gserialized: unable create geometry"); /* Ooops! */
1555 
1556  lwgeom->type = g_type;
1557  lwgeom->flags = g_flags;
1558 
1559  if ( gserialized_read_gbox_p(g, &bbox) == LW_SUCCESS )
1560  {
1561  lwgeom->bbox = gbox_copy(&bbox);
1562  }
1563  else if ( lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS) )
1564  {
1565  lwgeom->bbox = gbox_copy(&bbox);
1566  }
1567  else
1568  {
1569  lwgeom->bbox = NULL;
1570  }
1571 
1572  lwgeom_set_srid(lwgeom, g_srid);
1573 
1574  return lwgeom;
1575 }
char * s
Definition: cu_in_wkt.c:23
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition: g_box.c:712
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:433
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:446
static size_t gserialized_from_lwtriangle_size(const LWTRIANGLE *triangle)
Definition: g_serialized.c:702
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:808
static uint32_t gserialized_get_uint32_t(const uint8_t *loc)
Definition: g_serialized.c:35
static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Definition: g_serialized.c:461
static int gserialized_cmp_srid(const GSERIALIZED *s1, const GSERIALIZED *s2)
Definition: g_serialized.c:133
static size_t gserialized_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
Definition: g_serialized.c:958
static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
Definition: g_serialized.c:228
static size_t gserialized_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
Definition: g_serialized.c:904
static size_t gserialized_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
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
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
static LWPOINT * lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
static size_t gserialized_from_lwline(const LWLINE *line, uint8_t *buf)
Definition: g_serialized.c:863
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:45
static size_t gserialized_from_gbox(const GBOX *gbox, uint8_t *buf)
static size_t gserialized_from_lwpoint_size(const LWPOINT *point)
Definition: g_serialized.c:674
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_get_zm(const GSERIALIZED *gser)
Return a number indicating presence of Z and M coordinates.
Definition: g_serialized.c:55
static LWCIRCSTRING * lwcircstring_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:738
char * gserialized_to_string(const GSERIALIZED *g)
Return a WKT representation of the gserialized geometry.
Definition: g_serialized.c:193
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: g_serialized.c:179
static size_t gserialized_from_any_size(const LWGEOM *geom)
Definition: g_serialized.c:773
static size_t gserialized_from_lwpoly_size(const LWPOLY *poly)
Definition: g_serialized.c:716
GSERIALIZED * gserialized_copy(const GSERIALIZED *g)
Return a copy of the input serialized geometry.
Definition: g_serialized.c:142
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:640
static size_t gserialized_from_lwcollection_size(const LWCOLLECTION *col)
Definition: g_serialized.c:752
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
static LWTRIANGLE * lwtriangle_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
int gserialized_is_geodetic(const GSERIALIZED *gser)
Check if a GSERIALIZED is a geography.
Definition: g_serialized.c:65
static size_t gserialized_from_lwpoint(const LWPOINT *point, uint8_t *buf)
Definition: g_serialized.c:830
static LWCOLLECTION * lwcollection_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
int gserialized_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: g_serialized.c:60
int gserialized_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
Definition: g_serialized.c:50
int gserialized_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: g_serialized.c:40
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
static LWGEOM * lwgeom_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
static LWLINE * lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
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:414
static LWPOLY * lwpoly_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
static size_t gserialized_is_empty_recurse(const uint8_t *p, int *isempty)
Definition: g_serialized.c:152
static size_t gserialized_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
Definition: g_serialized.c:999
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
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
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
static size_t gserialized_from_lwline_size(const LWLINE *line)
Definition: g_serialized.c:688
static size_t gserialized_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
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:293
#define LW_FALSE
Definition: liblwgeom.h:77
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
#define COMPOUNDTYPE
Definition: liblwgeom.h:93
#define LW_FAILURE
Definition: liblwgeom.h:79
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
#define CURVEPOLYTYPE
Definition: liblwgeom.h:94
#define MULTILINETYPE
Definition: liblwgeom.h:89
#define MULTISURFACETYPE
Definition: liblwgeom.h:96
#define LINETYPE
Definition: liblwgeom.h:86
uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: ptarray.c:1750
#define LW_SUCCESS
Definition: liblwgeom.h:80
#define FLAGS_GET_BBOX(flags)
Definition: liblwgeom.h:142
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
#define FLAGS_SET_BBOX(flags, value)
Definition: liblwgeom.h:148
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
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1197
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1093
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:140
#define TINTYPE
Definition: liblwgeom.h:99
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
void lwfree(void *mem)
Definition: lwutil.c:244
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:152
size_t ptarray_point_size(const POINTARRAY *pa)
Definition: ptarray.c:54
#define POLYGONTYPE
Definition: liblwgeom.h:87
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:97
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:92
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:347
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
#define WKT_ISO
Definition: liblwgeom.h:2075
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:141
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:1393
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:676
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:153
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:746
#define MULTICURVETYPE
Definition: liblwgeom.h:95
#define TRIANGLETYPE
Definition: liblwgeom.h:98
void * lwalloc(size_t size)
Definition: lwutil.c:229
float next_float_up(double d)
Definition: lwgeom_api.c:73
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
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...
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:686
float next_float_down(double d)
Definition: lwgeom_api.c:52
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:143
#define SIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
#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:534
void normalize(POINT3D *p)
Normalize to a unit vector.
Definition: lwgeodetic.c:615
void cart2geog(const POINT3D *p, GEOGRAPHIC_POINT *g)
Convert cartesian coordinates on unit sphere to spherical coordinates.
Definition: lwgeodetic.c:414
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#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))
tuple g_size
Definition: genraster.py:41
type
Definition: ovdump.py:41
double ymax
Definition: liblwgeom.h:298
double zmax
Definition: liblwgeom.h:300
double xmax
Definition: liblwgeom.h:296
double zmin
Definition: liblwgeom.h:299
double mmax
Definition: liblwgeom.h:302
double ymin
Definition: liblwgeom.h:297
double xmin
Definition: liblwgeom.h:295
double mmin
Definition: liblwgeom.h:301
uint8_t flags
Definition: liblwgeom.h:294
Point in spherical coordinates on the world.
Definition: lwgeodetic.h:53
uint8_t flags
Definition: liblwgeom.h:386
uint8_t srid[3]
Definition: liblwgeom.h:385
uint32_t size
Definition: liblwgeom.h:384
uint8_t data[1]
Definition: liblwgeom.h:387
uint8_t type
Definition: liblwgeom.h:443
uint8_t flags
Definition: liblwgeom.h:444
int32_t srid
Definition: liblwgeom.h:446
POINTARRAY * points
Definition: liblwgeom.h:447
GBOX * bbox
Definition: liblwgeom.h:445
uint32_t ngeoms
Definition: liblwgeom.h:510
uint32_t maxgeoms
Definition: liblwgeom.h:511
uint8_t type
Definition: liblwgeom.h:506
GBOX * bbox
Definition: liblwgeom.h:508
uint8_t flags
Definition: liblwgeom.h:507
LWGEOM ** geoms
Definition: liblwgeom.h:512
int32_t srid
Definition: liblwgeom.h:509
uint8_t type
Definition: liblwgeom.h:399
GBOX * bbox
Definition: liblwgeom.h:401
uint8_t flags
Definition: liblwgeom.h:400
int32_t srid
Definition: liblwgeom.h:402
GBOX * bbox
Definition: liblwgeom.h:423
uint8_t flags
Definition: liblwgeom.h:422
POINTARRAY * points
Definition: liblwgeom.h:425
uint8_t type
Definition: liblwgeom.h:421
int32_t srid
Definition: liblwgeom.h:424
POINTARRAY * point
Definition: liblwgeom.h:414
uint8_t type
Definition: liblwgeom.h:410
GBOX * bbox
Definition: liblwgeom.h:412
uint8_t flags
Definition: liblwgeom.h:411
int32_t srid
Definition: liblwgeom.h:413
POINTARRAY ** rings
Definition: liblwgeom.h:460
uint8_t type
Definition: liblwgeom.h:454
uint32_t maxrings
Definition: liblwgeom.h:459
uint32_t nrings
Definition: liblwgeom.h:458
uint8_t flags
Definition: liblwgeom.h:455
GBOX * bbox
Definition: liblwgeom.h:456
int32_t srid
Definition: liblwgeom.h:457
int32_t srid
Definition: liblwgeom.h:435
uint8_t type
Definition: liblwgeom.h:432
GBOX * bbox
Definition: liblwgeom.h:434
POINTARRAY * points
Definition: liblwgeom.h:436
uint8_t flags
Definition: liblwgeom.h:433
double z
Definition: liblwgeom.h:343
double x
Definition: liblwgeom.h:343
double y
Definition: liblwgeom.h:343
uint32_t npoints
Definition: liblwgeom.h:374
uint8_t flags
Definition: liblwgeom.h:372
uint32_t u
Definition: g_serialized.c:255
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79