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