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