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