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