10#ifndef PBAT_GEOMETRY_SPATIALSEARCH_H
11#define PBAT_GEOMETRY_SPATIALSEARCH_H
14#include "pbat/HostDevice.h"
63 auto kStackDepth = 64>
68 FLeafObject fLeafObject,
69 FNodeOverlap fNodeOverlaps,
70 FObjectOverlap fObjectOverlaps,
113 class FLeafObjectLhs,
117 class FLeafObjectRhs,
119 class FObjectsOverlap,
123 class TIndex =
Index,
124 auto kStackDepth = 128>
127 FIsLeafLhs fIsLeafLhs,
128 FLeafSizeLhs fLeafSizeLhs,
129 FLeafObjectLhs fLeafObjectLhs,
131 FIsLeafRhs fIsLeafRhs,
132 FLeafSizeRhs fLeafSizeRhs,
133 FLeafObjectRhs fLeafObjectRhs,
134 FNodesOverlap fNodesOverlap,
135 FObjectsOverlap fObjectsOverlap,
171 class FObjectsOverlap,
174 class TIndex =
Index,
175 auto kStackDepth = 128>
180 FLeafObject fLeafObject,
181 FNodesOverlap fNodesOverlap,
182 FObjectsOverlap fObjectsOverlap,
236 class FDistanceLowerBound,
241 class TIndex =
Index,
242 auto kStackDepth = 64,
248 FLeafObject fLeafObject,
249 FDistanceLowerBound fLower,
252 bool bUseBestFirstSearch =
false,
253 TScalar fUpper = std::numeric_limits<TScalar>::max(),
254 TScalar eps = TScalar(0),
298 class FDistanceLowerBound,
303 class TIndex =
Index,
304 auto kHeapCapacity = N * 1024>
309 FLeafObject fLeafObject,
310 FDistanceLowerBound fLower,
313 TScalar fUpper = std::numeric_limits<TScalar>::max(),
348 class FDistanceLowerBound,
353 class TIndex =
Index,
354 auto kHeapCapacity = N * 1024>
359 FLeafObject fLeafObject,
360 FDistanceLowerBound fLower,
363 TScalar fUpper = std::numeric_limits<TScalar>::max(),
364 TScalar eps = TScalar(0),
408 class FDistanceLowerBound,
413 class TIndex =
Index,
414 auto kHeapCapacity = N * 1024>
419 FLeafObject fLeafObject,
420 FDistanceLowerBound fLower,
424 TScalar fUpper = std::numeric_limits<TScalar>::max(),
433 class FObjectOverlap,
442 FLeafObject fLeafObject,
443 FNodeOverlap fNodeOverlaps,
444 FObjectOverlap fObjectOverlaps,
449 auto fVisit = [&] PBAT_HOST_DEVICE(TIndex node) {
450 if (not fNodeOverlaps(node))
454 TIndex
const nLeafObjects = fLeafSize(node);
455 for (TIndex i = 0; i < nLeafObjects; ++i)
457 TIndex o = fLeafObject(node, i);
458 if (fObjectOverlaps(o))
475 if (not fVisit(root))
478 while (not stack.IsEmpty())
482 TIndex
const node = stack.Pop();
484 TIndex
const child = fChild.template operator()<i>(node);
486 if (fVisit(child) and not stack.IsFull())
497 class FLeafObjectLhs,
501 class FLeafObjectRhs,
503 class FObjectsOverlap,
511 FIsLeafLhs fIsLeafLhs,
512 FLeafSizeLhs fLeafSizeLhs,
513 FLeafObjectLhs fLeafObjectLhs,
515 FIsLeafRhs fIsLeafRhs,
516 FLeafSizeRhs fLeafSizeRhs,
517 FLeafObjectRhs fLeafObjectRhs,
518 FNodesOverlap fNodesOverlap,
519 FObjectsOverlap fObjectsOverlap,
524#include "pbat/warning/Push.h"
525#include "pbat/warning/SignConversion.h"
530 std::int16_t levelLhs;
531 std::int16_t levelRhs;
534 auto const fRecurseRight = [&] PBAT_HOST_DEVICE(Pair
const& p) {
536 TIndex
const childRhs = fChildRhs.template operator()<i>(p.nRhs);
537 if (childRhs >= 0 and not stack.IsFull())
539 {p.nLhs, childRhs, p.levelLhs,
static_cast<std::int16_t
>(p.levelRhs + 1)});
542 auto const fRecurseLeft = [&] PBAT_HOST_DEVICE(Pair
const& p) {
544 TIndex
const childLhs = fChildLhs.template operator()<i>(p.nLhs);
545 if (childLhs >= 0 and not stack.IsFull())
547 {childLhs, p.nRhs,
static_cast<std::int16_t
>(p.levelLhs + 1), p.levelRhs});
552 stack.
Push({rootLhs, rootRhs, std::int16_t{0}, std::int16_t{0}});
553 while (not stack.IsEmpty())
557 Pair
const p = stack.Pop();
558 if (not fNodesOverlap(p.nLhs, p.nRhs))
560 bool const bIsLhsLeaf = fIsLeafLhs(p.nLhs);
561 bool const bIsRhsLeaf = fIsLeafRhs(p.nRhs);
562 if (bIsLhsLeaf and bIsRhsLeaf)
564 TIndex
const nLeafObjectsLhs = fLeafSizeLhs(p.nLhs);
565 TIndex
const nLeafObjectsRhs = fLeafSizeRhs(p.nRhs);
566 for (TIndex i = 0; i < nLeafObjectsLhs; ++i)
568 TIndex
const oLhs = fLeafObjectLhs(p.nLhs, i);
569 for (TIndex j = 0; j < nLeafObjectsRhs; ++j)
571 TIndex
const oRhs = fLeafObjectRhs(p.nRhs, j);
572 if (fObjectsOverlap(oLhs, oRhs))
573 fOnFound(oLhs, oRhs, k++);
577 else if (bIsLhsLeaf and not bIsRhsLeaf)
581 else if (not bIsLhsLeaf and bIsRhsLeaf)
587 if (p.levelLhs > p.levelRhs)
598#include "pbat/warning/Pop.h"
607 class FObjectsOverlap,
616 FLeafObject fLeafObject,
617 FNodesOverlap fNodesOverlap,
618 FObjectsOverlap fObjectsOverlap,
622#include "pbat/warning/Push.h"
623#include "pbat/warning/SignConversion.h"
628 std::int16_t levelLhs;
629 std::int16_t levelRhs;
632 auto const fRecurseRight = [&] PBAT_HOST_DEVICE(Pair
const& p) {
634 TIndex
const childRhs = fChild.template operator()<i>(p.nRhs);
635 if (childRhs >= 0 and not stack.IsFull())
637 {p.nLhs, childRhs, p.levelLhs,
static_cast<std::int16_t
>(p.levelRhs + 1)});
640 auto const fRecurseLeft = [&] PBAT_HOST_DEVICE(Pair
const& p) {
642 TIndex
const childLhs = fChild.template operator()<i>(p.nLhs);
643 if (childLhs >= 0 and not stack.IsFull())
645 {childLhs, p.nRhs,
static_cast<std::int16_t
>(p.levelLhs + 1), p.levelRhs});
653 stack.
Push({root, root, std::int16_t{0}, std::int16_t{0}});
654 while (not stack.IsEmpty())
658 Pair
const p = stack.Pop();
660 if (p.nLhs == p.nRhs)
662 TIndex
const n = p.nLhs;
665 TIndex
const nLeafObjects = fLeafSize(n);
666 for (TIndex i = 0; i < nLeafObjects; ++i)
668 for (TIndex j = i + 1; j < nLeafObjects; ++j)
670 TIndex
const oLhs = fLeafObject(n, i);
671 TIndex
const oRhs = fLeafObject(n, j);
672 if (fObjectsOverlap(oLhs, oRhs))
673 fOnFound(oLhs, oRhs, k++);
680 std::array<TIndex, N> children;
682 children[i] = fChild.template operator()<i>(n);
685 std::int16_t
const nextLevel = p.levelLhs + std::int16_t{1};
691 stack.Push({children[i], children[i], nextLevel, nextLevel});
702 stack.Push({children[i], children[j], nextLevel, nextLevel});
709 if (not fNodesOverlap(p.nLhs, p.nRhs))
712 bool const bIsLeftLeaf = fIsLeaf(p.nLhs);
713 bool const bIsRightLeaf = fIsLeaf(p.nRhs);
714 if (bIsLeftLeaf and bIsRightLeaf)
716 TIndex
const nLeafObjectsLhs = fLeafSize(p.nLhs);
717 TIndex
const nLeafObjectsRhs = fLeafSize(p.nRhs);
718 for (TIndex i = 0; i < nLeafObjectsLhs; ++i)
720 TIndex
const oLhs = fLeafObject(p.nLhs, i);
721 for (TIndex j = 0; j < nLeafObjectsRhs; ++j)
723 TIndex
const oRhs = fLeafObject(p.nRhs, j);
724 if (fObjectsOverlap(oLhs, oRhs))
725 fOnFound(oLhs, oRhs, k++);
729 else if (bIsLeftLeaf and not bIsRightLeaf)
733 else if (not bIsLeftLeaf and bIsRightLeaf)
739 if (p.levelLhs > p.levelRhs)
747#include "pbat/warning/Pop.h"
755 class FDistanceLowerBound,
767 FLeafObject fLeafObject,
768 FDistanceLowerBound fLower,
771 bool bUseBestFirstSearch,
777 auto fDoVisit = [&] PBAT_HOST_DEVICE(TIndex node, TScalar lower) {
782 TIndex
const nLeafObjects = fLeafSize(node);
783 for (TIndex i = 0; i < nLeafObjects; ++i)
785 TIndex o = fLeafObject(node, i);
786 TScalar
const d = fDistance(o);
787 TScalar
const lo = fUpper - eps;
788 TScalar
const hi = fUpper + eps;
795 else if (d <= hi and not nn.IsFull())
803 auto fVisit = [&] PBAT_HOST_DEVICE(TIndex node) {
804 return fDoVisit(node, fLower(node));
811 if (not fVisit(root))
814 if (bUseBestFirstSearch)
816 std::array<TIndex, N> ordering{};
817 std::array<TIndex, N> children{};
818 std::array<TScalar, N> lowers{};
819 while (not stack.IsEmpty())
823 TIndex
const node = stack.Pop();
825 TIndex
const child = fChild.template operator()<i>(node);
828 bool const bHasChild = child >= 0;
829 lowers[i] = bHasChild ? fLower(child) : std::numeric_limits<TScalar>::max();
831 if constexpr (N == 2)
833 if (lowers[0] > lowers[1])
834 std::swap(ordering[0], ordering[1]);
838 std::sort(ordering.begin(), ordering.end(), [&](TIndex i, TIndex j) {
839 return lowers[i] < lowers[j];
842#include "pbat/warning/Push.h"
843#include "pbat/warning/SignConversion.h"
845 for (
int j = N - 1; j >= 0; --j)
847 auto const i = ordering[j];
848 if (children[i] >= 0)
850 if (fDoVisit(children[i], lowers[i]) and not stack.IsFull())
851 stack.Push(children[i]);
857#include "pbat/warning/Pop.h"
871 while (not stack.IsEmpty())
875 TIndex
const node = stack.Pop();
877 TIndex
const child = fChild.template operator()<i>(node);
879 if (fVisit(child) and not stack.IsFull())
885 while (not nn.IsEmpty())
889 fOnFound(o, fUpper, k++);
899 class FDistanceLowerBound,
910 FLeafObject fLeafObject,
911 FDistanceLowerBound fLower,
917 enum class EQueueItem { Node, Object };
926 auto fMakeNodeQueueItem = [&](TIndex node) {
927 return QueueItem{EQueueItem::Node, node, fLower(node)};
929 auto fMakeObjectQueueItem = [&](TIndex object) {
930 return QueueItem{EQueueItem::Object, object, fDistance(
object)};
932 auto fGreater = [](QueueItem
const& q1, QueueItem
const& q2) {
935 using Comparator =
decltype(fGreater);
937 MinHeap heap{fGreater};
938 heap.
Push(fMakeNodeQueueItem(root));
940 while (not heap.IsEmpty())
945 QueueItem
const q = heap.Pop();
948 if (q.type == EQueueItem::Node)
950 TIndex
const node = q.idx;
953 TIndex
const nLeafObjects = fLeafSize(node);
954 for (TIndex i = 0; i < nLeafObjects; ++i)
956 if (not heap.IsFull())
958 TIndex
const o = fLeafObject(node, i);
959 heap.Push(fMakeObjectQueueItem(o));
966 TIndex
const child = fChild.template operator()<i>(node);
967 if (child >= 0 and not heap.IsFull())
968 heap.Push(fMakeNodeQueueItem(child));
974 bool const bContinue = fOnFound(q.idx, q.d, k++);
987 class FDistanceLowerBound,
998 FLeafObject fLeafObject,
999 FDistanceLowerBound fLower,
1000 FDistance fDistance,
1007 auto fOnFoundWrapper = [&](TIndex o, TScalar d, TIndex k) {
1010 bool const bIsNearest = d <= dmin + eps;
1020 FDistanceLowerBound,
1022 decltype(fOnFoundWrapper),
1043 class FDistanceLowerBound,
1053 FLeafSize fLeafSize,
1054 FLeafObject fLeafObject,
1055 FDistanceLowerBound fLower,
1056 FDistance fDistance,
1062 auto fOnFoundWrapper = [&](TIndex o, TScalar d, TIndex k) {
1071 FDistanceLowerBound,
1073 decltype(fOnFoundWrapper),
Fixed-size heap implementation usable in both host and device code.
Generic n-ary tree traversals.
Fixed-size queue implementation usable in both host and device code.
Fixed-size max heap.
Definition Heap.h:30
PBAT_HOST_DEVICE void Push(T value)
Push an element to the heap.
Definition Heap.h:43
Fixed-size queue implementation.
Definition Queue.h:26
Fixed-size stack implementation.
Definition Stack.h:26
PBAT_HOST_DEVICE void Push(T value)
Add element to the stack.
Definition Stack.h:37
Fixed-size stack implementation usable in both host and device code.
constexpr void ForRange(F &&f)
Compile-time for loop over a range of values.
Definition ConstexprFor.h:55
Geometric queries, quantities and data structures.
Definition AabbKdTreeHierarchy.h:23
PBAT_HOST_DEVICE bool KNearestNeighbours(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FDistanceLowerBound fLower, FDistance fDistance, FOnFound fOnFound, TIndex K, TScalar fUpper=std::numeric_limits< TScalar >::max(), TIndex root=0)
Find the (sorted) K objects with the smallest distances in a branch and bound tree rooted in root.
Definition SpatialSearch.h:1050
PBAT_HOST_DEVICE bool DfsAllNearestNeighbours(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FDistanceLowerBound fLower, FDistance fDistance, FOnFound fOnFound, bool bUseBestFirstSearch=false, TScalar fUpper=std::numeric_limits< TScalar >::max(), TScalar eps=TScalar(0), TIndex root=0)
Find distance minimizing objects in branch and bound tree rooted in root.
Definition SpatialSearch.h:763
PBAT_HOST_DEVICE bool NearestToFurthestNeighbours(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FDistanceLowerBound fLower, FDistance fDistance, FOnFound fOnFound, TScalar fUpper=std::numeric_limits< TScalar >::max(), TIndex root=0)
Traverse objects in a branch and bound tree rooted in root in increasing order of distance.
Definition SpatialSearch.h:906
PBAT_HOST_DEVICE bool AllNearestNeighbours(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FDistanceLowerBound fLower, FDistance fDistance, FOnFound fOnFound, TScalar fUpper=std::numeric_limits< TScalar >::max(), TScalar eps=TScalar(0), TIndex root=0)
Find all global distance minimizers in a branch and bound tree rooted in root.
Definition SpatialSearch.h:994
PBAT_HOST_DEVICE bool SelfOverlaps(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FNodesOverlap fNodesOverlap, FObjectsOverlap fObjectsOverlap, FOnFound fOnFound, TIndex root=0)
Compute overlapping nodes from a branch and bound tree rooted in root.
Definition SpatialSearch.h:612
PBAT_HOST_DEVICE bool Overlaps(FChild fChild, FIsLeaf fIsLeaf, FLeafSize fLeafSize, FLeafObject fLeafObject, FNodeOverlap fNodeOverlaps, FObjectOverlap fObjectOverlaps, FOnFound fOnFound, TIndex root=0)
Find all nodes in a branch and bound tree that overlap with a given object.
Definition SpatialSearch.h:438
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
double Scalar
Scalar type.
Definition Aliases.h:18