parry2d/partitioning/bvh/
bvh_traverse.rs1use super::BvhNode;
2use crate::math::Real;
3use crate::partitioning::Bvh;
4use smallvec::SmallVec;
5
6const TRAVERSAL_STACK_SIZE: usize = 32;
7
8pub struct Leaves<'a, Check: Fn(&BvhNode) -> bool> {
9 tree: &'a Bvh,
10 next: Option<&'a BvhNode>,
11 stack: SmallVec<[&'a BvhNode; TRAVERSAL_STACK_SIZE]>,
12 check: Check,
13}
14
15impl<'a, Check: Fn(&BvhNode) -> bool> Leaves<'a, Check> {
16 pub fn new(tree: &'a Bvh, check: Check) -> Leaves<'a, Check> {
17 let mut stack = SmallVec::default();
18 let mut next = None;
19
20 if let Some(root) = tree.nodes.first() {
21 if check(&root.left) {
22 next = Some(&root.left);
23 }
24
25 if root.right.leaf_count() > 0 && check(&root.right) {
26 stack.push(&root.right);
27 }
28 }
29
30 Leaves {
31 tree,
32 next,
33 stack,
34 check,
35 }
36 }
37}
38
39impl<'a, Check: Fn(&BvhNode) -> bool> Iterator for Leaves<'a, Check> {
40 type Item = u32;
41 fn next(&mut self) -> Option<Self::Item> {
42 loop {
43 if self.next.is_none() {
44 self.next = self.stack.pop();
45 }
46
47 let node = self.next.take()?;
48
49 if node.is_leaf() {
50 return Some(node.children);
51 }
52
53 let children = &self.tree.nodes[node.children as usize];
54 let left = &children.left;
55 let right = &children.right;
56
57 if (self.check)(left) {
58 self.next = Some(left);
59 }
60
61 if (self.check)(right) {
62 if self.next.is_none() {
63 self.next = Some(right);
64 } else {
65 self.stack.push(right);
66 }
67 }
68 }
69 }
70}
71
72pub trait BvhLeafCost {
74 fn cost(&self) -> Real;
78}
79
80impl BvhLeafCost for Real {
81 #[inline(always)]
82 fn cost(&self) -> Real {
83 *self
84 }
85}
86
87impl<T> BvhLeafCost for (Real, T) {
88 #[inline(always)]
89 fn cost(&self) -> Real {
90 self.0
91 }
92}
93
94impl Bvh {
95 pub fn leaves<F: Fn(&BvhNode) -> bool>(&self, check_node: F) -> Leaves<'_, F> {
104 Leaves::new(self, check_node)
105 }
106}
107
108pub enum TraversalAction {
110 Continue,
112 Prune,
114 EarlyExit,
116}
117
118impl Bvh {
119 #[inline(always)]
120 pub(crate) fn traversal_stack() -> SmallVec<[u32; 32]> {
121 Default::default()
122 }
123
124 pub fn traverse(&self, mut check_node: impl FnMut(&BvhNode) -> TraversalAction) {
136 let mut stack = Self::traversal_stack();
137 let mut curr_id = 0;
138
139 if self.nodes.is_empty() {
140 return;
141 } else if self.nodes[0].right.leaf_count() == 0 {
142 let _ = check_node(&self.nodes[0].left);
144 return;
145 }
146
147 loop {
148 let node = &self.nodes[curr_id as usize];
149 let left = &node.left;
150 let right = &node.right;
151 let go_left = match check_node(left) {
152 TraversalAction::Continue => !left.is_leaf(),
153 TraversalAction::Prune => false,
154 TraversalAction::EarlyExit => return,
155 };
156 let go_right = match check_node(right) {
157 TraversalAction::Continue => !right.is_leaf(),
158 TraversalAction::Prune => false,
159 TraversalAction::EarlyExit => return,
160 };
161
162 match (go_left, go_right) {
163 (true, true) => {
164 curr_id = left.children;
165 stack.push(right.children);
166 }
167 (true, false) => curr_id = left.children,
168 (false, true) => curr_id = right.children,
169 (false, false) => {
170 let Some(next) = stack.pop() else {
171 return;
172 };
173 curr_id = next;
174 }
175 }
176 }
177 }
178
179 pub fn find_best<L: BvhLeafCost>(
181 &self,
182 max_cost: Real,
183 aabb_cost: impl Fn(&BvhNode, Real) -> Real,
184 leaf_cost: impl Fn(u32, Real) -> Option<L>,
185 ) -> Option<(u32, L)> {
186 let mut stack = Self::traversal_stack();
188 let mut best_val = None;
189 let mut best_cost = max_cost;
190 let mut best_id = u32::MAX;
191 let mut curr_id = 0;
192
193 if self.nodes.is_empty() {
194 return None;
195 } else if self.nodes[0].right.leaf_count() == 0 {
196 let leaf = &self.nodes[0].left;
198 if aabb_cost(leaf, max_cost) < max_cost {
199 let cost = leaf_cost(leaf.children, best_cost)?;
200 return (cost.cost() < max_cost).then_some((leaf.children, cost));
201 } else {
202 return None;
203 }
204 }
205
206 loop {
207 let node = &self.nodes[curr_id as usize];
208 let mut left = &node.left;
209 let mut right = &node.right;
210
211 let mut left_score = aabb_cost(left, best_cost);
212 let mut right_score = aabb_cost(right, best_cost);
213
214 if left_score > right_score {
215 core::mem::swap(&mut left_score, &mut right_score);
216 core::mem::swap(&mut left, &mut right);
217 }
218
219 let mut found_next = false;
220 if left_score < best_cost && left_score != Real::MAX {
221 if left.is_leaf() {
222 if let Some(primitive_val) = leaf_cost(left.children, best_cost) {
223 let primitive_score = primitive_val.cost();
224 if primitive_score < best_cost {
225 best_val = Some(primitive_val);
226 best_cost = primitive_score;
227 best_id = left.children;
228 }
229 }
230 } else {
231 curr_id = left.children;
232 found_next = true;
233 }
234 }
235
236 if right_score < best_cost && right_score != Real::MAX {
237 if right.is_leaf() {
238 if let Some(primitive_val) = leaf_cost(right.children, best_cost) {
239 let primitive_score = primitive_val.cost();
240 if primitive_score < best_cost {
241 best_val = Some(primitive_val);
242 best_cost = primitive_score;
243 best_id = right.children;
244 }
245 }
246 } else if found_next {
247 stack.push(right.children);
248 } else {
249 curr_id = right.children;
250 found_next = true;
251 }
252 }
253
254 if !found_next {
255 if let Some(next) = stack.pop() {
256 curr_id = next;
257 } else {
258 return best_val.map(|val| (best_id, val));
259 }
260 }
261 }
262 }
263}