1use fast_mesh_store::TriangleId;
4
5use crate::arena::{NONE, Node};
6use crate::{Aabb, Bvh};
7
8#[doc(hidden)]
11pub const TRAVERSE_STACK: usize = 64;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct NodeId(u32);
17
18impl NodeId {
19 pub fn index(self) -> usize {
23 self.0 as usize
24 }
25}
26
27#[derive(Debug, Clone, Copy)]
29pub enum NodeKind<'a> {
30 Inner {
32 left: NodeId,
34 right: NodeId,
36 },
37 Leaf {
39 triangles: &'a [TriangleId],
41 },
42}
43
44#[derive(Debug, Clone, Copy)]
46pub struct NodeView<'a> {
47 pub bounds: Aabb,
49 pub kind: NodeKind<'a>,
51}
52
53impl Bvh {
54 fn view(&self, node: &Node) -> NodeView<'_> {
55 let kind = if node.is_leaf() {
56 NodeKind::Leaf {
57 triangles: &self.arena.refs[node.leaf_range()],
58 }
59 } else {
60 NodeKind::Inner {
61 left: NodeId(node.a),
62 right: NodeId(node.b),
63 }
64 };
65 NodeView {
66 bounds: node.bounds,
67 kind,
68 }
69 }
70
71 pub fn root(&self) -> Option<NodeId> {
73 (self.root != NONE).then_some(NodeId(self.root))
74 }
75
76 pub fn node(&self, id: NodeId) -> NodeView<'_> {
80 self.view(&self.arena.nodes[id.0 as usize])
81 }
82
83 pub fn parent(&self, id: NodeId) -> Option<NodeId> {
85 let p = self.arena.parents[id.0 as usize];
86 (p != NONE).then_some(NodeId(p))
87 }
88
89 pub fn traverse(&self, mut visit: impl FnMut(NodeId, &NodeView) -> bool) {
93 self.arena
94 .traverse(self.root, |i, n| visit(NodeId(i), &self.view(n)));
95 }
96
97 pub fn traverse_ordered(
104 &self,
105 first_is_left: impl Fn(&Aabb, &Aabb) -> bool,
106 mut visit: impl FnMut(NodeId, &NodeView) -> bool,
107 ) {
108 self.arena
109 .traverse_ordered(self.root, first_is_left, |i, n| {
110 visit(NodeId(i), &self.view(n))
111 });
112 }
113
114 pub fn traverse_by_key<K: Copy + PartialOrd>(
131 &self,
132 key: impl FnMut(&Aabb) -> Option<K>,
133 visit: impl FnMut(NodeId, &NodeView, K) -> bool,
134 ) {
135 self.traverse_by_key_with::<TRAVERSE_STACK, K>(key, visit);
136 }
137
138 pub(crate) fn traverse_by_key_with<const N: usize, K: Copy + PartialOrd>(
141 &self,
142 key: impl FnMut(&Aabb) -> Option<K>,
143 mut visit: impl FnMut(NodeId, &NodeView, K) -> bool,
144 ) {
145 self.arena
146 .traverse_by_key::<N, K>(self.root, key, |i, n, k| visit(NodeId(i), &self.view(n), k));
147 }
148
149 pub fn traverse_from(&self, root: NodeId, mut visit: impl FnMut(NodeId, &NodeView) -> bool) {
155 self.arena
156 .traverse(root.0, |i, n| visit(NodeId(i), &self.view(n)));
157 }
158
159 pub fn node_slots(&self) -> usize {
162 self.arena.nodes.len()
163 }
164
165 pub fn generation(&self) -> u64 {
171 self.generation
172 }
173
174 pub fn mesh_uid(&self) -> u64 {
176 self.mesh_uid
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::BuildOptions;
184 use fast_mesh_store::Mesh;
185
186 fn grid(n: u32) -> Mesh {
188 let mut positions = Vec::new();
189 for y in 0..=n {
190 for x in 0..=n {
191 positions.extend([x as f32, y as f32, 0.0]);
192 }
193 }
194 let mut indices = Vec::new();
195 for y in 0..n {
196 for x in 0..n {
197 let a = y * (n + 1) + x;
198 indices.extend([a, a + 1, a + n + 2, a, a + n + 2, a + n + 1]);
199 }
200 }
201 Mesh::from_buffers(&positions, &indices).unwrap()
202 }
203
204 fn build(mesh: &Mesh) -> Bvh {
205 let opts = BuildOptions {
206 max_leaf_size: 2,
207 ..Default::default()
208 };
209 Bvh::build(mesh, &opts).unwrap()
210 }
211
212 #[test]
213 fn node_indices_are_dense_and_unique() {
214 let bvh = build(&grid(6));
215 let mut seen = vec![false; bvh.node_slots()];
216 let mut count = 0;
217 bvh.traverse(|id, _| {
218 assert!(id.index() < bvh.node_slots());
219 assert!(!seen[id.index()], "index {} repeated", id.index());
220 seen[id.index()] = true;
221 count += 1;
222 true
223 });
224 assert_eq!(count, bvh.node_count());
225 assert!(bvh.node_slots() >= bvh.node_count());
226 }
227
228 #[test]
229 fn traverse_visits_every_node_once() {
230 let bvh = build(&grid(6));
231 let mut ids = Vec::new();
232 bvh.traverse(|id, _| {
233 ids.push(id);
234 true
235 });
236 assert_eq!(ids.len(), bvh.node_count());
237 assert_eq!(ids.first().copied(), bvh.root());
238 let mut unique = ids.clone();
239 unique.sort_by_key(|id| id.0);
240 unique.dedup();
241 assert_eq!(unique.len(), ids.len());
242 }
243
244 #[test]
245 fn leaves_hold_every_alive_triangle_once() {
246 let mesh = grid(6);
247 let bvh = build(&mesh);
248 let mut all = Vec::new();
249 bvh.traverse(|_, view| {
250 if let NodeKind::Leaf { triangles } = view.kind {
251 all.extend_from_slice(triangles);
252 }
253 true
254 });
255 all.sort();
256 let expected: Vec<u32> = (0..mesh.triangle_count() as u32).collect();
257 assert_eq!(all, expected);
258 }
259
260 #[test]
261 fn parent_agrees_with_children() {
262 let bvh = build(&grid(6));
263 let root = bvh.root().unwrap();
264 assert_eq!(bvh.parent(root), None);
265 let mut inner = 0;
266 bvh.traverse(|id, view| {
267 if let NodeKind::Inner { left, right } = view.kind {
268 inner += 1;
269 assert_eq!(bvh.parent(left), Some(id));
270 assert_eq!(bvh.parent(right), Some(id));
271 }
272 true
273 });
274 assert!(inner > 0);
275 }
276
277 fn pre_order_swapped(bvh: &Bvh, id: NodeId, out: &mut Vec<NodeId>) {
278 out.push(id);
279 if let NodeKind::Inner { left, right } = bvh.node(id).kind {
280 pre_order_swapped(bvh, right, out);
281 pre_order_swapped(bvh, left, out);
282 }
283 }
284
285 #[test]
286 fn ordered_traversal_follows_first_is_left() {
287 let bvh = build(&grid(6));
288 let mut expected = Vec::new();
289 pre_order_swapped(&bvh, bvh.root().unwrap(), &mut expected);
290 let mut got = Vec::new();
291 bvh.traverse_ordered(
292 |_, _| false,
293 |id, _| {
294 got.push(id);
295 true
296 },
297 );
298 assert_eq!(got, expected);
299 assert_eq!(got.len(), bvh.node_count());
300 }
301
302 fn pre_order_by(
304 bvh: &Bvh,
305 id: NodeId,
306 first_is_left: &impl Fn(&Aabb, &Aabb) -> bool,
307 out: &mut Vec<NodeId>,
308 ) {
309 out.push(id);
310 if let NodeKind::Inner { left, right } = bvh.node(id).kind {
311 let (l, r) = (bvh.node(left).bounds, bvh.node(right).bounds);
312 let (first, second) = if first_is_left(&l, &r) {
313 (left, right)
314 } else {
315 (right, left)
316 };
317 pre_order_by(bvh, first, first_is_left, out);
318 pre_order_by(bvh, second, first_is_left, out);
319 }
320 }
321
322 #[test]
323 fn ordered_traversal_with_mixed_choices() {
324 let bvh = build(&grid(6));
325 let pred = |l: &Aabb, r: &Aabb| l.min[0] < r.min[0];
326 let (mut lefts, mut rights) = (0, 0);
328 bvh.traverse(|_, view| {
329 if let NodeKind::Inner { left, right } = view.kind {
330 if pred(&bvh.node(left).bounds, &bvh.node(right).bounds) {
331 lefts += 1;
332 } else {
333 rights += 1;
334 }
335 }
336 true
337 });
338 assert!(lefts > 0 && rights > 0, "lefts {lefts}, rights {rights}");
339
340 let mut expected = Vec::new();
341 pre_order_by(&bvh, bvh.root().unwrap(), &pred, &mut expected);
342 let mut got = Vec::new();
343 bvh.traverse_ordered(pred, |id, _| {
344 got.push(id);
345 true
346 });
347 assert_eq!(got, expected);
348 assert_eq!(got.len(), bvh.node_count());
349 }
350
351 #[test]
352 fn pruning_an_inner_node_skips_only_its_subtree() {
353 let bvh = build(&grid(6));
354 let root = bvh.root().unwrap();
355 let NodeKind::Inner { left, right } = bvh.node(root).kind else {
356 panic!("expected an inner root");
357 };
358 let NodeKind::Inner { .. } = bvh.node(left).kind else {
359 panic!("expected an inner left child");
360 };
361 let mut subtree = Vec::new();
362 pre_order_by(&bvh, left, &|_, _| true, &mut subtree);
363 assert!(subtree.len() > 1);
364
365 let run = |ordered: bool| {
366 let mut got = Vec::new();
367 let visit = |id: NodeId, _: &NodeView| {
368 got.push(id);
369 id != left
370 };
371 if ordered {
372 bvh.traverse_ordered(|_, _| true, visit);
373 } else {
374 bvh.traverse(visit);
375 }
376 got
377 };
378 for got in [run(false), run(true)] {
379 assert_eq!(got.len(), bvh.node_count() - (subtree.len() - 1));
380 assert!(got.contains(&left) && got.contains(&right));
381 for id in &subtree[1..] {
382 assert!(!got.contains(id));
383 }
384 let mut unique = got.clone();
385 unique.sort_by_key(|id| id.0);
386 unique.dedup();
387 assert_eq!(unique.len(), got.len());
388 }
389 }
390
391 #[test]
392 fn single_leaf_tree() {
393 let single = Mesh::from_buffers(&[0., 0., 0., 1., 0., 0., 0., 1., 0.], &[0, 1, 2]).unwrap();
394 let bvh = build(&single);
395 let root = bvh.root().unwrap();
396 assert!(matches!(
397 bvh.node(root).kind,
398 NodeKind::Leaf { triangles } if triangles == [0]
399 ));
400 assert_eq!(bvh.parent(root), None);
401 let mut calls = 0;
402 bvh.traverse(|_, _| {
403 calls += 1;
404 true
405 });
406 bvh.traverse_ordered(
407 |_, _| true,
408 |_, _| {
409 calls += 1;
410 true
411 },
412 );
413 assert_eq!(calls, 2);
414 }
415
416 #[test]
417 fn ordered_traversal_prunes() {
418 let bvh = build(&grid(6));
419 let mut visited = 0;
420 bvh.traverse_ordered(
421 |_, _| true,
422 |_, _| {
423 visited += 1;
424 false
425 },
426 );
427 assert_eq!(visited, 1);
428 }
429
430 fn by_key_ref<K: Copy + PartialOrd>(
434 bvh: &Bvh,
435 id: NodeId,
436 k: K,
437 key: &impl Fn(&Aabb) -> Option<K>,
438 descend: &impl Fn(NodeId) -> bool,
439 out: &mut Vec<(NodeId, K)>,
440 ) {
441 out.push((id, k));
442 if !descend(id) {
443 return;
444 }
445 if let NodeKind::Inner { left, right } = bvh.node(id).kind {
446 let kl = key(&bvh.node(left).bounds);
447 let kr = key(&bvh.node(right).bounds);
448 let order = if matches!((kl, kr), (Some(l), Some(r)) if r < l) {
449 [(right, kr), (left, kl)]
450 } else {
451 [(left, kl), (right, kr)]
452 };
453 for (c, kc) in order {
454 if let Some(kc) = kc {
455 by_key_ref(bvh, c, kc, key, descend, out);
456 }
457 }
458 }
459 }
460
461 fn reference<K: Copy + PartialOrd>(
462 bvh: &Bvh,
463 key: &impl Fn(&Aabb) -> Option<K>,
464 descend: &impl Fn(NodeId) -> bool,
465 ) -> Vec<(NodeId, K)> {
466 let mut out = Vec::new();
467 let root = bvh.root().unwrap();
468 if let Some(k) = key(&bvh.node(root).bounds) {
469 by_key_ref(bvh, root, k, key, descend, &mut out);
470 }
471 out
472 }
473
474 fn run_by_key<const N: usize, K: Copy + PartialOrd + std::fmt::Debug>(
477 bvh: &Bvh,
478 key: &impl Fn(&Aabb) -> Option<K>,
479 descend: &impl Fn(NodeId) -> bool,
480 ) -> (Vec<(NodeId, K)>, usize) {
481 let mut got = Vec::new();
482 let mut calls = 0;
483 bvh.traverse_by_key_with::<N, K>(
484 |b| {
485 calls += 1;
486 key(b)
487 },
488 |id, view, k| {
489 assert_eq!(key(&view.bounds), Some(k));
490 got.push((id, k));
491 descend(id)
492 },
493 );
494 (got, calls)
495 }
496
497 fn slanted(b: &Aabb) -> Option<f32> {
500 Some((b.min[0] - 3.1).abs() + 2.0 * (b.max[1] - 2.6).abs())
501 }
502
503 #[test]
504 fn by_key_matches_recursive_reference() {
505 let bvh = build(&grid(6));
506 let all = |_: NodeId| true;
507 let expected = reference(&bvh, &slanted, &all);
508 assert_eq!(expected.len(), bvh.node_count());
509 let (mut lefts, mut rights) = (0, 0);
512 bvh.traverse(|_, view| {
513 if let NodeKind::Inner { left, right } = view.kind {
514 if slanted(&bvh.node(right).bounds) < slanted(&bvh.node(left).bounds) {
515 rights += 1;
516 } else {
517 lefts += 1;
518 }
519 }
520 true
521 });
522 assert!(lefts > 0 && rights > 0, "lefts {lefts}, rights {rights}");
523
524 let mut got = Vec::new();
525 bvh.traverse_by_key(slanted, |id, _, k| {
526 got.push((id, k));
527 true
528 });
529 assert_eq!(got, expected);
530 let mut unique: Vec<u32> = got.iter().map(|(id, _)| id.0).collect();
531 unique.sort();
532 unique.dedup();
533 assert_eq!(unique.len(), bvh.node_count());
534 }
535
536 fn unique_inner_non_root(bvh: &Bvh) -> NodeId {
538 let mut all = Vec::new();
539 bvh.traverse(|id, view| {
540 all.push((id, view.bounds, matches!(view.kind, NodeKind::Inner { .. })));
541 true
542 });
543 all.iter()
544 .find(|&&(id, b, inner)| {
545 inner
546 && Some(id) != bvh.root()
547 && all.iter().filter(|&&(_, o, _)| o == b).count() == 1
548 })
549 .expect("no inner node with unique bounds")
550 .0
551 }
552
553 fn subtree(bvh: &Bvh, id: NodeId) -> Vec<NodeId> {
554 let mut out = Vec::new();
555 pre_order_by(bvh, id, &|_, _| true, &mut out);
556 out
557 }
558
559 #[test]
560 fn by_key_none_culls_subtree() {
561 let bvh = build(&grid(6));
562 let culled = unique_inner_non_root(&bvh);
563 let hidden = subtree(&bvh, culled);
564 assert!(hidden.len() > 1);
565 let cull_bounds = bvh.node(culled).bounds;
566 let key = |b: &Aabb| if *b == cull_bounds { None } else { slanted(b) };
567 let all = |_: NodeId| true;
568 let expected = reference(&bvh, &key, &all);
569 assert_eq!(expected.len(), bvh.node_count() - hidden.len());
570
571 let mut got = Vec::new();
572 bvh.traverse_by_key(key, |id, _, k| {
573 got.push((id, k));
574 true
575 });
576 assert_eq!(got, expected);
577 for id in &hidden {
578 assert!(!got.iter().any(|(g, _)| g == id));
579 }
580 }
581
582 #[test]
583 fn key_evaluated_once_per_node() {
584 let bvh = build(&grid(6));
585 let mut calls = 0;
586 let mut visits = 0;
587 bvh.traverse_by_key(
588 |b| {
589 calls += 1;
590 slanted(b)
591 },
592 |_, _, _| {
593 visits += 1;
594 true
595 },
596 );
597 assert_eq!(visits, bvh.node_count());
598 assert_eq!(calls, bvh.node_count());
599 }
600
601 #[test]
602 fn small_stack_overflow_falls_back() {
603 let bvh = build(&grid(8));
606 assert!(bvh.depth() > 4);
607 let mut plain = Vec::new();
608 bvh.traverse(|id, _| {
609 plain.push(id.0);
610 true
611 });
612 plain.sort();
613
614 let culled = unique_inner_non_root(&bvh);
615 let cull_bounds = bvh.node(culled).bounds;
616 let culling = |b: &Aabb| if *b == cull_bounds { None } else { slanted(b) };
617
618 let all = |_: NodeId| true;
619 let prune_one = |id: NodeId| id != culled;
620 let prune_root = |_: NodeId| false;
621 type Key<'a> = &'a dyn Fn(&Aabb) -> Option<f32>;
622 type Descend<'a> = &'a dyn Fn(NodeId) -> bool;
623 let cases: [(Key, Descend); 4] = [
624 (&slanted, &all),
625 (&slanted, &prune_one),
626 (&culling, &all),
627 (&slanted, &prune_root),
628 ];
629 for (key, descend) in cases {
630 let expected = reference(&bvh, &key, &descend);
631 let runs = [
632 run_by_key::<0, f32>(&bvh, &key, &descend),
633 run_by_key::<1, f32>(&bvh, &key, &descend),
634 run_by_key::<2, f32>(&bvh, &key, &descend),
635 run_by_key::<3, f32>(&bvh, &key, &descend),
636 run_by_key::<4, f32>(&bvh, &key, &descend),
637 run_by_key::<TRAVERSE_STACK, f32>(&bvh, &key, &descend),
638 ];
639 for (got, _) in &runs {
640 assert_eq!(*got, expected);
642 }
643 assert!(runs[5].1 <= bvh.node_count());
646 }
647
648 let (got, calls) = run_by_key::<2, f32>(&bvh, &slanted, &all);
649 assert!(calls > bvh.node_count(), "the fallback never ran");
650 let mut ids: Vec<u32> = got.iter().map(|(id, _)| id.0).collect();
651 ids.sort();
652 assert_eq!(ids, plain);
653
654 let (got, _) = run_by_key::<2, f32>(&bvh, &slanted, &prune_root);
655 assert_eq!(got.len(), 1);
656 }
657
658 #[test]
659 fn traverse_from_visits_subtree_only() {
660 let bvh = build(&grid(6));
661 let root = bvh.root().unwrap();
662 let NodeKind::Inner { left, .. } = bvh.node(root).kind else {
663 panic!("expected an inner root");
664 };
665 for id in [left, root] {
666 let expected = subtree(&bvh, id);
667 let mut got = Vec::new();
668 bvh.traverse_from(id, |i, _| {
669 got.push(i);
670 true
671 });
672 assert_eq!(got, expected);
673 }
674 let mut got = Vec::new();
675 bvh.traverse_from(left, |i, _| {
676 got.push(i);
677 false
678 });
679 assert_eq!(got, [left]);
680 }
681
682 #[test]
683 fn by_key_on_empty_and_single_leaf_trees() {
684 let empty = build(&Mesh::new());
685 let (mut keys, mut visits) = (0, 0);
686 empty.traverse_by_key(
687 |_| {
688 keys += 1;
689 Some(0.0)
690 },
691 |_, _, _| {
692 visits += 1;
693 true
694 },
695 );
696 assert_eq!((keys, visits), (0, 0));
697
698 let single = Mesh::from_buffers(&[0., 0., 0., 1., 0., 0., 0., 1., 0.], &[0, 1, 2]).unwrap();
699 let bvh = build(&single);
700 let mut visits = 0;
701 let root_key = slanted(&bvh.root_bounds().unwrap());
702 bvh.traverse_by_key(slanted, |_, _, k| {
703 assert_eq!(Some(k), root_key);
704 visits += 1;
705 true
706 });
707 assert_eq!(visits, 1);
708 bvh.traverse_by_key(|_| None::<f32>, |_, _, _| panic!("culled root visited"));
709 }
710
711 #[test]
712 fn empty_tree_has_no_root() {
713 let mesh = Mesh::new();
714 let bvh = build(&mesh);
715 assert_eq!(bvh.root(), None);
716 let mut calls = 0;
717 bvh.traverse(|_, _| {
718 calls += 1;
719 true
720 });
721 bvh.traverse_ordered(
722 |_, _| true,
723 |_, _| {
724 calls += 1;
725 true
726 },
727 );
728 assert_eq!(calls, 0);
729 }
730}