PostGIS  3.0.6dev-r@@SVN_REVISION@@
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 
73 #include "gserialized_spgist_3d.h"
74 #include "lwgeom_box3d.h"
75 #include "lwgeom_pg.h"
76 
77 #include <float.h>
78 
80 Datum 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 
92 Datum 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 
104 Datum 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 
116 Datum 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  */
134 static int
135 compareDoubles(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 
145 typedef 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  */
158 static 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  */
190 static 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  */
224 static CubeBox3D *
225 nextCubeBox3D(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? */
265 static bool
266 overlap6D(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? */
274 static bool
275 contain6D(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? */
283 static bool
284 left6D(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? */
290 static bool
291 overLeft6D(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? */
297 static bool
298 right6D(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? */
304 static bool
305 overRight6D(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? */
311 static bool
312 below6D(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? */
318 static bool
319 overBelow6D(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? */
325 static bool
326 above6D(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? */
332 static bool
333 overAbove6D(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? */
339 static bool
340 front6D(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? */
346 static bool
347 overFront6D(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? */
353 static bool
354 back6D(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? */
360 static bool
361 overBack6D(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 
372 PGDLLEXPORT 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 
396 PGDLLEXPORT 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 
421 PGDLLEXPORT 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);
425  BOX3D *centroid;
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 
506 PGDLLEXPORT 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;
514  BOX3D *centroid;
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 
670 PGDLLEXPORT 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 
771 PGDLLEXPORT 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)
static CubeBox3D * nextCubeBox3D(CubeBox3D *cube_box, BOX3D *centroid, uint8 octant)
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)
static CubeBox3D * initCubeBox(void)
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)
Datum gserialized_contained_3d(PG_FUNCTION_ARGS)
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)
Definition: lwgeom_box3d.c:390
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