PostGIS 3.7.0dev-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
349
350int
351gbox_within_2d(const GBOX *g1, const GBOX *g2)
352{
353 if ( ( g1->xmin < g2->xmin ) || ( g1->xmax > g2->xmax ) ||
354 ( g1->ymin < g2->ymin ) || ( g1->ymax > g2->ymax ) )
355 {
356 return LW_FALSE;
357 }
358 return LW_TRUE;
359}
360
361int
363{
364 if ( ( g->xmin <= p->x ) && ( g->xmax >= p->x ) &&
365 ( g->ymin <= p->y ) && ( g->ymax >= p->y ) )
366 {
367 return LW_TRUE;
368 }
369 return LW_FALSE;
370}
371
377{
378 const char *ptr = str;
379 char *nextptr;
380 char *gbox_start = strstr(str, "GBOX((");
381 GBOX *gbox = gbox_new(lwflags(0,0,1));
382 if ( ! gbox_start ) return NULL; /* No header found */
383 ptr += 6;
384 gbox->xmin = strtod(ptr, &nextptr);
385 if ( ptr == nextptr ) return NULL; /* No double found */
386 ptr = nextptr + 1;
387 gbox->ymin = strtod(ptr, &nextptr);
388 if ( ptr == nextptr ) return NULL; /* No double found */
389 ptr = nextptr + 1;
390 gbox->zmin = strtod(ptr, &nextptr);
391 if ( ptr == nextptr ) return NULL; /* No double found */
392 ptr = nextptr + 3;
393 gbox->xmax = strtod(ptr, &nextptr);
394 if ( ptr == nextptr ) return NULL; /* No double found */
395 ptr = nextptr + 1;
396 gbox->ymax = strtod(ptr, &nextptr);
397 if ( ptr == nextptr ) return NULL; /* No double found */
398 ptr = nextptr + 1;
399 gbox->zmax = strtod(ptr, &nextptr);
400 if ( ptr == nextptr ) return NULL; /* No double found */
401 return gbox;
402}
403
404char* gbox_to_string(const GBOX *gbox)
405{
406 const size_t sz = 138;
407 char *str = NULL;
408
409 if ( ! gbox )
410 return lwstrdup("NULL POINTER");
411
412 str = (char*)lwalloc(sz);
413
414 if ( FLAGS_GET_GEODETIC(gbox->flags) )
415 {
416 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->zmin, gbox->xmax, gbox->ymax, gbox->zmax);
417 return str;
418 }
419 if ( FLAGS_GET_Z(gbox->flags) && FLAGS_GET_M(gbox->flags) )
420 {
421 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);
422 return str;
423 }
424 if ( FLAGS_GET_Z(gbox->flags) )
425 {
426 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->zmin, gbox->xmax, gbox->ymax, gbox->zmax);
427 return str;
428 }
429 if ( FLAGS_GET_M(gbox->flags) )
430 {
431 snprintf(str, sz, "GBOX((%.8g,%.8g,%.8g),(%.8g,%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->mmin, gbox->xmax, gbox->ymax, gbox->mmax);
432 return str;
433 }
434 snprintf(str, sz, "GBOX((%.8g,%.8g),(%.8g,%.8g))", gbox->xmin, gbox->ymin, gbox->xmax, gbox->ymax);
435 return str;
436}
437
438GBOX* gbox_copy(const GBOX *box)
439{
440 GBOX *copy = (GBOX*)lwalloc(sizeof(GBOX));
441 memcpy(copy, box, sizeof(GBOX));
442 return copy;
443}
444
445void gbox_duplicate(const GBOX *original, GBOX *duplicate)
446{
447 assert(duplicate);
448 assert(original);
449 memcpy(duplicate, original, sizeof(GBOX));
450}
451
453{
454 if (FLAGS_GET_GEODETIC(flags))
455 return 6 * sizeof(float);
456 else
457 return 2 * FLAGS_NDIMS(flags) * sizeof(float);
458}
459
460
461/* ********************************************************************************
462** Compute cartesian bounding GBOX boxes from LWGEOM.
463*/
464
465int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
466{
467 POINT2D xmin, ymin, xmax, ymax;
468 POINT2D C;
469 int A2_side;
470 double radius_A;
471
472 LWDEBUG(2, "lw_arc_calculate_gbox_cartesian_2d called.");
473
474 radius_A = lw_arc_center(A1, A2, A3, &C);
475
476 /* Negative radius signals straight line, p1/p2/p3 are collinear */
477 if (radius_A < 0.0)
478 {
479 gbox->xmin = FP_MIN(A1->x, A3->x);
480 gbox->ymin = FP_MIN(A1->y, A3->y);
481 gbox->xmax = FP_MAX(A1->x, A3->x);
482 gbox->ymax = FP_MAX(A1->y, A3->y);
483 return LW_SUCCESS;
484 }
485
486 /* Matched start/end points imply circle */
487 if ( A1->x == A3->x && A1->y == A3->y )
488 {
489 gbox->xmin = C.x - radius_A;
490 gbox->ymin = C.y - radius_A;
491 gbox->xmax = C.x + radius_A;
492 gbox->ymax = C.y + radius_A;
493 return LW_SUCCESS;
494 }
495
496 /* First approximation, bounds of start/end points */
497 gbox->xmin = FP_MIN(A1->x, A3->x);
498 gbox->ymin = FP_MIN(A1->y, A3->y);
499 gbox->xmax = FP_MAX(A1->x, A3->x);
500 gbox->ymax = FP_MAX(A1->y, A3->y);
501
502 /* Create points for the possible extrema */
503 xmin.x = C.x - radius_A;
504 xmin.y = C.y;
505 ymin.x = C.x;
506 ymin.y = C.y - radius_A;
507 xmax.x = C.x + radius_A;
508 xmax.y = C.y;
509 ymax.x = C.x;
510 ymax.y = C.y + radius_A;
511
512 /* Divide the circle into two parts, one on each side of a line
513 joining p1 and p3. The circle extrema on the same side of that line
514 as p2 is on, are also the extrema of the bbox. */
515
516 A2_side = lw_segment_side(A1, A3, A2);
517
518 if ( A2_side == lw_segment_side(A1, A3, &xmin) )
519 gbox->xmin = xmin.x;
520
521 if ( A2_side == lw_segment_side(A1, A3, &ymin) )
522 gbox->ymin = ymin.y;
523
524 if ( A2_side == lw_segment_side(A1, A3, &xmax) )
525 gbox->xmax = xmax.x;
526
527 if ( A2_side == lw_segment_side(A1, A3, &ymax) )
528 gbox->ymax = ymax.y;
529
530 return LW_SUCCESS;
531}
532
533
534static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
535{
536 int rv;
537
538 LWDEBUG(2, "lw_arc_calculate_gbox_cartesian called.");
539
540 rv = lw_arc_calculate_gbox_cartesian_2d((POINT2D*)p1, (POINT2D*)p2, (POINT2D*)p3, gbox);
541 gbox->zmin = FP_MIN(p1->z, p3->z);
542 gbox->mmin = FP_MIN(p1->m, p3->m);
543 gbox->zmax = FP_MAX(p1->z, p3->z);
544 gbox->mmax = FP_MAX(p1->m, p3->m);
545 return rv;
546}
547
548static void
550{
551 const POINT2D *p = getPoint2d_cp(pa, 0);
552
553 gbox->xmax = gbox->xmin = p->x;
554 gbox->ymax = gbox->ymin = p->y;
555
556 for (uint32_t i = 1; i < pa->npoints; i++)
557 {
558 p = getPoint2d_cp(pa, i);
559 gbox->xmin = FP_MIN(gbox->xmin, p->x);
560 gbox->xmax = FP_MAX(gbox->xmax, p->x);
561 gbox->ymin = FP_MIN(gbox->ymin, p->y);
562 gbox->ymax = FP_MAX(gbox->ymax, p->y);
563 }
564}
565
566/* Works with X/Y/Z. Needs to be adjusted after if X/Y/M was required */
567static void
569{
570 const POINT3D *p = getPoint3d_cp(pa, 0);
571
572 gbox->xmax = gbox->xmin = p->x;
573 gbox->ymax = gbox->ymin = p->y;
574 gbox->zmax = gbox->zmin = p->z;
575
576 for (uint32_t i = 1; i < pa->npoints; i++)
577 {
578 p = getPoint3d_cp(pa, i);
579 gbox->xmin = FP_MIN(gbox->xmin, p->x);
580 gbox->xmax = FP_MAX(gbox->xmax, p->x);
581 gbox->ymin = FP_MIN(gbox->ymin, p->y);
582 gbox->ymax = FP_MAX(gbox->ymax, p->y);
583 gbox->zmin = FP_MIN(gbox->zmin, p->z);
584 gbox->zmax = FP_MAX(gbox->zmax, p->z);
585 }
586}
587
588static void
590{
591 const POINT4D *p = getPoint4d_cp(pa, 0);
592
593 gbox->xmax = gbox->xmin = p->x;
594 gbox->ymax = gbox->ymin = p->y;
595 gbox->zmax = gbox->zmin = p->z;
596 gbox->mmax = gbox->mmin = p->m;
597
598 for (uint32_t i = 1; i < pa->npoints; i++)
599 {
600 p = getPoint4d_cp(pa, i);
601 gbox->xmin = FP_MIN(gbox->xmin, p->x);
602 gbox->xmax = FP_MAX(gbox->xmax, p->x);
603 gbox->ymin = FP_MIN(gbox->ymin, p->y);
604 gbox->ymax = FP_MAX(gbox->ymax, p->y);
605 gbox->zmin = FP_MIN(gbox->zmin, p->z);
606 gbox->zmax = FP_MAX(gbox->zmax, p->z);
607 gbox->mmin = FP_MIN(gbox->mmin, p->m);
608 gbox->mmax = FP_MAX(gbox->mmax, p->m);
609 }
610}
611
612int
614{
615 if (!pa || pa->npoints == 0)
616 return LW_FAILURE;
617 if (!gbox)
618 return LW_FAILURE;
619
620 int has_z = FLAGS_GET_Z(pa->flags);
621 int has_m = FLAGS_GET_M(pa->flags);
622 gbox->flags = lwflags(has_z, has_m, 0);
623 LWDEBUGF(4, "ptarray_calculate_gbox Z: %d M: %d", has_z, has_m);
624 int coordinates = 2 + has_z + has_m;
625
626 switch (coordinates)
627 {
628 case 2:
629 {
631 break;
632 }
633 case 3:
634 {
635 if (has_z)
636 {
638 }
639 else
640 {
641 double zmin = gbox->zmin;
642 double zmax = gbox->zmax;
644 gbox->mmin = gbox->zmin;
645 gbox->mmax = gbox->zmax;
646 gbox->zmin = zmin;
647 gbox->zmax = zmax;
648 }
649 break;
650 }
651 default:
652 {
654 break;
655 }
656 }
657 return LW_SUCCESS;
658}
659
661{
662 GBOX tmp = {0};
663 POINT4D p1, p2, p3;
664 uint32_t i;
665
666 if (!curve) return LW_FAILURE;
667 if (curve->points->npoints < 3) return LW_FAILURE;
668
669 tmp.flags =
670 lwflags(FLAGS_GET_Z(curve->flags), FLAGS_GET_M(curve->flags), 0);
671
672 /* Initialize */
673 gbox->xmin = gbox->ymin = gbox->zmin = gbox->mmin = FLT_MAX;
674 gbox->xmax = gbox->ymax = gbox->zmax = gbox->mmax = -1*FLT_MAX;
675
676 for ( i = 2; i < curve->points->npoints; i += 2 )
677 {
678 getPoint4d_p(curve->points, i-2, &p1);
679 getPoint4d_p(curve->points, i-1, &p2);
680 getPoint4d_p(curve->points, i, &p3);
681
682 if (lw_arc_calculate_gbox_cartesian(&p1, &p2, &p3, &tmp) == LW_FAILURE)
683 continue;
684
685 gbox_merge(&tmp, gbox);
686 }
687
688 return LW_SUCCESS;
689}
690
692{
693 if ( ! point ) return LW_FAILURE;
694 return ptarray_calculate_gbox_cartesian( point->point, gbox );
695}
696
698{
699 if ( ! line ) return LW_FAILURE;
700 return ptarray_calculate_gbox_cartesian( line->points, gbox );
701}
702
704{
705 if ( ! triangle ) return LW_FAILURE;
706 return ptarray_calculate_gbox_cartesian( triangle->points, gbox );
707}
708
710{
711 if ( ! poly ) return LW_FAILURE;
712 if ( poly->nrings == 0 ) return LW_FAILURE;
713 /* Just need to check outer ring */
714 return ptarray_calculate_gbox_cartesian( poly->rings[0], gbox );
715}
716
718{
719 GBOX subbox = {0};
720 uint32_t i;
721 int result = LW_FAILURE;
722 int first = LW_TRUE;
723 assert(coll);
724 if ( (coll->ngeoms == 0) || !gbox)
725 return LW_FAILURE;
726
727 subbox.flags = coll->flags;
728
729 for ( i = 0; i < coll->ngeoms; i++ )
730 {
731 if ( lwgeom_calculate_gbox_cartesian((LWGEOM*)(coll->geoms[i]), &subbox) == LW_SUCCESS )
732 {
733 /* Keep a copy of the sub-bounding box for later
734 if ( coll->geoms[i]->bbox )
735 lwfree(coll->geoms[i]->bbox);
736 coll->geoms[i]->bbox = gbox_copy(&subbox); */
737 if ( first )
738 {
739 gbox_duplicate(&subbox, gbox);
740 first = LW_FALSE;
741 }
742 else
743 {
744 gbox_merge(&subbox, gbox);
745 }
747 }
748 }
749 return result;
750}
751
753{
754 if ( ! lwgeom ) return LW_FAILURE;
755 LWDEBUGF(4, "lwgeom_calculate_gbox got type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
756
757 switch (lwgeom->type)
758 {
759 case POINTTYPE:
760 return lwpoint_calculate_gbox_cartesian((LWPOINT *)lwgeom, gbox);
761 case LINETYPE:
762 return lwline_calculate_gbox_cartesian((LWLINE *)lwgeom, gbox);
763 case CIRCSTRINGTYPE:
765 case POLYGONTYPE:
766 return lwpoly_calculate_gbox_cartesian((LWPOLY *)lwgeom, gbox);
767 case TRIANGLETYPE:
768 return lwtriangle_calculate_gbox_cartesian((LWTRIANGLE *)lwgeom, gbox);
769 case COMPOUNDTYPE:
770 case CURVEPOLYTYPE:
771 case MULTIPOINTTYPE:
772 case MULTILINETYPE:
773 case MULTICURVETYPE:
774 case MULTIPOLYGONTYPE:
775 case MULTISURFACETYPE:
777 case TINTYPE:
778 case COLLECTIONTYPE:
780 }
781 /* Never get here, please. */
782 lwerror("unsupported type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
783 return LW_FAILURE;
784}
785
787{
788 gbox->xmin = next_float_down(gbox->xmin);
789 gbox->xmax = next_float_up(gbox->xmax);
790
791 gbox->ymin = next_float_down(gbox->ymin);
792 gbox->ymax = next_float_up(gbox->ymax);
793
794 if ( FLAGS_GET_M(gbox->flags) )
795 {
796 gbox->mmin = next_float_down(gbox->mmin);
797 gbox->mmax = next_float_up(gbox->mmax);
798 }
799
800 if ( FLAGS_GET_Z(gbox->flags) )
801 {
802 gbox->zmin = next_float_down(gbox->zmin);
803 gbox->zmax = next_float_up(gbox->zmax);
804 }
805}
806
807uint64_t
808gbox_get_sortable_hash(const GBOX *g, const int32_t srid)
809{
810 union floatuint {
811 uint32_t u;
812 float f;
813 };
814
815 union floatuint x, y;
816
817 /*
818 * Since in theory the bitwise representation of an IEEE
819 * float is sortable (exponents come before mantissa, etc)
820 * we just copy the bits directly into an int and then
821 * interleave those ints.
822 */
824 {
826 POINT3D p;
827 p.x = (g->xmax + g->xmin) / 2.0;
828 p.y = (g->ymax + g->ymin) / 2.0;
829 p.z = (g->zmax + g->zmin) / 2.0;
830 normalize(&p);
831 cart2geog(&p, &gpt);
832 /* We know range for geography, so build the curve taking it into account */
833 x.f = 1.5 + gpt.lon / 512.0;
834 y.f = 1.5 + gpt.lat / 256.0;
835 }
836 else
837 {
838 x.f = (g->xmax + g->xmin) / 2;
839 y.f = (g->ymax + g->ymin) / 2;
840 /*
841 * Tweak for popular SRID values: push floating point values into 1..2 range,
842 * a region where exponent is constant and thus Hilbert curve
843 * doesn't have compression artifact when X or Y value is close to 0.
844 * If someone has out of bounds value it will still expose the arifact but not crash.
845 * TODO: reconsider when we will have machinery to properly get bounds by SRID.
846 */
847 if (srid == 3857 || srid == 3395)
848 {
849 x.f = 1.5 + x.f / 67108864.0;
850 y.f = 1.5 + y.f / 67108864.0;
851 }
852 else if (srid == 4326)
853 {
854 x.f = 1.5 + x.f / 512.0;
855 y.f = 1.5 + y.f / 256.0;
856 }
857 }
858
859 return uint32_hilbert(y.u, x.u);
860}
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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:376
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:452
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition gbox.c:445
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:404
static void ptarray_calculate_gbox_cartesian_2d(const POINTARRAY *pa, GBOX *gbox)
Definition gbox.c:549
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition gbox.c:786
static int lwpoint_calculate_gbox_cartesian(LWPOINT *point, GBOX *gbox)
Definition gbox.c:691
static int lwpoly_calculate_gbox_cartesian(LWPOLY *poly, GBOX *gbox)
Definition gbox.c:709
static int lwtriangle_calculate_gbox_cartesian(LWTRIANGLE *triangle, GBOX *gbox)
Definition gbox.c:703
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:752
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:362
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:568
static int lwline_calculate_gbox_cartesian(LWLINE *line, GBOX *gbox)
Definition gbox.c:697
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:613
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:808
static int lwcircstring_calculate_gbox_cartesian(LWCIRCSTRING *curve, GBOX *gbox)
Definition gbox.c:660
GBOX * gbox_clone(const GBOX *gbox)
Definition gbox.c:45
int gbox_within_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX is within the second on the 2d plane, LW_FALSE otherwise.
Definition gbox.c:351
static int lwcollection_calculate_gbox_cartesian(LWCOLLECTION *coll, GBOX *gbox)
Definition gbox.c:717
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:589
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:438
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:465
static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
Definition gbox.c:534
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
#define COMPOUNDTYPE
Definition liblwgeom.h:110
#define LW_FAILURE
Definition liblwgeom.h:96
#define CURVEPOLYTYPE
Definition liblwgeom.h:111
#define MULTILINETYPE
Definition liblwgeom.h:106
#define MULTISURFACETYPE
Definition liblwgeom.h:113
#define LINETYPE
Definition liblwgeom.h:103
#define LW_SUCCESS
Definition liblwgeom.h:97
uint16_t lwflags_t
Definition liblwgeom.h:299
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
#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
#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
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
#define FLAGS_GET_ZM(flags)
Definition liblwgeom.h:180
#define MULTICURVETYPE
Definition liblwgeom.h:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
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 SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
float next_float_down(double d)
Definition lwgeom_api.c:53
#define FLAGS_GET_GEODETIC(flags)
Definition liblwgeom.h:168
#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:254
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition lwalgorithm.c:70
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:101
#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 uint64_t uint32_hilbert(uint32_t px, uint32_t py)
Definition lwinline.h:256
static const POINT3D * getPoint3d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT3D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:109
static const POINT4D * getPoint4d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT4D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:121
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:97
double xmax
Definition liblwgeom.h:340
double zmin
Definition liblwgeom.h:339
double ymax
Definition liblwgeom.h:340
double ymin
Definition liblwgeom.h:339
double zmax
Definition liblwgeom.h:340
double xmin
Definition liblwgeom.h:339
int32_t srid
Definition liblwgeom.h:341
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
Point in spherical coordinates on the world.
Definition lwgeodetic.h:54
lwflags_t flags
Definition liblwgeom.h:509
POINTARRAY * points
Definition liblwgeom.h:507
lwflags_t flags
Definition liblwgeom.h:577
uint32_t ngeoms
Definition liblwgeom.h:580
LWGEOM ** geoms
Definition liblwgeom.h:575
uint8_t type
Definition liblwgeom.h:462
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY * point
Definition liblwgeom.h:471
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524
POINTARRAY * points
Definition liblwgeom.h:495
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390
double z
Definition liblwgeom.h:402
double x
Definition liblwgeom.h:402
double y
Definition liblwgeom.h:402
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