PostGIS 3.7.0dev-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 result = BOX3D_overlaps_internal(box1, box2);
85 pfree(box1);
86 pfree(box2);
87
88 PG_RETURN_BOOL(result);
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 result = BOX3D_contains_internal(box1, box2);
97 pfree(box1);
98 pfree(box2);
99
100 PG_RETURN_BOOL(result);
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 result = BOX3D_contained_internal(box1, box2);
109 pfree(box1);
110 pfree(box2);
111
112 PG_RETURN_BOOL(result);
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 result = BOX3D_same_internal(box1, box2);
121 pfree(box1);
122 pfree(box2);
123
124 PG_RETURN_BOOL(result);
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
159getOctant(const BOX3D *centroid, const BOX3D *inBox)
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();
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 int32_t srid = SRID_UNKNOWN;
434
435 /* Calculate median of all 6D coordinates */
436 for (i = 0; i < in->nTuples; i++)
437 {
438 BOX3D* box_in = DatumGetBox3DP(in->datums[i]);
439 lowXs[i] = box_in->xmin;
440 highXs[i] = box_in->xmax;
441 lowYs[i] = box_in->ymin;
442 highYs[i] = box_in->ymax;
443 lowZs[i] = box_in->zmin;
444 highZs[i] = box_in->zmax;
445
446 if (i == 0)
447 srid = box_in->srid;
448 }
449
450 qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
451 qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
452 qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
453 qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
454 qsort(lowZs, in->nTuples, sizeof(double), compareDoubles);
455 qsort(highZs, in->nTuples, sizeof(double), compareDoubles);
456
457 median = in->nTuples / 2;
458
459 centroid = palloc(sizeof(BOX3D));
460
461 centroid->xmin = lowXs[median];
462 centroid->xmax = highXs[median];
463 centroid->ymin = lowYs[median];
464 centroid->ymax = highYs[median];
465 centroid->zmin = lowZs[median];
466 centroid->zmax = highZs[median];
467 centroid->srid = srid;
468
469 /* Fill the output */
470 out->hasPrefix = true;
471 out->prefixDatum = Box3DPGetDatum(centroid);
472
473 out->nNodes = 64;
474 out->nodeLabels = NULL; /* We don't need node labels. */
475
476 out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
477 out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
478
479 /*
480 * Assign ranges to corresponding nodes according to octants relative to
481 * the "centroid" range
482 */
483 for (i = 0; i < in->nTuples; i++)
484 {
485 BOX3D* box_in = DatumGetBox3DP(in->datums[i]);
486 uint8 octant = getOctant(centroid, box_in);
487
488 out->leafTupleDatums[i] = Box3DPGetDatum(box_in);
489 out->mapTuplesToNodes[i] = octant;
490 }
491
492 pfree(lowXs);
493 pfree(highXs);
494 pfree(lowYs);
495 pfree(highYs);
496 pfree(lowZs);
497 pfree(highZs);
498
499 PG_RETURN_VOID();
500}
501
502/*
503 * SP-GiST inner consistent function
504 */
506
507PGDLLEXPORT Datum gserialized_spgist_inner_consistent_3d(PG_FUNCTION_ARGS)
508{
509 spgInnerConsistentIn *in = (spgInnerConsistentIn *)PG_GETARG_POINTER(0);
510 spgInnerConsistentOut *out = (spgInnerConsistentOut *)PG_GETARG_POINTER(1);
511 int i;
512 MemoryContext old_ctx;
513 CubeBox3D *cube_box;
514 uint8 octant;
516 int *nodeNumbers;
517 void **traversalValues;
518
519 if (in->allTheSame)
520 {
521 /* Report that all nodes should be visited */
522 out->nNodes = in->nNodes;
523 out->nodeNumbers = (int *)palloc(sizeof(int) * in->nNodes);
524 for (i = 0; i < in->nNodes; i++)
525 out->nodeNumbers[i] = i;
526
527 PG_RETURN_VOID();
528 }
529
530 /*
531 * We are saving the traversal value or initialize it an unbounded one, if
532 * we have just begun to walk the tree.
533 */
534 if (in->traversalValue)
535 cube_box = in->traversalValue;
536 else
537 cube_box = initCubeBox();
538
539 centroid = DatumGetBox3DP(in->prefixDatum);
540
541 /* Allocate enough memory for nodes */
542 out->nNodes = 0;
543 nodeNumbers = (int *)palloc(sizeof(int) * in->nNodes);
544 traversalValues = (void **)palloc(sizeof(void *) * in->nNodes);
545
546 /*
547 * We switch memory context, because we want to allocate memory for new
548 * traversal values (next_cube_box) and pass these pieces of memory to
549 * further call of this function.
550 */
551 old_ctx = MemoryContextSwitchTo(in->traversalMemoryContext);
552
553 for (octant = 0; octant < (uint8)in->nNodes; octant++)
554 {
555 CubeBox3D *next_cube_box = nextCubeBox3D(cube_box, centroid, octant);
556 bool flag = true;
557
558 for (i = 0; i < in->nkeys; i++)
559 {
560 StrategyNumber strategy = in->scankeys[i].sk_strategy;
561 Datum query = in->scankeys[i].sk_argument;
562 BOX3D *box = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, query));
563
564 switch (strategy)
565 {
568 flag = overlap6D(next_cube_box, box);
569 break;
570
573 flag = contain6D(next_cube_box, box);
574 break;
575
577 flag = !overRight6D(next_cube_box, box);
578 break;
579
581 flag = !right6D(next_cube_box, box);
582 break;
583
585 flag = !overLeft6D(next_cube_box, box);
586 break;
587
589 flag = !left6D(next_cube_box, box);
590 break;
591
593 flag = !overBelow6D(next_cube_box, box);
594 break;
595
597 flag = !below6D(next_cube_box, box);
598 break;
599
601 flag = !overAbove6D(next_cube_box, box);
602 break;
603
605 flag = !above6D(next_cube_box, box);
606 break;
607
609 flag = !overFront6D(next_cube_box, box);
610 break;
611
613 flag = !front6D(next_cube_box, box);
614 break;
615
617 flag = !overBack6D(next_cube_box, box);
618 break;
619
621 flag = !back6D(next_cube_box, box);
622 break;
623
624 default:
625 elog(ERROR, "unrecognized strategy: %d", strategy);
626 }
627
628 /* If any check is failed, we have found our answer. */
629 if (!flag)
630 break;
631 }
632
633 if (flag)
634 {
635 traversalValues[out->nNodes] = next_cube_box;
636 nodeNumbers[out->nNodes] = octant;
637 out->nNodes++;
638 }
639 else
640 {
641 /*
642 * If this node is not selected, we don't need to keep the next
643 * traversal value in the memory context.
644 */
645 pfree(next_cube_box);
646 }
647 }
648
649 /* Pass to the next level only the values that need to be traversed */
650 out->nodeNumbers = (int *)palloc(sizeof(int) * out->nNodes);
651 out->traversalValues = (void **)palloc(sizeof(void *) * out->nNodes);
652 for (i = 0; i < out->nNodes; i++)
653 {
654 out->nodeNumbers[i] = nodeNumbers[i];
655 out->traversalValues[i] = traversalValues[i];
656 }
657 pfree(nodeNumbers);
658 pfree(traversalValues);
659
660 /* Switch after */
661 MemoryContextSwitchTo(old_ctx);
662
663 PG_RETURN_VOID();
664}
665
666/*
667 * SP-GiST inner consistent function
668 */
670
671PGDLLEXPORT Datum gserialized_spgist_leaf_consistent_3d(PG_FUNCTION_ARGS)
672{
673 spgLeafConsistentIn *in = (spgLeafConsistentIn *)PG_GETARG_POINTER(0);
674 spgLeafConsistentOut *out = (spgLeafConsistentOut *)PG_GETARG_POINTER(1);
675 BOX3D *leaf = DatumGetBox3DP(in->leafDatum);
676 bool flag = true;
677 int i;
678
679 /* All tests are exact. */
680 out->recheck = false;
681
682 /* leafDatum is what it is... */
683 out->leafValue = in->leafDatum;
684
685 /* Perform the required comparison(s) */
686 for (i = 0; i < in->nkeys; i++)
687 {
688 StrategyNumber strategy = in->scankeys[i].sk_strategy;
689 Datum query = in->scankeys[i].sk_argument;
690 BOX3D *box = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, query));
691
692 switch (strategy)
693 {
695 flag = BOX3D_overlaps_internal(leaf, box);
696 break;
697
699 flag = BOX3D_contains_internal(leaf, box);
700 break;
701
703 flag = BOX3D_contained_internal(leaf, box);
704 break;
705
707 flag = BOX3D_same_internal(leaf, box);
708 break;
709
711 flag = BOX3D_left_internal(leaf, box);
712 break;
713
715 flag = BOX3D_overleft_internal(leaf, box);
716 break;
717
719 flag = BOX3D_right_internal(leaf, box);
720 break;
721
723 flag = BOX3D_overright_internal(leaf, box);
724 break;
725
727 flag = BOX3D_above_internal(leaf, box);
728 break;
729
731 flag = BOX3D_overabove_internal(leaf, box);
732 break;
733
735 flag = BOX3D_below_internal(leaf, box);
736 break;
737
739 flag = BOX3D_overbelow_internal(leaf, box);
740 break;
741
743 flag = BOX3D_back_internal(leaf, box);
744 break;
745
747 flag = BOX3D_overback_internal(leaf, box);
748 break;
749
751 flag = BOX3D_front_internal(leaf, box);
752 break;
753
755 flag = BOX3D_overfront_internal(leaf, box);
756 break;
757
758 default:
759 elog(ERROR, "unrecognized strategy: %d", strategy);
760 }
761
762 /* If any check is failed, we have found our answer. */
763 if (!flag)
764 break;
765 }
766
767 PG_RETURN_BOOL(flag);
768}
769
771
772PGDLLEXPORT Datum gserialized_spgist_compress_3d(PG_FUNCTION_ARGS)
773{
774 BOX3D *result = DatumGetBox3DP(DirectFunctionCall1(LWGEOM_to_BOX3D, PG_GETARG_DATUM(0)));
775
776 /* Is the bounding box is null */
777 if (result == LW_FAILURE)
778 {
779 PG_RETURN_NULL();
780 }
781
782 /* Return BOX3D. */
783 PG_RETURN_POINTER(result);
784}
785
786/*****************************************************************************/
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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 uint8 getOctant(const BOX3D *centroid, const BOX3D *inBox)
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)
#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:96
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
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)
Needed for SP-GiST support.
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)
Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
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: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