13#ifndef INCLUDE_AABBTREE_TREE_HXX
14#define INCLUDE_AABBTREE_TREE_HXX
32 template <
typename Real, Integer N>
35 static_assert(std::is_floating_point<Real>::value,
"Tree Real type must be a floating-point type.");
36 static_assert(std::is_integral<Integer>::value,
"Tree dimension type must be an integer type.");
37 static_assert(N > 0,
"Tree dimension must be positive.");
40 constexpr static Real
EPS{std::numeric_limits<Real>::epsilon()};
41 constexpr static Real
INF{std::numeric_limits<Real>::infinity()};
86 os <<
"────────────────────────────────────────────────────────────────────────────────\n"
88 <<
"\n\tAmbient dimension : " << N
89 <<
"\n\tBasic type : " <<
typeid(Real).name()
91 <<
"\n\tNodes : " <<
nodes
92 <<
"\n\tLeafs : " <<
leafs
94 <<
"\n\tDepth : " <<
depth
107 <<
"\n────────────────────────────────────────────────────────────────────────────────\n";
184 constexpr char CMD[]{
"AABBtree::Tree::max_nodal_objects(...): "};
200 constexpr char CMD[]{
"AABBtree::Tree::separation_ratio_tolerance(...): " };
201 AABBTREE_ASSERT(ratio > 0.0 && ratio < 1.0, CMD <<
"input must be in the range [0, 1].");
265 void build(std::unique_ptr<BoxUniquePtrList> boxes_ptr) {
298 m_stack.reserve(2*num_boxes + 1);
315 Integer sorting[N]; std::iota(sorting, sorting + N, 0);
316 auto compare = [&sizes] (
Integer i,
Integer j) ->
bool {
return sizes[i] > sizes[j];};
317 std::sort(sorting, sorting + N, compare);
319 Integer axis, n_long, n_left, n_right, id_ini, id_end;
320 Real separation_line, separation_tolerance;
324 Integer axis_saved{sorting[0]};
326 for (
Integer dump{0}; dump < N; ++dump) {
327 axis = sorting[dump];
328 separation_line =
node.box.baricenter(axis);
332 n_long = n_left = n_right = 0;
333 id_ini =
node.box_ptr;
334 id_end =
node.box_ptr +
node.box_num;
336 Real baricenter{0.0};
337 while (id_ini < id_end) {
339 typename Box::Side const side{box_id.which_side(separation_line, separation_tolerance, axis)};
350 baricenter += box_id.max()[axis] + box_id.min()[axis];
352 baricenter /= 2.0*
node.box_num;
355 Integer n_diff{std::abs(n_left - n_right)};
356 if (n_long_saved > n_long || n_diff_saved > n_diff) {
357 n_long_saved = n_long;
358 n_diff_saved = n_diff;
376 n_long = n_long_saved;
378 separation_line =
node.box.baricenter(axis);
382 n_left = n_right = 0;
383 id_ini =
node.box_ptr + n_long;
384 id_end =
node.box_ptr +
node.box_num;
385 while (id_ini < id_end) {
387 typename Box::Side const side{box_id.which_side(separation_line, separation_tolerance, axis)};
426 node.box_num = n_long;
427 node.box_long.set_empty();
458 template <
typename Object>
464 if (this->
is_empty()) {
return false;}
472 m_stack.emplace_back(0);
489 if (
node.box_num > 0) {
493 for (
Integer i{id_ini}; i < id_end; ++i) {
506 return !candidates.empty();
533 auto negate = [] (
Integer const id) {
return -1-id;};
541 Integer const id_2{id_s2 < 0 ? negate(id_s2) : id_s2};
543 Integer const id_1{id_s1 < 0 ? negate(id_s1) : id_s1};
553 if (node_1.box_num > 0 && node_2.box_num > 0) {
555 Integer const id_1_ini{node_1.box_ptr};
556 Integer const id_1_end{node_1.box_ptr + node_1.box_num};
557 Integer const id_2_ini{node_2.box_ptr};
558 Integer const id_2_end{node_2.box_ptr + node_2.box_num};
559 if (node_1.box_num < node_2.box_num) {
560 for (
Integer i{id_1_ini}; i < id_1_end; ++i) {
562 if (++
m_check_counter; !boxes_1[pos_1]->intersects(node_2.box_long)) {
continue;}
563 for (
Integer j{id_2_ini}; j < id_2_end; ++j) {
565 if (++
m_check_counter; boxes_1[pos_1]->intersects(*boxes_2[pos_2])) candidates[pos_1].insert(pos_2);
569 for (
Integer j{id_2_ini}; j < id_2_end; ++j) {
571 if (++
m_check_counter; !boxes_2[pos_2]->intersects(node_1.box_long)) {
continue;}
572 for (
Integer i{id_1_ini}; i < id_1_end; ++i) {
574 if (++
m_check_counter; boxes_1[pos_1]->intersects(*boxes_2[pos_2])) candidates[pos_1].insert(pos_2);
582 bool const leaf_1{node_1.child_l < 0};
583 bool const leaf_2{node_2.child_l < 0};
584 if (leaf_1 && leaf_2) {
continue;}
587 auto stack_emplace_back = [
this](
Integer const node_1,
Integer const node_2) {
592 stack_emplace_back(id_1, node_2.child_l);
593 stack_emplace_back(id_1, node_2.child_r);
595 stack_emplace_back(node_1.child_l, id_2);
596 stack_emplace_back(node_1.child_r, id_2);
598 if (node_1.box_tot_num > node_2.box_tot_num) {
600 stack_emplace_back(node_1.child_l, id_s2);
601 stack_emplace_back(node_1.child_r, id_s2);
602 if (node_1.box_num > 0) stack_emplace_back(negate(id_1), id_2);
603 }
else if (id_s2 >= 0) {
604 stack_emplace_back(id_s1, node_2.child_l);
605 stack_emplace_back(id_s1, node_2.child_r);
609 stack_emplace_back(id_s1, node_2.child_l);
610 stack_emplace_back(id_s1, node_2.child_r);
611 if (node_2.box_num > 0) stack_emplace_back(id_1, negate(id_2));
612 }
else if (id_s1 >= 0) {
613 stack_emplace_back(node_1.child_l, id_s2);
614 stack_emplace_back(node_1.child_r, id_s2);
621 return !candidates.empty();
631 bool intersects{this->
intersect(*
this, candidates_map)};
633 for (
const auto & [key, values] : candidates_map) {
634 for (
int value : values) {candidates.emplace(key); candidates.emplace(value);}
647 template <
typename Object>
653 if (this->
is_empty()) {
return -1.0;}
661 m_stack.emplace_back(0);
677 Real tmp_distance{
node.box.interior_distance(obj)};
680 if (tmp_distance >
distance) {
continue;}
683 if (
node.box_num > 0) {
687 for (
Integer i{id_ini}; i < id_end; ++i) {
690 tmp_distance =
boxes[pos]->interior_distance(obj);
692 candidates.clear(); candidates.insert(pos);
distance = tmp_distance;
693 }
else if (tmp_distance ==
distance) {
694 candidates.insert(pos);
733 auto negate = [] (
Integer const id) {
return -1-id;};
742 Integer const id_2{id_s2 >= 0 ? id_s2 : negate(id_s2)};
744 Integer const id_1{id_s1 >= 0 ? id_s1 : negate(id_s1)};
752 Real tmp_distance{node_1.box.interior_distance(node_2.box)};
755 if (tmp_distance >
distance) {
continue;}
758 if (node_1.box_num > 0 && node_2.box_num > 0) {
760 Integer const id_1_ini{node_1.box_ptr};
761 Integer const id_1_end{node_1.box_ptr + node_1.box_num};
762 Integer const id_2_ini{node_2.box_ptr};
763 Integer const id_2_end{node_2.box_ptr + node_2.box_num};
764 if (node_1.box_num < node_2.box_num) {
765 for (
Integer i{id_1_ini}; i < id_1_end; ++i) {
767 ++
m_check_counter; tmp_distance = boxes_1[pos_1]->interior_distance(node_2.box_long);
768 if (tmp_distance >
distance) {
continue;}
769 for (
Integer j{id_2_ini}; j < id_2_end; ++j) {
771 ++
m_check_counter; tmp_distance = boxes_1[pos_1]->interior_distance(*boxes_2[pos_2]);
773 candidates.clear(); candidates[pos_1].insert(pos_2);
distance = tmp_distance;
774 }
else if (tmp_distance ==
distance) {
775 candidates[pos_1].insert(pos_2);
780 for (
Integer j{id_2_ini}; j < id_2_end; ++j) {
782 ++
m_check_counter; tmp_distance = boxes_2[pos_2]->interior_distance(node_1.box_long);
783 if (tmp_distance >
distance) {
continue;}
784 for (
Integer i{id_1_ini}; i < id_1_end; ++i) {
786 ++
m_check_counter; tmp_distance = boxes_1[pos_1]->interior_distance(*boxes_2[pos_2]);
788 candidates.clear(); candidates[pos_1].insert(pos_2);
distance = tmp_distance;
789 }
else if (tmp_distance ==
distance) {
790 candidates[pos_1].insert(pos_2);
799 bool const leaf_1{node_1.child_l < 0};
800 bool const leaf_2{node_2.child_l < 0};
801 if (leaf_1 && leaf_2) {
continue;}
804 auto stack_emplace_back = [
this](
Integer const node_1,
Integer const node_2) {
809 stack_emplace_back(id_1, node_2.child_l);
810 stack_emplace_back(id_1, node_2.child_r);
812 stack_emplace_back(node_1.child_l, id_2);
813 stack_emplace_back(node_1.child_r, id_2);
815 if (node_1.box_tot_num > node_2.box_tot_num) {
817 stack_emplace_back(node_1.child_l, id_s2);
818 stack_emplace_back(node_1.child_r, id_s2);
819 if (node_1.box_num > 0) stack_emplace_back(negate(id_1), id_2);
820 }
else if (id_s2 >= 0) {
821 stack_emplace_back(id_s1, node_2.child_l);
822 stack_emplace_back(id_s1, node_2.child_r);
826 stack_emplace_back(id_s1, node_2.child_l);
827 stack_emplace_back(id_s1, node_2.child_r);
828 if (node_2.box_num > 0) stack_emplace_back(id_1, negate(id_2));
829 }
else if (id_s1 >= 0) {
830 stack_emplace_back(node_1.child_l, id_s2);
831 stack_emplace_back(node_1.child_r, id_s2);
852 template <
typename Object,
typename Function = std::function<Real(Object const &, Box const &)>>
859 if (this->
is_empty()) {
return -1.0;}
870 using Pair = std::pair<Real, Integer>;
871 auto cmp = [](
const Pair & a,
const Pair & b) {
return a.first < b.first;};
872 std::priority_queue<Pair, std::vector<Pair>,
decltype(cmp)> queue(cmp);
887 Real tmp_distance{distance_function(obj,
node.box)};
890 if (tmp_distance >
distance) {
continue;}
893 if (
node.box_num > 0) {
896 for (
Integer i{id_ini}; i < id_end; ++i) {
899 tmp_distance = distance_function(obj, *
boxes[pos]);
901 if (
static_cast<Integer>(queue.size()) < n) {
902 queue.emplace(tmp_distance, pos);
904 queue.pop(); queue.emplace(tmp_distance, pos);
917 Real min_distance{queue.empty() ?
distance : queue.top().first};
918 while (!queue.empty()) {candidates.insert(queue.top().second); queue.pop();}
932 template <
typename Object,
typename Function = std::function<Real(Object const &, Box const &)>>
934 Function distance_function = [] (Object
const & o,
Box const & b) {
return b.
interior_distance(o);}
940 if (this->
is_empty()) {
return false;}
965 if (
distance > max_distance) {
continue;}
968 if (
node.box_num > 0) {
971 for (
Integer i{id_ini}; i < id_end; ++i) {
975 if (
distance <= max_distance) {candidates.insert(pos);}
985 return !candidates.empty();
998 m_stack.emplace_back(i);
999 std::vector<Integer> depth_stack;
1000 depth_stack.reserve(2*this->
size() + 1);
1001 depth_stack.emplace_back(0);
1007 depth =
static_cast<Integer>(depth_stack.back()); depth_stack.pop_back();
1008 if (
node.child_l == -1) {d = std::max(d,
depth);}
1009 else {
m_stack.emplace_back(
node.child_l); depth_stack.emplace_back(
depth+1);}
1010 if (
node.child_r == -1) {d = std::max(d,
depth);}
1011 else {
m_stack.emplace_back(
node.child_r); depth_stack.emplace_back(
depth+1);}
1024 if (i < 0) {
return;}
1027 m_stack.emplace_back(i);
1032 if (
node.child_l == -1) {++l;}
else {
m_stack.emplace_back(
node.child_l);}
1033 if (
node.child_r == -1) {++l;}
else {
m_stack.emplace_back(
node.child_r);}
1034 ++n; b +=
node.box_num;
1050 this->
nodes(m_tree_structure[0].child_l,
stats.left_leafs,
stats.left_nodes,
stats.left_long_boxes);
1051 this->
depth(m_tree_structure[0].child_l,
stats.left_depth);
1052 this->
nodes(m_tree_structure[0].child_r,
stats.right_leafs,
stats.right_nodes,
stats.right_long_boxes);
1053 this->
depth(m_tree_structure[0].child_r,
stats.right_depth);
1055 stats.balance_ratio =
static_cast<Real
>(
stats.left_leafs)/
static_cast<Real
>(
stats.right_leafs);
1056 stats.depth_ratio =
static_cast<Real
>(
stats.left_depth)/
static_cast<Real
>(
stats.right_depth);
#define AABBTREE_ASSERT(COND, MSG)
Definition AABBtree.hh:46
A class representing an axis-aligned bounding box (AABB) in N-dimensional space.
Definition Box.hxx:49
Box & extend(Point const &p)
Definition Box.hxx:459
void set_empty()
Definition Box.hxx:320
Real interior_distance(Point const &p) const
Definition Box.hxx:515
Side
Definition Box.hxx:401
@ RIGHT
Definition Box.hxx:401
@ LEFT
Definition Box.hxx:401
Real closest(Object const &obj, Integer const n, IndexSet &candidates, Function distance_function=[](Object const &o, Box const &b) {return b.interior_distance(o);}) const
Definition Tree.hxx:853
Integer max_nodal_objects() const
Definition Tree.hxx:193
PriorityQueue m_queue
Definition Tree.hxx:153
Integer m_check_counter
Definition Tree.hxx:148
bool intersect(Tree const &tree, IndexMap &candidates) const
Definition Tree.hxx:515
void max_nodal_objects(Integer const n)
Definition Tree.hxx:183
void build(std::unique_ptr< BoxUniquePtrList > boxes_ptr)
Definition Tree.hxx:265
Integer size() const
Definition Tree.hxx:228
AABBtree::BoxUniquePtr< Real, N > BoxUniquePtr
Definition Tree.hxx:115
AABBtree::Point< Real, N > Point
Definition Tree.hxx:118
std::unique_ptr< BoxUniquePtrList > m_boxes_ptr
Definition Tree.hxx:137
std::priority_queue< QueueItem, std::vector< QueueItem >, std::function< bool(QueueItem, QueueItem)> > PriorityQueue
Definition Tree.hxx:120
bool self_intersect(IndexSet &candidates) const
Definition Tree.hxx:629
void clear()
Definition Tree.hxx:255
std::tuple< Integer, Integer, Real > QueueItem
Definition Tree.hxx:119
static constexpr Real DUMMY_TOL
Definition Tree.hxx:42
Integer m_max_nodal_objects
Definition Tree.hxx:143
void dumping_mode(bool const mode)
Definition Tree.hxx:244
BoxUniquePtr const & box(Integer const i) const
Definition Tree.hxx:177
AABBtree::BoxUniquePtrList< Real, N > BoxUniquePtrList
Definition Tree.hxx:116
void nodes(Integer const i, Integer &l, Integer &n, Integer &b) const
Definition Tree.hxx:1022
Real separation_ratio_tolerance() const
Definition Tree.hxx:209
void disable_dumping_mode()
Definition Tree.hxx:238
AABBtree::Box< Real, N > Box
Definition Tree.hxx:114
void depth(Integer const i, Integer &d) const
Definition Tree.hxx:993
bool m_dumping_mode
Definition Tree.hxx:140
Real m_balance_ratio_tolerance
Definition Tree.hxx:145
std::vector< Node > const & structure() const
Definition Tree.hxx:215
Real m_separation_ratio_tolerance
Definition Tree.hxx:144
Node const & node(Integer const i) const
Definition Tree.hxx:222
Integer m_dump_counter
Definition Tree.hxx:149
static constexpr Real INF
Definition Tree.hxx:41
IndexList m_tree_boxes_map
Definition Tree.hxx:139
void enable_dumping_mode()
Definition Tree.hxx:233
Real distance(Object const &obj, IndexSet &candidates) const
Definition Tree.hxx:648
static constexpr Real EPS
Definition Tree.hxx:40
void print(OutStream &os) const
Definition Tree.hxx:1066
bool within_distance(Object const &obj, Real const max_distance, IndexSet &candidates, Function distance_function=[](Object const &o, Box const &b) {return b.interior_distance(o);}) const
Definition Tree.hxx:933
Real distance(Tree const &tree, IndexMap &candidates) const
Definition Tree.hxx:715
IndexList m_stack
Definition Tree.hxx:152
void stats(Statistics &stats) const
Definition Tree.hxx:1042
bool is_empty() const
Definition Tree.hxx:250
void separation_ratio_tolerance(Real const ratio)
Definition Tree.hxx:199
BoxUniquePtrList const & boxes() const
Definition Tree.hxx:170
AABBtree::Vector< Real, N > Vector
Definition Tree.hxx:117
bool intersect(Object const &obj, IndexSet &candidates) const
Definition Tree.hxx:459
std::vector< Node > m_tree_structure
Definition Tree.hxx:138
Namespace for the AABBtree library.
Definition AABBtree.hh:70
std::basic_ostream< char > OutStream
Definition AABBtree.hh:84
Eigen::Vector< Real, N > Point
Definition AABBtree.hh:91
std::map< Integer, IndexSet > IndexMap
Definition AABBtree.hh:82
std::set< Integer > IndexSet
Definition AABBtree.hh:81
std::unique_ptr< Box< Real, N > > BoxUniquePtr
Definition AABBtree.hh:88
std::vector< BoxUniquePtr< Real, N > > BoxUniquePtrList
Definition AABBtree.hh:89
std::vector< Integer > IndexList
Definition AABBtree.hh:83
Eigen::Vector< Real, N > Vector
Definition AABBtree.hh:90
AABBTREE_DEFAULT_INTEGER_TYPE Integer
The Integer type used in the AABBtree class.
Definition AABBtree.hh:78
Integer parent
Definition Tree.hxx:131
Box box_long
Definition Tree.hxx:127
Box box
Definition Tree.hxx:126
Integer child_l
Definition Tree.hxx:132
Integer box_num
Definition Tree.hxx:129
Integer box_tot_num
Definition Tree.hxx:130
Integer child_r
Definition Tree.hxx:133
Integer box_ptr
Definition Tree.hxx:128
Integer right_long_boxes
Definition Tree.hxx:60
void reset() noexcept
Definition Tree.hxx:78
Integer check_counter
Definition Tree.hxx:67
Integer right_leafs
Definition Tree.hxx:59
Integer depth
Definition Tree.hxx:53
Real depth_ratio
Definition Tree.hxx:64
Integer right_nodes
Definition Tree.hxx:58
Integer nodes
Definition Tree.hxx:50
Integer long_boxes
Definition Tree.hxx:52
Integer left_leafs
Definition Tree.hxx:55
Integer dump_counter
Definition Tree.hxx:62
Integer left_nodes
Definition Tree.hxx:54
Integer leafs
Definition Tree.hxx:51
Integer left_long_boxes
Definition Tree.hxx:56
void print(OutStream &os) const
Definition Tree.hxx:84
Integer right_depth
Definition Tree.hxx:61
Real balance_ratio
Definition Tree.hxx:63
Integer left_depth
Definition Tree.hxx:57
Integer objects
Definition Tree.hxx:49