PhysicsBasedAnimationToolkit 0.0.10
Cross-platform C++20 library of algorithms and data structures commonly used in computer graphics research on physically-based simulation.
Loading...
Searching...
No Matches
SpatialSearch.h
Go to the documentation of this file.
1
9
10#ifndef PBAT_GEOMETRY_SPATIALSEARCH_H
11#define PBAT_GEOMETRY_SPATIALSEARCH_H
12
13#include "pbat/Aliases.h"
14#include "pbat/HostDevice.h"
16#include "pbat/common/Heap.h"
18#include "pbat/common/Queue.h"
19#include "pbat/common/Stack.h"
20
21#include <algorithm>
22#include <array>
23#include <limits>
24#include <queue>
25#include <type_traits>
26
27namespace pbat::geometry {
53template <
54 class FChild,
55 class FIsLeaf,
56 class FLeafSize,
57 class FLeafObject,
58 class FNodeOverlap,
59 class FObjectOverlap,
60 class FOnFound,
61 auto N = 2,
62 class TIndex = Index,
63 auto kStackDepth = 64>
64PBAT_HOST_DEVICE bool Overlaps(
65 FChild fChild,
66 FIsLeaf fIsLeaf,
67 FLeafSize fLeafSize,
68 FLeafObject fLeafObject,
69 FNodeOverlap fNodeOverlaps,
70 FObjectOverlap fObjectOverlaps,
71 FOnFound fOnFound,
72 TIndex root = 0);
73
109template <
110 class FChildLhs,
111 class FIsLeafLhs,
112 class FLeafSizeLhs,
113 class FLeafObjectLhs,
114 class FChildRhs,
115 class FIsLeafRhs,
116 class FLeafSizeRhs,
117 class FLeafObjectRhs,
118 class FNodesOverlap,
119 class FObjectsOverlap,
120 class FOnFound,
121 auto NLhs = 2,
122 auto NRhs = 2,
123 class TIndex = Index,
124 auto kStackDepth = 128>
125PBAT_HOST_DEVICE bool Overlaps(
126 FChildLhs fChildLhs,
127 FIsLeafLhs fIsLeafLhs,
128 FLeafSizeLhs fLeafSizeLhs,
129 FLeafObjectLhs fLeafObjectLhs,
130 FChildRhs fChildRhs,
131 FIsLeafRhs fIsLeafRhs,
132 FLeafSizeRhs fLeafSizeRhs,
133 FLeafObjectRhs fLeafObjectRhs,
134 FNodesOverlap fNodesOverlap,
135 FObjectsOverlap fObjectsOverlap,
136 FOnFound fOnFound,
137 TIndex rootLhs = 0,
138 TIndex rootRhs = 0);
139
165template <
166 class FChild,
167 class FIsLeaf,
168 class FLeafSize,
169 class FLeafObject,
170 class FNodesOverlap,
171 class FObjectsOverlap,
172 class FOnFound,
173 auto N = 2,
174 class TIndex = Index,
175 auto kStackDepth = 128>
176PBAT_HOST_DEVICE bool SelfOverlaps(
177 FChild fChild,
178 FIsLeaf fIsLeaf,
179 FLeafSize fLeafSize,
180 FLeafObject fLeafObject,
181 FNodesOverlap fNodesOverlap,
182 FObjectsOverlap fObjectsOverlap,
183 FOnFound fOnFound,
184 TIndex root = 0);
185
231template <
232 class FChild,
233 class FIsLeaf,
234 class FLeafSize,
235 class FLeafObject,
236 class FDistanceLowerBound,
237 class FDistance,
238 class FOnFound,
239 auto N = 2,
240 class TScalar = Scalar,
241 class TIndex = Index,
242 auto kStackDepth = 64,
243 auto kQueueSize = 8>
244PBAT_HOST_DEVICE bool DfsAllNearestNeighbours(
245 FChild fChild,
246 FIsLeaf fIsLeaf,
247 FLeafSize fLeafSize,
248 FLeafObject fLeafObject,
249 FDistanceLowerBound fLower,
250 FDistance fDistance,
251 FOnFound fOnFound,
252 bool bUseBestFirstSearch = false,
253 TScalar fUpper = std::numeric_limits<TScalar>::max(),
254 TScalar eps = TScalar(0),
255 TIndex root = 0);
256
293template <
294 class FChild,
295 class FIsLeaf,
296 class FLeafSize,
297 class FLeafObject,
298 class FDistanceLowerBound,
299 class FDistance,
300 class FOnFound,
301 auto N = 2,
302 class TScalar = Scalar,
303 class TIndex = Index,
304 auto kHeapCapacity = N * 1024>
305PBAT_HOST_DEVICE bool NearestToFurthestNeighbours(
306 FChild fChild,
307 FIsLeaf fIsLeaf,
308 FLeafSize fLeafSize,
309 FLeafObject fLeafObject,
310 FDistanceLowerBound fLower,
311 FDistance fDistance,
312 FOnFound fOnFound,
313 TScalar fUpper = std::numeric_limits<TScalar>::max(),
314 TIndex root = 0);
315
343template <
344 class FChild,
345 class FIsLeaf,
346 class FLeafSize,
347 class FLeafObject,
348 class FDistanceLowerBound,
349 class FDistance,
350 class FOnFound,
351 auto N = 2,
352 class TScalar = Scalar,
353 class TIndex = Index,
354 auto kHeapCapacity = N * 1024>
355PBAT_HOST_DEVICE bool AllNearestNeighbours(
356 FChild fChild,
357 FIsLeaf fIsLeaf,
358 FLeafSize fLeafSize,
359 FLeafObject fLeafObject,
360 FDistanceLowerBound fLower,
361 FDistance fDistance,
362 FOnFound fOnFound,
363 TScalar fUpper = std::numeric_limits<TScalar>::max(),
364 TScalar eps = TScalar(0),
365 TIndex root = 0);
366
403template <
404 class FChild,
405 class FIsLeaf,
406 class FLeafSize,
407 class FLeafObject,
408 class FDistanceLowerBound,
409 class FDistance,
410 class FOnFound,
411 auto N = 2,
412 class TScalar = Scalar,
413 class TIndex = Index,
414 auto kHeapCapacity = N * 1024>
415PBAT_HOST_DEVICE bool KNearestNeighbours(
416 FChild fChild,
417 FIsLeaf fIsLeaf,
418 FLeafSize fLeafSize,
419 FLeafObject fLeafObject,
420 FDistanceLowerBound fLower,
421 FDistance fDistance,
422 FOnFound fOnFound,
423 TIndex K,
424 TScalar fUpper = std::numeric_limits<TScalar>::max(),
425 TIndex root = 0);
426
427template <
428 class FChild,
429 class FIsLeaf,
430 class FLeafSize,
431 class FLeafObject,
432 class FNodeOverlap,
433 class FObjectOverlap,
434 class FOnFound,
435 auto N,
436 class TIndex,
437 auto kStackDepth>
439 FChild fChild,
440 FIsLeaf fIsLeaf,
441 FLeafSize fLeafSize,
442 FLeafObject fLeafObject,
443 FNodeOverlap fNodeOverlaps,
444 FObjectOverlap fObjectOverlaps,
445 FOnFound fOnFound,
446 TIndex root)
447{
448 Index k{0};
449 auto fVisit = [&] PBAT_HOST_DEVICE(TIndex node) {
450 if (not fNodeOverlaps(node))
451 return false;
452 if (fIsLeaf(node))
453 {
454 TIndex const nLeafObjects = fLeafSize(node);
455 for (TIndex i = 0; i < nLeafObjects; ++i)
456 {
457 TIndex o = fLeafObject(node, i);
458 if (fObjectOverlaps(o))
459 fOnFound(o, k++);
460 }
461 }
462 return true;
463 };
464 // NOTE:
465 // Instead of using a pre-order traversal, we visit children of the currently visited node
466 // simultaneously. This is because the branch and bound tree might store each node's
467 // children in contiguous memory, or at least with some notion of locality. Thus, the fLower
468 // function will benefit from many cache hits.
469 // using FVisit = decltype(fVisit);
470 // common::TraverseNAryTreePseudoPreOrder<FVisit, FChild, TIndex, N, kStackDepth>(
471 // fVisit,
472 // fChild,
473 // root);
475 if (not fVisit(root))
476 return true;
477 stack.Push(root);
478 while (not stack.IsEmpty())
479 {
480 if (stack.IsFull())
481 return false;
482 TIndex const node = stack.Pop();
483 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
484 TIndex const child = fChild.template operator()<i>(node);
485 if (child >= 0)
486 if (fVisit(child) and not stack.IsFull())
487 stack.Push(child);
488 });
489 }
490 return true;
491}
492
493template <
494 class FChildLhs,
495 class FIsLeafLhs,
496 class FLeafSizeLhs,
497 class FLeafObjectLhs,
498 class FChildRhs,
499 class FIsLeafRhs,
500 class FLeafSizeRhs,
501 class FLeafObjectRhs,
502 class FNodesOverlap,
503 class FObjectsOverlap,
504 class FOnFound,
505 auto NLhs,
506 auto NRhs,
507 class TIndex,
508 auto kStackDepth>
509PBAT_HOST_DEVICE bool Overlaps(
510 FChildLhs fChildLhs,
511 FIsLeafLhs fIsLeafLhs,
512 FLeafSizeLhs fLeafSizeLhs,
513 FLeafObjectLhs fLeafObjectLhs,
514 FChildRhs fChildRhs,
515 FIsLeafRhs fIsLeafRhs,
516 FLeafSizeRhs fLeafSizeRhs,
517 FLeafObjectRhs fLeafObjectRhs,
518 FNodesOverlap fNodesOverlap,
519 FObjectsOverlap fObjectsOverlap,
520 FOnFound fOnFound,
521 TIndex rootLhs,
522 TIndex rootRhs)
523{
524#include "pbat/warning/Push.h"
525#include "pbat/warning/SignConversion.h"
526 struct Pair
527 {
528 TIndex nLhs;
529 TIndex nRhs;
530 std::int16_t levelLhs;
531 std::int16_t levelRhs;
532 };
534 auto const fRecurseRight = [&] PBAT_HOST_DEVICE(Pair const& p) {
535 common::ForRange<0, NRhs>([&]<auto i> PBAT_HOST_DEVICE() {
536 TIndex const childRhs = fChildRhs.template operator()<i>(p.nRhs);
537 if (childRhs >= 0 and not stack.IsFull())
538 stack.Push(
539 {p.nLhs, childRhs, p.levelLhs, static_cast<std::int16_t>(p.levelRhs + 1)});
540 });
541 };
542 auto const fRecurseLeft = [&] PBAT_HOST_DEVICE(Pair const& p) {
543 common::ForRange<0, NLhs>([&]<auto i> PBAT_HOST_DEVICE() {
544 TIndex const childLhs = fChildLhs.template operator()<i>(p.nLhs);
545 if (childLhs >= 0 and not stack.IsFull())
546 stack.Push(
547 {childLhs, p.nRhs, static_cast<std::int16_t>(p.levelLhs + 1), p.levelRhs});
548 });
549 };
550 // Traverse top-down
551 TIndex k{0};
552 stack.Push({rootLhs, rootRhs, std::int16_t{0}, std::int16_t{0}});
553 while (not stack.IsEmpty())
554 {
555 if (stack.IsFull())
556 return false;
557 Pair const p = stack.Pop();
558 if (not fNodesOverlap(p.nLhs, p.nRhs))
559 continue;
560 bool const bIsLhsLeaf = fIsLeafLhs(p.nLhs);
561 bool const bIsRhsLeaf = fIsLeafRhs(p.nRhs);
562 if (bIsLhsLeaf and bIsRhsLeaf)
563 {
564 TIndex const nLeafObjectsLhs = fLeafSizeLhs(p.nLhs);
565 TIndex const nLeafObjectsRhs = fLeafSizeRhs(p.nRhs);
566 for (TIndex i = 0; i < nLeafObjectsLhs; ++i)
567 {
568 TIndex const oLhs = fLeafObjectLhs(p.nLhs, i);
569 for (TIndex j = 0; j < nLeafObjectsRhs; ++j)
570 {
571 TIndex const oRhs = fLeafObjectRhs(p.nRhs, j);
572 if (fObjectsOverlap(oLhs, oRhs))
573 fOnFound(oLhs, oRhs, k++);
574 }
575 }
576 }
577 else if (bIsLhsLeaf and not bIsRhsLeaf)
578 {
579 fRecurseRight(p);
580 }
581 else if (not bIsLhsLeaf and bIsRhsLeaf)
582 {
583 fRecurseLeft(p);
584 }
585 else
586 {
587 if (p.levelLhs > p.levelRhs)
588 {
589 fRecurseRight(p);
590 }
591 else
592 {
593 fRecurseLeft(p);
594 }
595 }
596 }
597 return true;
598#include "pbat/warning/Pop.h"
599};
600
601template <
602 class FChild,
603 class FIsLeaf,
604 class FLeafSize,
605 class FLeafObject,
606 class FNodesOverlap,
607 class FObjectsOverlap,
608 class FOnFound,
609 auto N,
610 class TIndex,
611 auto kStackDepth>
612PBAT_HOST_DEVICE bool SelfOverlaps(
613 FChild fChild,
614 FIsLeaf fIsLeaf,
615 FLeafSize fLeafSize,
616 FLeafObject fLeafObject,
617 FNodesOverlap fNodesOverlap,
618 FObjectsOverlap fObjectsOverlap,
619 FOnFound fOnFound,
620 TIndex root)
621{
622#include "pbat/warning/Push.h"
623#include "pbat/warning/SignConversion.h"
624 struct Pair
625 {
626 TIndex nLhs;
627 TIndex nRhs;
628 std::int16_t levelLhs;
629 std::int16_t levelRhs;
630 };
632 auto const fRecurseRight = [&] PBAT_HOST_DEVICE(Pair const& p) {
633 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
634 TIndex const childRhs = fChild.template operator()<i>(p.nRhs);
635 if (childRhs >= 0 and not stack.IsFull())
636 stack.Push(
637 {p.nLhs, childRhs, p.levelLhs, static_cast<std::int16_t>(p.levelRhs + 1)});
638 });
639 };
640 auto const fRecurseLeft = [&] PBAT_HOST_DEVICE(Pair const& p) {
641 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
642 TIndex const childLhs = fChild.template operator()<i>(p.nLhs);
643 if (childLhs >= 0 and not stack.IsFull())
644 stack.Push(
645 {childLhs, p.nRhs, static_cast<std::int16_t>(p.levelLhs + 1), p.levelRhs});
646 });
647 };
648 // For any given nodes (n,a) where a is an ancestor of n, it is guaranteed that
649 // (n,a) are overlapping, since n is embedded in a. We need to find a way to avoid
650 // adding pairs (n,a) to the stack. A pair (ni,nj) should only exist or be tested
651 // if neither ni nor nj is an ancestor of the other.
652 TIndex k{0};
653 stack.Push({root, root, std::int16_t{0}, std::int16_t{0}});
654 while (not stack.IsEmpty())
655 {
656 if (stack.IsFull())
657 return false;
658 Pair const p = stack.Pop();
659 // This is a node visitor, not a pair to check for overlap, add children to stack
660 if (p.nLhs == p.nRhs)
661 {
662 TIndex const n = p.nLhs;
663 if (fIsLeaf(n))
664 {
665 TIndex const nLeafObjects = fLeafSize(n);
666 for (TIndex i = 0; i < nLeafObjects; ++i)
667 {
668 for (TIndex j = i + 1; j < nLeafObjects; ++j)
669 {
670 TIndex const oLhs = fLeafObject(n, i);
671 TIndex const oRhs = fLeafObject(n, j);
672 if (fObjectsOverlap(oLhs, oRhs))
673 fOnFound(oLhs, oRhs, k++);
674 }
675 }
676 }
677 else
678 {
679 // Collect children
680 std::array<TIndex, N> children;
681 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
682 children[i] = fChild.template operator()<i>(n);
683 });
684 // Add node visitors first, so that we don't traverse the whole tree in one go
685 std::int16_t const nextLevel = p.levelLhs + std::int16_t{1};
686 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
687 if (stack.IsFull())
688 return;
689 if (children[i] < 0)
690 return;
691 stack.Push({children[i], children[i], nextLevel, nextLevel});
692 });
693 // Add all distinct child pairs to the stack
694 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
695 if (children[i] < 0)
696 return;
697 common::ForRange<i + 1, N>([&]<auto j> PBAT_HOST_DEVICE() {
698 if (stack.IsFull())
699 return;
700 if (children[j] < 0)
701 return;
702 stack.Push({children[i], children[j], nextLevel, nextLevel});
703 });
704 });
705 }
706 }
707 else
708 {
709 if (not fNodesOverlap(p.nLhs, p.nRhs))
710 continue;
711
712 bool const bIsLeftLeaf = fIsLeaf(p.nLhs);
713 bool const bIsRightLeaf = fIsLeaf(p.nRhs);
714 if (bIsLeftLeaf and bIsRightLeaf)
715 {
716 TIndex const nLeafObjectsLhs = fLeafSize(p.nLhs);
717 TIndex const nLeafObjectsRhs = fLeafSize(p.nRhs);
718 for (TIndex i = 0; i < nLeafObjectsLhs; ++i)
719 {
720 TIndex const oLhs = fLeafObject(p.nLhs, i);
721 for (TIndex j = 0; j < nLeafObjectsRhs; ++j)
722 {
723 TIndex const oRhs = fLeafObject(p.nRhs, j);
724 if (fObjectsOverlap(oLhs, oRhs))
725 fOnFound(oLhs, oRhs, k++);
726 }
727 }
728 }
729 else if (bIsLeftLeaf and not bIsRightLeaf)
730 {
731 fRecurseRight(p);
732 }
733 else if (not bIsLeftLeaf and bIsRightLeaf)
734 {
735 fRecurseLeft(p);
736 }
737 else
738 {
739 if (p.levelLhs > p.levelRhs)
740 fRecurseRight(p);
741 else
742 fRecurseLeft(p);
743 }
744 }
745 }
746 return true;
747#include "pbat/warning/Pop.h"
748}
749
750template <
751 class FChild,
752 class FIsLeaf,
753 class FLeafSize,
754 class FLeafObject,
755 class FDistanceLowerBound,
756 class FDistance,
757 class FOnFound,
758 auto N,
759 class TScalar,
760 class TIndex,
761 auto kStackDepth,
762 auto kQueueSize>
764 FChild fChild,
765 FIsLeaf fIsLeaf,
766 FLeafSize fLeafSize,
767 FLeafObject fLeafObject,
768 FDistanceLowerBound fLower,
769 FDistance fDistance,
770 FOnFound fOnFound,
771 bool bUseBestFirstSearch,
772 TScalar fUpper,
773 TScalar eps,
774 TIndex root)
775{
777 auto fDoVisit = [&] PBAT_HOST_DEVICE(TIndex node, TScalar lower) {
778 if (lower > fUpper)
779 return false;
780 if (fIsLeaf(node))
781 {
782 TIndex const nLeafObjects = fLeafSize(node);
783 for (TIndex i = 0; i < nLeafObjects; ++i)
784 {
785 TIndex o = fLeafObject(node, i);
786 TScalar const d = fDistance(o);
787 TScalar const lo = fUpper - eps;
788 TScalar const hi = fUpper + eps;
789 if (d < lo)
790 {
791 nn.Clear();
792 nn.Push(o);
793 fUpper = d;
794 }
795 else if (d <= hi and not nn.IsFull())
796 {
797 nn.Push(o);
798 }
799 }
800 }
801 return true;
802 };
803 auto fVisit = [&] PBAT_HOST_DEVICE(TIndex node) {
804 return fDoVisit(node, fLower(node));
805 };
806 // For the nearest neighbour search, it might be best not to blindly run a pre-order
807 // traversal of the branch and bound tree. If requested, let's optimistically run a best-first
808 // search. At each node, we will sort the children by their lower bounds and visit them in that
809 // order.
811 if (not fVisit(root))
812 return true;
813 stack.Push(root);
814 if (bUseBestFirstSearch)
815 {
816 std::array<TIndex, N> ordering{};
817 std::array<TIndex, N> children{};
818 std::array<TScalar, N> lowers{};
819 while (not stack.IsEmpty())
820 {
821 if (stack.IsFull())
822 return false;
823 TIndex const node = stack.Pop();
824 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
825 TIndex const child = fChild.template operator()<i>(node);
826 ordering[i] = i;
827 children[i] = child;
828 bool const bHasChild = child >= 0;
829 lowers[i] = bHasChild ? fLower(child) : std::numeric_limits<TScalar>::max();
830 });
831 if constexpr (N == 2)
832 {
833 if (lowers[0] > lowers[1])
834 std::swap(ordering[0], ordering[1]);
835 }
836 else
837 {
838 std::sort(ordering.begin(), ordering.end(), [&](TIndex i, TIndex j) {
839 return lowers[i] < lowers[j];
840 });
841 }
842#include "pbat/warning/Push.h"
843#include "pbat/warning/SignConversion.h"
844 // NOTE: I hope this loop gets unrolled by the compiler!!
845 for (int j = N - 1; j >= 0; --j)
846 {
847 auto const i = ordering[j];
848 if (children[i] >= 0)
849 {
850 if (fDoVisit(children[i], lowers[i]) and not stack.IsFull())
851 stack.Push(children[i]);
852 }
853 else
854 break; // The ordering is such that all non-children are at the end, so exit as
855 // soon as we encounter non-child.
856 }
857#include "pbat/warning/Pop.h"
858 }
859 }
860 else
861 {
862 // NOTE:
863 // Instead of using a pre-order traversal, we visit children of the currently visited node
864 // simultaneously. This is because the branch and bound tree might store each node's
865 // children in contiguous memory, or at least with some notion of locality. Thus, the fLower
866 // function will benefit from many cache hits.
867 // common::TraverseNAryTreePseudoPreOrder<FVisit, FChild, TIndex, N, kStackDepth>(
868 // fVisit,
869 // fChild,
870 // root);
871 while (not stack.IsEmpty())
872 {
873 if (stack.IsFull())
874 return false;
875 TIndex const node = stack.Pop();
876 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
877 TIndex const child = fChild.template operator()<i>(node);
878 if (child >= 0)
879 if (fVisit(child) and not stack.IsFull())
880 stack.Push(child);
881 });
882 }
883 }
884 TIndex k{0};
885 while (not nn.IsEmpty())
886 {
887 TIndex o = nn.Top();
888 nn.Pop();
889 fOnFound(o, fUpper, k++);
890 }
891 return true;
892}
893
894template <
895 class FChild,
896 class FIsLeaf,
897 class FLeafSize,
898 class FLeafObject,
899 class FDistanceLowerBound,
900 class FDistance,
901 class FOnFound,
902 auto N,
903 class TScalar,
904 class TIndex,
905 auto kHeapCapacity>
907 FChild fChild,
908 FIsLeaf fIsLeaf,
909 FLeafSize fLeafSize,
910 FLeafObject fLeafObject,
911 FDistanceLowerBound fLower,
912 FDistance fDistance,
913 FOnFound fOnFound,
914 TScalar fUpper,
915 TIndex root)
916{
917 enum class EQueueItem { Node, Object };
918 struct QueueItem
919 {
920 EQueueItem type; // Indicates if this QueueItem holds a primitive or a volume
921 TIndex idx; // Index of the primitive, if this QueueItem holds a primitive, or index
922 // of the node, if this QueueItem holds a volume (recall that node_idx =
923 // bv_idx + 1)
924 TScalar d; // Distance from this QueueItem to p
925 };
926 auto fMakeNodeQueueItem = [&](TIndex node) {
927 return QueueItem{EQueueItem::Node, node, fLower(node)};
928 };
929 auto fMakeObjectQueueItem = [&](TIndex object) {
930 return QueueItem{EQueueItem::Object, object, fDistance(object)};
931 };
932 auto fGreater = [](QueueItem const& q1, QueueItem const& q2) {
933 return q1.d > q2.d;
934 };
935 using Comparator = decltype(fGreater);
937 MinHeap heap{fGreater};
938 heap.Push(fMakeNodeQueueItem(root));
939 TIndex k{0};
940 while (not heap.IsEmpty())
941 {
942 if (heap.IsFull())
943 return false;
944
945 QueueItem const q = heap.Pop();
946 if (q.d > fUpper)
947 break;
948 if (q.type == EQueueItem::Node)
949 {
950 TIndex const node = q.idx;
951 if (fIsLeaf(node))
952 {
953 TIndex const nLeafObjects = fLeafSize(node);
954 for (TIndex i = 0; i < nLeafObjects; ++i)
955 {
956 if (not heap.IsFull())
957 {
958 TIndex const o = fLeafObject(node, i);
959 heap.Push(fMakeObjectQueueItem(o));
960 }
961 }
962 }
963 else
964 {
965 common::ForRange<0, N>([&]<auto i> PBAT_HOST_DEVICE() {
966 TIndex const child = fChild.template operator()<i>(node);
967 if (child >= 0 and not heap.IsFull())
968 heap.Push(fMakeNodeQueueItem(child));
969 });
970 }
971 }
972 else
973 {
974 bool const bContinue = fOnFound(q.idx, q.d, k++);
975 if (not bContinue)
976 break;
977 }
978 }
979 return true;
980}
981
982template <
983 class FChild,
984 class FIsLeaf,
985 class FLeafSize,
986 class FLeafObject,
987 class FDistanceLowerBound,
988 class FDistance,
989 class FOnFound,
990 auto N,
991 class TScalar,
992 class TIndex,
993 auto kHeapCapacity>
994PBAT_HOST_DEVICE bool AllNearestNeighbours(
995 FChild fChild,
996 FIsLeaf fIsLeaf,
997 FLeafSize fLeafSize,
998 FLeafObject fLeafObject,
999 FDistanceLowerBound fLower,
1000 FDistance fDistance,
1001 FOnFound fOnFound,
1002 TScalar fUpper,
1003 TScalar eps,
1004 TIndex root)
1005{
1006 TScalar dmin;
1007 auto fOnFoundWrapper = [&](TIndex o, TScalar d, TIndex k) {
1008 if (k == 0)
1009 dmin = d;
1010 bool const bIsNearest = d <= dmin + eps;
1011 if (bIsNearest)
1012 fOnFound(o, d, k);
1013 return bIsNearest;
1014 };
1016 FChild,
1017 FIsLeaf,
1018 FLeafSize,
1019 FLeafObject,
1020 FDistanceLowerBound,
1021 FDistance,
1022 decltype(fOnFoundWrapper),
1023 N,
1024 TScalar,
1025 TIndex,
1026 kHeapCapacity>(
1027 fChild,
1028 fIsLeaf,
1029 fLeafSize,
1030 fLeafObject,
1031 fLower,
1032 fDistance,
1033 fOnFoundWrapper,
1034 fUpper,
1035 root);
1036}
1037
1038template <
1039 class FChild,
1040 class FIsLeaf,
1041 class FLeafSize,
1042 class FLeafObject,
1043 class FDistanceLowerBound,
1044 class FDistance,
1045 class FOnFound,
1046 auto N,
1047 class TScalar,
1048 class TIndex,
1049 auto kHeapCapacity>
1051 FChild fChild,
1052 FIsLeaf fIsLeaf,
1053 FLeafSize fLeafSize,
1054 FLeafObject fLeafObject,
1055 FDistanceLowerBound fLower,
1056 FDistance fDistance,
1057 FOnFound fOnFound,
1058 TIndex K,
1059 TScalar fUpper,
1060 TIndex root)
1061{
1062 auto fOnFoundWrapper = [&](TIndex o, TScalar d, TIndex k) {
1063 fOnFound(o, d, k);
1064 return (k + 1) < K;
1065 };
1067 FChild,
1068 FIsLeaf,
1069 FLeafSize,
1070 FLeafObject,
1071 FDistanceLowerBound,
1072 FDistance,
1073 decltype(fOnFoundWrapper),
1074 N,
1075 TScalar,
1076 TIndex,
1077 kHeapCapacity>(
1078 fChild,
1079 fIsLeaf,
1080 fLeafSize,
1081 fLeafObject,
1082 fLower,
1083 fDistance,
1084 fOnFoundWrapper,
1085 fUpper,
1086 root);
1087}
1088} // namespace pbat::geometry
1089
1090#endif // PBAT_GEOMETRY_SPATIALSEARCH_H
Compile-time for loops.
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