PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
gserialized1.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
22 * Copyright 2017 Darafei Praliaskouski <me@komzpa.net>
23 *
24 **********************************************************************/
25
26
27#include "liblwgeom_internal.h"
28#include "lwgeom_log.h"
29#include "lwgeodetic.h"
30#include "gserialized1.h"
31
32#include <stddef.h>
33
34/***********************************************************************
35* GSERIALIZED metadata utility functions.
36*/
37
38static int gserialized1_read_gbox_p(const GSERIALIZED *g, GBOX *gbox);
39
40
52
63
64
65static size_t gserialized1_box_size(const GSERIALIZED *g)
66{
68 return 6 * sizeof(float);
69 else
70 return 2 * G1FLAGS_NDIMS(g->gflags) * sizeof(float);
71}
72
73/* handle missaligned uint32_t data */
74static inline uint32_t gserialized1_get_uint32_t(const uint8_t *loc)
75{
76 return *((uint32_t*)loc);
77}
78
79uint8_t g1flags(int has_z, int has_m, int is_geodetic)
80{
81 uint8_t gflags = 0;
82 if (has_z)
83 G1FLAGS_SET_Z(gflags, 1);
84 if (has_m)
85 G1FLAGS_SET_M(gflags, 1);
86 if (is_geodetic)
87 G1FLAGS_SET_GEODETIC(gflags, 1);
88 return gflags;
89}
90
92{
93 return G1FLAGS_GET_BBOX(gser->gflags);
94}
95
97{
98 return G1FLAGS_GET_Z(gser->gflags);
99}
100
102{
103 return G1FLAGS_GET_M(gser->gflags);
104}
105
107{
108 return G1FLAGS_NDIMS(gser->gflags);
109}
110
112{
113 return G1FLAGS_GET_GEODETIC(gser->gflags);
114}
115
117{
118 /* GSERIALIZED size + max bbox according gbox_serialized_size (XYZM*2) + extended flags + type */
119 return offsetof(GSERIALIZED, data) + 8 * sizeof(float) + sizeof(uint32_t);
120}
121
122static uint32_t gserialized1_header_size(const GSERIALIZED *gser)
123{
124 uint32_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
125
126 if (gserialized1_has_bbox(gser))
127 sz += gserialized1_box_size(gser);
128
129 return sz;
130}
131
133{
134 uint32_t *ptr;
135 ptr = (uint32_t*)(g->data);
136 if ( G1FLAGS_GET_BBOX(g->gflags) )
137 {
138 ptr += (gserialized1_box_size(g) / sizeof(uint32_t));
139 }
140 return *ptr;
141}
142
144{
145 int32_t srid = 0;
146 srid = srid | (s->srid[0] << 16);
147 srid = srid | (s->srid[1] << 8);
148 srid = srid | s->srid[2];
149 /* Only the first 21 bits are set. Slide up and back to pull
150 the negative bits down, if we need them. */
151 srid = (srid<<11)>>11;
152
153 /* 0 is our internal unknown value. We'll map back and forth here for now */
154 if ( srid == 0 )
155 return SRID_UNKNOWN;
156 else
157 return srid;
158}
159
161{
162 LWDEBUGF(3, "%s called with srid = %d", __func__, srid);
163
164 srid = clamp_srid(srid);
165
166 /* 0 is our internal unknown value.
167 * We'll map back and forth here for now */
168 if ( srid == SRID_UNKNOWN )
169 srid = 0;
170
171 s->srid[0] = (srid & 0x001F0000) >> 16;
172 s->srid[1] = (srid & 0x0000FF00) >> 8;
173 s->srid[2] = (srid & 0x000000FF);
174}
175
176static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty);
177static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty)
178{
179 int i;
180 int32_t type, num;
181
182 memcpy(&type, p, 4);
183 memcpy(&num, p+4, 4);
184
185 if ( lwtype_is_collection(type) )
186 {
187 size_t lz = 8;
188 for ( i = 0; i < num; i++ )
189 {
190 lz += gserialized1_is_empty_recurse(p+lz, isempty);
191 if ( ! *isempty )
192 return lz;
193 }
194 *isempty = LW_TRUE;
195 return lz;
196 }
197 else
198 {
199 *isempty = (num == 0 ? LW_TRUE : LW_FALSE);
200 return 8;
201 }
202}
203
205{
206 uint8_t *p = (uint8_t*)g;
207 int isempty = 0;
208 assert(g);
209
210 p += 8; /* Skip varhdr and srid/flags */
212 p += gserialized1_box_size(g); /* Skip the box */
213
215 return isempty;
216}
217
218
219/* Prototype for lookup3.c */
220/* key = the key to hash */
221/* length = length of the key */
222/* pc = IN: primary initval, OUT: primary hash */
223/* pb = IN: secondary initval, OUT: secondary hash */
224void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);
225
226int32_t
228{
229 int32_t hval;
230 int32_t pb = 0, pc = 0;
231 /* Point to just the type/coordinate part of buffer */
232 size_t hsz1 = gserialized1_header_size(g1);
233 uint8_t *b1 = (uint8_t*)g1 + hsz1;
234 /* Calculate size of type/coordinate buffer */
235 size_t sz1 = LWSIZE_GET(g1->size);
236 size_t bsz1 = sz1 - hsz1;
237 /* Calculate size of srid/type/coordinate buffer */
238 int32_t srid = gserialized1_get_srid(g1);
239 size_t bsz2 = bsz1 + sizeof(int);
240 uint8_t *b2 = lwalloc(bsz2);
241 /* Copy srid into front of combined buffer */
242 memcpy(b2, &srid, sizeof(int));
243 /* Copy type/coordinates into rest of combined buffer */
244 memcpy(b2+sizeof(int), b1, bsz1);
245 /* Hash combined buffer */
246 hashlittle2(b2, bsz2, (uint32_t *)&pb, (uint32_t *)&pc);
247 lwfree(b2);
248 hval = pb ^ pc;
249 return hval;
250}
251
253{
254
255 /* Null input! */
256 if ( ! ( g && gbox ) ) return LW_FAILURE;
257
258 /* Initialize the flags on the box */
260
261 /* Has pre-calculated box */
262 if ( G1FLAGS_GET_BBOX(g->gflags) )
263 {
264 int i = 0;
265 float *fbox = (float*)(g->data);
266 gbox->xmin = fbox[i++];
267 gbox->xmax = fbox[i++];
268 gbox->ymin = fbox[i++];
269 gbox->ymax = fbox[i++];
270
271 /* Geodetic? Read next dimension (geocentric Z) and return */
273 {
274 gbox->zmin = fbox[i++];
275 gbox->zmax = fbox[i++];
276 return LW_SUCCESS;
277 }
278 /* Cartesian? Read extra dimensions (if there) and return */
279 if ( G1FLAGS_GET_Z(g->gflags) )
280 {
281 gbox->zmin = fbox[i++];
282 gbox->zmax = fbox[i++];
283 }
284 if ( G1FLAGS_GET_M(g->gflags) )
285 {
286 gbox->mmin = fbox[i++];
287 gbox->mmax = fbox[i++];
288 }
289 return LW_SUCCESS;
290 }
291 return LW_FAILURE;
292}
293
294/*
295* Populate a bounding box *without* allocating an LWGEOM. Useful
296* for some performance purposes.
297*/
298int
300{
301 uint32_t type = gserialized1_get_type(g);
302
303 /* Peeking doesn't help if you already have a box or are geodetic */
305 {
306 return LW_FAILURE;
307 }
308
309 /* Boxes of points are easy peasy */
310 if ( type == POINTTYPE )
311 {
312 int i = 1; /* Start past <pointtype><padding> */
313 double *dptr = (double*)(g->data);
314
315 /* Read the empty flag */
316 int32_t *iptr = (int32_t *)(g->data);
317 int isempty = (iptr[1] == 0);
318
319 /* EMPTY point has no box */
320 if ( isempty ) return LW_FAILURE;
321
322 gbox->xmin = gbox->xmax = dptr[i++];
323 gbox->ymin = gbox->ymax = dptr[i++];
325 if ( G1FLAGS_GET_Z(g->gflags) )
326 {
327 gbox->zmin = gbox->zmax = dptr[i++];
328 }
329 if ( G1FLAGS_GET_M(g->gflags) )
330 {
331 gbox->mmin = gbox->mmax = dptr[i++];
332 }
333 gbox_float_round(gbox);
334 return LW_SUCCESS;
335 }
336 /* We can calculate the box of a two-point cartesian line trivially */
337 else if ( type == LINETYPE )
338 {
339 int ndims = G1FLAGS_NDIMS(g->gflags);
340 int i = 0; /* Start at <linetype><npoints> */
341 double *dptr = (double*)(g->data);
342 int32_t *iptr = (int32_t *)(g->data);
343 int npoints = iptr[1]; /* Read the npoints */
344
345 /* This only works with 2-point lines */
346 if ( npoints != 2 )
347 return LW_FAILURE;
348
349 /* Advance to X */
350 /* Past <linetype><npoints> */
351 i++;
352 gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
353 gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
354
355 /* Advance to Y */
356 i++;
357 gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
358 gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
359
361 if ( G1FLAGS_GET_Z(g->gflags) )
362 {
363 /* Advance to Z */
364 i++;
365 gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
366 gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
367 }
368 if ( G1FLAGS_GET_M(g->gflags) )
369 {
370 /* Advance to M */
371 i++;
372 gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
373 gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
374 }
375 gbox_float_round(gbox);
376 return LW_SUCCESS;
377 }
378 /* We can also do single-entry multi-points */
379 else if ( type == MULTIPOINTTYPE )
380 {
381 int i = 0; /* Start at <multipointtype><ngeoms> */
382 double *dptr = (double*)(g->data);
383 int32_t *iptr = (int32_t *)(g->data);
384 int ngeoms = iptr[1]; /* Read the ngeoms */
385 int npoints;
386
387 /* This only works with single-entry multipoints */
388 if ( ngeoms != 1 )
389 return LW_FAILURE;
390
391 /* Npoints is at <multipointtype><ngeoms><pointtype><npoints> */
392 npoints = iptr[3];
393
394 /* The check below is necessary because we can have a MULTIPOINT
395 * that contains a single, empty POINT (ngeoms = 1, npoints = 0) */
396 if ( npoints != 1 )
397 return LW_FAILURE;
398
399 /* Move forward two doubles (four ints) */
400 /* Past <multipointtype><ngeoms> */
401 /* Past <pointtype><npoints> */
402 i += 2;
403
404 /* Read the doubles from the one point */
405 gbox->xmin = gbox->xmax = dptr[i++];
406 gbox->ymin = gbox->ymax = dptr[i++];
408 if ( G1FLAGS_GET_Z(g->gflags) )
409 {
410 gbox->zmin = gbox->zmax = dptr[i++];
411 }
412 if ( G1FLAGS_GET_M(g->gflags) )
413 {
414 gbox->mmin = gbox->mmax = dptr[i++];
415 }
416 gbox_float_round(gbox);
417 return LW_SUCCESS;
418 }
419 /* And we can do single-entry multi-lines with two vertices (!!!) */
420 else if ( type == MULTILINETYPE )
421 {
422 int ndims = G1FLAGS_NDIMS(g->gflags);
423 int i = 0; /* Start at <multilinetype><ngeoms> */
424 double *dptr = (double*)(g->data);
425 int32_t *iptr = (int32_t *)(g->data);
426 int ngeoms = iptr[1]; /* Read the ngeoms */
427 int npoints;
428
429 /* This only works with 1-line multilines */
430 if ( ngeoms != 1 )
431 return LW_FAILURE;
432
433 /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */
434 npoints = iptr[3];
435
436 if ( npoints != 2 )
437 return LW_FAILURE;
438
439 /* Advance to X */
440 /* Move forward two doubles (four ints) */
441 /* Past <multilinetype><ngeoms> */
442 /* Past <linetype><npoints> */
443 i += 2;
444 gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]);
445 gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]);
446
447 /* Advance to Y */
448 i++;
449 gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]);
450 gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]);
451
453 if ( G1FLAGS_GET_Z(g->gflags) )
454 {
455 /* Advance to Z */
456 i++;
457 gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]);
458 gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]);
459 }
460 if ( G1FLAGS_GET_M(g->gflags) )
461 {
462 /* Advance to M */
463 i++;
464 gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]);
465 gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]);
466 }
467 gbox_float_round(gbox);
468 return LW_SUCCESS;
469 }
470
471 return LW_FAILURE;
472}
473
474static inline void
475gserialized1_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
476{
477 uint8_t dim = 0;
478 out_point->x = dptr[dim++];
479 out_point->y = dptr[dim++];
480
481 if (G1FLAGS_GET_Z(flags))
482 {
483 out_point->z = dptr[dim++];
484 }
485 if (G1FLAGS_GET_M(flags))
486 {
487 out_point->m = dptr[dim];
488 }
489}
490
491int
493{
494 uint8_t *geometry_start = ((uint8_t *)g->data);
496 {
497 geometry_start += gserialized1_box_size(g);
498 }
499
500 uint32_t isEmpty = (((uint32_t *)geometry_start)[1]) == 0;
501 if (isEmpty)
502 {
503 return LW_FAILURE;
504 }
505
506 uint32_t type = (((uint32_t *)geometry_start)[0]);
507 /* Setup double_array_start depending on the geometry type */
508 double *double_array_start = NULL;
509 switch (type)
510 {
511 case (POINTTYPE):
512 /* For points we only need to jump over the type and npoints 32b ints */
513 double_array_start = (double *)(geometry_start + 2 * sizeof(uint32_t));
514 break;
515
516 default:
517 lwerror("%s is currently not implemented for type %d", __func__, type);
518 return LW_FAILURE;
519 }
520
521 gserialized1_copy_point(double_array_start, g->gflags, out_point);
522 return LW_SUCCESS;
523}
524
530{
531 /* Try to just read the serialized box. */
532 if ( gserialized1_read_gbox_p(g, box) == LW_SUCCESS )
533 {
534 return LW_SUCCESS;
535 }
536 /* No box? Try to peek into simpler geometries and */
537 /* derive a box without creating an lwgeom */
538 else if ( gserialized1_peek_gbox_p(g, box) == LW_SUCCESS )
539 {
540 return LW_SUCCESS;
541 }
542 /* Damn! Nothing for it but to create an lwgeom... */
543 /* See http://trac.osgeo.org/postgis/ticket/1023 */
544 else
545 {
546 LWGEOM *lwgeom = lwgeom_from_gserialized(g);
547 int ret = lwgeom_calculate_gbox(lwgeom, box);
548 gbox_float_round(box);
549 lwgeom_free(lwgeom);
550 return ret;
551 }
552}
553
559{
560 /* Try to just read the serialized box. */
561 if ( gserialized1_read_gbox_p(g, box) == LW_SUCCESS )
562 {
563 return LW_SUCCESS;
564 }
565 /* No box? Try to peek into simpler geometries and */
566 /* derive a box without creating an lwgeom */
567 else if ( gserialized1_peek_gbox_p(g, box) == LW_SUCCESS )
568 {
569 return LW_SUCCESS;
570 }
571 else
572 {
573 return LW_FAILURE;
574 }
575}
576
577
578
579
580/***********************************************************************
581* Calculate the GSERIALIZED size for an LWGEOM.
582*/
583
584/* Private functions */
585
586static size_t gserialized1_from_any_size(const LWGEOM *geom); /* Local prototype */
587
588static size_t gserialized1_from_lwpoint_size(const LWPOINT *point)
589{
590 size_t size = 4; /* Type number. */
591
592 assert(point);
593
594 size += 4; /* Number of points (one or zero (empty)). */
595 size += sizeof(double) * point->point->npoints * FLAGS_NDIMS(point->flags);
596
597 LWDEBUGF(3, "point size = %zu", size);
598
599 return size;
600}
601
602static size_t gserialized1_from_lwline_size(const LWLINE *line)
603{
604 size_t size = 4; /* Type number. */
605
606 assert(line);
607
608 size += 4; /* Number of points (zero => empty). */
609 size += sizeof(double) * line->points->npoints * FLAGS_NDIMS(line->flags);
610
611 LWDEBUGF(3, "linestring size = %zu", size);
612
613 return size;
614}
615
616static size_t gserialized1_from_lwtriangle_size(const LWTRIANGLE *triangle)
617{
618 size_t size = 4; /* Type number. */
619
620 assert(triangle);
621
622 size += 4; /* Number of points (zero => empty). */
623 size += sizeof(double) * triangle->points->npoints * FLAGS_NDIMS(triangle->flags);
624
625 LWDEBUGF(3, "triangle size = %zu", size);
626
627 return size;
628}
629
630static size_t gserialized1_from_lwpoly_size(const LWPOLY *poly)
631{
632 size_t size = 4; /* Type number. */
633 uint32_t i = 0;
634
635 assert(poly);
636
637 size += 4; /* Number of rings (zero => empty). */
638 if ( poly->nrings % 2 )
639 size += 4; /* Padding to double alignment. */
640
641 for ( i = 0; i < poly->nrings; i++ )
642 {
643 size += 4; /* Number of points in ring. */
644 size += sizeof(double) * poly->rings[i]->npoints * FLAGS_NDIMS(poly->flags);
645 }
646
647 LWDEBUGF(3, "polygon size = %zu", size);
648
649 return size;
650}
651
653{
654 size_t size = 4; /* Type number. */
655
656 assert(curve);
657
658 size += 4; /* Number of points (zero => empty). */
659 size += sizeof(double) * curve->points->npoints * FLAGS_NDIMS(curve->flags);
660
661 LWDEBUGF(3, "circstring size = %zu", size);
662
663 return size;
664}
665
667{
668 size_t size = 4; /* Type number. */
669 uint32_t i = 0;
670
671 assert(col);
672
673 size += 4; /* Number of sub-geometries (zero => empty). */
674
675 for ( i = 0; i < col->ngeoms; i++ )
676 {
677 size_t subsize = gserialized1_from_any_size(col->geoms[i]);
678 size += subsize;
679 LWDEBUGF(3, "lwcollection subgeom(%d) size = %zu", i, subsize);
680 }
681
682 LWDEBUGF(3, "lwcollection size = %zu", size);
683
684 return size;
685}
686
687static size_t gserialized1_from_any_size(const LWGEOM *geom)
688{
689 LWDEBUGF(2, "Input type: %s", lwtype_name(geom->type));
690
691 switch (geom->type)
692 {
693 case POINTTYPE:
695 case LINETYPE:
697 case POLYGONTYPE:
699 case TRIANGLETYPE:
701 case CIRCSTRINGTYPE:
703 case CURVEPOLYTYPE:
704 case COMPOUNDTYPE:
705 case MULTIPOINTTYPE:
706 case MULTILINETYPE:
707 case MULTICURVETYPE:
708 case MULTIPOLYGONTYPE:
709 case MULTISURFACETYPE:
711 case TINTYPE:
712 case COLLECTIONTYPE:
714 default:
715 lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
716 return 0;
717 }
718}
719
720/* Public function */
721
723{
724 size_t size = 8; /* Header overhead. */
725 assert(geom);
726
727 if (geom->bbox)
728 size += gbox_serialized_size(geom->flags);
729
730 size += gserialized1_from_any_size(geom);
731 LWDEBUGF(3, "%s size = %zu", __func__, size);
732
733 return size;
734}
735
736/***********************************************************************
737* Serialize an LWGEOM into GSERIALIZED.
738*/
739
740/* Private functions */
741
742static size_t gserialized1_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf);
743
744static size_t gserialized1_from_lwpoint(const LWPOINT *point, uint8_t *buf)
745{
746 uint8_t *loc;
747 int ptsize = ptarray_point_size(point->point);
748 int type = POINTTYPE;
749
750 assert(point);
751 assert(buf);
752
753 if ( FLAGS_GET_ZM(point->flags) != FLAGS_GET_ZM(point->point->flags) )
754 lwerror("Dimensions mismatch in lwpoint");
755
756 LWDEBUGF(2, "%s (%p, %p) called", __func__, point, buf);
757
758 loc = buf;
759
760 /* Write in the type. */
761 memcpy(loc, &type, sizeof(uint32_t));
762 loc += sizeof(uint32_t);
763 /* Write in the number of points (0 => empty). */
764 memcpy(loc, &(point->point->npoints), sizeof(uint32_t));
765 loc += sizeof(uint32_t);
766
767 /* Copy in the ordinates. */
768 if ( point->point->npoints > 0 )
769 {
770 memcpy(loc, getPoint_internal(point->point, 0), ptsize);
771 loc += ptsize;
772 }
773
774 return (size_t)(loc - buf);
775}
776
777static size_t gserialized1_from_lwline(const LWLINE *line, uint8_t *buf)
778{
779 uint8_t *loc;
780 int ptsize;
781 size_t size;
782 int type = LINETYPE;
783
784 assert(line);
785 assert(buf);
786
787 LWDEBUGF(2, "%s (%p, %p) called", __func__, line, buf);
788
789 if ( FLAGS_GET_Z(line->flags) != FLAGS_GET_Z(line->points->flags) )
790 lwerror("Dimensions mismatch in lwline");
791
792 ptsize = ptarray_point_size(line->points);
793
794 loc = buf;
795
796 /* Write in the type. */
797 memcpy(loc, &type, sizeof(uint32_t));
798 loc += sizeof(uint32_t);
799
800 /* Write in the npoints. */
801 memcpy(loc, &(line->points->npoints), sizeof(uint32_t));
802 loc += sizeof(uint32_t);
803
804 LWDEBUGF(3, "%s added npoints (%d)", __func__, line->points->npoints);
805
806 /* Copy in the ordinates. */
807 if ( line->points->npoints > 0 )
808 {
809 size = (size_t)line->points->npoints * ptsize;
810 memcpy(loc, getPoint_internal(line->points, 0), size);
811 loc += size;
812 }
813 LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * line->points->npoints);
814
815 return (size_t)(loc - buf);
816}
817
818static size_t gserialized1_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
819{
820 uint32_t i;
821 uint8_t *loc;
822 int ptsize;
823 int type = POLYGONTYPE;
824
825 assert(poly);
826 assert(buf);
827
828 LWDEBUGF(2, "%s called", __func__);
829
830 ptsize = sizeof(double) * FLAGS_NDIMS(poly->flags);
831 loc = buf;
832
833 /* Write in the type. */
834 memcpy(loc, &type, sizeof(uint32_t));
835 loc += sizeof(uint32_t);
836
837 /* Write in the nrings. */
838 memcpy(loc, &(poly->nrings), sizeof(uint32_t));
839 loc += sizeof(uint32_t);
840
841 /* Write in the npoints per ring. */
842 for ( i = 0; i < poly->nrings; i++ )
843 {
844 memcpy(loc, &(poly->rings[i]->npoints), sizeof(uint32_t));
845 loc += sizeof(uint32_t);
846 }
847
848 /* Add in padding if necessary to remain double aligned. */
849 if ( poly->nrings % 2 )
850 {
851 memset(loc, 0, sizeof(uint32_t));
852 loc += sizeof(uint32_t);
853 }
854
855 /* Copy in the ordinates. */
856 for ( i = 0; i < poly->nrings; i++ )
857 {
858 POINTARRAY *pa = poly->rings[i];
859 size_t pasize;
860
861 if ( FLAGS_GET_ZM(poly->flags) != FLAGS_GET_ZM(pa->flags) )
862 lwerror("Dimensions mismatch in lwpoly");
863
864 pasize = (size_t)pa->npoints * ptsize;
865 if ( pa->npoints > 0 )
866 memcpy(loc, getPoint_internal(pa, 0), pasize);
867 loc += pasize;
868 }
869 return (size_t)(loc - buf);
870}
871
872static size_t gserialized1_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
873{
874 uint8_t *loc;
875 int ptsize;
876 size_t size;
877 int type = TRIANGLETYPE;
878
879 assert(triangle);
880 assert(buf);
881
882 LWDEBUGF(2, "%s (%p, %p) called", __func__, triangle, buf);
883
884 if ( FLAGS_GET_ZM(triangle->flags) != FLAGS_GET_ZM(triangle->points->flags) )
885 lwerror("Dimensions mismatch in lwtriangle");
886
887 ptsize = ptarray_point_size(triangle->points);
888
889 loc = buf;
890
891 /* Write in the type. */
892 memcpy(loc, &type, sizeof(uint32_t));
893 loc += sizeof(uint32_t);
894
895 /* Write in the npoints. */
896 memcpy(loc, &(triangle->points->npoints), sizeof(uint32_t));
897 loc += sizeof(uint32_t);
898
899 LWDEBUGF(3, "%s added npoints (%d)", __func__, triangle->points->npoints);
900
901 /* Copy in the ordinates. */
902 if ( triangle->points->npoints > 0 )
903 {
904 size = (size_t)triangle->points->npoints * ptsize;
905 memcpy(loc, getPoint_internal(triangle->points, 0), size);
906 loc += size;
907 }
908 LWDEBUGF(3, "%s copied serialized_pointlist (%d bytes)", __func__, ptsize * triangle->points->npoints);
909
910 return (size_t)(loc - buf);
911}
912
913static size_t gserialized1_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
914{
915 uint8_t *loc;
916 int ptsize;
917 size_t size;
918 int type = CIRCSTRINGTYPE;
919
920 assert(curve);
921 assert(buf);
922
923 if (FLAGS_GET_ZM(curve->flags) != FLAGS_GET_ZM(curve->points->flags))
924 lwerror("Dimensions mismatch in lwcircstring");
925
926
927 ptsize = ptarray_point_size(curve->points);
928 loc = buf;
929
930 /* Write in the type. */
931 memcpy(loc, &type, sizeof(uint32_t));
932 loc += sizeof(uint32_t);
933
934 /* Write in the npoints. */
935 memcpy(loc, &curve->points->npoints, sizeof(uint32_t));
936 loc += sizeof(uint32_t);
937
938 /* Copy in the ordinates. */
939 if ( curve->points->npoints > 0 )
940 {
941 size = (size_t)curve->points->npoints * ptsize;
942 memcpy(loc, getPoint_internal(curve->points, 0), size);
943 loc += size;
944 }
945
946 return (size_t)(loc - buf);
947}
948
949static size_t gserialized1_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
950{
951 size_t subsize = 0;
952 uint8_t *loc;
953 uint32_t i;
954 int type;
955
956 assert(coll);
957 assert(buf);
958
959 type = coll->type;
960 loc = buf;
961
962 /* Write in the type. */
963 memcpy(loc, &type, sizeof(uint32_t));
964 loc += sizeof(uint32_t);
965
966 /* Write in the number of subgeoms. */
967 memcpy(loc, &coll->ngeoms, sizeof(uint32_t));
968 loc += sizeof(uint32_t);
969
970 /* Serialize subgeoms. */
971 for ( i=0; i<coll->ngeoms; i++ )
972 {
973 if (FLAGS_GET_ZM(coll->flags) != FLAGS_GET_ZM(coll->geoms[i]->flags))
974 lwerror("Dimensions mismatch in lwcollection");
975 subsize = gserialized1_from_lwgeom_any(coll->geoms[i], loc);
976 loc += subsize;
977 }
978
979 return (size_t)(loc - buf);
980}
981
982static size_t gserialized1_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
983{
984 assert(geom);
985 assert(buf);
986
987 LWDEBUGF(2, "Input type (%d) %s, hasz: %d hasm: %d",
988 geom->type, lwtype_name(geom->type),
989 FLAGS_GET_Z(geom->flags), FLAGS_GET_M(geom->flags));
990 LWDEBUGF(2, "LWGEOM(%p) uint8_t(%p)", geom, buf);
991
992 switch (geom->type)
993 {
994 case POINTTYPE:
995 return gserialized1_from_lwpoint((LWPOINT *)geom, buf);
996 case LINETYPE:
997 return gserialized1_from_lwline((LWLINE *)geom, buf);
998 case POLYGONTYPE:
999 return gserialized1_from_lwpoly((LWPOLY *)geom, buf);
1000 case TRIANGLETYPE:
1001 return gserialized1_from_lwtriangle((LWTRIANGLE *)geom, buf);
1002 case CIRCSTRINGTYPE:
1003 return gserialized1_from_lwcircstring((LWCIRCSTRING *)geom, buf);
1004 case CURVEPOLYTYPE:
1005 case COMPOUNDTYPE:
1006 case MULTIPOINTTYPE:
1007 case MULTILINETYPE:
1008 case MULTICURVETYPE:
1009 case MULTIPOLYGONTYPE:
1010 case MULTISURFACETYPE:
1012 case TINTYPE:
1013 case COLLECTIONTYPE:
1014 return gserialized1_from_lwcollection((LWCOLLECTION *)geom, buf);
1015 default:
1016 lwerror("Unknown geometry type: %d - %s", geom->type, lwtype_name(geom->type));
1017 return 0;
1018 }
1019 return 0;
1020}
1021
1022static size_t gserialized1_from_gbox(const GBOX *gbox, uint8_t *buf)
1023{
1024 uint8_t *loc = buf;
1025 float f;
1026 size_t return_size;
1027
1028 assert(buf);
1029
1030 f = next_float_down(gbox->xmin);
1031 memcpy(loc, &f, sizeof(float));
1032 loc += sizeof(float);
1033
1034 f = next_float_up(gbox->xmax);
1035 memcpy(loc, &f, sizeof(float));
1036 loc += sizeof(float);
1037
1038 f = next_float_down(gbox->ymin);
1039 memcpy(loc, &f, sizeof(float));
1040 loc += sizeof(float);
1041
1042 f = next_float_up(gbox->ymax);
1043 memcpy(loc, &f, sizeof(float));
1044 loc += sizeof(float);
1045
1046 if ( FLAGS_GET_GEODETIC(gbox->flags) )
1047 {
1048 f = next_float_down(gbox->zmin);
1049 memcpy(loc, &f, sizeof(float));
1050 loc += sizeof(float);
1051
1052 f = next_float_up(gbox->zmax);
1053 memcpy(loc, &f, sizeof(float));
1054 loc += sizeof(float);
1055
1056 return_size = (size_t)(loc - buf);
1057 LWDEBUGF(4, "returning size %zu", return_size);
1058 return return_size;
1059 }
1060
1061 if ( FLAGS_GET_Z(gbox->flags) )
1062 {
1063 f = next_float_down(gbox->zmin);
1064 memcpy(loc, &f, sizeof(float));
1065 loc += sizeof(float);
1066
1067 f = next_float_up(gbox->zmax);
1068 memcpy(loc, &f, sizeof(float));
1069 loc += sizeof(float);
1070
1071 }
1072
1073 if ( FLAGS_GET_M(gbox->flags) )
1074 {
1075 f = next_float_down(gbox->mmin);
1076 memcpy(loc, &f, sizeof(float));
1077 loc += sizeof(float);
1078
1079 f = next_float_up(gbox->mmax);
1080 memcpy(loc, &f, sizeof(float));
1081 loc += sizeof(float);
1082 }
1083 return_size = (size_t)(loc - buf);
1084 LWDEBUGF(4, "returning size %zu", return_size);
1085 return return_size;
1086}
1087
1088/* Public function */
1089
1091{
1092 size_t expected_size = 0;
1093 size_t return_size = 0;
1094 uint8_t *serialized = NULL;
1095 uint8_t *ptr = NULL;
1096 GSERIALIZED *g = NULL;
1097 assert(geom);
1098
1099 /*
1100 ** See if we need a bounding box, add one if we don't have one.
1101 */
1102 if ( (! geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)) )
1103 {
1104 lwgeom_add_bbox(geom);
1105 }
1106
1107 /*
1108 ** Harmonize the flags to the state of the lwgeom
1109 */
1110 if ( geom->bbox )
1111 FLAGS_SET_BBOX(geom->flags, 1);
1112 else
1113 FLAGS_SET_BBOX(geom->flags, 0);
1114
1115 /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */
1116 expected_size = gserialized1_from_lwgeom_size(geom);
1117 serialized = lwalloc(expected_size);
1118 ptr = serialized;
1119
1120 /* Move past size, srid and flags. */
1121 ptr += 8;
1122
1123 /* Write in the serialized form of the gbox, if necessary. */
1124 if ( geom->bbox )
1125 ptr += gserialized1_from_gbox(geom->bbox, ptr);
1126
1127 /* Write in the serialized form of the geometry. */
1128 ptr += gserialized1_from_lwgeom_any(geom, ptr);
1129
1130 /* Calculate size as returned by data processing functions. */
1131 return_size = ptr - serialized;
1132
1133 if ( expected_size != return_size ) /* Uh oh! */
1134 {
1135 lwerror("Return size (%zu) not equal to expected size (%zu)!", return_size, expected_size);
1136 return NULL;
1137 }
1138
1139 if ( size ) /* Return the output size to the caller if necessary. */
1140 *size = return_size;
1141
1142 g = (GSERIALIZED*)serialized;
1143
1144 /*
1145 ** We are aping PgSQL code here, PostGIS code should use
1146 ** VARSIZE to set this for real.
1147 */
1148 g->size = return_size << 2;
1149
1150 /* Set the SRID! */
1151 gserialized1_set_srid(g, geom->srid);
1152
1153 g->gflags = lwflags_get_g1flags(geom->flags);
1154
1155 return g;
1156}
1157
1158/***********************************************************************
1159* De-serialize GSERIALIZED into an LWGEOM.
1160*/
1161
1162static LWGEOM* lwgeom_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size);
1163
1164static LWPOINT* lwpoint_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
1165{
1166 uint8_t *start_ptr = data_ptr;
1167 LWPOINT *point;
1168 uint32_t npoints = 0;
1169
1170 assert(data_ptr);
1171
1172 point = (LWPOINT*)lwalloc(sizeof(LWPOINT));
1173 point->srid = SRID_UNKNOWN; /* Default */
1174 point->bbox = NULL;
1175 point->type = POINTTYPE;
1176 point->flags = lwflags;
1177
1178 data_ptr += 4; /* Skip past the type. */
1179 npoints = gserialized1_get_uint32_t(data_ptr); /* Zero => empty geometry */
1180 data_ptr += 4; /* Skip past the npoints. */
1181
1182 if ( npoints > 0 )
1184 else
1185 point->point = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty point */
1186
1187 data_ptr += sizeof(double) * npoints * FLAGS_NDIMS(lwflags);
1188
1189 if ( size )
1190 *size = data_ptr - start_ptr;
1191
1192 return point;
1193}
1194
1195static LWLINE* lwline_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
1196{
1197 uint8_t *start_ptr = data_ptr;
1198 LWLINE *line;
1199 uint32_t npoints = 0;
1200
1201 assert(data_ptr);
1202
1203 line = (LWLINE*)lwalloc(sizeof(LWLINE));
1204 line->srid = SRID_UNKNOWN; /* Default */
1205 line->bbox = NULL;
1206 line->type = LINETYPE;
1207 line->flags = lwflags;
1208
1209 data_ptr += 4; /* Skip past the type. */
1210 npoints = gserialized1_get_uint32_t(data_ptr); /* Zero => empty geometry */
1211 data_ptr += 4; /* Skip past the npoints. */
1212
1213 if ( npoints > 0 )
1215
1216 else
1217 line->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty linestring */
1218
1219 data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1220
1221 if ( size )
1222 *size = data_ptr - start_ptr;
1223
1224 return line;
1225}
1226
1227static LWPOLY* lwpoly_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
1228{
1229 uint8_t *start_ptr = data_ptr;
1230 LWPOLY *poly;
1231 uint8_t *ordinate_ptr;
1232 uint32_t nrings = 0;
1233 uint32_t i = 0;
1234
1235 assert(data_ptr);
1236
1237 poly = (LWPOLY*)lwalloc(sizeof(LWPOLY));
1238 poly->srid = SRID_UNKNOWN; /* Default */
1239 poly->bbox = NULL;
1240 poly->type = POLYGONTYPE;
1241 poly->flags = lwflags;
1242
1243 data_ptr += 4; /* Skip past the polygontype. */
1244 nrings = gserialized1_get_uint32_t(data_ptr); /* Zero => empty geometry */
1245 poly->nrings = nrings;
1246 LWDEBUGF(4, "nrings = %d", nrings);
1247 data_ptr += 4; /* Skip past the nrings. */
1248
1249 ordinate_ptr = data_ptr; /* Start the ordinate pointer. */
1250 if ( nrings > 0)
1251 {
1252 poly->rings = (POINTARRAY**)lwalloc( sizeof(POINTARRAY*) * nrings );
1253 poly->maxrings = nrings;
1254 ordinate_ptr += nrings * 4; /* Move past all the npoints values. */
1255 if ( nrings % 2 ) /* If there is padding, move past that too. */
1256 ordinate_ptr += 4;
1257 }
1258 else /* Empty polygon */
1259 {
1260 poly->rings = NULL;
1261 poly->maxrings = 0;
1262 }
1263
1264 for ( i = 0; i < nrings; i++ )
1265 {
1266 uint32_t npoints = 0;
1267
1268 /* Read in the number of points. */
1269 npoints = gserialized1_get_uint32_t(data_ptr);
1270 data_ptr += 4;
1271
1272 /* Make a point array for the ring, and move the ordinate pointer past the ring ordinates. */
1273 poly->rings[i] = ptarray_construct_reference_data(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), npoints, ordinate_ptr);
1274
1275 ordinate_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1276 }
1277
1278 if ( size )
1279 *size = ordinate_ptr - start_ptr;
1280
1281 return poly;
1282}
1283
1284static LWTRIANGLE* lwtriangle_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
1285{
1286 uint8_t *start_ptr = data_ptr;
1287 LWTRIANGLE *triangle;
1288 uint32_t npoints = 0;
1289
1290 assert(data_ptr);
1291
1292 triangle = (LWTRIANGLE*)lwalloc(sizeof(LWTRIANGLE));
1293 triangle->srid = SRID_UNKNOWN; /* Default */
1294 triangle->bbox = NULL;
1295 triangle->type = TRIANGLETYPE;
1296 triangle->flags = lwflags;
1297
1298 data_ptr += 4; /* Skip past the type. */
1299 npoints = gserialized1_get_uint32_t(data_ptr); /* Zero => empty geometry */
1300 data_ptr += 4; /* Skip past the npoints. */
1301
1302 if ( npoints > 0 )
1304 else
1305 triangle->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty triangle */
1306
1307 data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1308
1309 if ( size )
1310 *size = data_ptr - start_ptr;
1311
1312 return triangle;
1313}
1314
1316{
1317 uint8_t *start_ptr = data_ptr;
1318 LWCIRCSTRING *circstring;
1319 uint32_t npoints = 0;
1320
1321 assert(data_ptr);
1322
1323 circstring = (LWCIRCSTRING*)lwalloc(sizeof(LWCIRCSTRING));
1324 circstring->srid = SRID_UNKNOWN; /* Default */
1325 circstring->bbox = NULL;
1326 circstring->type = CIRCSTRINGTYPE;
1327 circstring->flags = lwflags;
1328
1329 data_ptr += 4; /* Skip past the circstringtype. */
1330 npoints = gserialized1_get_uint32_t(data_ptr); /* Zero => empty geometry */
1331 data_ptr += 4; /* Skip past the npoints. */
1332
1333 if ( npoints > 0 )
1335 else
1336 circstring->points = ptarray_construct(FLAGS_GET_Z(lwflags), FLAGS_GET_M(lwflags), 0); /* Empty circularstring */
1337
1338 data_ptr += sizeof(double) * FLAGS_NDIMS(lwflags) * npoints;
1339
1340 if ( size )
1341 *size = data_ptr - start_ptr;
1342
1343 return circstring;
1344}
1345
1347{
1348 uint32_t type;
1349 uint8_t *start_ptr = data_ptr;
1350 LWCOLLECTION *collection;
1351 uint32_t ngeoms = 0;
1352 uint32_t i = 0;
1353
1354 assert(data_ptr);
1355
1356 type = gserialized1_get_uint32_t(data_ptr);
1357 data_ptr += 4; /* Skip past the type. */
1358
1359 collection = (LWCOLLECTION*)lwalloc(sizeof(LWCOLLECTION));
1360 collection->srid = SRID_UNKNOWN; /* Default */
1361 collection->bbox = NULL;
1362 collection->type = type;
1363 collection->flags = lwflags;
1364
1365 ngeoms = gserialized1_get_uint32_t(data_ptr);
1366 collection->ngeoms = ngeoms; /* Zero => empty geometry */
1367 data_ptr += 4; /* Skip past the ngeoms. */
1368
1369 if ( ngeoms > 0 )
1370 {
1371 collection->geoms = lwalloc(sizeof(LWGEOM*) * ngeoms);
1372 collection->maxgeoms = ngeoms;
1373 }
1374 else
1375 {
1376 collection->geoms = NULL;
1377 collection->maxgeoms = 0;
1378 }
1379
1380 /* Sub-geometries are never de-serialized with boxes (#1254) */
1382
1383 for ( i = 0; i < ngeoms; i++ )
1384 {
1385 uint32_t subtype = gserialized1_get_uint32_t(data_ptr);
1386 size_t subsize = 0;
1387
1388 if ( ! lwcollection_allows_subtype(type, subtype) )
1389 {
1390 lwerror("Invalid subtype (%s) for collection type (%s)", lwtype_name(subtype), lwtype_name(type));
1391 lwfree(collection);
1392 return NULL;
1393 }
1394 collection->geoms[i] = lwgeom_from_gserialized1_buffer(data_ptr, lwflags, &subsize);
1395 data_ptr += subsize;
1396 }
1397
1398 if ( size )
1399 *size = data_ptr - start_ptr;
1400
1401 return collection;
1402}
1403
1404LWGEOM* lwgeom_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *g_size)
1405{
1406 uint32_t type;
1407
1408 assert(data_ptr);
1409
1410 type = gserialized1_get_uint32_t(data_ptr);
1411
1412 LWDEBUGF(2, "Got type %d (%s), hasz=%d hasm=%d geodetic=%d hasbox=%d", type, lwtype_name(type),
1414
1415 switch (type)
1416 {
1417 case POINTTYPE:
1418 return (LWGEOM *)lwpoint_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1419 case LINETYPE:
1420 return (LWGEOM *)lwline_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1421 case CIRCSTRINGTYPE:
1422 return (LWGEOM *)lwcircstring_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1423 case POLYGONTYPE:
1424 return (LWGEOM *)lwpoly_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1425 case TRIANGLETYPE:
1426 return (LWGEOM *)lwtriangle_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1427 case MULTIPOINTTYPE:
1428 case MULTILINETYPE:
1429 case MULTIPOLYGONTYPE:
1430 case COMPOUNDTYPE:
1431 case CURVEPOLYTYPE:
1432 case MULTICURVETYPE:
1433 case MULTISURFACETYPE:
1435 case TINTYPE:
1436 case COLLECTIONTYPE:
1437 return (LWGEOM *)lwcollection_from_gserialized1_buffer(data_ptr, lwflags, g_size);
1438 default:
1439 lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
1440 return NULL;
1441 }
1442}
1443
1445{
1446 lwflags_t lwflags = 0;
1447 int32_t srid = 0;
1448 uint32_t lwtype = 0;
1449 uint8_t *data_ptr = NULL;
1450 LWGEOM *lwgeom = NULL;
1451 GBOX bbox;
1452 size_t size = 0;
1453
1454 assert(g);
1455
1456 srid = gserialized1_get_srid(g);
1457 lwtype = gserialized1_get_type(g);
1459
1460 LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
1461
1462 data_ptr = (uint8_t*)g->data;
1464 data_ptr += gbox_serialized_size(lwflags);
1465
1466 lwgeom = lwgeom_from_gserialized1_buffer(data_ptr, lwflags, &size);
1467
1468 if ( ! lwgeom )
1469 lwerror("%s: unable create geometry", __func__); /* Ooops! */
1470
1471 lwgeom->type = lwtype;
1472 lwgeom->flags = lwflags;
1473
1474 if ( gserialized1_read_gbox_p(g, &bbox) == LW_SUCCESS )
1475 {
1476 lwgeom->bbox = gbox_copy(&bbox);
1477 }
1478 else if ( lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS) )
1479 {
1480 lwgeom->bbox = gbox_copy(&bbox);
1481 }
1482 else
1483 {
1484 lwgeom->bbox = NULL;
1485 }
1486
1487 lwgeom_set_srid(lwgeom, srid);
1488
1489 return lwgeom;
1490}
1491
1492const float * gserialized1_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
1493{
1494 if (ndims)
1495 *ndims = G1FLAGS_NDIMS_BOX(g->gflags);
1496 if (!g) return NULL;
1497 if (!G1FLAGS_GET_BBOX(g->gflags)) return NULL;
1498 return (const float *)(g->data);
1499}
1500
1510{
1511
1512 int g_ndims = G1FLAGS_NDIMS_BOX(g->gflags);
1513 int box_ndims = FLAGS_NDIMS_BOX(gbox->flags);
1514 GSERIALIZED *g_out = NULL;
1515 size_t box_size = 2 * g_ndims * sizeof(float);
1516 float *fbox;
1517 int fbox_pos = 0;
1518
1519 /* The dimensionality of the inputs has to match or we are SOL. */
1520 if ( g_ndims != box_ndims )
1521 {
1522 return NULL;
1523 }
1524
1525 /* Serialized already has room for a box. */
1526 if (G1FLAGS_GET_BBOX(g->gflags))
1527 {
1528 g_out = g;
1529 }
1530 /* Serialized has no box. We need to allocate enough space for the old
1531 data plus the box, and leave a gap in the memory segment to write
1532 the new values into.
1533 */
1534 else
1535 {
1536 size_t varsize_new = LWSIZE_GET(g->size) + box_size;
1537 uint8_t *ptr;
1538 g_out = lwalloc(varsize_new);
1539 /* Copy the head of g into place */
1540 memcpy(g_out, g, 8);
1541 /* Copy the body of g into place after leaving space for the box */
1542 ptr = g_out->data;
1543 ptr += box_size;
1544 memcpy(ptr, g->data, LWSIZE_GET(g->size) - 8);
1545 G1FLAGS_SET_BBOX(g_out->gflags, 1);
1546 LWSIZE_SET(g_out->size, varsize_new);
1547 }
1548
1549 /* Move bounds to nearest float values */
1550 gbox_float_round(gbox);
1551 /* Now write the float box values into the memory segment */
1552 fbox = (float*)(g_out->data);
1553 /* Copy in X/Y */
1554 fbox[fbox_pos++] = gbox->xmin;
1555 fbox[fbox_pos++] = gbox->xmax;
1556 fbox[fbox_pos++] = gbox->ymin;
1557 fbox[fbox_pos++] = gbox->ymax;
1558 /* Optionally copy in higher dims */
1560 {
1561 fbox[fbox_pos++] = gbox->zmin;
1562 fbox[fbox_pos++] = gbox->zmax;
1563 }
1565 {
1566 fbox[fbox_pos++] = gbox->mmin;
1567 fbox[fbox_pos++] = gbox->mmax;
1568 }
1569
1570 return g_out;
1571}
1572
1573
1579{
1580 int g_ndims = G1FLAGS_NDIMS_BOX(g->gflags);
1581 size_t box_size = 2 * g_ndims * sizeof(float);
1582 size_t g_out_size = LWSIZE_GET(g->size) - box_size;
1583 GSERIALIZED *g_out = lwalloc(g_out_size);
1584
1585 /* Copy the contents while omitting the box */
1586 if ( G1FLAGS_GET_BBOX(g->gflags) )
1587 {
1588 uint8_t *outptr = (uint8_t*)g_out;
1589 uint8_t *inptr = (uint8_t*)g;
1590 /* Copy the header (size+type) of g into place */
1591 memcpy(outptr, inptr, 8);
1592 outptr += 8;
1593 inptr += 8 + box_size;
1594 /* Copy parts after the box into place */
1595 memcpy(outptr, inptr, g_out_size - 8);
1596 G1FLAGS_SET_BBOX(g_out->gflags, 0);
1597 LWSIZE_SET(g_out->size, g_out_size);
1598 }
1599 /* No box? Nothing to do but copy and return. */
1600 else
1601 {
1602 memcpy(g_out, g, g_out_size);
1603 }
1604
1605 return g_out;
1606}
1607
char * s
Definition cu_in_wkt.c:23
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 void gserialized1_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
LWGEOM * lwgeom_from_gserialized1(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
const float * gserialized1_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
Point into the float box area of the serialization.
static size_t gserialized1_from_lwgeom_any(const LWGEOM *geom, uint8_t *buf)
int gserialized1_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
uint8_t g1flags(int has_z, int has_m, int is_geodetic)
int gserialized1_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
int32_t gserialized1_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
int gserialized1_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
GSERIALIZED * gserialized1_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...
void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb)
Definition lookup3.c:479
static size_t gserialized1_from_lwtriangle(const LWTRIANGLE *triangle, uint8_t *buf)
static size_t gserialized1_from_lwcollection_size(const LWCOLLECTION *col)
static LWPOINT * lwpoint_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
lwflags_t gserialized1_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
int32_t gserialized1_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
static size_t gserialized1_from_lwpoint_size(const LWPOINT *point)
int gserialized1_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 LWPOLY * lwpoly_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
uint32_t gserialized1_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
static size_t gserialized1_from_gbox(const GBOX *gbox, uint8_t *buf)
GSERIALIZED * gserialized1_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
static size_t gserialized1_from_lwtriangle_size(const LWTRIANGLE *triangle)
static LWGEOM * lwgeom_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
int gserialized1_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
int gserialized1_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
static LWLINE * lwline_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
uint32_t gserialized1_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
int gserialized1_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
static size_t gserialized1_from_lwpoint(const LWPOINT *point, uint8_t *buf)
static LWCIRCSTRING * lwcircstring_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
static uint32_t gserialized1_get_uint32_t(const uint8_t *loc)
static uint32_t gserialized1_header_size(const GSERIALIZED *gser)
int gserialized1_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
int gserialized1_is_geodetic(const GSERIALIZED *gser)
Check if a GSERIALIZED is a geography.
GSERIALIZED * gserialized1_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
static size_t gserialized1_from_lwcircstring(const LWCIRCSTRING *curve, uint8_t *buf)
static size_t gserialized1_from_lwcollection(const LWCOLLECTION *coll, uint8_t *buf)
static size_t gserialized1_from_lwcircstring_size(const LWCIRCSTRING *curve)
size_t gserialized1_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
uint8_t lwflags_get_g1flags(lwflags_t lwflags)
static size_t gserialized1_from_lwline_size(const LWLINE *line)
static size_t gserialized1_box_size(const GSERIALIZED *g)
static size_t gserialized1_from_lwpoly(const LWPOLY *poly, uint8_t *buf)
static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty)
void gserialized1_set_srid(GSERIALIZED *s, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
static size_t gserialized1_from_lwpoly_size(const LWPOLY *poly)
static size_t gserialized1_from_lwline(const LWLINE *line, uint8_t *buf)
static int gserialized1_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
static LWCOLLECTION * lwcollection_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
static size_t gserialized1_from_any_size(const LWGEOM *geom)
static LWTRIANGLE * lwtriangle_from_gserialized1_buffer(uint8_t *data_ptr, lwflags_t lwflags, size_t *size)
int gserialized1_fast_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and fail if it is not already there.
#define G1FLAGS_SET_SOLID(gflags, value)
#define G1FLAGS_SET_Z(gflags, value)
#define G1FLAGS_GET_M(gflags)
#define G1FLAGS_SET_M(gflags, value)
#define G1FLAGS_GET_SOLID(gflags)
#define G1FLAGS_SET_BBOX(gflags, value)
#define G1FLAGS_NDIMS(gflags)
#define G1FLAGS_GET_BBOX(gflags)
#define G1FLAGS_SET_GEODETIC(gflags, value)
#define G1FLAGS_NDIMS_BOX(gflags)
#define G1FLAGS_GET_GEODETIC(gflags)
#define G1FLAGS_GET_Z(gflags)
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
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:1638
#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 LW_SUCCESS
Definition liblwgeom.h:97
uint16_t lwflags_t
Definition liblwgeom.h:299
#define FLAGS_GET_BBOX(flags)
Definition liblwgeom.h:167
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
#define FLAGS_SET_BBOX(flags, value)
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: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 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
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