PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
gbox.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 *
23 **********************************************************************/
24
25#include "liblwgeom_internal.h"
26#include "lwgeodetic.h"
27#include "lwgeom_log.h"
28#include <stdlib.h>
29#include <math.h>
30
31
33{
34 GBOX *g = (GBOX*)lwalloc(sizeof(GBOX));
35 gbox_init(g);
36 g->flags = flags;
37 return g;
38}
39
40void gbox_init(GBOX *gbox)
41{
42 memset(gbox, 0, sizeof(GBOX));
43}
44
45GBOX* gbox_clone(const GBOX *gbox)
46{
47 GBOX *g = lwalloc(sizeof(GBOX));
48 memcpy(g, gbox, sizeof(GBOX));
49 return g;
50}
51
52/* TODO to be removed */
54{
55 BOX3D *b;
56 assert(gbox);
57
58 b = lwalloc(sizeof(BOX3D));
59
60 b->xmin = gbox->xmin;
61 b->xmax = gbox->xmax;
62 b->ymin = gbox->ymin;
63 b->ymax = gbox->ymax;
64
65 if ( FLAGS_GET_Z(gbox->flags) )
66 {
67 b->zmin = gbox->zmin;
68 b->zmax = gbox->zmax;
69 }
70 else
71 {
72 b->zmin = b->zmax = 0.0;
73 }
74
75 b->srid = SRID_UNKNOWN;
76 return b;
77}
78
79/* TODO to be removed */
81{
82 GBOX *b;
83 assert(b3d);
84
85 b = lwalloc(sizeof(GBOX));
86
87 b->xmin = b3d->xmin;
88 b->xmax = b3d->xmax;
89 b->ymin = b3d->ymin;
90 b->ymax = b3d->ymax;
91 b->zmin = b3d->zmin;
92 b->zmax = b3d->zmax;
93
94 return b;
95}
96
97void gbox_expand(GBOX *g, double d)
98{
99 g->xmin -= d;
100 g->xmax += d;
101 g->ymin -= d;
102 g->ymax += d;
104 {
105 g->zmin -= d;
106 g->zmax += d;
107 }
108 if (FLAGS_GET_M(g->flags))
109 {
110 g->mmin -= d;
111 g->mmax += d;
112 }
113}
114
115void gbox_expand_xyzm(GBOX *g, double dx, double dy, double dz, double dm)
116{
117 g->xmin -= dx;
118 g->xmax += dx;
119 g->ymin -= dy;
120 g->ymax += dy;
121
122 if (FLAGS_GET_Z(g->flags))
123 {
124 g->zmin -= dz;
125 g->zmax += dz;
126 }
127
128 if (FLAGS_GET_M(g->flags))
129 {
130 g->mmin -= dm;
131 g->mmax += dm;
132 }
133}
134
135int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
136{
137 if ( ( ! g1 ) && ( ! g2 ) )
138 return LW_FALSE;
139 else if (!g1)
140 {
141 memcpy(gout, g2, sizeof(GBOX));
142 return LW_TRUE;
143 }
144 else if (!g2)
145 {
146 memcpy(gout, g1, sizeof(GBOX));
147 return LW_TRUE;
148 }
149
150 gout->flags = g1->flags;
151
152 gout->xmin = FP_MIN(g1->xmin, g2->xmin);
153 gout->xmax = FP_MAX(g1->xmax, g2->xmax);
154
155 gout->ymin = FP_MIN(g1->ymin, g2->ymin);
156 gout->ymax = FP_MAX(g1->ymax, g2->ymax);
157
158 gout->zmin = FP_MIN(g1->zmin, g2->zmin);
159 gout->zmax = FP_MAX(g1->zmax, g2->zmax);
160
161 return LW_TRUE;
162}
163
164int gbox_same(const GBOX *g1, const GBOX *g2)
165{
166 if (FLAGS_GET_ZM(g1->flags) != FLAGS_GET_ZM(g2->flags))
167 return LW_FALSE;
168
169 if (!gbox_same_2d(g1, g2)) return LW_FALSE;
170
171 if (FLAGS_GET_Z(g1->flags) && (g1->zmin != g2->zmin || g1->zmax != g2->zmax))
172 return LW_FALSE;
173 if (FLAGS_GET_M(g1->flags) && (g1->mmin != g2->mmin || g1->mmax != g2->mmax))
174 return LW_FALSE;
175
176 return LW_TRUE;
177}
178
179int gbox_same_2d(const GBOX *g1, const GBOX *g2)
180{
181 if (g1->xmin == g2->xmin && g1->ymin == g2->ymin &&
182 g1->xmax == g2->xmax && g1->ymax == g2->ymax)
183 return LW_TRUE;
184 return LW_FALSE;
185}
186
187int gbox_same_2d_float(const GBOX *g1, const GBOX *g2)
188{
189 if ((g1->xmax == g2->xmax || next_float_up(g1->xmax) == next_float_up(g2->xmax)) &&
190 (g1->ymax == g2->ymax || next_float_up(g1->ymax) == next_float_up(g2->ymax)) &&
191 (g1->xmin == g2->xmin || next_float_down(g1->xmin) == next_float_down(g1->xmin)) &&
192 (g1->ymin == g2->ymin || next_float_down(g2->ymin) == next_float_down(g2->ymin)))
193 return LW_TRUE;
194 return LW_FALSE;
195}
196
197int gbox_is_valid(const GBOX *gbox)
198{
199 /* X */
200 if ( ! isfinite(gbox->xmin) || isnan(gbox->xmin) ||
201 ! isfinite(gbox->xmax) || isnan(gbox->xmax) )
202 return LW_FALSE;
203
204 /* Y */
205 if ( ! isfinite(gbox->ymin) || isnan(gbox->ymin) ||
206 ! isfinite(gbox->ymax) || isnan(gbox->ymax) )
207 return LW_FALSE;
208
209 /* Z */
210 if ( FLAGS_GET_GEODETIC(gbox->flags) || FLAGS_GET_Z(gbox->flags) )
211 {
212 if ( ! isfinite(gbox->zmin) || isnan(gbox->zmin) ||
213 ! isfinite(gbox->zmax) || isnan(gbox->zmax) )
214 return LW_FALSE;
215 }
216
217 /* M */
218 if ( FLAGS_GET_M(gbox->flags) )
219 {
220 if ( ! isfinite(gbox->mmin) || isnan(gbox->mmin) ||
221 ! isfinite(gbox->mmax) || isnan(gbox->mmax) )
222 return LW_FALSE;
223 }
224
225 return LW_TRUE;
226}
227
228int gbox_merge_point3d(const POINT3D *p, GBOX *gbox)
229{
230 if ( gbox->xmin > p->x ) gbox->xmin = p->x;
231 if ( gbox->ymin > p->y ) gbox->ymin = p->y;
232 if ( gbox->zmin > p->z ) gbox->zmin = p->z;
233 if ( gbox->xmax < p->x ) gbox->xmax = p->x;
234 if ( gbox->ymax < p->y ) gbox->ymax = p->y;
235 if ( gbox->zmax < p->z ) gbox->zmax = p->z;
236 return LW_SUCCESS;
237}
238
239int gbox_init_point3d(const POINT3D *p, GBOX *gbox)
240{
241 gbox->xmin = gbox->xmax = p->x;
242 gbox->ymin = gbox->ymax = p->y;
243 gbox->zmin = gbox->zmax = p->z;
244 return LW_SUCCESS;
245}
246
247int gbox_contains_point3d(const GBOX *gbox, const POINT3D *pt)
248{
249 if ( gbox->xmin > pt->x || gbox->ymin > pt->y || gbox->zmin > pt->z ||
250 gbox->xmax < pt->x || gbox->ymax < pt->y || gbox->zmax < pt->z )
251 {
252 return LW_FALSE;
253 }
254 return LW_TRUE;
255}
256
257int gbox_merge(const GBOX *new_box, GBOX *merge_box)
258{
259 assert(merge_box);
260
261 if ( FLAGS_GET_ZM(merge_box->flags) != FLAGS_GET_ZM(new_box->flags) )
262 return LW_FAILURE;
263
264 if ( new_box->xmin < merge_box->xmin) merge_box->xmin = new_box->xmin;
265 if ( new_box->ymin < merge_box->ymin) merge_box->ymin = new_box->ymin;
266 if ( new_box->xmax > merge_box->xmax) merge_box->xmax = new_box->xmax;
267 if ( new_box->ymax > merge_box->ymax) merge_box->ymax = new_box->ymax;
268
269 if ( FLAGS_GET_Z(merge_box->flags) || FLAGS_GET_GEODETIC(merge_box->flags) )
270 {
271 if ( new_box->zmin < merge_box->zmin) merge_box->zmin = new_box->zmin;
272 if ( new_box->zmax > merge_box->zmax) merge_box->zmax = new_box->zmax;
273 }
274 if ( FLAGS_GET_M(merge_box->flags) )
275 {
276 if ( new_box->mmin < merge_box->mmin) merge_box->mmin = new_box->mmin;
277 if ( new_box->mmax > merge_box->mmax) merge_box->mmax = new_box->mmax;
278 }
279
280 return LW_SUCCESS;
281}
282
283int gbox_overlaps(const GBOX *g1, const GBOX *g2)
284{
285
286 /* Make sure our boxes are consistent */
288 lwerror("gbox_overlaps: cannot compare geodetic and non-geodetic boxes");
289
290 /* Check X/Y first */
291 if ( g1->xmax < g2->xmin || g1->ymax < g2->ymin ||
292 g1->xmin > g2->xmax || g1->ymin > g2->ymax )
293 return LW_FALSE;
294
295 /* Deal with the geodetic case special: we only compare the geodetic boxes (x/y/z) */
296 /* Never the M dimension */
298 {
299 if ( g1->zmax < g2->zmin || g1->zmin > g2->zmax )
300 return LW_FALSE;
301 else
302 return LW_TRUE;
303 }
304
305 /* If both geodetic or both have Z, check Z */
306 if ( FLAGS_GET_Z(g1->flags) && FLAGS_GET_Z(g2->flags) )
307 {
308 if ( g1->zmax < g2->zmin || g1->zmin > g2->zmax )
309 return LW_FALSE;
310 }
311
312 /* If both have M, check M */
313 if ( FLAGS_GET_M(g1->flags) && FLAGS_GET_M(g2->flags) )
314 {
315 if ( g1->mmax < g2->mmin || g1->mmin > g2->mmax )
316 return LW_FALSE;
317 }
318
319 return LW_TRUE;
320}
321
322int
323gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
324{
325
326 /* Make sure our boxes are consistent */
328 lwerror("gbox_overlaps: cannot compare geodetic and non-geodetic boxes");
329
330 /* Check X/Y first */
331 if ( g1->xmax < g2->xmin || g1->ymax < g2->ymin ||
332 g1->xmin > g2->xmax || g1->ymin > g2->ymax )
333 return LW_FALSE;
334
335 return LW_TRUE;
336}
337
338int
339gbox_contains_2d(const GBOX *g1, const GBOX *g2)
340{
341 if ( ( g2->xmin < g1->xmin ) || ( g2->xmax > g1->xmax ) ||
342 ( g2->ymin < g1->ymin ) || ( g2->ymax > g1->ymax ) )
343 {
344 return LW_FALSE;
345 }
346 return LW_TRUE;
347}
348
349int
351{
352 if ( ( g->xmin <= p->x ) && ( g->xmax >= p->x ) &&
353 ( g->ymin <= p->y ) && ( g->ymax >= p->y ) )
354 {
355 return LW_TRUE;
356 }
357 return LW_FALSE;
358}
359
365{
366 const char *ptr = str;
367 char *nextptr;
368 char *gbox_start = strstr(str, "GBOX((");
369 GBOX *gbox = gbox_new(lwflags(0,0,1));
370 if ( ! gbox_start ) return NULL; /* No header found */
371 ptr += 6;
372 gbox->xmin = strtod(ptr, &nextptr);
373 if ( ptr == nextptr ) return NULL; /* No double found */
374 ptr = nextptr + 1;
375 gbox->ymin = strtod(ptr, &nextptr);
376 if ( ptr == nextptr ) return NULL; /* No double found */
377 ptr = nextptr + 1;
378 gbox->zmin = strtod(ptr, &nextptr);
379 if ( ptr == nextptr ) return NULL; /* No double found */
380 ptr = nextptr + 3;
381 gbox->xmax = strtod(ptr, &nextptr);
382 if ( ptr == nextptr ) return NULL; /* No double found */
383 ptr = nextptr + 1;
384 gbox->ymax = strtod(ptr, &nextptr);
385 if ( ptr == nextptr ) return NULL; /* No double found */
386 ptr = nextptr + 1;
387 gbox->zmax = strtod(ptr, &nextptr);
388 if ( ptr == nextptr ) return NULL; /* No double found */
389 return gbox;
390}
391
392char* gbox_to_string(const GBOX *gbox)
393{
394 const size_t sz = 138;
395 char *str = NULL;
396
397 if ( ! gbox )
398 return lwstrdup("NULL POINTER");
399
400 str = (char*)lwalloc(sz);
401
402 if ( FLAGS_GET_GEODETIC(gbox->flags) )
403 {
404 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->zmin, gbox->xmax, gbox->ymax, gbox->zmax);
405 return str;
406 }
407 if ( FLAGS_GET_Z(gbox->flags) && FLAGS_GET_M(gbox->flags) )
408 {
409 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->zmin, gbox->mmin, gbox->xmax, gbox->ymax, gbox->zmax, gbox->mmax);
410 return str;
411 }
412 if ( FLAGS_GET_Z(gbox->flags) )
413 {
414 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->zmin, gbox->xmax, gbox->ymax, gbox->zmax);
415 return str;
416 }
417 if ( FLAGS_GET_M(gbox->flags) )
418 {
419 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->mmin, gbox->xmax, gbox->ymax, gbox->mmax);
420 return str;
421 }
422 snprintf(str, sz, "GBOX((%.8g,%.8g),(%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->xmax, gbox->ymax);
423 return str;
424}
425
426GBOX* gbox_copy(const GBOX *box)
427{
428 GBOX *copy = (GBOX*)lwalloc(sizeof(GBOX));
429 memcpy(copy, box, sizeof(GBOX));
430 return copy;
431}
432
433void gbox_duplicate(const GBOX *original, GBOX *duplicate)
434{
435 assert(duplicate);
436 assert(original);
437 memcpy(duplicate, original, sizeof(GBOX));
438}
439
441{
442 if (FLAGS_GET_GEODETIC(flags))
443 return 6 * sizeof(float);
444 else
445 return 2 * FLAGS_NDIMS(flags) * sizeof(float);
446}
447
448
449/* ********************************************************************************
450** Compute cartesian bounding GBOX boxes from LWGEOM.
451*/
452
453int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
454{
455 POINT2D xmin, ymin, xmax, ymax;
456 POINT2D C;
457 int A2_side;
458 double radius_A;
459
460 LWDEBUG(2, "lw_arc_calculate_gbox_cartesian_2d called.");
461
462 radius_A = lw_arc_center(A1, A2, A3, &C);
463
464 /* Negative radius signals straight line, p1/p2/p3 are collinear */
465 if (radius_A < 0.0)
466 {
467 gbox->xmin = FP_MIN(A1->x, A3->x);
468 gbox->ymin = FP_MIN(A1->y, A3->y);
469 gbox->xmax = FP_MAX(A1->x, A3->x);
470 gbox->ymax = FP_MAX(A1->y, A3->y);
471 return LW_SUCCESS;
472 }
473
474 /* Matched start/end points imply circle */
475 if ( A1->x == A3->x && A1->y == A3->y )
476 {
477 gbox->xmin = C.x - radius_A;
478 gbox->ymin = C.y - radius_A;
479 gbox->xmax = C.x + radius_A;
480 gbox->ymax = C.y + radius_A;
481 return LW_SUCCESS;
482 }
483
484 /* First approximation, bounds of start/end points */
485 gbox->xmin = FP_MIN(A1->x, A3->x);
486 gbox->ymin = FP_MIN(A1->y, A3->y);
487 gbox->xmax = FP_MAX(A1->x, A3->x);
488 gbox->ymax = FP_MAX(A1->y, A3->y);
489
490 /* Create points for the possible extrema */
491 xmin.x = C.x - radius_A;
492 xmin.y = C.y;
493 ymin.x = C.x;
494 ymin.y = C.y - radius_A;
495 xmax.x = C.x + radius_A;
496 xmax.y = C.y;
497 ymax.x = C.x;
498 ymax.y = C.y + radius_A;
499
500 /* Divide the circle into two parts, one on each side of a line
501 joining p1 and p3. The circle extrema on the same side of that line
502 as p2 is on, are also the extrema of the bbox. */
503
504 A2_side = lw_segment_side(A1, A3, A2);
505
506 if ( A2_side == lw_segment_side(A1, A3, &xmin) )
507 gbox->xmin = xmin.x;
508
509 if ( A2_side == lw_segment_side(A1, A3, &ymin) )
510 gbox->ymin = ymin.y;
511
512 if ( A2_side == lw_segment_side(A1, A3, &xmax) )
513 gbox->xmax = xmax.x;
514
515 if ( A2_side == lw_segment_side(A1, A3, &ymax) )
516 gbox->ymax = ymax.y;
517
518 return LW_SUCCESS;
519}
520
521
522static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
523{
524 int rv;
525
526 LWDEBUG(2, "lw_arc_calculate_gbox_cartesian called.");
527
528 rv = lw_arc_calculate_gbox_cartesian_2d((POINT2D*)p1, (POINT2D*)p2, (POINT2D*)p3, gbox);
529 gbox->zmin = FP_MIN(p1->z, p3->z);
530 gbox->mmin = FP_MIN(p1->m, p3->m);
531 gbox->zmax = FP_MAX(p1->z, p3->z);
532 gbox->mmax = FP_MAX(p1->m, p3->m);
533 return rv;
534}
535
536static void
538{
539 const POINT2D *p = getPoint2d_cp(pa, 0);
540
541 gbox->xmax = gbox->xmin = p->x;
542 gbox->ymax = gbox->ymin = p->y;
543
544 for (uint32_t i = 1; i < pa->npoints; i++)
545 {
546 p = getPoint2d_cp(pa, i);
547 gbox->xmin = FP_MIN(gbox->xmin, p->x);
548 gbox->xmax = FP_MAX(gbox->xmax, p->x);
549 gbox->ymin = FP_MIN(gbox->ymin, p->y);
550 gbox->ymax = FP_MAX(gbox->ymax, p->y);
551 }
552}
553
554/* Works with X/Y/Z. Needs to be adjusted after if X/Y/M was required */
555static void
557{
558 const POINT3D *p = getPoint3d_cp(pa, 0);
559
560 gbox->xmax = gbox->xmin = p->x;
561 gbox->ymax = gbox->ymin = p->y;
562 gbox->zmax = gbox->zmin = p->z;
563
564 for (uint32_t i = 1; i < pa->npoints; i++)
565 {
566 p = getPoint3d_cp(pa, i);
567 gbox->xmin = FP_MIN(gbox->xmin, p->x);
568 gbox->xmax = FP_MAX(gbox->xmax, p->x);
569 gbox->ymin = FP_MIN(gbox->ymin, p->y);
570 gbox->ymax = FP_MAX(gbox->ymax, p->y);
571 gbox->zmin = FP_MIN(gbox->zmin, p->z);
572 gbox->zmax = FP_MAX(gbox->zmax, p->z);
573 }
574}
575
576static void
578{
579 const POINT4D *p = getPoint4d_cp(pa, 0);
580
581 gbox->xmax = gbox->xmin = p->x;
582 gbox->ymax = gbox->ymin = p->y;
583 gbox->zmax = gbox->zmin = p->z;
584 gbox->mmax = gbox->mmin = p->m;
585
586 for (uint32_t i = 1; i < pa->npoints; i++)
587 {
588 p = getPoint4d_cp(pa, i);
589 gbox->xmin = FP_MIN(gbox->xmin, p->x);
590 gbox->xmax = FP_MAX(gbox->xmax, p->x);
591 gbox->ymin = FP_MIN(gbox->ymin, p->y);
592 gbox->ymax = FP_MAX(gbox->ymax, p->y);
593 gbox->zmin = FP_MIN(gbox->zmin, p->z);
594 gbox->zmax = FP_MAX(gbox->zmax, p->z);
595 gbox->mmin = FP_MIN(gbox->mmin, p->m);
596 gbox->mmax = FP_MAX(gbox->mmax, p->m);
597 }
598}
599
600int
602{
603 if (!pa || pa->npoints == 0)
604 return LW_FAILURE;
605 if (!gbox)
606 return LW_FAILURE;
607
608 int has_z = FLAGS_GET_Z(pa->flags);
609 int has_m = FLAGS_GET_M(pa->flags);
610 gbox->flags = lwflags(has_z, has_m, 0);
611 LWDEBUGF(4, "ptarray_calculate_gbox Z: %d M: %d", has_z, has_m);
612 int coordinates = 2 + has_z + has_m;
613
614 switch (coordinates)
615 {
616 case 2:
617 {
619 break;
620 }
621 case 3:
622 {
623 if (has_z)
624 {
626 }
627 else
628 {
629 double zmin = gbox->zmin;
630 double zmax = gbox->zmax;
632 gbox->mmin = gbox->zmin;
633 gbox->mmax = gbox->zmax;
634 gbox->zmin = zmin;
635 gbox->zmax = zmax;
636 }
637 break;
638 }
639 default:
640 {
642 break;
643 }
644 }
645 return LW_SUCCESS;
646}
647
649{
650 GBOX tmp;
651 POINT4D p1, p2, p3;
652 uint32_t i;
653
654 if (!curve) return LW_FAILURE;
655 if (curve->points->npoints < 3) return LW_FAILURE;
656
657 tmp.flags =
658 lwflags(FLAGS_GET_Z(curve->flags), FLAGS_GET_M(curve->flags), 0);
659
660 /* Initialize */
661 gbox->xmin = gbox->ymin = gbox->zmin = gbox->mmin = FLT_MAX;
662 gbox->xmax = gbox->ymax = gbox->zmax = gbox->mmax = -1*FLT_MAX;
663
664 for ( i = 2; i < curve->points->npoints; i += 2 )
665 {
666 getPoint4d_p(curve->points, i-2, &p1);
667 getPoint4d_p(curve->points, i-1, &p2);
668 getPoint4d_p(curve->points, i, &p3);
669
670 if (lw_arc_calculate_gbox_cartesian(&p1, &p2, &p3, &tmp) == LW_FAILURE)
671 continue;
672
673 gbox_merge(&tmp, gbox);
674 }
675
676 return LW_SUCCESS;
677}
678
680{
681 if ( ! point ) return LW_FAILURE;
682 return ptarray_calculate_gbox_cartesian( point->point, gbox );
683}
684
686{
687 if ( ! line ) return LW_FAILURE;
688 return ptarray_calculate_gbox_cartesian( line->points, gbox );
689}
690
692{
693 if ( ! triangle ) return LW_FAILURE;
694 return ptarray_calculate_gbox_cartesian( triangle->points, gbox );
695}
696
698{
699 if ( ! poly ) return LW_FAILURE;
700 if ( poly->nrings == 0 ) return LW_FAILURE;
701 /* Just need to check outer ring */
702 return ptarray_calculate_gbox_cartesian( poly->rings[0], gbox );
703}
704
706{
707 GBOX subbox;
708 uint32_t i;
709 int result = LW_FAILURE;
710 int first = LW_TRUE;
711 assert(coll);
712 if ( (coll->ngeoms == 0) || !gbox)
713 return LW_FAILURE;
714
715 subbox.flags = coll->flags;
716
717 for ( i = 0; i < coll->ngeoms; i++ )
718 {
719 if ( lwgeom_calculate_gbox_cartesian((LWGEOM*)(coll->geoms[i]), &subbox) == LW_SUCCESS )
720 {
721 /* Keep a copy of the sub-bounding box for later
722 if ( coll->geoms[i]->bbox )
723 lwfree(coll->geoms[i]->bbox);
724 coll->geoms[i]->bbox = gbox_copy(&subbox); */
725 if ( first )
726 {
727 gbox_duplicate(&subbox, gbox);
728 first = LW_FALSE;
729 }
730 else
731 {
732 gbox_merge(&subbox, gbox);
733 }
734 result = LW_SUCCESS;
735 }
736 }
737 return result;
738}
739
741{
742 if ( ! lwgeom ) return LW_FAILURE;
743 LWDEBUGF(4, "lwgeom_calculate_gbox got type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
744
745 switch (lwgeom->type)
746 {
747 case POINTTYPE:
748 return lwpoint_calculate_gbox_cartesian((LWPOINT *)lwgeom, gbox);
749 case LINETYPE:
750 return lwline_calculate_gbox_cartesian((LWLINE *)lwgeom, gbox);
751 case CIRCSTRINGTYPE:
753 case POLYGONTYPE:
754 return lwpoly_calculate_gbox_cartesian((LWPOLY *)lwgeom, gbox);
755 case TRIANGLETYPE:
756 return lwtriangle_calculate_gbox_cartesian((LWTRIANGLE *)lwgeom, gbox);
757 case COMPOUNDTYPE:
758 case CURVEPOLYTYPE:
759 case MULTIPOINTTYPE:
760 case MULTILINETYPE:
761 case MULTICURVETYPE:
762 case MULTIPOLYGONTYPE:
763 case MULTISURFACETYPE:
765 case TINTYPE:
766 case COLLECTIONTYPE:
768 }
769 /* Never get here, please. */
770 lwerror("unsupported type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
771 return LW_FAILURE;
772}
773
775{
776 gbox->xmin = next_float_down(gbox->xmin);
777 gbox->xmax = next_float_up(gbox->xmax);
778
779 gbox->ymin = next_float_down(gbox->ymin);
780 gbox->ymax = next_float_up(gbox->ymax);
781
782 if ( FLAGS_GET_M(gbox->flags) )
783 {
784 gbox->mmin = next_float_down(gbox->mmin);
785 gbox->mmax = next_float_up(gbox->mmax);
786 }
787
788 if ( FLAGS_GET_Z(gbox->flags) )
789 {
790 gbox->zmin = next_float_down(gbox->zmin);
791 gbox->zmax = next_float_up(gbox->zmax);
792 }
793}
794
795inline static uint64_t
796uint64_interleave_2(uint64_t x, uint64_t y)
797{
798 x = (x | (x << 16)) & 0x0000FFFF0000FFFFULL;
799 x = (x | (x << 8)) & 0x00FF00FF00FF00FFULL;
800 x = (x | (x << 4)) & 0x0F0F0F0F0F0F0F0FULL;
801 x = (x | (x << 2)) & 0x3333333333333333ULL;
802 x = (x | (x << 1)) & 0x5555555555555555ULL;
803
804 y = (y | (y << 16)) & 0x0000FFFF0000FFFFULL;
805 y = (y | (y << 8)) & 0x00FF00FF00FF00FFULL;
806 y = (y | (y << 4)) & 0x0F0F0F0F0F0F0F0FULL;
807 y = (y | (y << 2)) & 0x3333333333333333ULL;
808 y = (y | (y << 1)) & 0x5555555555555555ULL;
809
810 return x | (y << 1);
811}
812
813/* Based on https://github.com/rawrunprotected/hilbert_curves Public Domain code */
814inline static uint64_t
815uint32_hilbert(uint32_t px, uint32_t py)
816{
817 uint64_t x = px;
818 uint64_t y = py;
819
820 uint64_t A, B, C, D;
821
822 // Initial prefix scan round, prime with x and y
823 {
824 uint64_t a = x ^ y;
825 uint64_t b = 0xFFFFFFFFULL ^ a;
826 uint64_t c = 0xFFFFFFFFULL ^ (x | y);
827 uint64_t d = x & (y ^ 0xFFFFFFFFULL);
828
829 A = a | (b >> 1);
830 B = (a >> 1) ^ a;
831 C = ((c >> 1) ^ (b & (d >> 1))) ^ c;
832 D = ((a & (c >> 1)) ^ (d >> 1)) ^ d;
833 }
834
835 {
836 uint64_t a = A;
837 uint64_t b = B;
838 uint64_t c = C;
839 uint64_t d = D;
840
841 A = ((a & (a >> 2)) ^ (b & (b >> 2)));
842 B = ((a & (b >> 2)) ^ (b & ((a ^ b) >> 2)));
843 C ^= ((a & (c >> 2)) ^ (b & (d >> 2)));
844 D ^= ((b & (c >> 2)) ^ ((a ^ b) & (d >> 2)));
845 }
846
847 {
848 uint64_t a = A;
849 uint64_t b = B;
850 uint64_t c = C;
851 uint64_t d = D;
852
853 A = ((a & (a >> 4)) ^ (b & (b >> 4)));
854 B = ((a & (b >> 4)) ^ (b & ((a ^ b) >> 4)));
855 C ^= ((a & (c >> 4)) ^ (b & (d >> 4)));
856 D ^= ((b & (c >> 4)) ^ ((a ^ b) & (d >> 4)));
857 }
858
859 {
860 uint64_t a = A;
861 uint64_t b = B;
862 uint64_t c = C;
863 uint64_t d = D;
864
865 A = ((a & (a >> 8)) ^ (b & (b >> 8)));
866 B = ((a & (b >> 8)) ^ (b & ((a ^ b) >> 8)));
867 C ^= ((a & (c >> 8)) ^ (b & (d >> 8)));
868 D ^= ((b & (c >> 8)) ^ ((a ^ b) & (d >> 8)));
869 }
870
871 {
872 uint64_t a = A;
873 uint64_t b = B;
874 uint64_t c = C;
875 uint64_t d = D;
876
877 C ^= ((a & (c >> 16)) ^ (b & (d >> 16)));
878 D ^= ((b & (c >> 16)) ^ ((a ^ b) & (d >> 16)));
879 }
880
881 // Undo transformation prefix scan
882 uint64_t a = C ^ (C >> 1);
883 uint64_t b = D ^ (D >> 1);
884
885 // Recover index bits
886 uint64_t i0 = x ^ y;
887 uint64_t i1 = b | (0xFFFFFFFFULL ^ (i0 | a));
888
889 return uint64_interleave_2(i0, i1);
890}
891
892uint64_t
893gbox_get_sortable_hash(const GBOX *g, const int32_t srid)
894{
895 union floatuint {
896 uint32_t u;
897 float f;
898 };
899
900 union floatuint x, y;
901
902 /*
903 * Since in theory the bitwise representation of an IEEE
904 * float is sortable (exponents come before mantissa, etc)
905 * we just copy the bits directly into an int and then
906 * interleave those ints.
907 */
909 {
911 POINT3D p;
912 p.x = (g->xmax + g->xmin) / 2.0;
913 p.y = (g->ymax + g->ymin) / 2.0;
914 p.z = (g->zmax + g->zmin) / 2.0;
915 normalize(&p);
916 cart2geog(&p, &gpt);
917 /* We know range for geography, so build the curve taking it into account */
918 x.f = 1.5 + gpt.lon / 512.0;
919 y.f = 1.5 + gpt.lat / 256.0;
920 }
921 else
922 {
923 x.f = (g->xmax + g->xmin) / 2;
924 y.f = (g->ymax + g->ymin) / 2;
925 /*
926 * Tweak for popular SRID values: push floating point values into 1..2 range,
927 * a region where exponent is constant and thus Hilbert curve
928 * doesn't have compression artifact when X or Y value is close to 0.
929 * If someone has out of bounds value it will still expose the arifact but not crash.
930 * TODO: reconsider when we will have machinery to properly get bounds by SRID.
931 */
932 if (srid == 3857 || srid == 3395)
933 {
934 x.f = 1.5 + x.f / 67108864.0;
935 y.f = 1.5 + y.f / 67108864.0;
936 }
937 else if (srid == 4326)
938 {
939 x.f = 1.5 + x.f / 512.0;
940 y.f = 1.5 + y.f / 256.0;
941 }
942 }
943
944 return uint32_hilbert(y.u, x.u);
945}
GBOX * gbox_from_string(const char *str)
Warning, this function is only good for x/y/z boxes, used in unit testing of geodetic box generation.
Definition gbox.c:364
int gbox_merge(const GBOX *new_box, GBOX *merge_box)
Update the merged GBOX to be large enough to include itself and the new box.
Definition gbox.c:257
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition gbox.c:164
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
Definition gbox.c:135
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_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition gbox.c:433
GBOX * gbox_new(lwflags_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition gbox.c:32
int gbox_same_2d(const GBOX *g1, const GBOX *g2)
Check if 2 given GBOX are the same in x and y.
Definition gbox.c:179
GBOX * box3d_to_gbox(const BOX3D *b3d)
Definition gbox.c:80
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition gbox.c:97
int gbox_contains_point3d(const GBOX *gbox, const POINT3D *pt)
Return true if the point is inside the gbox.
Definition gbox.c:247
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
Definition gbox.c:392
static void ptarray_calculate_gbox_cartesian_2d(const POINTARRAY *pa, GBOX *gbox)
Definition gbox.c:537
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition gbox.c:774
static uint64_t uint32_hilbert(uint32_t px, uint32_t py)
Definition gbox.c:815
static int lwpoint_calculate_gbox_cartesian(LWPOINT *point, GBOX *gbox)
Definition gbox.c:679
static int lwpoly_calculate_gbox_cartesian(LWPOLY *poly, GBOX *gbox)
Definition gbox.c:697
static int lwtriangle_calculate_gbox_cartesian(LWTRIANGLE *triangle, GBOX *gbox)
Definition gbox.c:691
int gbox_merge_point3d(const POINT3D *p, GBOX *gbox)
Update the GBOX to be large enough to include itself and the new point.
Definition gbox.c:228
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition gbox.c:740
int gbox_overlaps(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps, LW_FALSE otherwise.
Definition gbox.c:283
int gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps on the 2d plane, LW_FALSE otherwise.
Definition gbox.c:323
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
Definition gbox.c:350
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition gbox.c:40
void gbox_expand_xyzm(GBOX *g, double dx, double dy, double dz, double dm)
Move the box minimums down and the maximums up by the distances provided.
Definition gbox.c:115
static void ptarray_calculate_gbox_cartesian_3d(const POINTARRAY *pa, GBOX *gbox)
Definition gbox.c:556
static int lwline_calculate_gbox_cartesian(LWLINE *line, GBOX *gbox)
Definition gbox.c:685
int gbox_init_point3d(const POINT3D *p, GBOX *gbox)
Initialize a GBOX using the values of the point.
Definition gbox.c:239
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
Definition gbox.c:601
uint64_t gbox_get_sortable_hash(const GBOX *g, const int32_t srid)
Return a sortable key based on the center point of the GBOX.
Definition gbox.c:893
static int lwcircstring_calculate_gbox_cartesian(LWCIRCSTRING *curve, GBOX *gbox)
Definition gbox.c:648
GBOX * gbox_clone(const GBOX *gbox)
Definition gbox.c:45
static int lwcollection_calculate_gbox_cartesian(LWCOLLECTION *coll, GBOX *gbox)
Definition gbox.c:705
static uint64_t uint64_interleave_2(uint64_t x, uint64_t y)
Definition gbox.c:796
BOX3D * box3d_from_gbox(const GBOX *gbox)
Definition gbox.c:53
static void ptarray_calculate_gbox_cartesian_4d(const POINTARRAY *pa, GBOX *gbox)
Definition gbox.c:577
int gbox_same_2d_float(const GBOX *g1, const GBOX *g2)
Check if two given GBOX are the same in x and y, or would round to the same GBOX in x and if serializ...
Definition gbox.c:187
int gbox_is_valid(const GBOX *gbox)
Return false if any of the dimensions is NaN or infinite.
Definition gbox.c:197
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition gbox.c:426
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
Definition gbox.c:339
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition gbox.c:453
static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
Definition gbox.c:522
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
#define LW_FAILURE
Definition liblwgeom.h:110
#define CURVEPOLYTYPE
Definition liblwgeom.h:125
#define MULTILINETYPE
Definition liblwgeom.h:120
#define MULTISURFACETYPE
Definition liblwgeom.h:127
#define LINETYPE
Definition liblwgeom.h:117
#define LW_SUCCESS
Definition liblwgeom.h:111
uint16_t lwflags_t
Definition liblwgeom.h:313
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
#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
#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
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:194
#define MULTICURVETYPE
Definition liblwgeom.h:126
#define TRIANGLETYPE
Definition liblwgeom.h:129
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 SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:229
float next_float_down(double d)
Definition lwgeom_api.c:54
#define FLAGS_GET_GEODETIC(flags)
Definition liblwgeom.h:182
#define FP_MAX(A, B)
#define FP_MIN(A, B)
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
char * lwstrdup(const char *a)
Definition lwutil.c:248
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition lwalgorithm.c:65
void normalize(POINT3D *p)
Normalize to a unit vector.
Definition lwgeodetic.c:615
void cart2geog(const POINT3D *p, GEOGRAPHIC_POINT *g)
Convert cartesian coordinates on unit sphere to spherical coordinates.
Definition lwgeodetic.c:414
#define str(s)
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:83
#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 const POINT3D * getPoint3d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:103
static const POINT4D * getPoint4d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:115
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:91
double xmax
Definition liblwgeom.h:326
double zmin
Definition liblwgeom.h:325
double ymax
Definition liblwgeom.h:326
double ymin
Definition liblwgeom.h:325
double zmax
Definition liblwgeom.h:326
double xmin
Definition liblwgeom.h:325
int32_t srid
Definition liblwgeom.h:327
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
Point in spherical coordinates on the world.
Definition lwgeodetic.h:54
lwflags_t flags
Definition liblwgeom.h:495
POINTARRAY * points
Definition liblwgeom.h:493
lwflags_t flags
Definition liblwgeom.h:563
uint32_t ngeoms
Definition liblwgeom.h:566
LWGEOM ** geoms
Definition liblwgeom.h:561
uint8_t type
Definition liblwgeom.h:448
POINTARRAY * points
Definition liblwgeom.h:469
POINTARRAY * point
Definition liblwgeom.h:457
POINTARRAY ** rings
Definition liblwgeom.h:505
uint32_t nrings
Definition liblwgeom.h:510
POINTARRAY * points
Definition liblwgeom.h:481
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376
double z
Definition liblwgeom.h:388
double x
Definition liblwgeom.h:388
double y
Definition liblwgeom.h:388
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