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