PostGIS  3.7.0dev-r@@SVN_REVISION@@
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 
40 void gbox_init(GBOX *gbox)
41 {
42  memset(gbox, 0, sizeof(GBOX));
43 }
44 
45 GBOX* 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 */
53 BOX3D* box3d_from_gbox(const GBOX *gbox)
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 */
80 GBOX* box3d_to_gbox(const BOX3D *b3d)
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 
97 void gbox_expand(GBOX *g, double d)
98 {
99  g->xmin -= d;
100  g->xmax += d;
101  g->ymin -= d;
102  g->ymax += d;
103  if (FLAGS_GET_Z(g->flags) || FLAGS_GET_GEODETIC(g->flags))
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 
115 void 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 
135 int 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 
164 int 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 
179 int 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 
187 int 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 
197 int 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 
228 int 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 
239 int 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 
247 int 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 
257 int 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 
283 int 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 
322 int
323 gbox_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 
338 int
339 gbox_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 
350 int
351 gbox_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 
361 int
362 gbox_contains_point2d(const GBOX *g, const POINT2D *p)
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 
376 GBOX* gbox_from_string(const char *str)
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 
404 char* 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 
438 GBOX* gbox_copy(const GBOX *box)
439 {
440  GBOX *copy = (GBOX*)lwalloc(sizeof(GBOX));
441  memcpy(copy, box, sizeof(GBOX));
442  return copy;
443 }
444 
445 void 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 
465 int 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 
534 static 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 
548 static 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 */
567 static 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 
588 static 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 
612 int
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  }
746  result = LW_SUCCESS;
747  }
748  }
749  return result;
750 }
751 
752 int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
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:
764  return lwcircstring_calculate_gbox_cartesian((LWCIRCSTRING *)lwgeom, gbox);
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:
779  return lwcollection_calculate_gbox_cartesian((LWCOLLECTION *)lwgeom, gbox);
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 
807 uint64_t
808 gbox_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  */
823  if (FLAGS_GET_GEODETIC(g->flags))
824  {
825  GEOGRAPHIC_POINT gpt;
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
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
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
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
BOX3D * box3d_from_gbox(const GBOX *gbox)
Definition: gbox.c:53
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
GBOX * gbox_new(lwflags_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition: gbox.c:32
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
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: gbox.c:438
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_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_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
static void ptarray_calculate_gbox_cartesian_4d(const POINTARRAY *pa, GBOX *gbox)
Definition: gbox.c:589
GBOX * gbox_clone(const GBOX *gbox)
Definition: gbox.c:45
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
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
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
Definition: gbox.c:404
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
#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
#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
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#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
void * lwalloc(size_t size)
Definition: lwutil.c:227
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
char * lwstrdup(const char *a)
Definition: lwutil.c:254
#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.
Definition: lwalgorithm.c:234
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 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
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 uint64_t uint32_hilbert(uint32_t px, uint32_t py)
Definition: lwinline.h:256
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