PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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"
32
33#include "../postgis_config.h"
34#include "lwgeom_pg.h"
35#include "liblwgeom.h"
36#include "lwgeom_box3d.h"
37
38#include <math.h>
39#include <float.h>
40#include <string.h>
41#include <stdio.h>
42
43#define SHOW_DIGS_DOUBLE 15
44#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 + 1)
45
56Datum 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
121Datum 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
152Datum 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
159static void
160box3d_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
173Datum 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
183Datum 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;
213
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;
228 pt.x = box->xmax;
229 pt.y = box->ymax;
230 pt.z = box->zmax;
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
335void
336expand_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
347static void
348expand_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
359Datum 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
390Datum 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
409Datum 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
416Datum 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
423Datum 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
430Datum 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
437Datum 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
444Datum 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
456Datum 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
523Datum 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
551Datum 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 if (lwgeom_is_empty(minpoint) || lwgeom_is_empty(maxpoint) ){
569 elog(ERROR, "BOX3D_construct: args can not be empty points");
570 PG_RETURN_NULL();
571 }
572
573 gserialized_error_if_srid_mismatch(min, max, __func__);
574
575 getPoint3dz_p(((LWPOINT *)minpoint)->point, 0, &minp);
576 getPoint3dz_p(((LWPOINT *)maxpoint)->point, 0, &maxp);
577
578 result->xmax = maxp.x;
579 result->ymax = maxp.y;
580 result->zmax = maxp.z;
581
582 result->xmin = minp.x;
583 result->ymin = minp.y;
584 result->zmin = minp.z;
585
586 result->srid = minpoint->srid;
587
588 PG_RETURN_POINTER(result);
589}
590
592#if POSTGIS_PGSQL_VERSION > 100
593/*****************************************************************************
594 * BOX3D functions
595 *****************************************************************************/
596
597/* contains? */
598bool
600{
601 return (box1->xmax >= box2->xmax && box1->xmin <= box2->xmin) &&
602 (box1->ymax >= box2->ymax && box1->ymin <= box2->ymin) &&
603 (box1->zmax >= box2->zmax && box1->zmin <= box2->zmin);
604}
605
606PG_FUNCTION_INFO_V1(BOX3D_contains);
607
608PGDLLEXPORT Datum BOX3D_contains(PG_FUNCTION_ARGS)
609{
610 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
611 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
612 bool result = BOX3D_contains_internal(box1, box2);
613 PG_RETURN_BOOL(result);
614}
615
616/* contained by? */
617bool
619{
620 return BOX3D_contains_internal(box2, box1);
621}
622
623PG_FUNCTION_INFO_V1(BOX3D_contained);
624
625PGDLLEXPORT Datum BOX3D_contained(PG_FUNCTION_ARGS)
626{
627 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
628 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
629 bool result = BOX3D_contained_internal(box1, box2);
630 PG_RETURN_BOOL(result);
631}
632
633/* overlaps? */
634bool
636{
637 return (box1->xmin <= box2->xmax && box2->xmin <= box1->xmax) &&
638 (box1->ymin <= box2->ymax && box2->ymin <= box1->ymax) &&
639 (box1->zmin <= box2->zmax && box2->zmin <= box1->zmax);
640}
641
642PG_FUNCTION_INFO_V1(BOX3D_overlaps);
643
644PGDLLEXPORT Datum BOX3D_overlaps(PG_FUNCTION_ARGS)
645{
646 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
647 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
648 bool result = BOX3D_overlaps_internal(box1, box2);
649 PG_RETURN_BOOL(result);
650}
651
652/* same? */
653bool
654BOX3D_same_internal(BOX3D *box1, BOX3D *box2)
655{
656 return (FPeq(box1->xmax, box2->xmax) && FPeq(box1->xmin, box2->xmin)) &&
657 (FPeq(box1->ymax, box2->ymax) && FPeq(box1->ymin, box2->ymin)) &&
658 (FPeq(box1->zmax, box2->zmax) && FPeq(box1->zmin, box2->zmin));
659}
660
661PG_FUNCTION_INFO_V1(BOX3D_same);
662
663PGDLLEXPORT Datum BOX3D_same(PG_FUNCTION_ARGS)
664{
665 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
666 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
667 bool result = BOX3D_same_internal(box1, box2);
668 PG_RETURN_BOOL(result);
669}
670
671/* strictly left of? */
672bool
673BOX3D_left_internal(BOX3D *box1, BOX3D *box2)
674{
675 return box1->xmax < box2->xmin;
676}
677
678PG_FUNCTION_INFO_V1(BOX3D_left);
679
680PGDLLEXPORT Datum BOX3D_left(PG_FUNCTION_ARGS)
681{
682 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
683 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
684 bool result = BOX3D_left_internal(box1, box2);
685 PG_RETURN_BOOL(result);
686}
687
688/* does not extend to right of? */
689bool
691{
692 return box1->xmax <= box2->xmax;
693}
694
695PG_FUNCTION_INFO_V1(BOX3D_overleft);
696
697PGDLLEXPORT Datum BOX3D_overleft(PG_FUNCTION_ARGS)
698{
699 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
700 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
701 bool result = BOX3D_overleft_internal(box1, box2);
702 PG_RETURN_BOOL(result);
703}
704
705/* strictly right of? */
706bool
707BOX3D_right_internal(BOX3D *box1, BOX3D *box2)
708{
709 return box1->xmin > box2->xmax;
710}
711
712PG_FUNCTION_INFO_V1(BOX3D_right);
713
714PGDLLEXPORT Datum BOX3D_right(PG_FUNCTION_ARGS)
715{
716 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
717 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
718 bool result = BOX3D_right_internal(box1, box2);
719 PG_RETURN_BOOL(result);
720}
721
722/* does not extend to left of? */
723bool
725{
726 return box1->xmin >= box2->xmin;
727}
728
729PG_FUNCTION_INFO_V1(BOX3D_overright);
730
731PGDLLEXPORT Datum BOX3D_overright(PG_FUNCTION_ARGS)
732{
733 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
734 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
735 bool result = BOX3D_overright_internal(box1, box2);
736 PG_RETURN_BOOL(result);
737}
738
739/* strictly below of? */
740bool
741BOX3D_below_internal(BOX3D *box1, BOX3D *box2)
742{
743 return box1->ymax < box2->ymin;
744}
745
746PG_FUNCTION_INFO_V1(BOX3D_below);
747
748PGDLLEXPORT Datum BOX3D_below(PG_FUNCTION_ARGS)
749{
750 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
751 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
752 bool result = BOX3D_below_internal(box1, box2);
753 PG_RETURN_BOOL(result);
754}
755
756/* does not extend above of? */
757bool
759{
760 return box1->ymax <= box2->ymax;
761}
762
763PG_FUNCTION_INFO_V1(BOX3D_overbelow);
764
765PGDLLEXPORT Datum BOX3D_overbelow(PG_FUNCTION_ARGS)
766{
767 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
768 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
769 bool result = BOX3D_overbelow_internal(box1, box2);
770 PG_RETURN_BOOL(result);
771}
772
773/* strictly above of? */
774bool
775BOX3D_above_internal(BOX3D *box1, BOX3D *box2)
776{
777 return box1->ymin > box2->ymax;
778}
779
780PG_FUNCTION_INFO_V1(BOX3D_above);
781
782PGDLLEXPORT Datum BOX3D_above(PG_FUNCTION_ARGS)
783{
784 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
785 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
786 bool result = BOX3D_above_internal(box1, box2);
787 PG_RETURN_BOOL(result);
788}
789
790/* does not extend below of? */
791bool
793{
794 return box1->ymin >= box2->ymin;
795}
796
797PG_FUNCTION_INFO_V1(BOX3D_overabove);
798
799PGDLLEXPORT Datum BOX3D_overabove(PG_FUNCTION_ARGS)
800{
801 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
802 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
803 bool result = BOX3D_overabove_internal(box1, box2);
804 PG_RETURN_BOOL(result);
805}
806
807/* strictly in before of? */
808bool
809BOX3D_front_internal(BOX3D *box1, BOX3D *box2)
810{
811 return box1->zmax < box2->zmin;
812}
813
814PG_FUNCTION_INFO_V1(BOX3D_front);
815
816PGDLLEXPORT Datum BOX3D_front(PG_FUNCTION_ARGS)
817{
818 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
819 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
820 bool result = BOX3D_front_internal(box1, box2);
821 PG_RETURN_BOOL(result);
822}
823
824/* does not extend to the after of? */
825bool
827{
828 return box1->zmax <= box2->zmax;
829}
830
831PG_FUNCTION_INFO_V1(BOX3D_overfront);
832
833PGDLLEXPORT Datum BOX3D_overfront(PG_FUNCTION_ARGS)
834{
835 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
836 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
837 bool result = BOX3D_overfront_internal(box1, box2);
838 PG_RETURN_BOOL(result);
839}
840
841/* strictly after of? */
842bool
843BOX3D_back_internal(BOX3D *box1, BOX3D *box2)
844{
845 return box1->zmin > box2->zmax;
846}
847
848PG_FUNCTION_INFO_V1(BOX3D_back);
849
850PGDLLEXPORT Datum BOX3D_back(PG_FUNCTION_ARGS)
851{
852 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
853 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
854 bool result = BOX3D_back_internal(box1, box2);
855 PG_RETURN_BOOL(result);
856}
857
858/* does not extend to the before of? */
859bool
861{
862 return box1->zmin >= box2->zmin;
863}
864
865PG_FUNCTION_INFO_V1(BOX3D_overback);
866
867PGDLLEXPORT Datum BOX3D_overback(PG_FUNCTION_ARGS)
868{
869 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
870 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
871 bool result = BOX3D_overback_internal(box1, box2);
872 PG_RETURN_BOOL(result);
873}
874
875/* Minimum distance between 2 bounding boxes */
876double
878{
879 double sqrDist = 0;
880 double d;
881
882 if (BOX3D_overlaps_internal(box1, box2))
883 return 0.0;
884
885 /* X axis */
886 if (box1->xmax < box2->xmin)
887 {
888 d = box1->xmax - box2->xmin;
889 sqrDist += d * d;
890 }
891 else if (box1->xmin > box2->xmax)
892 {
893 d = box1->xmin - box2->xmax;
894 sqrDist += d * d;
895 }
896 /* Y axis */
897 if (box1->ymax < box2->ymin)
898 {
899 d = box1->ymax - box2->ymin;
900 sqrDist += d * d;
901 }
902 else if (box1->ymin > box2->ymax)
903 {
904 d = box1->ymin - box2->ymax;
905 sqrDist += d * d;
906 }
907 /* Z axis */
908 if (box1->zmax < box2->zmin)
909 {
910 d = box1->zmax - box2->zmin;
911 sqrDist += d * d;
912 }
913 else if (box1->zmin > box2->zmax)
914 {
915 d = box1->zmin - box2->zmax;
916 sqrDist += d * d;
917 }
918
919 return sqrt(sqrDist);
920}
921
922PG_FUNCTION_INFO_V1(BOX3D_distance);
923
924PGDLLEXPORT Datum BOX3D_distance(PG_FUNCTION_ARGS)
925{
926 BOX3D *box1 = PG_GETARG_BOX3D_P(0);
927 BOX3D *box2 = PG_GETARG_BOX3D_P(1);
928 PG_RETURN_FLOAT8(BOX3D_distance_internal(box1, box2));
929}
930#endif
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)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
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).
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:326
#define LW_FALSE
Definition liblwgeom.h:108
void lwpoint_free(LWPOINT *pt)
Definition lwpoint.c:213
#define LW_FAILURE
Definition liblwgeom.h:110
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition lwpoint.c:129
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition ptarray.c:59
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
void * lwalloc(size_t size)
Definition lwutil.c:227
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *point)
Definition lwgeom_api.c:215
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:321
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:128
void lwcollection_free(LWCOLLECTION *col)
LWPOLY * lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4)
Definition lwpoly.c:80
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:737
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 lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:229
#define FLAGS_SET_SOLID(flags, value)
Definition liblwgeom.h:191
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:311
void lwline_free(LWLINE *line)
Definition lwline.c:67
This library is the generic geometry handling section of PostGIS.
Datum BOX3D_to_BOX(PG_FUNCTION_ARGS)
static void box3d_to_box_p(BOX3D *box, BOX *out)
Datum BOX3D_to_LWGEOM(PG_FUNCTION_ARGS)
Datum BOX3D_ymax(PG_FUNCTION_ARGS)
Datum BOX3D_zmax(PG_FUNCTION_ARGS)
#define MAX_DIGS_DOUBLE
Datum BOX3D_xmax(PG_FUNCTION_ARGS)
Datum BOX3D_combine(PG_FUNCTION_ARGS)
Datum BOX3D_zmin(PG_FUNCTION_ARGS)
static void expand_box3d_xyz(BOX3D *box, double dx, double dy, double dz)
PG_FUNCTION_INFO_V1(BOX3D_in)
BOX3D_in - takes a string rep of BOX3D and returns internal rep.
Datum BOX3D_construct(PG_FUNCTION_ARGS)
Datum BOX3D_to_BOX2D(PG_FUNCTION_ARGS)
Datum BOX3D_out(PG_FUNCTION_ARGS)
Datum BOX3D_in(PG_FUNCTION_ARGS)
Datum BOX3D_expand(PG_FUNCTION_ARGS)
void expand_box3d(BOX3D *box, double d)
Expand given box of 'd' units in all directions.
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
Datum BOX3D_xmin(PG_FUNCTION_ARGS)
Datum BOX3D_combine_BOX3D(PG_FUNCTION_ARGS)
Datum BOX3D_ymin(PG_FUNCTION_ARGS)
bool BOX3D_above_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_back_internal(BOX3D *box1, BOX3D *box2)
double BOX3D_distance_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overlaps_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_contains_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overabove_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_right_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overback_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overleft_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_below_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_left_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overright_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_same_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_contained_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_front_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overfront_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_overbelow_internal(BOX3D *box1, BOX3D *box2)
#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:193
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
double xmax
Definition liblwgeom.h:326
double zmin
Definition liblwgeom.h:325
double ymax
Definition liblwgeom.h:326
double ymin
Definition liblwgeom.h:325
double zmax
Definition liblwgeom.h:326
double xmin
Definition liblwgeom.h:325
int32_t srid
Definition liblwgeom.h:327
double ymax
Definition liblwgeom.h:343
double zmax
Definition liblwgeom.h:345
double xmax
Definition liblwgeom.h:341
double zmin
Definition liblwgeom.h:344
double ymin
Definition liblwgeom.h:342
double xmin
Definition liblwgeom.h:340
uint8_t type
Definition liblwgeom.h:448
int32_t srid
Definition liblwgeom.h:446
lwflags_t flags
Definition liblwgeom.h:447
double z
Definition liblwgeom.h:382
double x
Definition liblwgeom.h:382
double y
Definition liblwgeom.h:382
double x
Definition liblwgeom.h:400
double z
Definition liblwgeom.h:400
double y
Definition liblwgeom.h:400