Skip to main content

parry2d/partitioning/bvh/
bvh_traverse_bvtt.rs

1use super::{Bvh, BvhNode, BvhWorkspace};
2use alloc::vec::Vec;
3use smallvec::SmallVec;
4
5const TRAVERSAL_STACK_SIZE: usize = 32;
6
7impl Bvh {
8    /*
9     * Traversal of a tree against itself.
10     */
11    // NOTE PERF: change detection doesn’t make a huge difference in 2D (it can
12    //            occasionally even make it slower!) Once we support a static/dynamic tree
13    //            instead of a single tree, we might want to fully disable change detection
14    //            in 2D.
15    /// Traverses the Bounding Volume Test Tree of a tree against itself.
16    ///
17    /// The closure `f` will be called on each pair of leaf that passed the AABB intersection checks.
18    /// If `CHANGE_DETECTION` is `true`, then only pairs of leaves where at least one was detected
19    /// as changed during [`Self::insert_or_update_partially`] will be traversed.
20    pub fn traverse_bvtt_single_tree<const CHANGE_DETECTION: bool>(
21        &self,
22        workspace: &mut BvhWorkspace,
23        f: &mut impl FnMut(u32, u32),
24    ) {
25        if self.nodes.is_empty() || self.nodes[0].right.leaf_count() == 0 {
26            // Not enough nodes for any overlap.
27            return;
28        }
29
30        workspace.traversal_stack.clear();
31        self.self_intersect_node::<CHANGE_DETECTION>(&mut workspace.traversal_stack, 0, f)
32    }
33
34    // Traverses overlaps of a single node with itself.
35    // This as special case to:
36    // - Ensure we don’t traverse the same branch twice.
37    // - Only check the left/right overlap. Left/left and right/right checks trivially pass.
38    // TODO: take change detection into account.
39    fn self_intersect_node<const CHANGE_DETECTION: bool>(
40        &self,
41        stack: &mut Vec<u32>,
42        id: u32,
43        f: &mut impl FnMut(u32, u32),
44    ) {
45        let node = &self.nodes[id as usize];
46
47        if CHANGE_DETECTION && !node.right.is_changed() && !node.left.is_changed() {
48            return;
49        }
50
51        let left_right_intersect = node.left.intersects(&node.right);
52        let left_child = node.left.children;
53        let right_child = node.right.children;
54        let left_is_leaf = node.left.is_leaf();
55        let right_is_leaf = node.right.is_leaf();
56
57        if (!CHANGE_DETECTION || node.left.is_changed()) && !left_is_leaf {
58            self.self_intersect_node::<CHANGE_DETECTION>(stack, left_child, f);
59        }
60
61        if (!CHANGE_DETECTION || node.right.is_changed()) && !right_is_leaf {
62            self.self_intersect_node::<CHANGE_DETECTION>(stack, right_child, f);
63        }
64
65        if left_right_intersect {
66            match (left_is_leaf, right_is_leaf) {
67                (true, true) => f(left_child, right_child),
68                (true, false) => self.traverse_single_subtree::<CHANGE_DETECTION>(
69                    stack,
70                    &node.left,
71                    right_child,
72                    f,
73                ),
74                (false, true) => self.traverse_single_subtree::<CHANGE_DETECTION>(
75                    stack,
76                    &node.right,
77                    left_child,
78                    f,
79                ),
80                (false, false) => self.traverse_two_branches::<CHANGE_DETECTION>(
81                    stack,
82                    left_child,
83                    right_child,
84                    f,
85                ),
86            }
87        }
88    }
89
90    fn traverse_two_branches<const CHANGE_DETECTION: bool>(
91        &self,
92        stack: &mut Vec<u32>,
93        a: u32,
94        b: u32,
95        f: &mut impl FnMut(u32, u32),
96    ) {
97        let node1 = &self.nodes[a as usize];
98        let node2 = &self.nodes[b as usize];
99
100        let left1 = &node1.left;
101        let right1 = &node1.right;
102        let left2 = &node2.left;
103        let right2 = &node2.right;
104
105        let left_left = (!CHANGE_DETECTION || left1.is_changed() || left2.is_changed())
106            && left1.intersects(left2);
107        let left_right = (!CHANGE_DETECTION || left1.is_changed() || right2.is_changed())
108            && left1.intersects(right2);
109        let right_left = (!CHANGE_DETECTION || right1.is_changed() || left2.is_changed())
110            && right1.intersects(left2);
111        let right_right = (!CHANGE_DETECTION || right1.is_changed() || right2.is_changed())
112            && right1.intersects(right2);
113
114        macro_rules! dispatch(
115            ($check: ident, $child_a: ident, $child_b: ident) => {
116                if $check {
117                    match ($child_a.is_leaf(), $child_b.is_leaf()) {
118                        (true, true) => f($child_a.children, $child_b.children),
119                        (true, false) => {
120                            self.traverse_single_subtree::<CHANGE_DETECTION>(stack, $child_a, $child_b.children, f)
121                        }
122                        (false, true) => self.traverse_single_subtree::<CHANGE_DETECTION>(
123                            stack,
124                            $child_b,
125                            $child_a.children,
126                            f,
127                        ),
128                        (false, false) => self.traverse_two_branches::<CHANGE_DETECTION>(
129                            stack,
130                            $child_a.children,
131                            $child_b.children,
132                            f,
133                        ),
134                    }
135                }
136            }
137        );
138
139        dispatch!(left_left, left1, left2);
140        dispatch!(left_right, left1, right2);
141        dispatch!(right_left, right1, left2);
142        dispatch!(right_right, right1, right2);
143    }
144
145    // Checks overlap between a single node and a subtree.
146    fn traverse_single_subtree<const CHANGE_DETECTION: bool>(
147        &self,
148        stack: &mut Vec<u32>,
149        node: &BvhNode,
150        subtree: u32,
151        f: &mut impl FnMut(u32, u32),
152    ) {
153        debug_assert!(stack.is_empty());
154
155        // Since this is traversing against a single node it is more efficient to keep the leaf reference
156        // around and traverse the branch using a manual stack. Left branches are traversed by the main
157        // loop whereas the right branches are pushed to the stack.
158        let mut curr_id = subtree;
159        let node_changed = node.is_changed();
160
161        loop {
162            let curr = &self.nodes[curr_id as usize];
163            let left = &curr.left;
164            let right = &curr.right;
165            let left_check =
166                (!CHANGE_DETECTION || node_changed || left.is_changed()) && node.intersects(left);
167            let right_check =
168                (!CHANGE_DETECTION || node_changed || right.is_changed()) && node.intersects(right);
169            let left_is_leaf = left.is_leaf();
170            let right_is_leaf = right.is_leaf();
171            let mut found_next = false;
172
173            if left_check {
174                if left_is_leaf {
175                    f(node.children, left.children)
176                } else {
177                    curr_id = left.children;
178                    found_next = true;
179                }
180            }
181
182            if right_check {
183                if right_is_leaf {
184                    f(node.children, right.children)
185                } else if !found_next {
186                    curr_id = right.children;
187                    found_next = true;
188                } else {
189                    // We already advanced in curr_id once, push the other
190                    // branch to the stack.
191                    stack.push(right.children);
192                }
193            }
194
195            if !found_next {
196                // Pop the stack to find the next candidate.
197                if let Some(next_id) = stack.pop() {
198                    curr_id = next_id;
199                } else {
200                    // Traversal is finished.
201                    return;
202                }
203            }
204        }
205    }
206
207    /// Parallel version of [`Self::traverse_bvtt_single_tree`], returning the reached
208    /// leaf pairs instead of invoking a closure.
209    ///
210    /// The returned pairs are in the exact same order as the calls the sequential
211    /// traversal would have made, so both versions are interchangeable, including for
212    /// determinism-sensitive callers.
213    #[cfg(feature = "parallel")]
214    pub fn traverse_bvtt_single_tree_parallel<const CHANGE_DETECTION: bool>(
215        &self,
216    ) -> Vec<(u32, u32)> {
217        if self.nodes.is_empty() || self.nodes[0].right.leaf_count() == 0 {
218            // Not enough nodes for any overlap.
219            return Vec::new();
220        }
221
222        const MAX_SPLIT_DEPTH: u32 = 6;
223        self.self_intersect_node_parallel::<CHANGE_DETECTION>(0, MAX_SPLIT_DEPTH)
224    }
225
226    /// Task-parallel mirror of `self_intersect_node`: the recursions become tasks and
227    /// their results are concatenated in the same order as the sequential recursion.
228    #[cfg(feature = "parallel")]
229    fn self_intersect_node_parallel<const CHANGE_DETECTION: bool>(
230        &self,
231        id: u32,
232        depth: u32,
233    ) -> Vec<(u32, u32)> {
234        // Subtrees below this leaf count are traversed sequentially.
235        const SEQ_LEAF_THRESHOLD: u32 = 512;
236
237        let node = &self.nodes[id as usize];
238
239        if CHANGE_DETECTION && !node.right.is_changed() && !node.left.is_changed() {
240            return Vec::new();
241        }
242
243        if depth == 0 || node.left.leaf_count() + node.right.leaf_count() <= SEQ_LEAF_THRESHOLD {
244            let mut out = Vec::new();
245            let mut stack = Vec::new();
246            self.self_intersect_node::<CHANGE_DETECTION>(&mut stack, id, &mut |a, b| {
247                out.push((a, b))
248            });
249            return out;
250        }
251
252        let left_right_intersect = node.left.intersects(&node.right);
253        let left_child = node.left.children;
254        let right_child = node.right.children;
255        let left_is_leaf = node.left.is_leaf();
256        let right_is_leaf = node.right.is_leaf();
257
258        let (mut left_pairs, (mut right_pairs, mut cross_pairs)) = rayon::join(
259            || {
260                if (!CHANGE_DETECTION || node.left.is_changed()) && !left_is_leaf {
261                    self.self_intersect_node_parallel::<CHANGE_DETECTION>(left_child, depth - 1)
262                } else {
263                    Vec::new()
264                }
265            },
266            || {
267                rayon::join(
268                    || {
269                        if (!CHANGE_DETECTION || node.right.is_changed()) && !right_is_leaf {
270                            self.self_intersect_node_parallel::<CHANGE_DETECTION>(
271                                right_child,
272                                depth - 1,
273                            )
274                        } else {
275                            Vec::new()
276                        }
277                    },
278                    || {
279                        let mut out = Vec::new();
280                        if left_right_intersect {
281                            match (left_is_leaf, right_is_leaf) {
282                                (true, true) => out.push((left_child, right_child)),
283                                (true, false) => {
284                                    let mut stack = Vec::new();
285                                    self.traverse_single_subtree::<CHANGE_DETECTION>(
286                                        &mut stack,
287                                        &node.left,
288                                        right_child,
289                                        &mut |a, b| out.push((a, b)),
290                                    );
291                                }
292                                (false, true) => {
293                                    let mut stack = Vec::new();
294                                    self.traverse_single_subtree::<CHANGE_DETECTION>(
295                                        &mut stack,
296                                        &node.right,
297                                        left_child,
298                                        &mut |a, b| out.push((a, b)),
299                                    );
300                                }
301                                (false, false) => {
302                                    out = self.traverse_two_branches_parallel::<CHANGE_DETECTION>(
303                                        left_child,
304                                        right_child,
305                                        depth - 1,
306                                    );
307                                }
308                            }
309                        }
310                        out
311                    },
312                )
313            },
314        );
315
316        left_pairs.append(&mut right_pairs);
317        left_pairs.append(&mut cross_pairs);
318        left_pairs
319    }
320
321    /// Task-parallel mirror of `traverse_two_branches`, preserving its dispatch order
322    /// (left/left, left/right, right/left, right/right).
323    #[cfg(feature = "parallel")]
324    fn traverse_two_branches_parallel<const CHANGE_DETECTION: bool>(
325        &self,
326        a: u32,
327        b: u32,
328        depth: u32,
329    ) -> Vec<(u32, u32)> {
330        const SEQ_LEAF_THRESHOLD: u32 = 512;
331
332        let node1 = &self.nodes[a as usize];
333        let node2 = &self.nodes[b as usize];
334        let leaf_count = node1.left.leaf_count()
335            + node1.right.leaf_count()
336            + node2.left.leaf_count()
337            + node2.right.leaf_count();
338
339        if depth == 0 || leaf_count <= SEQ_LEAF_THRESHOLD {
340            let mut out = Vec::new();
341            let mut stack = Vec::new();
342            self.traverse_two_branches::<CHANGE_DETECTION>(&mut stack, a, b, &mut |a, b| {
343                out.push((a, b))
344            });
345            return out;
346        }
347
348        let dispatch = |child_a: &BvhNode, child_b: &BvhNode, check: bool| -> Vec<(u32, u32)> {
349            let mut out = Vec::new();
350            if check {
351                match (child_a.is_leaf(), child_b.is_leaf()) {
352                    (true, true) => out.push((child_a.children, child_b.children)),
353                    (true, false) => {
354                        let mut stack = Vec::new();
355                        self.traverse_single_subtree::<CHANGE_DETECTION>(
356                            &mut stack,
357                            child_a,
358                            child_b.children,
359                            &mut |a, b| out.push((a, b)),
360                        );
361                    }
362                    (false, true) => {
363                        let mut stack = Vec::new();
364                        self.traverse_single_subtree::<CHANGE_DETECTION>(
365                            &mut stack,
366                            child_b,
367                            child_a.children,
368                            &mut |a, b| out.push((a, b)),
369                        );
370                    }
371                    (false, false) => {
372                        out = self.traverse_two_branches_parallel::<CHANGE_DETECTION>(
373                            child_a.children,
374                            child_b.children,
375                            depth - 1,
376                        );
377                    }
378                }
379            }
380            out
381        };
382
383        let left1 = &node1.left;
384        let right1 = &node1.right;
385        let left2 = &node2.left;
386        let right2 = &node2.right;
387
388        let left_left = (!CHANGE_DETECTION || left1.is_changed() || left2.is_changed())
389            && left1.intersects(left2);
390        let left_right = (!CHANGE_DETECTION || left1.is_changed() || right2.is_changed())
391            && left1.intersects(right2);
392        let right_left = (!CHANGE_DETECTION || right1.is_changed() || left2.is_changed())
393            && right1.intersects(left2);
394        let right_right = (!CHANGE_DETECTION || right1.is_changed() || right2.is_changed())
395            && right1.intersects(right2);
396
397        let ((mut ll, mut lr), (mut rl, mut rr)) = rayon::join(
398            || {
399                rayon::join(
400                    || dispatch(left1, left2, left_left),
401                    || dispatch(left1, right2, left_right),
402                )
403            },
404            || {
405                rayon::join(
406                    || dispatch(right1, left2, right_left),
407                    || dispatch(right1, right2, right_right),
408                )
409            },
410        );
411
412        ll.append(&mut lr);
413        ll.append(&mut rl);
414        ll.append(&mut rr);
415        ll
416    }
417
418    /// Performs a simultaneous traversal of the BVHs `self` and `other`, and yields the pairs
419    /// of leaves it reached.
420    ///
421    /// Any node pairs failing the given `check` will be excluded from the traversal.
422    pub fn leaf_pairs<'a, F: Fn(&BvhNode, &BvhNode) -> bool>(
423        &'a self,
424        other: &'a Self,
425        check: F,
426    ) -> LeafPairs<'a, F> {
427        if let (Some(root1), Some(root2)) = (self.nodes.first(), other.nodes.first()) {
428            let mut stack = SmallVec::default();
429
430            if root1.left.leaf_count() > 0 && root2.right.leaf_count() > 0 {
431                stack.push((&root1.left, &root2.right));
432                // NOTE: we don’t need to push (&root1.left, &root2.left), it is already given as
433                //       the initial value of `LeafPairs::next`.
434                // stack.push((&root1.left, &root2.left))
435            }
436
437            if root1.right.leaf_count() > 0 {
438                if root2.right.leaf_count() > 0 {
439                    stack.push((&root1.right, &root2.right));
440                }
441                stack.push((&root1.right, &root2.left))
442            }
443
444            LeafPairs {
445                tree1: self,
446                tree2: other,
447                next: Some((&root1.left, &root2.left)),
448                stack,
449                check,
450            }
451        } else {
452            LeafPairs {
453                tree1: self,
454                tree2: other,
455                next: None,
456                stack: Default::default(),
457                check,
458            }
459        }
460    }
461}
462
463pub struct LeafPairs<'a, Check: Fn(&BvhNode, &BvhNode) -> bool> {
464    tree1: &'a Bvh,
465    tree2: &'a Bvh,
466    next: Option<(&'a BvhNode, &'a BvhNode)>,
467    stack: SmallVec<[(&'a BvhNode, &'a BvhNode); TRAVERSAL_STACK_SIZE]>,
468    check: Check,
469}
470
471impl<'a, Check: Fn(&BvhNode, &BvhNode) -> bool> Iterator for LeafPairs<'a, Check> {
472    type Item = (u32, u32);
473    fn next(&mut self) -> Option<Self::Item> {
474        loop {
475            if self.next.is_none() {
476                self.next = self.stack.pop();
477            }
478
479            let (node1, node2) = self.next.take()?;
480
481            match (node1.is_leaf(), node2.is_leaf()) {
482                (true, true) => return Some((node1.children, node2.children)),
483                (true, false) => {
484                    let child2 = &self.tree2.nodes[node2.children as usize];
485                    if (self.check)(node1, &child2.left) {
486                        self.next = Some((node1, &child2.left));
487                    }
488                    if (self.check)(node1, &child2.right) {
489                        if self.next.is_none() {
490                            self.next = Some((node1, &child2.right));
491                        } else {
492                            self.stack.push((node1, &child2.right));
493                        }
494                    }
495                }
496                (false, true) => {
497                    let child1 = &self.tree1.nodes[node1.children as usize];
498                    if (self.check)(&child1.left, node2) {
499                        self.next = Some((&child1.left, node2));
500                    }
501                    if (self.check)(&child1.right, node2) {
502                        if self.next.is_none() {
503                            self.next = Some((&child1.right, node2));
504                        } else {
505                            self.stack.push((&child1.right, node2));
506                        }
507                    }
508                }
509                (false, false) => {
510                    let child1 = &self.tree1.nodes[node1.children as usize];
511                    let child2 = &self.tree2.nodes[node2.children as usize];
512                    if (self.check)(&child1.left, &child2.left) {
513                        self.stack.push((&child1.left, &child2.left));
514                    }
515                    if (self.check)(&child1.right, &child2.left) {
516                        self.stack.push((&child1.right, &child2.left));
517                    }
518                    if (self.check)(&child1.left, &child2.right) {
519                        self.stack.push((&child1.left, &child2.right));
520                    }
521                    if (self.check)(&child1.right, &child2.right) {
522                        self.stack.push((&child1.right, &child2.right));
523                    }
524                }
525            }
526        }
527    }
528}