PostGIS  2.5.0dev-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 
1197  /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1198  expected_size = gserialized_from_lwgeom_size(geom);
1199  serialized = lwalloc(expected_size);
1200  ptr = serialized;
1201 
1202  /* Move past size, srid and flags. */
1203  ptr += 8;
1204 
1205  /* Write in the serialized form of the gbox, if necessary. */
1206  if ( geom->bbox )
1207  ptr += gserialized_from_gbox(geom->bbox, ptr);
1208 
1209  /* Write in the serialized form of the geometry. */
1210  ptr += gserialized_from_lwgeom_any(geom, ptr);
1211 
1212  /* Calculate size as returned by data processing functions. */
1213  return_size = ptr - serialized;
1214 
1215  if ( expected_size != return_size ) /* Uh oh! */
1216  {
1217  lwerror("Return size (%d) not equal to expected size (%d)!", return_size, expected_size);
1218  return NULL;
1219  }
1220 
1221  if ( size ) /* Return the output size to the caller if necessary. */
1222  *size = return_size;
1223 
1224  g = (GSERIALIZED*)serialized;
1225 
1226  /*
1227  ** We are aping PgSQL code here, PostGIS code should use
1228  ** VARSIZE to set this for real.
1229  */
1230  g->size = return_size << 2;
1231 
1232  /* Set the SRID! */
1233  gserialized_set_srid(g, geom->srid);
1234 
1235  g->flags = geom->flags;
1236 
1237  return g;
1238 }
1239 
1240 /***********************************************************************
1241 * De-serialize GSERIALIZED into an LWGEOM.
1242 */
1243 
1244 static LWGEOM* lwgeom_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size);
1245 
1246 static LWPOINT* lwpoint_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1247 {
1248  uint8_t *start_ptr = data_ptr;
1249  LWPOINT *point;
1250  uint32_t npoints = 0;
1251 
1252  assert(data_ptr);
1253 
1254  point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1255  point->srid = SRID_UNKNOWN; /* Default */
1256  point->bbox = NULL;
1257  point->type = POINTTYPE;
1258  point->flags = g_flags;
1259 
1260  data_ptr += 4; /* Skip past the type. */
1261  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1262  data_ptr += 4; /* Skip past the npoints. */
1263 
1264  if ( npoints > 0 )
1265  point->point = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 1, data_ptr);
1266  else
1267  point->point = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty point */
1268 
1269  data_ptr += npoints * FLAGS_NDIMS(g_flags) * sizeof(double);
1270 
1271  if ( g_size )
1272  *g_size = data_ptr - start_ptr;
1273 
1274  return point;
1275 }
1276 
1277 static LWLINE* lwline_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1278 {
1279  uint8_t *start_ptr = data_ptr;
1280  LWLINE *line;
1281  uint32_t npoints = 0;
1282 
1283  assert(data_ptr);
1284 
1285  line = (LWLINE*)lwalloc(sizeof(LWLINE));
1286  line->srid = SRID_UNKNOWN; /* Default */
1287  line->bbox = NULL;
1288  line->type = LINETYPE;
1289  line->flags = g_flags;
1290 
1291  data_ptr += 4; /* Skip past the type. */
1292  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1293  data_ptr += 4; /* Skip past the npoints. */
1294 
1295  if ( npoints > 0 )
1296  line->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1297 
1298  else
1299  line->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty linestring */
1300 
1301  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1302 
1303  if ( g_size )
1304  *g_size = data_ptr - start_ptr;
1305 
1306  return line;
1307 }
1308 
1309 static LWPOLY* lwpoly_from_gserialized_buffer(uint8_t *data_ptr, uint8_t g_flags, size_t *g_size)
1310 {
1311  uint8_t *start_ptr = data_ptr;
1312  LWPOLY *poly;
1313  uint8_t *ordinate_ptr;
1314  uint32_t nrings = 0;
1315  uint32_t i = 0;
1316 
1317  assert(data_ptr);
1318 
1319  poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1320  poly->srid = SRID_UNKNOWN; /* Default */
1321  poly->bbox = NULL;
1322  poly->type = POLYGONTYPE;
1323  poly->flags = g_flags;
1324 
1325  data_ptr += 4; /* Skip past the polygontype. */
1326  nrings = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1327  poly->nrings = nrings;
1328  LWDEBUGF(4, "nrings = %d", nrings);
1329  data_ptr += 4; /* Skip past the nrings. */
1330 
1331  ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1332  if ( nrings > 0)
1333  {
1334  poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1335  poly->maxrings = nrings;
1336  ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1337  if ( nrings % 2 ) /* If there is padding, move past that too. */
1338  ordinate_ptr += 4;
1339  }
1340  else /* Empty polygon */
1341  {
1342  poly->rings = NULL;
1343  poly->maxrings = 0;
1344  }
1345 
1346  for ( i = 0; i < nrings; i++ )
1347  {
1348  uint32_t npoints = 0;
1349 
1350  /* Read in the number of points. */
1351  npoints = gserialized_get_uint32_t(data_ptr);
1352  data_ptr += 4;
1353 
1354  /* Make a point array for the ring, and move the ordinate pointer past the ring ordinates. */
1355  poly->rings[i] = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, ordinate_ptr);
1356 
1357  ordinate_ptr += sizeof(double) * FLAGS_NDIMS(g_flags) * npoints;
1358  }
1359 
1360  if ( g_size )
1361  *g_size = ordinate_ptr - start_ptr;
1362 
1363  return poly;
1364 }
1365 
1367 {
1368  uint8_t *start_ptr = data_ptr;
1369  LWTRIANGLE *triangle;
1370  uint32_t npoints = 0;
1371 
1372  assert(data_ptr);
1373 
1374  triangle = (LWTRIANGLE*)lwalloc(sizeof(LWTRIANGLE));
1375  triangle->srid = SRID_UNKNOWN; /* Default */
1376  triangle->bbox = NULL;
1377  triangle->type = TRIANGLETYPE;
1378  triangle->flags = g_flags;
1379 
1380  data_ptr += 4; /* Skip past the type. */
1381  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1382  data_ptr += 4; /* Skip past the npoints. */
1383 
1384  if ( npoints > 0 )
1385  triangle->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1386  else
1387  triangle->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty triangle */
1388 
1389  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1390 
1391  if ( g_size )
1392  *g_size = data_ptr - start_ptr;
1393 
1394  return triangle;
1395 }
1396 
1398 {
1399  uint8_t *start_ptr = data_ptr;
1400  LWCIRCSTRING *circstring;
1401  uint32_t npoints = 0;
1402 
1403  assert(data_ptr);
1404 
1405  circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING));
1406  circstring->srid = SRID_UNKNOWN; /* Default */
1407  circstring->bbox = NULL;
1408  circstring->type = CIRCSTRINGTYPE;
1409  circstring->flags = g_flags;
1410 
1411  data_ptr += 4; /* Skip past the circstringtype. */
1412  npoints = gserialized_get_uint32_t(data_ptr); /* Zero => empty geometry */
1413  data_ptr += 4; /* Skip past the npoints. */
1414 
1415  if ( npoints > 0 )
1416  circstring->points = ptarray_construct_reference_data(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), npoints, data_ptr);
1417  else
1418  circstring->points = ptarray_construct(FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), 0); /* Empty circularstring */
1419 
1420  data_ptr += FLAGS_NDIMS(g_flags) * npoints * sizeof(double);
1421 
1422  if ( g_size )
1423  *g_size = data_ptr - start_ptr;
1424 
1425  return circstring;
1426 }
1427 
1429 {
1430  uint32_t type;
1431  uint8_t *start_ptr = data_ptr;
1432  LWCOLLECTION *collection;
1433  uint32_t ngeoms = 0;
1434  uint32_t i = 0;
1435 
1436  assert(data_ptr);
1437 
1438  type = gserialized_get_uint32_t(data_ptr);
1439  data_ptr += 4; /* Skip past the type. */
1440 
1441  collection = (LWCOLLECTION*)lwalloc(sizeof(LWCOLLECTION));
1442  collection->srid = SRID_UNKNOWN; /* Default */
1443  collection->bbox = NULL;
1444  collection->type = type;
1445  collection->flags = g_flags;
1446 
1447  ngeoms = gserialized_get_uint32_t(data_ptr);
1448  collection->ngeoms = ngeoms; /* Zero => empty geometry */
1449  data_ptr += 4; /* Skip past the ngeoms. */
1450 
1451  if ( ngeoms > 0 )
1452  {
1453  collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1454  collection->maxgeoms = ngeoms;
1455  }
1456  else
1457  {
1458  collection->geoms = NULL;
1459  collection->maxgeoms = 0;
1460  }
1461 
1462  /* Sub-geometries are never de-serialized with boxes (#1254) */
1463  FLAGS_SET_BBOX(g_flags, 0);
1464 
1465  for ( i = 0; i < ngeoms; i++ )
1466  {
1467  uint32_t subtype = gserialized_get_uint32_t(data_ptr);
1468  size_t subsize = 0;
1469 
1470  if ( ! lwcollection_allows_subtype(type, subtype) )
1471  {
1472  lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1473  lwfree(collection);
1474  return NULL;
1475  }
1476  collection->geoms[i] = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &subsize);
1477  data_ptr += subsize;
1478  }
1479 
1480  if ( g_size )
1481  *g_size = data_ptr - start_ptr;
1482 
1483  return collection;
1484 }
1485 
1487 {
1488  uint32_t type;
1489 
1490  assert(data_ptr);
1491 
1492  type = gserialized_get_uint32_t(data_ptr);
1493 
1494  LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1495  FLAGS_GET_Z(g_flags), FLAGS_GET_M(g_flags), FLAGS_GET_GEODETIC(g_flags), FLAGS_GET_BBOX(g_flags));
1496 
1497  switch (type)
1498  {
1499  case POINTTYPE:
1500  return (LWGEOM *)lwpoint_from_gserialized_buffer(data_ptr, g_flags, g_size);
1501  case LINETYPE:
1502  return (LWGEOM *)lwline_from_gserialized_buffer(data_ptr, g_flags, g_size);
1503  case CIRCSTRINGTYPE:
1504  return (LWGEOM *)lwcircstring_from_gserialized_buffer(data_ptr, g_flags, g_size);
1505  case POLYGONTYPE:
1506  return (LWGEOM *)lwpoly_from_gserialized_buffer(data_ptr, g_flags, g_size);
1507  case TRIANGLETYPE:
1508  return (LWGEOM *)lwtriangle_from_gserialized_buffer(data_ptr, g_flags, g_size);
1509  case MULTIPOINTTYPE:
1510  case MULTILINETYPE:
1511  case MULTIPOLYGONTYPE:
1512  case COMPOUNDTYPE:
1513  case CURVEPOLYTYPE:
1514  case MULTICURVETYPE:
1515  case MULTISURFACETYPE:
1516  case POLYHEDRALSURFACETYPE:
1517  case TINTYPE:
1518  case COLLECTIONTYPE:
1519  return (LWGEOM *)lwcollection_from_gserialized_buffer(data_ptr, g_flags, g_size);
1520  default:
1521  lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1522  return NULL;
1523  }
1524 }
1525 
1527 {
1528  uint8_t g_flags = 0;
1529  int32_t g_srid = 0;
1530  uint32_t g_type = 0;
1531  uint8_t *data_ptr = NULL;
1532  LWGEOM *lwgeom = NULL;
1533  GBOX bbox;
1534  size_t g_size = 0;
1535 
1536  assert(g);
1537 
1538  g_srid = gserialized_get_srid(g);
1539  g_flags = g->flags;
1540  g_type = gserialized_get_type(g);
1541  LWDEBUGF(4, "Got type %d (%s), srid=%d", g_type, lwtype_name(g_type), g_srid);
1542 
1543  data_ptr = (uint8_t*)g->data;
1544  if ( FLAGS_GET_BBOX(g_flags) )
1545  data_ptr += gbox_serialized_size(g_flags);
1546 
1547  lwgeom = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &g_size);
1548 
1549  if ( ! lwgeom )
1550  lwerror("lwgeom_from_gserialized: unable create geometry"); /* Ooops! */
1551 
1552  lwgeom->type = g_type;
1553  lwgeom->flags = g_flags;
1554 
1555  if ( gserialized_read_gbox_p(g, &bbox) == LW_SUCCESS )
1556  {
1557  lwgeom->bbox = gbox_copy(&bbox);
1558  }
1559  else if ( lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS) )
1560  {
1561  lwgeom->bbox = gbox_copy(&bbox);
1562  }
1563  else
1564  {
1565  lwgeom->bbox = NULL;
1566  }
1567 
1568  lwgeom_set_srid(lwgeom, g_srid);
1569 
1570  return lwgeom;
1571 }
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:675
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:1743
#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