PostGIS  2.4.9dev-r@@SVN_REVISION@@
g_box.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 
26 #if !HAVE_ISFINITE
27 #endif
28 
29 #include "liblwgeom_internal.h"
30 #include "lwgeom_log.h"
31 #include <stdlib.h>
32 #include <math.h>
33 
34 /* Fall back to older finite() if necessary */
35 #ifndef HAVE_ISFINITE
36 # ifdef HAVE_GNU_ISFINITE
37 # define _GNU_SOURCE
38 # else
39 # define isfinite finite
40 # endif
41 #endif
42 
44 {
45  GBOX *g = (GBOX*)lwalloc(sizeof(GBOX));
46  gbox_init(g);
47  g->flags = flags;
48  return g;
49 }
50 
51 void gbox_init(GBOX *gbox)
52 {
53  memset(gbox, 0, sizeof(GBOX));
54 }
55 
56 GBOX* gbox_clone(const GBOX *gbox)
57 {
58  GBOX *g = lwalloc(sizeof(GBOX));
59  memcpy(g, gbox, sizeof(GBOX));
60  return g;
61 }
62 
63 /* TODO to be removed */
64 BOX3D* box3d_from_gbox(const GBOX *gbox)
65 {
66  BOX3D *b;
67  assert(gbox);
68 
69  b = lwalloc(sizeof(BOX3D));
70 
71  b->xmin = gbox->xmin;
72  b->xmax = gbox->xmax;
73  b->ymin = gbox->ymin;
74  b->ymax = gbox->ymax;
75 
76  if ( FLAGS_GET_Z(gbox->flags) )
77  {
78  b->zmin = gbox->zmin;
79  b->zmax = gbox->zmax;
80  }
81  else
82  {
83  b->zmin = b->zmax = 0.0;
84  }
85 
86  b->srid = SRID_UNKNOWN;
87  return b;
88 }
89 
90 /* TODO to be removed */
91 GBOX* box3d_to_gbox(const BOX3D *b3d)
92 {
93  GBOX *b;
94  assert(b3d);
95 
96  b = lwalloc(sizeof(GBOX));
97 
98  b->xmin = b3d->xmin;
99  b->xmax = b3d->xmax;
100  b->ymin = b3d->ymin;
101  b->ymax = b3d->ymax;
102  b->zmin = b3d->zmin;
103  b->zmax = b3d->zmax;
104 
105  return b;
106 }
107 
108 void gbox_expand(GBOX *g, double d)
109 {
110  g->xmin -= d;
111  g->xmax += d;
112  g->ymin -= d;
113  g->ymax += d;
114  if ( FLAGS_GET_Z(g->flags) )
115  {
116  g->zmin -= d;
117  g->zmax += d;
118  }
119  if ( FLAGS_GET_M(g->flags) )
120  {
121  g->mmin -= d;
122  g->mmax += d;
123  }
124 }
125 
126 void gbox_expand_xyzm(GBOX *g, double dx, double dy, double dz, double dm)
127 {
128  g->xmin -= dx;
129  g->xmax += dx;
130  g->ymin -= dy;
131  g->ymax += dy;
132 
133  if (FLAGS_GET_Z(g->flags))
134  {
135  g->zmin -= dz;
136  g->zmax += dz;
137  }
138 
139  if (FLAGS_GET_M(g->flags))
140  {
141  g->mmin -= dm;
142  g->mmax += dm;
143  }
144 }
145 
146 int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
147 {
148  if ( ( ! g1 ) && ( ! g2 ) )
149  return LW_FALSE;
150 
151  if ( ! g1 )
152  {
153  memcpy(gout, g2, sizeof(GBOX));
154  return LW_TRUE;
155  }
156  if ( ! g2 )
157  {
158  memcpy(gout, g1, sizeof(GBOX));
159  return LW_TRUE;
160  }
161 
162  gout->flags = g1->flags;
163 
164  gout->xmin = FP_MIN(g1->xmin, g2->xmin);
165  gout->xmax = FP_MAX(g1->xmax, g2->xmax);
166 
167  gout->ymin = FP_MIN(g1->ymin, g2->ymin);
168  gout->ymax = FP_MAX(g1->ymax, g2->ymax);
169 
170  gout->zmin = FP_MIN(g1->zmin, g2->zmin);
171  gout->zmax = FP_MAX(g1->zmax, g2->zmax);
172 
173  return LW_TRUE;
174 }
175 
176 int gbox_same(const GBOX *g1, const GBOX *g2)
177 {
178  if (FLAGS_GET_ZM(g1->flags) != FLAGS_GET_ZM(g2->flags))
179  return LW_FALSE;
180 
181  if (!gbox_same_2d(g1, g2)) return LW_FALSE;
182 
183  if (FLAGS_GET_Z(g1->flags) && (g1->zmin != g2->zmin || g1->zmax != g2->zmax))
184  return LW_FALSE;
185  if (FLAGS_GET_M(g1->flags) && (g1->mmin != g2->mmin || g1->mmax != g2->mmax))
186  return LW_FALSE;
187 
188  return LW_TRUE;
189 }
190 
191 int gbox_same_2d(const GBOX *g1, const GBOX *g2)
192 {
193  if (g1->xmin == g2->xmin && g1->ymin == g2->ymin &&
194  g1->xmax == g2->xmax && g1->ymax == g2->ymax)
195  return LW_TRUE;
196  return LW_FALSE;
197 }
198 
199 int gbox_same_2d_float(const GBOX *g1, const GBOX *g2)
200 {
201  if ((g1->xmax == g2->xmax || next_float_up(g1->xmax) == next_float_up(g2->xmax)) &&
202  (g1->ymax == g2->ymax || next_float_up(g1->ymax) == next_float_up(g2->ymax)) &&
203  (g1->xmin == g2->xmin || next_float_down(g1->xmin) == next_float_down(g1->xmin)) &&
204  (g1->ymin == g2->ymin || next_float_down(g2->ymin) == next_float_down(g2->ymin)))
205  return LW_TRUE;
206  return LW_FALSE;
207 }
208 
209 int gbox_is_valid(const GBOX *gbox)
210 {
211  /* X */
212  if ( ! isfinite(gbox->xmin) || isnan(gbox->xmin) ||
213  ! isfinite(gbox->xmax) || isnan(gbox->xmax) )
214  return LW_FALSE;
215 
216  /* Y */
217  if ( ! isfinite(gbox->ymin) || isnan(gbox->ymin) ||
218  ! isfinite(gbox->ymax) || isnan(gbox->ymax) )
219  return LW_FALSE;
220 
221  /* Z */
222  if ( FLAGS_GET_GEODETIC(gbox->flags) || FLAGS_GET_Z(gbox->flags) )
223  {
224  if ( ! isfinite(gbox->zmin) || isnan(gbox->zmin) ||
225  ! isfinite(gbox->zmax) || isnan(gbox->zmax) )
226  return LW_FALSE;
227  }
228 
229  /* M */
230  if ( FLAGS_GET_M(gbox->flags) )
231  {
232  if ( ! isfinite(gbox->mmin) || isnan(gbox->mmin) ||
233  ! isfinite(gbox->mmax) || isnan(gbox->mmax) )
234  return LW_FALSE;
235  }
236 
237  return LW_TRUE;
238 }
239 
240 int gbox_merge_point3d(const POINT3D *p, GBOX *gbox)
241 {
242  if ( gbox->xmin > p->x ) gbox->xmin = p->x;
243  if ( gbox->ymin > p->y ) gbox->ymin = p->y;
244  if ( gbox->zmin > p->z ) gbox->zmin = p->z;
245  if ( gbox->xmax < p->x ) gbox->xmax = p->x;
246  if ( gbox->ymax < p->y ) gbox->ymax = p->y;
247  if ( gbox->zmax < p->z ) gbox->zmax = p->z;
248  return LW_SUCCESS;
249 }
250 
251 int gbox_init_point3d(const POINT3D *p, GBOX *gbox)
252 {
253  gbox->xmin = gbox->xmax = p->x;
254  gbox->ymin = gbox->ymax = p->y;
255  gbox->zmin = gbox->zmax = p->z;
256  return LW_SUCCESS;
257 }
258 
259 int gbox_contains_point3d(const GBOX *gbox, const POINT3D *pt)
260 {
261  if ( gbox->xmin > pt->x || gbox->ymin > pt->y || gbox->zmin > pt->z ||
262  gbox->xmax < pt->x || gbox->ymax < pt->y || gbox->zmax < pt->z )
263  {
264  return LW_FALSE;
265  }
266  return LW_TRUE;
267 }
268 
269 int gbox_merge(const GBOX *new_box, GBOX *merge_box)
270 {
271  assert(merge_box);
272 
273  if ( FLAGS_GET_ZM(merge_box->flags) != FLAGS_GET_ZM(new_box->flags) )
274  return LW_FAILURE;
275 
276  if ( new_box->xmin < merge_box->xmin) merge_box->xmin = new_box->xmin;
277  if ( new_box->ymin < merge_box->ymin) merge_box->ymin = new_box->ymin;
278  if ( new_box->xmax > merge_box->xmax) merge_box->xmax = new_box->xmax;
279  if ( new_box->ymax > merge_box->ymax) merge_box->ymax = new_box->ymax;
280 
281  if ( FLAGS_GET_Z(merge_box->flags) || FLAGS_GET_GEODETIC(merge_box->flags) )
282  {
283  if ( new_box->zmin < merge_box->zmin) merge_box->zmin = new_box->zmin;
284  if ( new_box->zmax > merge_box->zmax) merge_box->zmax = new_box->zmax;
285  }
286  if ( FLAGS_GET_M(merge_box->flags) )
287  {
288  if ( new_box->mmin < merge_box->mmin) merge_box->mmin = new_box->mmin;
289  if ( new_box->mmax > merge_box->mmax) merge_box->mmax = new_box->mmax;
290  }
291 
292  return LW_SUCCESS;
293 }
294 
295 int gbox_overlaps(const GBOX *g1, const GBOX *g2)
296 {
297 
298  /* Make sure our boxes are consistent */
300  lwerror("gbox_overlaps: cannot compare geodetic and non-geodetic boxes");
301 
302  /* Check X/Y first */
303  if ( g1->xmax < g2->xmin || g1->ymax < g2->ymin ||
304  g1->xmin > g2->xmax || g1->ymin > g2->ymax )
305  return LW_FALSE;
306 
307  /* Deal with the geodetic case special: we only compare the geodetic boxes (x/y/z) */
308  /* Never the M dimension */
310  {
311  if ( g1->zmax < g2->zmin || g1->zmin > g2->zmax )
312  return LW_FALSE;
313  else
314  return LW_TRUE;
315  }
316 
317  /* If both geodetic or both have Z, check Z */
318  if ( FLAGS_GET_Z(g1->flags) && FLAGS_GET_Z(g2->flags) )
319  {
320  if ( g1->zmax < g2->zmin || g1->zmin > g2->zmax )
321  return LW_FALSE;
322  }
323 
324  /* If both have M, check M */
325  if ( FLAGS_GET_M(g1->flags) && FLAGS_GET_M(g2->flags) )
326  {
327  if ( g1->mmax < g2->mmin || g1->mmin > g2->mmax )
328  return LW_FALSE;
329  }
330 
331  return LW_TRUE;
332 }
333 
334 int
335 gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
336 {
337 
338  /* Make sure our boxes are consistent */
340  lwerror("gbox_overlaps: cannot compare geodetic and non-geodetic boxes");
341 
342  /* Check X/Y first */
343  if ( g1->xmax < g2->xmin || g1->ymax < g2->ymin ||
344  g1->xmin > g2->xmax || g1->ymin > g2->ymax )
345  return LW_FALSE;
346 
347  return LW_TRUE;
348 }
349 
350 int
351 gbox_contains_2d(const GBOX *g1, const GBOX *g2)
352 {
353  if ( ( g2->xmin < g1->xmin ) || ( g2->xmax > g1->xmax ) ||
354  ( g2->ymin < g1->ymin ) || ( g2->ymax > g1->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(gflags(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  static int sz = 138;
407  char *str = NULL;
408 
409  if ( ! gbox )
410  return strdup("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  memcpy(duplicate, original, sizeof(GBOX));
449 }
450 
452 {
453  if ( FLAGS_GET_GEODETIC(flags) )
454  return 6 * sizeof(float);
455  else
456  return 2 * FLAGS_NDIMS(flags) * sizeof(float);
457 }
458 
459 
460 /* ********************************************************************************
461 ** Compute cartesian bounding GBOX boxes from LWGEOM.
462 */
463 
464 int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
465 {
466  POINT2D xmin, ymin, xmax, ymax;
467  POINT2D C;
468  int A2_side;
469  double radius_A;
470 
471  LWDEBUG(2, "lw_arc_calculate_gbox_cartesian_2d called.");
472 
473  radius_A = lw_arc_center(A1, A2, A3, &C);
474 
475  /* Negative radius signals straight line, p1/p2/p3 are colinear */
476  if (radius_A < 0.0)
477  {
478  gbox->xmin = FP_MIN(A1->x, A3->x);
479  gbox->ymin = FP_MIN(A1->y, A3->y);
480  gbox->xmax = FP_MAX(A1->x, A3->x);
481  gbox->ymax = FP_MAX(A1->y, A3->y);
482  return LW_SUCCESS;
483  }
484 
485  /* Matched start/end points imply circle */
486  if ( A1->x == A3->x && A1->y == A3->y )
487  {
488  gbox->xmin = C.x - radius_A;
489  gbox->ymin = C.y - radius_A;
490  gbox->xmax = C.x + radius_A;
491  gbox->ymax = C.y + radius_A;
492  return LW_SUCCESS;
493  }
494 
495  /* First approximation, bounds of start/end points */
496  gbox->xmin = FP_MIN(A1->x, A3->x);
497  gbox->ymin = FP_MIN(A1->y, A3->y);
498  gbox->xmax = FP_MAX(A1->x, A3->x);
499  gbox->ymax = FP_MAX(A1->y, A3->y);
500 
501  /* Create points for the possible extrema */
502  xmin.x = C.x - radius_A;
503  xmin.y = C.y;
504  ymin.x = C.x;
505  ymin.y = C.y - radius_A;
506  xmax.x = C.x + radius_A;
507  xmax.y = C.y;
508  ymax.x = C.x;
509  ymax.y = C.y + radius_A;
510 
511  /* Divide the circle into two parts, one on each side of a line
512  joining p1 and p3. The circle extrema on the same side of that line
513  as p2 is on, are also the extrema of the bbox. */
514 
515  A2_side = lw_segment_side(A1, A3, A2);
516 
517  if ( A2_side == lw_segment_side(A1, A3, &xmin) )
518  gbox->xmin = xmin.x;
519 
520  if ( A2_side == lw_segment_side(A1, A3, &ymin) )
521  gbox->ymin = ymin.y;
522 
523  if ( A2_side == lw_segment_side(A1, A3, &xmax) )
524  gbox->xmax = xmax.x;
525 
526  if ( A2_side == lw_segment_side(A1, A3, &ymax) )
527  gbox->ymax = ymax.y;
528 
529  return LW_SUCCESS;
530 }
531 
532 
533 static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
534 {
535  int rv;
536 
537  LWDEBUG(2, "lw_arc_calculate_gbox_cartesian called.");
538 
539  rv = lw_arc_calculate_gbox_cartesian_2d((POINT2D*)p1, (POINT2D*)p2, (POINT2D*)p3, gbox);
540  gbox->zmin = FP_MIN(p1->z, p3->z);
541  gbox->mmin = FP_MIN(p1->m, p3->m);
542  gbox->zmax = FP_MAX(p1->z, p3->z);
543  gbox->mmax = FP_MAX(p1->m, p3->m);
544  return rv;
545 }
546 
548 {
549  int i;
550  POINT4D p;
551  int has_z, has_m;
552 
553  if ( ! pa ) return LW_FAILURE;
554  if ( ! gbox ) return LW_FAILURE;
555  if ( pa->npoints < 1 ) return LW_FAILURE;
556 
557  has_z = FLAGS_GET_Z(pa->flags);
558  has_m = FLAGS_GET_M(pa->flags);
559  gbox->flags = gflags(has_z, has_m, 0);
560  LWDEBUGF(4, "ptarray_calculate_gbox Z: %d M: %d", has_z, has_m);
561 
562  getPoint4d_p(pa, 0, &p);
563  gbox->xmin = gbox->xmax = p.x;
564  gbox->ymin = gbox->ymax = p.y;
565  if ( has_z )
566  gbox->zmin = gbox->zmax = p.z;
567  if ( has_m )
568  gbox->mmin = gbox->mmax = p.m;
569 
570  for ( i = 1 ; i < pa->npoints; i++ )
571  {
572  getPoint4d_p(pa, i, &p);
573  gbox->xmin = FP_MIN(gbox->xmin, p.x);
574  gbox->xmax = FP_MAX(gbox->xmax, p.x);
575  gbox->ymin = FP_MIN(gbox->ymin, p.y);
576  gbox->ymax = FP_MAX(gbox->ymax, p.y);
577  if ( has_z )
578  {
579  gbox->zmin = FP_MIN(gbox->zmin, p.z);
580  gbox->zmax = FP_MAX(gbox->zmax, p.z);
581  }
582  if ( has_m )
583  {
584  gbox->mmin = FP_MIN(gbox->mmin, p.m);
585  gbox->mmax = FP_MAX(gbox->mmax, p.m);
586  }
587  }
588  return LW_SUCCESS;
589 }
590 
592 {
593  uint8_t flags = gflags(FLAGS_GET_Z(curve->flags), FLAGS_GET_M(curve->flags), 0);
594  GBOX tmp;
595  POINT4D p1, p2, p3;
596  int i;
597 
598  if ( ! curve ) return LW_FAILURE;
599  if ( curve->points->npoints < 3 ) return LW_FAILURE;
600 
601  tmp.flags = flags;
602 
603  /* Initialize */
604  gbox->xmin = gbox->ymin = gbox->zmin = gbox->mmin = FLT_MAX;
605  gbox->xmax = gbox->ymax = gbox->zmax = gbox->mmax = -1*FLT_MAX;
606 
607  for ( i = 2; i < curve->points->npoints; i += 2 )
608  {
609  getPoint4d_p(curve->points, i-2, &p1);
610  getPoint4d_p(curve->points, i-1, &p2);
611  getPoint4d_p(curve->points, i, &p3);
612 
613  if (lw_arc_calculate_gbox_cartesian(&p1, &p2, &p3, &tmp) == LW_FAILURE)
614  continue;
615 
616  gbox_merge(&tmp, gbox);
617  }
618 
619  return LW_SUCCESS;
620 }
621 
623 {
624  if ( ! point ) return LW_FAILURE;
625  return ptarray_calculate_gbox_cartesian( point->point, gbox );
626 }
627 
629 {
630  if ( ! line ) return LW_FAILURE;
631  return ptarray_calculate_gbox_cartesian( line->points, gbox );
632 }
633 
635 {
636  if ( ! triangle ) return LW_FAILURE;
637  return ptarray_calculate_gbox_cartesian( triangle->points, gbox );
638 }
639 
641 {
642  if ( ! poly ) return LW_FAILURE;
643  if ( poly->nrings == 0 ) return LW_FAILURE;
644  /* Just need to check outer ring */
645  return ptarray_calculate_gbox_cartesian( poly->rings[0], gbox );
646 }
647 
649 {
650  GBOX subbox;
651  int i;
652  int result = LW_FAILURE;
653  int first = LW_TRUE;
654  assert(coll);
655  if ( (coll->ngeoms == 0) || !gbox)
656  return LW_FAILURE;
657 
658  subbox.flags = coll->flags;
659 
660  for ( i = 0; i < coll->ngeoms; i++ )
661  {
662  if ( lwgeom_calculate_gbox_cartesian((LWGEOM*)(coll->geoms[i]), &subbox) == LW_SUCCESS )
663  {
664  /* Keep a copy of the sub-bounding box for later
665  if ( coll->geoms[i]->bbox )
666  lwfree(coll->geoms[i]->bbox);
667  coll->geoms[i]->bbox = gbox_copy(&subbox); */
668  if ( first )
669  {
670  gbox_duplicate(&subbox, gbox);
671  first = LW_FALSE;
672  }
673  else
674  {
675  gbox_merge(&subbox, gbox);
676  }
677  result = LW_SUCCESS;
678  }
679  }
680  return result;
681 }
682 
683 int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
684 {
685  if ( ! lwgeom ) return LW_FAILURE;
686  LWDEBUGF(4, "lwgeom_calculate_gbox got type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
687 
688  switch (lwgeom->type)
689  {
690  case POINTTYPE:
691  return lwpoint_calculate_gbox_cartesian((LWPOINT *)lwgeom, gbox);
692  case LINETYPE:
693  return lwline_calculate_gbox_cartesian((LWLINE *)lwgeom, gbox);
694  case CIRCSTRINGTYPE:
695  return lwcircstring_calculate_gbox_cartesian((LWCIRCSTRING *)lwgeom, gbox);
696  case POLYGONTYPE:
697  return lwpoly_calculate_gbox_cartesian((LWPOLY *)lwgeom, gbox);
698  case TRIANGLETYPE:
699  return lwtriangle_calculate_gbox_cartesian((LWTRIANGLE *)lwgeom, gbox);
700  case COMPOUNDTYPE:
701  case CURVEPOLYTYPE:
702  case MULTIPOINTTYPE:
703  case MULTILINETYPE:
704  case MULTICURVETYPE:
705  case MULTIPOLYGONTYPE:
706  case MULTISURFACETYPE:
708  case TINTYPE:
709  case COLLECTIONTYPE:
710  return lwcollection_calculate_gbox_cartesian((LWCOLLECTION *)lwgeom, gbox);
711  }
712  /* Never get here, please. */
713  lwerror("unsupported type (%d) - %s", lwgeom->type, lwtype_name(lwgeom->type));
714  return LW_FAILURE;
715 }
716 
718 {
719  gbox->xmin = next_float_down(gbox->xmin);
720  gbox->xmax = next_float_up(gbox->xmax);
721 
722  gbox->ymin = next_float_down(gbox->ymin);
723  gbox->ymax = next_float_up(gbox->ymax);
724 
725  if ( FLAGS_GET_M(gbox->flags) )
726  {
727  gbox->mmin = next_float_down(gbox->mmin);
728  gbox->mmax = next_float_up(gbox->mmax);
729  }
730 
731  if ( FLAGS_GET_Z(gbox->flags) )
732  {
733  gbox->zmin = next_float_down(gbox->zmin);
734  gbox->zmax = next_float_up(gbox->zmax);
735  }
736 }
737 
double x
Definition: liblwgeom.h:352
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:227
#define LINETYPE
Definition: liblwgeom.h:86
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
Definition: g_box.c:547
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:438
int32_t srid
Definition: liblwgeom.h:279
GBOX * gbox_new(uint8_t flags)
Create a new gbox with the dimensionality indicated by the flags.
Definition: g_box.c:43
uint8_t flags
Definition: liblwgeom.h:441
POINTARRAY * points
Definition: liblwgeom.h:433
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: g_box.c:126
double m
Definition: liblwgeom.h:352
#define MULTICURVETYPE
Definition: liblwgeom.h:95
void gbox_duplicate(const GBOX *original, GBOX *duplicate)
Copy the values of original GBOX into duplicate.
Definition: g_box.c:445
int gbox_is_valid(const GBOX *gbox)
Return false if any of the dimensions is NaN or infinite.
Definition: g_box.c:209
static int lwpoint_calculate_gbox_cartesian(LWPOINT *point, GBOX *gbox)
Definition: g_box.c:622
double y
Definition: liblwgeom.h:340
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
Definition: g_box.c:404
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition: g_box.c:464
int npoints
Definition: liblwgeom.h:371
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:108
static int lw_arc_calculate_gbox_cartesian(const POINT4D *p1, const POINT4D *p2, const POINT4D *p3, GBOX *gbox)
Definition: g_box.c:533
#define FLAGS_GET_GEODETIC(flags)
Definition: liblwgeom.h:143
#define POLYGONTYPE
Definition: liblwgeom.h:87
double xmax
Definition: liblwgeom.h:293
#define CURVEPOLYTYPE
Definition: liblwgeom.h:94
#define COMPOUNDTYPE
Definition: liblwgeom.h:93
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
int gbox_contains_point3d(const GBOX *gbox, const POINT3D *pt)
Return true if the point is inside the gbox.
Definition: g_box.c:259
static int lwpoly_calculate_gbox_cartesian(LWPOLY *poly, GBOX *gbox)
Definition: g_box.c:640
#define LW_SUCCESS
Definition: liblwgeom.h:80
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:153
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define TRIANGLETYPE
Definition: liblwgeom.h:98
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: g_box.c:351
double x
Definition: liblwgeom.h:340
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:97
double ymin
Definition: liblwgeom.h:277
int gbox_init_point3d(const POINT3D *p, GBOX *gbox)
Initialize a GBOX using the values of the point.
Definition: g_box.c:251
float next_float_down(double d)
Definition: lwgeom_api.c:51
#define FP_MIN(A, B)
static int lwcollection_calculate_gbox_cartesian(LWCOLLECTION *coll, GBOX *gbox)
Definition: g_box.c:648
POINTARRAY * point
Definition: liblwgeom.h:411
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: g_box.c:269
#define LW_FAILURE
Definition: liblwgeom.h:79
float next_float_up(double d)
Definition: lwgeom_api.c:72
double z
Definition: liblwgeom.h:340
double x
Definition: liblwgeom.h:328
uint8_t flags
Definition: liblwgeom.h:504
void gbox_float_round(GBOX *gbox)
Round given GBOX to float boundaries.
Definition: g_box.c:717
double zmax
Definition: liblwgeom.h:297
double ymin
Definition: liblwgeom.h:294
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition: g_box.c:51
double xmin
Definition: liblwgeom.h:292
#define LW_FALSE
Definition: liblwgeom.h:77
double xmin
Definition: liblwgeom.h:277
uint8_t flags
Definition: liblwgeom.h:369
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
LWGEOM ** geoms
Definition: liblwgeom.h:509
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
#define TINTYPE
Definition: liblwgeom.h:99
int gbox_merge_point3d(const POINT3D *p, GBOX *gbox)
Update the GBOX to be large enough to include itself and the new point.
Definition: g_box.c:240
POINTARRAY ** rings
Definition: liblwgeom.h:457
int nrings
Definition: liblwgeom.h:455
double ymax
Definition: liblwgeom.h:295
double y
Definition: liblwgeom.h:328
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:140
int gbox_same_2d(const GBOX *g1, const GBOX *g2)
Check if 2 given GBOX are the same in x and y.
Definition: g_box.c:191
double z
Definition: liblwgeom.h:352
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
Definition: g_box.c:146
uint8_t flags
Definition: liblwgeom.h:291
uint8_t gflags(int hasz, int hasm, int geodetic)
Construct a new flags char.
Definition: g_util.c:145
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
GBOX * box3d_to_gbox(const BOX3D *b3d)
Definition: g_box.c:91
static int lwcircstring_calculate_gbox_cartesian(LWCIRCSTRING *curve, GBOX *gbox)
Definition: g_box.c:591
BOX3D * box3d_from_gbox(const GBOX *gbox)
Definition: g_box.c:64
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: g_box.c:335
#define MULTISURFACETYPE
Definition: liblwgeom.h:96
double xmax
Definition: liblwgeom.h:278
double mmin
Definition: liblwgeom.h:298
double zmin
Definition: liblwgeom.h:296
static int lwline_calculate_gbox_cartesian(LWLINE *line, GBOX *gbox)
Definition: g_box.c:628
static int lwtriangle_calculate_gbox_cartesian(LWTRIANGLE *triangle, GBOX *gbox)
Definition: g_box.c:634
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:141
int gbox_overlaps(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps, LW_FALSE otherwise.
Definition: g_box.c:295
uint8_t type
Definition: liblwgeom.h:396
double mmax
Definition: liblwgeom.h:299
POINTARRAY * points
Definition: liblwgeom.h:444
GBOX * gbox_clone(const GBOX *gbox)
Definition: g_box.c:56
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:92
void * lwalloc(size_t size)
Definition: lwutil.c:229
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:64
double y
Definition: liblwgeom.h:352
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: g_box.c:199
#define MULTILINETYPE
Definition: liblwgeom.h:89
double ymax
Definition: liblwgeom.h:278
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: g_box.c:376
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:152
unsigned char uint8_t
Definition: uthash.h:79
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition: g_box.c:176
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
Definition: g_box.c:362
size_t gbox_serialized_size(uint8_t flags)
Return the number of bytes necessary to hold a GBOX of this dimension in serialized form...
Definition: g_box.c:451
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:122
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
#define FP_MAX(A, B)
double zmax
Definition: liblwgeom.h:278
POINTARRAY * points
Definition: liblwgeom.h:422
double zmin
Definition: liblwgeom.h:277
int lwgeom_calculate_gbox_cartesian(const LWGEOM *lwgeom, GBOX *gbox)
Calculate the 2-4D bounding box of a geometry.
Definition: g_box.c:683