PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
gserialized_spgist_3d.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * gserialized_spgist_3d.c
4 * SP-GiST implementation of 6-dimensional oct-tree over 3D boxes
5 *
6 * This module provides SP-GiST implementation for boxes using oct tree
7 * analogy in 4-dimensional space. SP-GiST doesn't allow indexing of
8 * overlapping objects. We are making 3D objects never-overlapping in
9 * 6D space. This technique has some benefits compared to traditional
10 * R-Tree which is implemented as GiST. The performance tests reveal
11 * that this technique especially beneficial with too much overlapping
12 * objects, so called "spaghetti data".
13 *
14 * Unlike the original oct-tree, we are splitting the tree into 64
15 * octants in 6D space. It is easier to imagine it as splitting space
16 * three times into 3:
17 *
18 * | | | |
19 * | | | |
20 * | -----+----- | -----+-----
21 * | | | |
22 * | | | |
23 * -------------+------------- -+- -------------+-------------
24 * | |
25 * | |
26 * | |
27 * | |
28 * | |
29 * FRONT BACK
30 *
31 * We are using box3D data type as the prefix, but we are treating them
32 * as points in 6-dimensional space, because 3D boxes are not enough
33 * to represent the octant boundaries in 6D space. They however are
34 * sufficient to point out the additional boundaries of the next
35 * octant.
36 *
37 * We are using traversal values provided by SP-GiST to calculate and
38 * to store the bounds of the octants, while traversing into the tree.
39 * Traversal value has all the boundaries in the 6D space, and is is
40 * capable of transferring the required boundaries to the following
41 * traversal values. In conclusion, three things are necessary
42 * to calculate the next traversal value:
43 *
44 * (1) the traversal value of the parent
45 * (2) the octant of the current node
46 * (3) the prefix of the current node
47 *
48 * If we visualize them on our simplified drawing (see the drawing above);
49 * transferred boundaries of (1) would be the outer axis, relevant part
50 * of (2) would be the up range_y part of the other axis, and (3) would be
51 * the inner axis.
52 *
53 * For example, consider the case of overlapping. When recursion
54 * descends deeper and deeper down the tree, all octants in
55 * the current node will be checked for overlapping. The boundaries
56 * will be re-calculated for all octants. Overlap check answers
57 * the question: can any box from this octant overlap with the given
58 * box? If yes, then this octant will be walked. If no, then this
59 * octant will be skipped.
60 *
61 * This method provides restrictions for minimum and maximum values of
62 * every dimension of every corner of the box on every level of the tree
63 * except the root. For the root node, we are setting the boundaries
64 * that we don't yet have as infinity.
65 *
66 * Portions Copyright (c) 2018, Esteban Zimanyi, Arthur Lesuisse,
67 * Université Libre de Bruxelles
68 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
69 * Portions Copyright (c) 1994, Regents of the University of California
70 *
71 *****************************************************************************/
72
74#include "lwgeom_box3d.h"
75#include "lwgeom_pg.h"
76
77#include <float.h>
78
80Datum gserialized_overlaps_3d(PG_FUNCTION_ARGS)
81{
82 BOX3D *box1 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
83 BOX3D *box2 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(1)));
84 bool resut = BOX3D_overlaps_internal(box1, box2);
85 pfree(box1);
86 pfree(box2);
87
88 PG_RETURN_BOOL(resut);
89}
90
92Datum gserialized_contains_3d(PG_FUNCTION_ARGS)
93{
94 BOX3D *box1 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
95 BOX3D *box2 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(1)));
96 bool resut = BOX3D_contains_internal(box1, box2);
97 pfree(box1);
98 pfree(box2);
99
100 PG_RETURN_BOOL(resut);
101}
102
104Datum gserialized_contained_3d(PG_FUNCTION_ARGS)
105{
106 BOX3D *box1 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
107 BOX3D *box2 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(1)));
108 bool resut = BOX3D_contained_internal(box1, box2);
109 pfree(box1);
110 pfree(box2);
111
112 PG_RETURN_BOOL(resut);
113}
114
116Datum gserialized_same_3d(PG_FUNCTION_ARGS)
117{
118 BOX3D *box1 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
119 BOX3D *box2 = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(1)));
120 bool resut = BOX3D_same_internal(box1, box2);
121 pfree(box1);
122 pfree(box2);
123
124 PG_RETURN_BOOL(resut);
125}
126
127/*
128 * Comparator for qsort
129 *
130 * We don't need to use the floating point macros in here, because this
131 * is only going to be used in a place to effect the performance
132 * of the index, not the correctness.
133 */
134static int
135compareDoubles(const void *a, const void *b)
136{
137 double x = *(double *)a;
138 double y = *(double *)b;
139
140 if (x == y)
141 return 0;
142 return (x > y) ? 1 : -1;
143}
144
145typedef struct
146{
149} CubeBox3D;
150
151/*
152 * Calculate the octant
153 *
154 * The octant is 8 bit unsigned integer with 6 least bits in use.
155 * This function accepts 2 BOX3D as input. All 6 bits are set by comparing
156 * a corner of the box. This makes 64 octants in total.
157 */
158static uint8
160{
161 uint8 octant = 0;
162
163 if (inBox->xmin > centroid->xmin)
164 octant |= 0x20;
165
166 if (inBox->xmax > centroid->xmax)
167 octant |= 0x10;
168
169 if (inBox->ymin > centroid->ymin)
170 octant |= 0x08;
171
172 if (inBox->ymax > centroid->ymax)
173 octant |= 0x04;
174
175 if (inBox->zmin > centroid->zmin)
176 octant |= 0x02;
177
178 if (inBox->zmax > centroid->zmax)
179 octant |= 0x01;
180
181 return octant;
182}
183
184/*
185 * Initialize the traversal value
186 *
187 * In the beginning, we don't have any restrictions. We have to
188 * initialize the struct to cover the whole 6D space.
189 */
190static CubeBox3D *
192{
193 CubeBox3D *cube_box = (CubeBox3D *)palloc(sizeof(CubeBox3D));
194 double infinity = DBL_MAX;
195
196 cube_box->left.xmin = -infinity;
197 cube_box->left.xmax = infinity;
198
199 cube_box->left.ymin = -infinity;
200 cube_box->left.ymax = infinity;
201
202 cube_box->left.zmin = -infinity;
203 cube_box->left.zmax = infinity;
204
205 cube_box->right.xmin = -infinity;
206 cube_box->right.xmax = infinity;
207
208 cube_box->right.ymin = -infinity;
209 cube_box->right.ymax = infinity;
210
211 cube_box->right.zmin = -infinity;
212 cube_box->right.zmax = infinity;
213
214 return cube_box;
215}
216
217/*
218 * Calculate the next traversal value
219 *
220 * All centroids are bounded by CubeBox3D, but SP-GiST only keeps boxes.
221 * When we are traversing the tree, we must calculate CubeBox3D,
222 * using centroid and octant.
223 */
224static CubeBox3D *
225nextCubeBox3D(CubeBox3D *cube_box, BOX3D *centroid, uint8 octant)
226{
227 CubeBox3D *next_cube_box = (CubeBox3D *)palloc(sizeof(CubeBox3D));
228
229 memcpy(next_cube_box, cube_box, sizeof(CubeBox3D));
230
231 if (octant & 0x20)
232 next_cube_box->left.xmin = centroid->xmin;
233 else
234 next_cube_box->left.xmax = centroid->xmin;
235
236 if (octant & 0x10)
237 next_cube_box->right.xmin = centroid->xmax;
238 else
239 next_cube_box->right.xmax = centroid->xmax;
240
241 if (octant & 0x08)
242 next_cube_box->left.ymin = centroid->ymin;
243 else
244 next_cube_box->left.ymax = centroid->ymin;
245
246 if (octant & 0x04)
247 next_cube_box->right.ymin = centroid->ymax;
248 else
249 next_cube_box->right.ymax = centroid->ymax;
250
251 if (octant & 0x02)
252 next_cube_box->left.zmin = centroid->zmin;
253 else
254 next_cube_box->left.zmax = centroid->zmin;
255
256 if (octant & 0x01)
257 next_cube_box->right.zmin = centroid->zmax;
258 else
259 next_cube_box->right.zmax = centroid->zmax;
260
261 return next_cube_box;
262}
263
264/* Can any cube from cube_box overlap with query? */
265static bool
266overlap6D(CubeBox3D *cube_box, BOX3D *query)
267{
268 return (cube_box->left.xmin <= query->xmax) && (cube_box->right.xmax >= query->xmin) &&
269 (cube_box->left.ymin <= query->ymax) && (cube_box->right.ymax >= query->ymin) &&
270 (cube_box->left.zmin <= query->zmax) && (cube_box->right.zmax >= query->zmin);
271}
272
273/* Can any cube from cube_box contain query? */
274static bool
275contain6D(CubeBox3D *cube_box, BOX3D *query)
276{
277 return (cube_box->right.xmax >= query->xmax) && (cube_box->left.xmin <= query->xmin) &&
278 (cube_box->right.ymax >= query->ymax) && (cube_box->left.ymin <= query->ymin) &&
279 (cube_box->right.zmax >= query->zmax) && (cube_box->left.zmin <= query->zmin);
280}
281
282/* Can any cube from cube_box be left of query? */
283static bool
284left6D(CubeBox3D *cube_box, BOX3D *query)
285{
286 return (cube_box->right.xmax < query->xmin);
287}
288
289/* Can any cube from cube_box does not extend the right of query? */
290static bool
291overLeft6D(CubeBox3D *cube_box, BOX3D *query)
292{
293 return (cube_box->right.xmax <= query->xmax);
294}
295
296/* Can any cube from cube_box be right of query? */
297static bool
298right6D(CubeBox3D *cube_box, BOX3D *query)
299{
300 return (cube_box->left.xmin > query->xmax);
301}
302
303/* Can any cube from cube_box does not extend the left of query? */
304static bool
305overRight6D(CubeBox3D *cube_box, BOX3D *query)
306{
307 return (cube_box->left.xmin >= query->xmin);
308}
309
310/* Can any cube from cube_box be below of query? */
311static bool
312below6D(CubeBox3D *cube_box, BOX3D *query)
313{
314 return (cube_box->right.ymax < query->ymin);
315}
316
317/* Can any cube from cube_box does not extend above query? */
318static bool
319overBelow6D(CubeBox3D *cube_box, BOX3D *query)
320{
321 return (cube_box->right.ymax <= query->ymax);
322}
323
324/* Can any cube from cube_box be above of query? */
325static bool
326above6D(CubeBox3D *cube_box, BOX3D *query)
327{
328 return (cube_box->left.ymin > query->ymax);
329}
330
331/* Can any cube from cube_box does not extend below of query? */
332static bool
333overAbove6D(CubeBox3D *cube_box, BOX3D *query)
334{
335 return (cube_box->left.ymin >= query->ymin);
336}
337
338/* Can any cube from cube_box be before of query? */
339static bool
340front6D(CubeBox3D *cube_box, BOX3D *query)
341{
342 return (cube_box->right.zmax < query->zmin);
343}
344
345/* Can any cube from cube_box does not extend the after of query? */
346static bool
347overFront6D(CubeBox3D *cube_box, BOX3D *query)
348{
349 return (cube_box->right.zmax <= query->zmax);
350}
351
352/* Can any cube from cube_box be after of query? */
353static bool
354back6D(CubeBox3D *cube_box, BOX3D *query)
355{
356 return (cube_box->left.zmin > query->zmax);
357}
358
359/* Can any cube from cube_box does not extend the before of query? */
360static bool
361overBack6D(CubeBox3D *cube_box, BOX3D *query)
362{
363 return (cube_box->left.zmin >= query->zmin);
364}
365
366/*
367 * SP-GiST config function
368 */
369
371
372PGDLLEXPORT Datum gserialized_spgist_config_3d(PG_FUNCTION_ARGS)
373{
374 spgConfigOut *cfg = (spgConfigOut *)PG_GETARG_POINTER(1);
375
376 Oid boxoid = InvalidOid;
377 /* We need to initialize the internal cache to access it later via postgis_oid() */
378 postgis_initialize_cache(fcinfo);
379 boxoid = postgis_oid(BOX3DOID);
380
381 cfg->prefixType = boxoid;
382 cfg->labelType = VOIDOID; /* We don't need node labels. */
383 cfg->leafType = boxoid;
384 cfg->canReturnData = false;
385 cfg->longValuesOK = false;
386
387 PG_RETURN_VOID();
388}
389
390/*
391 * SP-GiST choose function
392 */
393
395
396PGDLLEXPORT Datum gserialized_spgist_choose_3d(PG_FUNCTION_ARGS)
397{
398 spgChooseIn *in = (spgChooseIn *)PG_GETARG_POINTER(0);
399 spgChooseOut *out = (spgChooseOut *)PG_GETARG_POINTER(1);
400 BOX3D *centroid = DatumGetBox3DP(in->prefixDatum);
401 BOX3D *box = DatumGetBox3DP(in->leafDatum);
402
403 out->resultType = spgMatchNode;
404 out->result.matchNode.restDatum = Box3DPGetDatum(box);
405
406 /* nodeN will be set by core, when allTheSame. */
407 if (!in->allTheSame)
408 out->result.matchNode.nodeN = getOctant(centroid, box);
409
410 PG_RETURN_VOID();
411}
412
413/*
414 * SP-GiST pick-split function
415 *
416 * It splits a list of boxes into octants by choosing a central 6D
417 * point as the median of the coordinates of the boxes.
418 */
420
421PGDLLEXPORT Datum gserialized_spgist_picksplit_3d(PG_FUNCTION_ARGS)
422{
423 spgPickSplitIn *in = (spgPickSplitIn *)PG_GETARG_POINTER(0);
424 spgPickSplitOut *out = (spgPickSplitOut *)PG_GETARG_POINTER(1);
426 int median, i;
427 double *lowXs = palloc(sizeof(double) * in->nTuples);
428 double *highXs = palloc(sizeof(double) * in->nTuples);
429 double *lowYs = palloc(sizeof(double) * in->nTuples);
430 double *highYs = palloc(sizeof(double) * in->nTuples);
431 double *lowZs = palloc(sizeof(double) * in->nTuples);
432 double *highZs = palloc(sizeof(double) * in->nTuples);
433 BOX3D *box = DatumGetBox3DP(in->datums[0]);
434 int32_t srid = box->srid;
435
436 /* Calculate median of all 6D coordinates */
437 for (i = 0; i < in->nTuples; i++)
438 {
439 BOX3D *box = DatumGetBox3DP(in->datums[i]);
440
441 lowXs[i] = box->xmin;
442 highXs[i] = box->xmax;
443 lowYs[i] = box->ymin;
444 highYs[i] = box->ymax;
445 lowZs[i] = box->zmin;
446 highZs[i] = box->zmax;
447 }
448
449 qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
450 qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
451 qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
452 qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
453 qsort(lowZs, in->nTuples, sizeof(double), compareDoubles);
454 qsort(highZs, in->nTuples, sizeof(double), compareDoubles);
455
456 median = in->nTuples / 2;
457
458 centroid = palloc(sizeof(BOX3D));
459
460 centroid->xmin = lowXs[median];
461 centroid->xmax = highXs[median];
462 centroid->ymin = lowYs[median];
463 centroid->ymax = highYs[median];
464 centroid->zmin = lowZs[median];
465 centroid->zmax = highZs[median];
466 centroid->srid = srid;
467
468 /* Fill the output */
469 out->hasPrefix = true;
470 out->prefixDatum = Box3DPGetDatum(centroid);
471
472 out->nNodes = 64;
473 out->nodeLabels = NULL; /* We don't need node labels. */
474
475 out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
476 out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
477
478 /*
479 * Assign ranges to corresponding nodes according to octants relative to
480 * the "centroid" range
481 */
482 for (i = 0; i < in->nTuples; i++)
483 {
484 BOX3D *box = DatumGetBox3DP(in->datums[i]);
485 uint8 octant = getOctant(centroid, box);
486
487 out->leafTupleDatums[i] = Box3DPGetDatum(box);
488 out->mapTuplesToNodes[i] = octant;
489 }
490
491 pfree(lowXs);
492 pfree(highXs);
493 pfree(lowYs);
494 pfree(highYs);
495 pfree(lowZs);
496 pfree(highZs);
497
498 PG_RETURN_VOID();
499}
500
501/*
502 * SP-GiST inner consistent function
503 */
505
506PGDLLEXPORT Datum gserialized_spgist_inner_consistent_3d(PG_FUNCTION_ARGS)
507{
508 spgInnerConsistentIn *in = (spgInnerConsistentIn *)PG_GETARG_POINTER(0);
509 spgInnerConsistentOut *out = (spgInnerConsistentOut *)PG_GETARG_POINTER(1);
510 int i;
511 MemoryContext old_ctx;
512 CubeBox3D *cube_box;
513 uint8 octant;
515 int *nodeNumbers;
516 void **traversalValues;
517
518 if (in->allTheSame)
519 {
520 /* Report that all nodes should be visited */
521 out->nNodes = in->nNodes;
522 out->nodeNumbers = (int *)palloc(sizeof(int) * in->nNodes);
523 for (i = 0; i < in->nNodes; i++)
524 out->nodeNumbers[i] = i;
525
526 PG_RETURN_VOID();
527 }
528
529 /*
530 * We are saving the traversal value or initialize it an unbounded one, if
531 * we have just begun to walk the tree.
532 */
533 if (in->traversalValue)
534 cube_box = in->traversalValue;
535 else
536 cube_box = initCubeBox();
537
538 centroid = DatumGetBox3DP(in->prefixDatum);
539
540 /* Allocate enough memory for nodes */
541 out->nNodes = 0;
542 nodeNumbers = (int *)palloc(sizeof(int) * in->nNodes);
543 traversalValues = (void **)palloc(sizeof(void *) * in->nNodes);
544
545 /*
546 * We switch memory context, because we want to allocate memory for new
547 * traversal values (next_cube_box) and pass these pieces of memory to
548 * further call of this function.
549 */
550 old_ctx = MemoryContextSwitchTo(in->traversalMemoryContext);
551
552 for (octant = 0; octant < in->nNodes; octant++)
553 {
554 CubeBox3D *next_cube_box = nextCubeBox3D(cube_box, centroid, octant);
555 bool flag = true;
556
557 for (i = 0; i < in->nkeys; i++)
558 {
559 StrategyNumber strategy = in->scankeys[i].sk_strategy;
560 Datum query = in->scankeys[i].sk_argument;
561 BOX3D *box = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, query));
562
563 switch (strategy)
564 {
567 flag = overlap6D(next_cube_box, box);
568 break;
569
572 flag = contain6D(next_cube_box, box);
573 break;
574
576 flag = !overRight6D(next_cube_box, box);
577 break;
578
580 flag = !right6D(next_cube_box, box);
581 break;
582
584 flag = !overLeft6D(next_cube_box, box);
585 break;
586
588 flag = !left6D(next_cube_box, box);
589 break;
590
592 flag = !overBelow6D(next_cube_box, box);
593 break;
594
596 flag = !below6D(next_cube_box, box);
597 break;
598
600 flag = !overAbove6D(next_cube_box, box);
601 break;
602
604 flag = !above6D(next_cube_box, box);
605 break;
606
608 flag = !overFront6D(next_cube_box, box);
609 break;
610
612 flag = !front6D(next_cube_box, box);
613 break;
614
616 flag = !overBack6D(next_cube_box, box);
617 break;
618
620 flag = !back6D(next_cube_box, box);
621 break;
622
623 default:
624 elog(ERROR, "unrecognized strategy: %d", strategy);
625 }
626
627 /* If any check is failed, we have found our answer. */
628 if (!flag)
629 break;
630 }
631
632 if (flag)
633 {
634 traversalValues[out->nNodes] = next_cube_box;
635 nodeNumbers[out->nNodes] = octant;
636 out->nNodes++;
637 }
638 else
639 {
640 /*
641 * If this node is not selected, we don't need to keep the next
642 * traversal value in the memory context.
643 */
644 pfree(next_cube_box);
645 }
646 }
647
648 /* Pass to the next level only the values that need to be traversed */
649 out->nodeNumbers = (int *)palloc(sizeof(int) * out->nNodes);
650 out->traversalValues = (void **)palloc(sizeof(void *) * out->nNodes);
651 for (i = 0; i < out->nNodes; i++)
652 {
653 out->nodeNumbers[i] = nodeNumbers[i];
654 out->traversalValues[i] = traversalValues[i];
655 }
656 pfree(nodeNumbers);
657 pfree(traversalValues);
658
659 /* Switch after */
660 MemoryContextSwitchTo(old_ctx);
661
662 PG_RETURN_VOID();
663}
664
665/*
666 * SP-GiST inner consistent function
667 */
669
670PGDLLEXPORT Datum gserialized_spgist_leaf_consistent_3d(PG_FUNCTION_ARGS)
671{
672 spgLeafConsistentIn *in = (spgLeafConsistentIn *)PG_GETARG_POINTER(0);
673 spgLeafConsistentOut *out = (spgLeafConsistentOut *)PG_GETARG_POINTER(1);
674 BOX3D *leaf = DatumGetBox3DP(in->leafDatum);
675 bool flag = true;
676 int i;
677
678 /* All tests are exact. */
679 out->recheck = false;
680
681 /* leafDatum is what it is... */
682 out->leafValue = in->leafDatum;
683
684 /* Perform the required comparison(s) */
685 for (i = 0; i < in->nkeys; i++)
686 {
687 StrategyNumber strategy = in->scankeys[i].sk_strategy;
688 Datum query = in->scankeys[i].sk_argument;
689 BOX3D *box = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, query));
690
691 switch (strategy)
692 {
694 flag = BOX3D_overlaps_internal(leaf, box);
695 break;
696
698 flag = BOX3D_contains_internal(leaf, box);
699 break;
700
702 flag = BOX3D_contained_internal(leaf, box);
703 break;
704
706 flag = BOX3D_same_internal(leaf, box);
707 break;
708
710 flag = BOX3D_left_internal(leaf, box);
711 break;
712
714 flag = BOX3D_overleft_internal(leaf, box);
715 break;
716
718 flag = BOX3D_right_internal(leaf, box);
719 break;
720
722 flag = BOX3D_overright_internal(leaf, box);
723 break;
724
726 flag = BOX3D_above_internal(leaf, box);
727 break;
728
730 flag = BOX3D_overabove_internal(leaf, box);
731 break;
732
734 flag = BOX3D_below_internal(leaf, box);
735 break;
736
738 flag = BOX3D_overbelow_internal(leaf, box);
739 break;
740
742 flag = BOX3D_back_internal(leaf, box);
743 break;
744
746 flag = BOX3D_overback_internal(leaf, box);
747 break;
748
750 flag = BOX3D_front_internal(leaf, box);
751 break;
752
754 flag = BOX3D_overfront_internal(leaf, box);
755 break;
756
757 default:
758 elog(ERROR, "unrecognized strategy: %d", strategy);
759 }
760
761 /* If any check is failed, we have found our answer. */
762 if (!flag)
763 break;
764 }
765
766 PG_RETURN_BOOL(flag);
767}
768
770
771PGDLLEXPORT Datum gserialized_spgist_compress_3d(PG_FUNCTION_ARGS)
772{
773 BOX3D *result = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
774
775 /* Is the bounding box is null */
776 if (result == LW_FAILURE)
777 {
778 PG_RETURN_NULL();
779 }
780
781 /* Return BOX3D. */
782 PG_RETURN_POINTER(result);
783}
784
785/*****************************************************************************/
static bool front6D(CubeBox3D *cube_box, BOX3D *query)
static bool back6D(CubeBox3D *cube_box, BOX3D *query)
static bool right6D(CubeBox3D *cube_box, BOX3D *query)
Datum gserialized_overlaps_3d(PG_FUNCTION_ARGS)
static bool overBack6D(CubeBox3D *cube_box, BOX3D *query)
static bool overAbove6D(CubeBox3D *cube_box, BOX3D *query)
PG_FUNCTION_INFO_V1(gserialized_overlaps_3d)
static bool overlap6D(CubeBox3D *cube_box, BOX3D *query)
Datum gserialized_contains_3d(PG_FUNCTION_ARGS)
static int compareDoubles(const void *a, const void *b)
PGDLLEXPORT Datum gserialized_spgist_picksplit_3d(PG_FUNCTION_ARGS)
static bool overRight6D(CubeBox3D *cube_box, BOX3D *query)
static bool overFront6D(CubeBox3D *cube_box, BOX3D *query)
PGDLLEXPORT Datum gserialized_spgist_config_3d(PG_FUNCTION_ARGS)
PGDLLEXPORT Datum gserialized_spgist_inner_consistent_3d(PG_FUNCTION_ARGS)
Datum gserialized_same_3d(PG_FUNCTION_ARGS)
PGDLLEXPORT Datum gserialized_spgist_compress_3d(PG_FUNCTION_ARGS)
static bool contain6D(CubeBox3D *cube_box, BOX3D *query)
static bool overBelow6D(CubeBox3D *cube_box, BOX3D *query)
static bool above6D(CubeBox3D *cube_box, BOX3D *query)
PGDLLEXPORT Datum gserialized_spgist_choose_3d(PG_FUNCTION_ARGS)
static CubeBox3D * nextCubeBox3D(CubeBox3D *cube_box, BOX3D *centroid, uint8 octant)
Datum gserialized_contained_3d(PG_FUNCTION_ARGS)
static CubeBox3D * initCubeBox(void)
static bool below6D(CubeBox3D *cube_box, BOX3D *query)
static bool overLeft6D(CubeBox3D *cube_box, BOX3D *query)
PGDLLEXPORT Datum gserialized_spgist_leaf_consistent_3d(PG_FUNCTION_ARGS)
static bool left6D(CubeBox3D *cube_box, BOX3D *query)
static uint8 getOctant(BOX3D *centroid, BOX3D *inBox)
#define SPGOverlapStrategyNumber
#define SPGOverLeftStrategyNumber
#define SPGLeftStrategyNumber
#define SPGAboveStrategyNumber
#define SPGSameStrategyNumber
#define SPGOverBackStrategyNumber
#define SPGContainedByStrategyNumber
#define SPGOverRightStrategyNumber
#define SPGFrontStrategyNumber
#define SPGBelowStrategyNumber
#define SPGRightStrategyNumber
#define SPGOverFrontStrategyNumber
#define SPGContainsStrategyNumber
#define SPGOverBelowStrategyNumber
#define SPGBackStrategyNumber
#define SPGOverAboveStrategyNumber
#define LW_FAILURE
Definition liblwgeom.h:110
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
bool BOX3D_above_internal(BOX3D *box1, BOX3D *box2)
bool BOX3D_back_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)
Datum centroid(PG_FUNCTION_ARGS)
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