PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwgeom_box3d.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 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
22  * Copyright 2009-2017 Paul Ramsey <pramsey@cleverelephant.ca>
23  * Copyright 2018 Darafei Praliaskouski <me@komzpa.net>
24  *
25  **********************************************************************/
26 
27 #include "postgres.h"
28 #include "fmgr.h"
29 #include "utils/elog.h"
30 #include "utils/geo_decls.h"
31 #include "gserialized_spgist_3d.h"
32 
33 #include "../postgis_config.h"
34 #include "lwgeom_pg.h"
35 #include "liblwgeom.h"
36 #include "liblwgeom_internal.h"
37 #include "lwgeom_box3d.h"
38 
39 #include <math.h>
40 #include <float.h>
41 #include <string.h>
42 #include <stdio.h>
43 
44 
55 Datum BOX3D_in(PG_FUNCTION_ARGS)
56 {
57  char *str = PG_GETARG_CSTRING(0);
58  int nitems;
59  BOX3D *box = (BOX3D *)palloc(sizeof(BOX3D));
60  box->zmin = 0;
61  box->zmax = 0;
62 
63  if (strstr(str, "BOX3D(") != str)
64  {
65  pfree(box);
66  elog(ERROR, "BOX3D parser - doesn't start with BOX3D(");
67  PG_RETURN_NULL();
68  }
69 
70  nitems = sscanf(str,
71  "BOX3D(%le %le %le ,%le %le %le)",
72  &box->xmin,
73  &box->ymin,
74  &box->zmin,
75  &box->xmax,
76  &box->ymax,
77  &box->zmax);
78  if (nitems != 6)
79  {
80  nitems = sscanf(str, "BOX3D(%le %le ,%le %le)", &box->xmin, &box->ymin, &box->xmax, &box->ymax);
81  if (nitems != 4)
82  {
83  pfree(box);
84  elog(
85  ERROR,
86  "BOX3D parser - couldn't parse. It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
87  PG_RETURN_NULL();
88  }
89  }
90 
91  if (box->xmin > box->xmax)
92  {
93  float tmp = box->xmin;
94  box->xmin = box->xmax;
95  box->xmax = tmp;
96  }
97  if (box->ymin > box->ymax)
98  {
99  float tmp = box->ymin;
100  box->ymin = box->ymax;
101  box->ymax = tmp;
102  }
103  if (box->zmin > box->zmax)
104  {
105  float tmp = box->zmin;
106  box->zmin = box->zmax;
107  box->zmax = tmp;
108  }
109  box->srid = SRID_UNKNOWN;
110  PG_RETURN_POINTER(box);
111 }
112 
120 Datum BOX3D_out(PG_FUNCTION_ARGS)
121 {
122  BOX3D *bbox = (BOX3D *)PG_GETARG_POINTER(0);
123  static const int precision = 15;
124  static int size = OUT_MAX_BYTES_DOUBLE * 6 + 5 + 2 + 4 + 5 + 1; /* double * 6 + "BOX3D"+ "()" + commas + null */
125  int i = 0;
126  char *result;
127 
128  if (bbox == NULL)
129  {
130  result = palloc(5);
131  strcat(result, "NULL");
132  PG_RETURN_CSTRING(result);
133  }
134 
135  result = (char *)palloc(size);
136  result[i++] = 'B';
137  result[i++] = 'O';
138  result[i++] = 'X';
139  result[i++] = '3';
140  result[i++] = 'D';
141  result[i++] = '(';
142  i += lwprint_double(bbox->xmin, precision, &result[i]);
143  result[i++] = ' ';
144  i += lwprint_double(bbox->ymin, precision, &result[i]);
145  result[i++] = ' ';
146  i += lwprint_double(bbox->zmin, precision, &result[i]);
147  result[i++] = ',';
148  i += lwprint_double(bbox->xmax, precision, &result[i]);
149  result[i++] = ' ';
150  i += lwprint_double(bbox->ymax, precision, &result[i]);
151  result[i++] = ' ';
152  i += lwprint_double(bbox->zmax, precision, &result[i]);
153  result[i++] = ')';
154  result[i++] = '\0';
155 
156  PG_RETURN_CSTRING(result);
157 }
158 
160 Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS)
161 {
162  BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
163  GBOX *out = box3d_to_gbox(in);
164  PG_RETURN_POINTER(out);
165 }
166 
167 static void
168 box3d_to_box_p(BOX3D *box, BOX *out)
169 {
170  if (!box)
171  return;
172 
173  out->low.x = box->xmin;
174  out->low.y = box->ymin;
175 
176  out->high.x = box->xmax;
177  out->high.y = box->ymax;
178 }
179 
181 Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
182 {
183  BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
184  BOX *box = palloc(sizeof(BOX));
185 
186  box3d_to_box_p(in, box);
187  PG_RETURN_POINTER(box);
188 }
189 
191 Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
192 {
193  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
194  POINTARRAY *pa;
196  POINT4D pt;
197 
211 
212  /* BOX3D is a point */
213  if ((box->xmin == box->xmax) && (box->ymin == box->ymax) && (box->zmin == box->zmax))
214  {
215  LWPOINT *lwpt = lwpoint_construct(SRID_UNKNOWN, NULL, pa);
216 
217  pt.x = box->xmin;
218  pt.y = box->ymin;
219  pt.z = box->zmin;
220  ptarray_append_point(pa, &pt, LW_TRUE);
221 
222  result = geometry_serialize(lwpoint_as_lwgeom(lwpt));
223  lwpoint_free(lwpt);
224  }
225  /* BOX3D is a line */
226  else if (((box->xmin == box->xmax || box->ymin == box->ymax) && box->zmin == box->zmax) ||
227  ((box->xmin == box->xmax || box->zmin == box->zmax) && box->ymin == box->ymax) ||
228  ((box->ymin == box->ymax || box->zmin == box->zmax) && box->xmin == box->xmax))
229  {
230  LWLINE *lwline = lwline_construct(SRID_UNKNOWN, NULL, pa);
231 
232  pt.x = box->xmin;
233  pt.y = box->ymin;
234  pt.z = box->zmin;
235  ptarray_append_point(pa, &pt, LW_TRUE);
236  pt.x = box->xmax;
237  pt.y = box->ymax;
238  pt.z = box->zmax;
239  ptarray_append_point(pa, &pt, LW_TRUE);
240 
241  result = geometry_serialize(lwline_as_lwgeom(lwline));
242  lwline_free(lwline);
243  }
244  /* BOX3D is a polygon in the X plane */
245  else if (box->xmin == box->xmax)
246  {
247  POINT4D points[4];
248  LWPOLY *lwpoly;
249 
250  /* Initialize the 4 vertices of the polygon */
251  points[0] = (POINT4D){box->xmin, box->ymin, box->zmin, 0.0};
252  points[1] = (POINT4D){box->xmin, box->ymax, box->zmin, 0.0};
253  points[2] = (POINT4D){box->xmin, box->ymax, box->zmax, 0.0};
254  points[3] = (POINT4D){box->xmin, box->ymin, box->zmax, 0.0};
255 
256  lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[1], &points[2], &points[3]);
257  result = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
258  lwpoly_free(lwpoly);
259  }
260  /* BOX3D is a polygon in the Y plane */
261  else if (box->ymin == box->ymax)
262  {
263  POINT4D points[4];
264  LWPOLY *lwpoly;
265 
266  /* Initialize the 4 vertices of the polygon */
267  points[0] = (POINT4D){box->xmin, box->ymin, box->zmin, 0.0};
268  points[1] = (POINT4D){box->xmax, box->ymin, box->zmin, 0.0};
269  points[2] = (POINT4D){box->xmax, box->ymin, box->zmax, 0.0};
270  points[3] = (POINT4D){box->xmin, box->ymin, box->zmax, 0.0};
271 
272  lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[1], &points[2], &points[3]);
273  result = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
274  lwpoly_free(lwpoly);
275  }
276  /* BOX3D is a polygon in the Z plane */
277  else if (box->zmin == box->zmax)
278  {
279  POINT4D points[4];
280  LWPOLY *lwpoly;
281 
282  /* Initialize the 4 vertices of the polygon */
283  points[0] = (POINT4D){box->xmin, box->ymin, box->zmin, 0.0};
284  points[1] = (POINT4D){box->xmin, box->ymax, box->zmin, 0.0};
285  points[2] = (POINT4D){box->xmax, box->ymax, box->zmin, 0.0};
286  points[3] = (POINT4D){box->xmax, box->ymin, box->zmin, 0.0};
287 
288  lwpoly = lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[1], &points[2], &points[3]);
289  result = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
290  lwpoly_free(lwpoly);
291  }
292  /* BOX3D is a polyhedron */
293  else
294  {
295  POINT4D points[8];
296  static const int ngeoms = 6;
297  LWGEOM **geoms = (LWGEOM **)lwalloc(sizeof(LWGEOM *) * ngeoms);
298  LWGEOM *geom = NULL;
299 
300  /* Initialize the 8 vertices of the box */
301  points[0] = (POINT4D){box->xmin, box->ymin, box->zmin, 0.0};
302  points[1] = (POINT4D){box->xmin, box->ymax, box->zmin, 0.0};
303  points[2] = (POINT4D){box->xmax, box->ymax, box->zmin, 0.0};
304  points[3] = (POINT4D){box->xmax, box->ymin, box->zmin, 0.0};
305  points[4] = (POINT4D){box->xmin, box->ymin, box->zmax, 0.0};
306  points[5] = (POINT4D){box->xmin, box->ymax, box->zmax, 0.0};
307  points[6] = (POINT4D){box->xmax, box->ymax, box->zmax, 0.0};
308  points[7] = (POINT4D){box->xmax, box->ymin, box->zmax, 0.0};
309 
310  /* add bottom polygon */
311  geoms[0] = lwpoly_as_lwgeom(
312  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[1], &points[2], &points[3]));
313  /* add top polygon */
314  geoms[1] = lwpoly_as_lwgeom(
315  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[4], &points[7], &points[6], &points[5]));
316  /* add left polygon */
317  geoms[2] = lwpoly_as_lwgeom(
318  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[4], &points[5], &points[1]));
319  /* add right polygon */
320  geoms[3] = lwpoly_as_lwgeom(
321  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[3], &points[2], &points[6], &points[7]));
322  /* add front polygon */
323  geoms[4] = lwpoly_as_lwgeom(
324  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[0], &points[3], &points[7], &points[4]));
325  /* add back polygon */
326  geoms[5] = lwpoly_as_lwgeom(
327  lwpoly_construct_rectangle(LW_TRUE, LW_FALSE, &points[1], &points[5], &points[6], &points[2]));
328 
329  geom = (LWGEOM *)lwcollection_construct(POLYHEDRALSURFACETYPE, SRID_UNKNOWN, NULL, ngeoms, geoms);
330 
331  FLAGS_SET_SOLID(geom->flags, 1);
332 
333  result = geometry_serialize(geom);
335  }
336 
338 
339  PG_RETURN_POINTER(result);
340 }
341 
343 void
344 expand_box3d(BOX3D *box, double d)
345 {
346  box->xmin -= d;
347  box->ymin -= d;
348  box->zmin -= d;
349 
350  box->xmax += d;
351  box->ymax += d;
352  box->zmax += d;
353 }
354 
355 static void
356 expand_box3d_xyz(BOX3D *box, double dx, double dy, double dz)
357 {
358  box->xmin -= dx;
359  box->xmax += dx;
360  box->ymin -= dy;
361  box->ymax += dy;
362  box->zmin -= dz;
363  box->zmax += dz;
364 }
365 
367 Datum BOX3D_expand(PG_FUNCTION_ARGS)
368 {
369  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
370  BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
371  memcpy(result, box, sizeof(BOX3D));
372 
373  if (PG_NARGS() == 2)
374  {
375  /* Expand the box the same amount in all directions */
376  double d = PG_GETARG_FLOAT8(1);
377  expand_box3d(result, d);
378  }
379  else
380  {
381  double dx = PG_GETARG_FLOAT8(1);
382  double dy = PG_GETARG_FLOAT8(2);
383  double dz = PG_GETARG_FLOAT8(3);
384 
385  expand_box3d_xyz(result, dx, dy, dz);
386  }
387 
388  PG_RETURN_POINTER(result);
389 }
390 
398 Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
399 {
400  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
401  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
402  GBOX gbox;
403  BOX3D *result;
404  int rv = lwgeom_calculate_gbox(lwgeom, &gbox);
405 
406  if (rv == LW_FAILURE)
407  PG_RETURN_NULL();
408 
409  result = box3d_from_gbox(&gbox);
410  result->srid = lwgeom->srid;
411 
412  lwgeom_free(lwgeom);
413  PG_RETURN_POINTER(result);
414 }
415 
417 Datum BOX3D_xmin(PG_FUNCTION_ARGS)
418 {
419  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
420  PG_RETURN_FLOAT8(Min(box->xmin, box->xmax));
421 }
422 
424 Datum BOX3D_ymin(PG_FUNCTION_ARGS)
425 {
426  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
427  PG_RETURN_FLOAT8(Min(box->ymin, box->ymax));
428 }
429 
431 Datum BOX3D_zmin(PG_FUNCTION_ARGS)
432 {
433  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
434  PG_RETURN_FLOAT8(Min(box->zmin, box->zmax));
435 }
436 
438 Datum BOX3D_xmax(PG_FUNCTION_ARGS)
439 {
440  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
441  PG_RETURN_FLOAT8(Max(box->xmin, box->xmax));
442 }
443 
445 Datum BOX3D_ymax(PG_FUNCTION_ARGS)
446 {
447  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
448  PG_RETURN_FLOAT8(Max(box->ymin, box->ymax));
449 }
450 
452 Datum BOX3D_zmax(PG_FUNCTION_ARGS)
453 {
454  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
455  PG_RETURN_FLOAT8(Max(box->zmin, box->zmax));
456 }
457 
458 
459 Datum ST_MMin(PG_FUNCTION_ARGS);
461 Datum ST_MMin(PG_FUNCTION_ARGS)
462 {
463  GBOX gbox;
464  GSERIALIZED *gser = PG_GETARG_GSERIALIZED_P(0);
465 
466  if (gserialized_get_gbox_p(gser, &gbox) != LW_TRUE)
467  PG_RETURN_NULL();
468 
469  if (!FLAGS_GET_M(gbox.flags))
470  PG_RETURN_NULL();
471 
472  PG_RETURN_FLOAT8(Min(gbox.mmin, gbox.mmax));
473 }
474 
475 
476 Datum ST_MMax(PG_FUNCTION_ARGS);
478 Datum ST_MMax(PG_FUNCTION_ARGS)
479 {
480  GBOX gbox;
481  GSERIALIZED *gser = PG_GETARG_GSERIALIZED_P(0);
482 
483  if (gserialized_get_gbox_p(gser, &gbox) != LW_TRUE)
484  PG_RETURN_NULL();
485 
486  if (!FLAGS_GET_M(gbox.flags))
487  PG_RETURN_NULL();
488 
489  PG_RETURN_FLOAT8(Max(gbox.mmin, gbox.mmax));
490 }
491 
492 
499 Datum BOX3D_combine(PG_FUNCTION_ARGS)
500 {
501  BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
502  GSERIALIZED *geom = PG_ARGISNULL(1) ? NULL : (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
503  LWGEOM *lwgeom = NULL;
504  BOX3D *result = NULL;
505  GBOX gbox;
506  int32_t srid;
507  int rv;
508 
509  /* Can't do anything with null inputs */
510  if (!box && !geom)
511  {
512  PG_RETURN_NULL();
513  }
514  /* Null geometry but non-null box, return the box */
515  else if (!geom)
516  {
517  result = palloc(sizeof(BOX3D));
518  memcpy(result, box, sizeof(BOX3D));
519  PG_RETURN_POINTER(result);
520  }
521 
522  /*
523  * Deserialize geometry and *calculate* the box
524  * We can't use the cached box because it's float, we *must* calculate
525  */
526  lwgeom = lwgeom_from_gserialized(geom);
527  srid = lwgeom->srid;
528  rv = lwgeom_calculate_gbox(lwgeom, &gbox);
529  lwgeom_free(lwgeom);
530 
531  /* If we couldn't calculate the box, return what we know */
532  if (rv == LW_FAILURE)
533  {
534  PG_FREE_IF_COPY(geom, 1);
535  /* No geom box, no input box, so null return */
536  if (!box)
537  PG_RETURN_NULL();
538  result = palloc(sizeof(BOX3D));
539  memcpy(result, box, sizeof(BOX3D));
540  PG_RETURN_POINTER(result);
541  }
542 
543  /* Null box and non-null geometry, just return the geometry box */
544  if (!box)
545  {
546  PG_FREE_IF_COPY(geom, 1);
547  result = box3d_from_gbox(&gbox);
548  result->srid = srid;
549  PG_RETURN_POINTER(result);
550  }
551 
552  result = palloc(sizeof(BOX3D));
553  result->xmax = Max(box->xmax, gbox.xmax);
554  result->ymax = Max(box->ymax, gbox.ymax);
555  result->zmax = Max(box->zmax, gbox.zmax);
556  result->xmin = Min(box->xmin, gbox.xmin);
557  result->ymin = Min(box->ymin, gbox.ymin);
558  result->zmin = Min(box->zmin, gbox.zmin);
559  result->srid = srid;
560 
561  PG_FREE_IF_COPY(geom, 1);
562  PG_RETURN_POINTER(result);
563 }
564 
566 Datum BOX3D_combine_BOX3D(PG_FUNCTION_ARGS)
567 {
568  BOX3D *box0 = (BOX3D *)(PG_ARGISNULL(0) ? NULL : PG_GETARG_POINTER(0));
569  BOX3D *box1 = (BOX3D *)(PG_ARGISNULL(1) ? NULL : PG_GETARG_POINTER(1));
570  BOX3D *result;
571 
572  if (box0 && !box1)
573  PG_RETURN_POINTER(box0);
574 
575  if (box1 && !box0)
576  PG_RETURN_POINTER(box1);
577 
578  if (!box1 && !box0)
579  PG_RETURN_NULL();
580 
581  result = palloc(sizeof(BOX3D));
582  result->xmax = Max(box0->xmax, box1->xmax);
583  result->ymax = Max(box0->ymax, box1->ymax);
584  result->zmax = Max(box0->zmax, box1->zmax);
585  result->xmin = Min(box0->xmin, box1->xmin);
586  result->ymin = Min(box0->ymin, box1->ymin);
587  result->zmin = Min(box0->zmin, box1->zmin);
588  result->srid = box0->srid;
589 
590  PG_RETURN_POINTER(result);
591 }
592 
594 Datum BOX3D_construct(PG_FUNCTION_ARGS)
595 {
596  GSERIALIZED *min = PG_GETARG_GSERIALIZED_P(0);
597  GSERIALIZED *max = PG_GETARG_GSERIALIZED_P(1);
598  BOX3D *result = palloc(sizeof(BOX3D));
599  LWGEOM *minpoint, *maxpoint;
600  POINT3DZ minp, maxp;
601 
602  minpoint = lwgeom_from_gserialized(min);
603  maxpoint = lwgeom_from_gserialized(max);
604 
605  if (minpoint->type != POINTTYPE || maxpoint->type != POINTTYPE)
606  {
607  elog(ERROR, "BOX3D_construct: args must be points");
608  PG_RETURN_NULL();
609  }
610 
611  if (lwgeom_is_empty(minpoint) || lwgeom_is_empty(maxpoint) ){
612  elog(ERROR, "BOX3D_construct: args can not be empty points");
613  PG_RETURN_NULL();
614  }
615 
616  gserialized_error_if_srid_mismatch(min, max, __func__);
617 
618  getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
619  getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
620 
621  result->xmax = maxp.x;
622  result->ymax = maxp.y;
623  result->zmax = maxp.z;
624 
625  result->xmin = minp.x;
626  result->ymin = minp.y;
627  result->zmin = minp.z;
628 
629  result->srid = minpoint->srid;
630 
631  PG_RETURN_POINTER(result);
632 }
633 
635 /*****************************************************************************
636  * BOX3D functions
637  *****************************************************************************/
638 
639 /* contains? */
640 bool
642 {
643  return (box1->xmax >= box2->xmax && box1->xmin <= box2->xmin) &&
644  (box1->ymax >= box2->ymax && box1->ymin <= box2->ymin) &&
645  (box1->zmax >= box2->zmax && box1->zmin <= box2->zmin);
646 }
647 
649 
650 PGDLLEXPORT Datum BOX3D_contains(PG_FUNCTION_ARGS)
651 {
652  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
653  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
654  bool result = BOX3D_contains_internal(box1, box2);
655  PG_RETURN_BOOL(result);
656 }
657 
658 /* contained by? */
659 bool
661 {
662  return BOX3D_contains_internal(box2, box1);
663 }
664 
666 
667 PGDLLEXPORT Datum BOX3D_contained(PG_FUNCTION_ARGS)
668 {
669  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
670  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
671  bool result = BOX3D_contained_internal(box1, box2);
672  PG_RETURN_BOOL(result);
673 }
674 
675 /* overlaps? */
676 bool
678 {
679  return (box1->xmin <= box2->xmax && box2->xmin <= box1->xmax) &&
680  (box1->ymin <= box2->ymax && box2->ymin <= box1->ymax) &&
681  (box1->zmin <= box2->zmax && box2->zmin <= box1->zmax);
682 }
683 
685 
686 PGDLLEXPORT Datum BOX3D_overlaps(PG_FUNCTION_ARGS)
687 {
688  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
689  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
690  bool result = BOX3D_overlaps_internal(box1, box2);
691  PG_RETURN_BOOL(result);
692 }
693 
694 /* same? */
695 bool
697 {
698  return (FPeq(box1->xmax, box2->xmax) && FPeq(box1->xmin, box2->xmin)) &&
699  (FPeq(box1->ymax, box2->ymax) && FPeq(box1->ymin, box2->ymin)) &&
700  (FPeq(box1->zmax, box2->zmax) && FPeq(box1->zmin, box2->zmin));
701 }
702 
704 
705 PGDLLEXPORT Datum BOX3D_same(PG_FUNCTION_ARGS)
706 {
707  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
708  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
709  bool result = BOX3D_same_internal(box1, box2);
710  PG_RETURN_BOOL(result);
711 }
712 
713 /* strictly left of? */
714 bool
716 {
717  return box1->xmax < box2->xmin;
718 }
719 
721 
722 PGDLLEXPORT Datum BOX3D_left(PG_FUNCTION_ARGS)
723 {
724  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
725  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
726  bool result = BOX3D_left_internal(box1, box2);
727  PG_RETURN_BOOL(result);
728 }
729 
730 /* does not extend to right of? */
731 bool
733 {
734  return box1->xmax <= box2->xmax;
735 }
736 
738 
739 PGDLLEXPORT Datum BOX3D_overleft(PG_FUNCTION_ARGS)
740 {
741  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
742  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
743  bool result = BOX3D_overleft_internal(box1, box2);
744  PG_RETURN_BOOL(result);
745 }
746 
747 /* strictly right of? */
748 bool
750 {
751  return box1->xmin > box2->xmax;
752 }
753 
755 
756 PGDLLEXPORT Datum BOX3D_right(PG_FUNCTION_ARGS)
757 {
758  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
759  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
760  bool result = BOX3D_right_internal(box1, box2);
761  PG_RETURN_BOOL(result);
762 }
763 
764 /* does not extend to left of? */
765 bool
767 {
768  return box1->xmin >= box2->xmin;
769 }
770 
772 
773 PGDLLEXPORT Datum BOX3D_overright(PG_FUNCTION_ARGS)
774 {
775  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
776  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
777  bool result = BOX3D_overright_internal(box1, box2);
778  PG_RETURN_BOOL(result);
779 }
780 
781 /* strictly below of? */
782 bool
784 {
785  return box1->ymax < box2->ymin;
786 }
787 
789 
790 PGDLLEXPORT Datum BOX3D_below(PG_FUNCTION_ARGS)
791 {
792  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
793  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
794  bool result = BOX3D_below_internal(box1, box2);
795  PG_RETURN_BOOL(result);
796 }
797 
798 /* does not extend above of? */
799 bool
801 {
802  return box1->ymax <= box2->ymax;
803 }
804 
806 
807 PGDLLEXPORT Datum BOX3D_overbelow(PG_FUNCTION_ARGS)
808 {
809  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
810  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
811  bool result = BOX3D_overbelow_internal(box1, box2);
812  PG_RETURN_BOOL(result);
813 }
814 
815 /* strictly above of? */
816 bool
818 {
819  return box1->ymin > box2->ymax;
820 }
821 
823 
824 PGDLLEXPORT Datum BOX3D_above(PG_FUNCTION_ARGS)
825 {
826  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
827  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
828  bool result = BOX3D_above_internal(box1, box2);
829  PG_RETURN_BOOL(result);
830 }
831 
832 /* does not extend below of? */
833 bool
835 {
836  return box1->ymin >= box2->ymin;
837 }
838 
840 
841 PGDLLEXPORT Datum BOX3D_overabove(PG_FUNCTION_ARGS)
842 {
843  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
844  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
845  bool result = BOX3D_overabove_internal(box1, box2);
846  PG_RETURN_BOOL(result);
847 }
848 
849 /* strictly in before of? */
850 bool
852 {
853  return box1->zmax < box2->zmin;
854 }
855 
857 
858 PGDLLEXPORT Datum BOX3D_front(PG_FUNCTION_ARGS)
859 {
860  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
861  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
862  bool result = BOX3D_front_internal(box1, box2);
863  PG_RETURN_BOOL(result);
864 }
865 
866 /* does not extend to the after of? */
867 bool
869 {
870  return box1->zmax <= box2->zmax;
871 }
872 
874 
875 PGDLLEXPORT Datum BOX3D_overfront(PG_FUNCTION_ARGS)
876 {
877  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
878  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
879  bool result = BOX3D_overfront_internal(box1, box2);
880  PG_RETURN_BOOL(result);
881 }
882 
883 /* strictly after of? */
884 bool
886 {
887  return box1->zmin > box2->zmax;
888 }
889 
891 
892 PGDLLEXPORT Datum BOX3D_back(PG_FUNCTION_ARGS)
893 {
894  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
895  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
896  bool result = BOX3D_back_internal(box1, box2);
897  PG_RETURN_BOOL(result);
898 }
899 
900 /* does not extend to the before of? */
901 bool
903 {
904  return box1->zmin >= box2->zmin;
905 }
906 
908 
909 PGDLLEXPORT Datum BOX3D_overback(PG_FUNCTION_ARGS)
910 {
911  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
912  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
913  bool result = BOX3D_overback_internal(box1, box2);
914  PG_RETURN_BOOL(result);
915 }
916 
917 /* Minimum distance between 2 bounding boxes */
918 double
920 {
921  double sqrDist = 0;
922  double d;
923 
924  if (BOX3D_overlaps_internal(box1, box2))
925  return 0.0;
926 
927  /* X axis */
928  if (box1->xmax < box2->xmin)
929  {
930  d = box1->xmax - box2->xmin;
931  sqrDist += d * d;
932  }
933  else if (box1->xmin > box2->xmax)
934  {
935  d = box1->xmin - box2->xmax;
936  sqrDist += d * d;
937  }
938  /* Y axis */
939  if (box1->ymax < box2->ymin)
940  {
941  d = box1->ymax - box2->ymin;
942  sqrDist += d * d;
943  }
944  else if (box1->ymin > box2->ymax)
945  {
946  d = box1->ymin - box2->ymax;
947  sqrDist += d * d;
948  }
949  /* Z axis */
950  if (box1->zmax < box2->zmin)
951  {
952  d = box1->zmax - box2->zmin;
953  sqrDist += d * d;
954  }
955  else if (box1->zmin > box2->zmax)
956  {
957  d = box1->zmin - box2->zmax;
958  sqrDist += d * d;
959  }
960 
961  return sqrt(sqrDist);
962 }
963 
965 
966 PGDLLEXPORT Datum BOX3D_distance(PG_FUNCTION_ARGS)
967 {
968  BOX3D *box1 = PG_GETARG_BOX3D_P(0);
969  BOX3D *box2 = PG_GETARG_BOX3D_P(1);
970  PG_RETURN_FLOAT8(BOX3D_distance_internal(box1, box2));
971 }
static uint8_t precision
Definition: cu_in_twkb.c:25
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
GBOX * box3d_to_gbox(const BOX3D *b3d)
Definition: gbox.c:80
BOX3D * box3d_from_gbox(const GBOX *gbox)
Definition: gbox.c:53
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
Definition: gserialized.c:432
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
Definition: gserialized.c:94
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
void gserialized_set_srid(GSERIALIZED *g, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized.c:167
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:367
#define LW_FALSE
Definition: liblwgeom.h:94
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1246
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:357
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWPOLY * lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4)
Definition: lwpoly.c:80
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *point)
Definition: lwgeom_api.c:215
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:372
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:166
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:357
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition: lwgeom.c:783
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:42
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
#define FLAGS_SET_SOLID(flags, value)
Definition: liblwgeom.h:177
void lwline_free(LWLINE *line)
Definition: lwline.c:67
This library is the generic geometry handling section of PostGIS.
#define OUT_MAX_BYTES_DOUBLE
int lwprint_double(double d, int maxdd, char *buf)
Definition: lwprint.c:463
PGDLLEXPORT Datum BOX3D_below(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:790
bool BOX3D_above_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:817
PGDLLEXPORT Datum BOX3D_left(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:722
bool BOX3D_back_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:885
PGDLLEXPORT Datum BOX3D_overlaps(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:686
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:181
static void box3d_to_box_p(BOX3D *box, BOX *out)
Definition: lwgeom_box3d.c:168
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:191
PGDLLEXPORT Datum BOX3D_contained(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:667
PGDLLEXPORT Datum BOX3D_overfront(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:875
Datum BOX3D_ymax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:445
Datum BOX3D_zmax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:452
PGDLLEXPORT Datum BOX3D_front(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:858
Datum BOX3D_xmax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:438
Datum BOX3D_combine(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:499
Datum BOX3D_zmin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:431
double BOX3D_distance_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:919
static void expand_box3d_xyz(BOX3D *box, double dx, double dy, double dz)
Definition: lwgeom_box3d.c:356
bool BOX3D_overlaps_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:677
PG_FUNCTION_INFO_V1(BOX3D_in)
BOX3D_in - takes a string rep of BOX3D and returns internal rep.
Datum ST_MMin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:461
PGDLLEXPORT Datum BOX3D_overright(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:773
Datum BOX3D_construct(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:594
bool BOX3D_contains_internal(BOX3D *box1, BOX3D *box2)
needed for sp-gist support PostgreSQL 11+
Definition: lwgeom_box3d.c:641
Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:160
bool BOX3D_overabove_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:834
PGDLLEXPORT Datum BOX3D_overleft(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:739
Datum BOX3D_out(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:120
bool BOX3D_right_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:749
Datum BOX3D_in(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:55
bool BOX3D_overback_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:902
bool BOX3D_overleft_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:732
PGDLLEXPORT Datum BOX3D_contains(PG_FUNCTION_ARGS)
needed for sp-gist support PostgreSQL 11+
Definition: lwgeom_box3d.c:650
bool BOX3D_below_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:783
PGDLLEXPORT Datum BOX3D_back(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:892
PGDLLEXPORT Datum BOX3D_overback(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:909
Datum BOX3D_expand(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:367
void expand_box3d(BOX3D *box, double d)
Expand given box of 'd' units in all directions.
Definition: lwgeom_box3d.c:344
Datum ST_MMax(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:478
PGDLLEXPORT Datum BOX3D_above(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:824
bool BOX3D_left_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:715
bool BOX3D_overright_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:766
bool BOX3D_same_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:696
bool BOX3D_contained_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:660
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:398
Datum BOX3D_xmin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:417
bool BOX3D_front_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:851
bool BOX3D_overfront_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:868
PGDLLEXPORT Datum BOX3D_right(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:756
PGDLLEXPORT Datum BOX3D_overabove(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:841
PGDLLEXPORT Datum BOX3D_overbelow(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:807
PGDLLEXPORT Datum BOX3D_same(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:705
bool BOX3D_overbelow_internal(BOX3D *box1, BOX3D *box2)
Definition: lwgeom_box3d.c:800
Datum BOX3D_combine_BOX3D(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:566
Datum BOX3D_ymin(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:424
PGDLLEXPORT Datum BOX3D_distance(PG_FUNCTION_ARGS)
Definition: lwgeom_box3d.c:966
#define str(s)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:199
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
uint8_t type
Definition: liblwgeom.h:462
int32_t srid
Definition: liblwgeom.h:460
lwflags_t flags
Definition: liblwgeom.h:461
double z
Definition: liblwgeom.h:396
double x
Definition: liblwgeom.h:396
double y
Definition: liblwgeom.h:396
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414