Fix stack overflow during BVH construction

The epsilon for float equality was too small which prevented the
function from terminating. Additionally, it has been rewritten in terms
of a loop because tail-call optimization was not happening.
This commit is contained in:
Ryan 2022-07-17 22:07:51 -07:00
parent b604dafe73
commit 044a735729

View file

@ -6,7 +6,7 @@
use std::iter::FusedIterator; use std::iter::FusedIterator;
use std::mem; use std::mem;
use approx::relative_eq; use approx::abs_diff_eq;
use rayon::iter::{ use rayon::iter::{
IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
}; };
@ -180,7 +180,7 @@ impl<'a, T> Internal<'a, T> {
fn build_rec<T: Send>( fn build_rec<T: Send>(
idx: NodeIdx, idx: NodeIdx,
bounds: Aabb<f64>, mut bounds: Aabb<f64>,
internal_nodes: &mut [InternalNode], internal_nodes: &mut [InternalNode],
leaf_nodes: &mut [LeafNode<T>], leaf_nodes: &mut [LeafNode<T>],
total_leaf_count: NodeIdx, total_leaf_count: NodeIdx,
@ -192,6 +192,7 @@ fn build_rec<T: Send>(
return (total_leaf_count - 1 + idx, leaf_nodes[0].bb); return (total_leaf_count - 1 + idx, leaf_nodes[0].bb);
} }
loop {
debug_assert!(bounds.is_valid()); debug_assert!(bounds.is_valid());
let dims = bounds.max - bounds.min; let dims = bounds.max - bounds.min;
@ -221,28 +222,26 @@ fn build_rec<T: Send>(
// Check if one of the halves is empty. (We can't have empty nodes) // Check if one of the halves is empty. (We can't have empty nodes)
// Also take care to handle the edge case of overlapping points. // Also take care to handle the edge case of overlapping points.
if split == 0 { if split == 0 {
if relative_eq!(bounds_right.min, bounds_right.max) { if abs_diff_eq!(
bounds_right.min,
bounds_right.max,
epsilon = f64::EPSILON * 100.0
) {
split += 1; split += 1;
} else { } else {
return build_rec( bounds = bounds_right;
idx, continue;
bounds_right,
internal_nodes,
leaf_nodes,
total_leaf_count,
);
} }
} else if split == leaf_nodes.len() { } else if split == leaf_nodes.len() {
if relative_eq!(bounds_left.min, bounds_left.max) { if abs_diff_eq!(
bounds_left.min,
bounds_left.max,
epsilon = f64::EPSILON * 100.0
) {
split -= 1; split -= 1;
} else { } else {
return build_rec( bounds = bounds_left;
idx, continue;
bounds_left,
internal_nodes,
leaf_nodes,
total_leaf_count,
);
} }
} }
@ -276,7 +275,8 @@ fn build_rec<T: Send>(
internal.left = left; internal.left = left;
internal.right = right; internal.right = right;
(idx + split as NodeIdx - 1, internal.bb) break (idx + split as NodeIdx - 1, internal.bb);
}
} }
fn partition<T>(s: &mut [T], mut pred: impl FnMut(&T) -> bool) -> usize { fn partition<T>(s: &mut [T], mut pred: impl FnMut(&T) -> bool) -> usize {