diff --git a/geometry/src/aabb.rs b/geometry/src/aabb.rs index 425170f8..f11c8c0a 100644 --- a/geometry/src/aabb.rs +++ b/geometry/src/aabb.rs @@ -4,110 +4,98 @@ use super::aap::Aap; #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub struct Aabb { - center: Vector3, - half_size: Vector3, + min: Vector3, + max: Vector3, } impl Aabb { - pub fn from_extents(min: &Vector3, max: &Vector3) -> Aabb { - let size = max - min; - let half_size = size / 2.; - Aabb { - center: min + half_size, - half_size, - } + pub fn from_extents(min: Vector3, max: Vector3) -> Aabb { + debug_assert!(min <= max); + Aabb { min, max } } pub fn empty() -> Aabb { Aabb { - center: Vector3::zeros(), - half_size: Vector3::zeros(), + min: Vector3::zeros(), + max: Vector3::zeros(), } } pub fn unit() -> Aabb { Aabb { - center: Vector3::new(0., 0., 0.), - half_size: Vector3::new(0.5, 0.5, 0.5), + min: Vector3::new(0., 0., 0.), + max: Vector3::new(1., 1., 1.), } } + pub fn is_empty(&self) -> bool { + self.min == self.max + } + pub fn center(&self) -> Vector3 { - self.center + self.min + self.half_size() } pub fn half_size(&self) -> Vector3 { - self.half_size + self.size() / 2.0 } pub fn size(&self) -> Vector3 { - 2.0 * self.half_size + self.max - self.min } pub fn min(&self) -> Vector3 { - self.center - self.half_size + self.min } pub fn max(&self) -> Vector3 { - self.center + self.half_size + self.max } pub fn surface_area(&self) -> f32 { - 8. * (self.half_size.x * self.half_size.y - + self.half_size.x * self.half_size.z - + self.half_size.y * self.half_size.z) + let size = self.size(); + 2. * (size.x * size.y + size.x * size.z + size.y * size.z) } pub fn volume(&self) -> f32 { - 8. * self.half_size.x * self.half_size.y * self.half_size.z - } - - #[must_use] - pub fn translate(&self, delta: &Vector3) -> Aabb { - Aabb { - center: self.center + delta, - half_size: self.half_size, - } + let size = self.size(); + size.x * size.y * size.z } #[must_use] pub fn enlarge(&self, delta: &Vector3) -> Aabb { + let half_delta = delta / 2.0; Aabb { - center: self.center, - half_size: self.half_size + delta, + min: self.min - half_delta, + max: self.max + half_delta, } } pub fn split(&self, plane: &Aap) -> (Aabb, Aabb) { - let fst_half_axis = (plane.distance - self.min()[plane.axis]) / 2.; - let snd_half_axis = (self.max()[plane.axis] - plane.distance) / 2.; - debug_assert!( - fst_half_axis >= 0.0, - "fst_half_axis is negative {fst_half_axis}", - ); - debug_assert!( - snd_half_axis >= 0.0, - "snd_half_axis is negative {snd_half_axis}", - ); - - let mut fst_center = self.center; - let mut fst_half_size = self.half_size; - fst_center[plane.axis] = plane.distance - fst_half_axis; - fst_half_size[plane.axis] = fst_half_axis; - - let mut snd_center = self.center; - let mut snd_half_size = self.half_size; - snd_center[plane.axis] = plane.distance + snd_half_axis; - snd_half_size[plane.axis] = snd_half_axis; - - let fst = Aabb { - center: fst_center, - half_size: fst_half_size, - }; - let snd = Aabb { - center: snd_center, - half_size: snd_half_size, - }; + let mut new_max = self.max; + new_max[plane.axis] = plane.distance; + + let mut new_min = self.min; + new_min[plane.axis] = plane.distance; + + let fst = Aabb::from_extents(self.min, new_max); + let snd = Aabb::from_extents(new_min, self.max); (fst, snd) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn split_in_half_halves_the_volume() { + let aabb = Aabb::unit(); + + let actual = aabb.split(&Aap::new_x(0.5)); + + assert_eq!(aabb.volume(), 1.0); + assert_eq!(actual.0.volume(), 0.5); + assert_eq!(actual.1.volume(), 0.5); + } +} diff --git a/geometry/src/algorithms.rs b/geometry/src/algorithms.rs index e782bfeb..cc85b23f 100644 --- a/geometry/src/algorithms.rs +++ b/geometry/src/algorithms.rs @@ -340,7 +340,7 @@ mod tests_intersect_triangle_aabb { v1: Vector3::new(2., 1., 1.), v2: Vector3::new(1., 2., 1.), }; - let aabb = Aabb::from_extents(&Vector3::new(0., 0., 0.), &Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); assert_eq!(intersect_triangle_aabb(&triangle, &aabb), true); } @@ -352,7 +352,7 @@ mod tests_intersect_triangle_aabb { v1: Vector3::new(2., 1., 2.), v2: Vector3::new(1., 2., 2.), }; - let aabb = Aabb::from_extents(&Vector3::new(0., 0., 0.), &Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); assert_eq!(intersect_triangle_aabb(&triangle, &aabb), true); } @@ -364,7 +364,7 @@ mod tests_intersect_triangle_aabb { v1: Vector3::new(11., 10., 10.), v2: Vector3::new(10., 11., 10.), }; - let aabb = Aabb::from_extents(&Vector3::new(0., 0., 0.), &Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); assert_eq!(intersect_triangle_aabb(&triangle, &aabb), false); } @@ -380,7 +380,7 @@ pub fn triangles_bounding_box(triangles: &[Triangle]) -> Aabb { a = a.inf(&triangle.min()); b = b.sup(&triangle.max()); } - Aabb::from_extents(&a, &b) + Aabb::from_extents(a, b) } #[cfg(test)] @@ -404,7 +404,7 @@ mod tests { let actual = triangles_bounding_box(&triangles); - let expected = Aabb::from_extents(&Vector3::new(-1., -1., -1.), &Vector3::new(1., 1., 1.)); + let expected = Aabb::from_extents(Vector3::new(-1., -1., -1.), Vector3::new(1., 1., 1.)); assert_eq!(actual, expected); } } @@ -586,7 +586,7 @@ mod tests_clip_triangle_aabb { v1: Vector3::new(2.0, 1.0, 1.0), v2: Vector3::new(2.0, 2.0, 1.0), }; - let aabb = Aabb::from_extents(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(3.0, 3.0, 3.0)); + let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(3.0, 3.0, 3.0)); let actual = clip_triangle_aabb(&triangle, &aabb); @@ -601,7 +601,7 @@ mod tests_clip_triangle_aabb { v1: Vector3::new(1.0, 2.0, 0.0), v2: Vector3::new(1.0, 2.0, 1.0), }; - let aabb = Aabb::from_extents(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(1.0, 1.0, 1.0)); + let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); let actual = clip_triangle_aabb(&triangle, &aabb); @@ -616,7 +616,7 @@ mod tests_clip_triangle_aabb { v1: Vector3::new(1.0, -1.0, 0.0), v2: Vector3::new(1.0, -1.0, 1.0), }; - let aabb = Aabb::from_extents(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(1.0, 1.0, 1.0)); + let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); let actual = clip_triangle_aabb(&triangle, &aabb); @@ -631,7 +631,7 @@ mod tests_clip_triangle_aabb { v1: Vector3::new(12.0, 0.0, 0.0), v2: Vector3::new(6.0, 6.0, 0.0), }; - let aabb = Aabb::from_extents(&Vector3::new(2.0, -1.0, 0.0), &Vector3::new(10.0, 4.0, 0.0)); + let aabb = Aabb::from_extents(Vector3::new(2.0, -1.0, 0.0), Vector3::new(10.0, 4.0, 0.0)); let actual = clip_triangle_aabb(&triangle, &aabb); diff --git a/kdtree/src/build_sah.rs b/kdtree/src/build_sah.rs index 2a5fcce5..b5ed5929 100644 --- a/kdtree/src/build_sah.rs +++ b/kdtree/src/build_sah.rs @@ -74,12 +74,9 @@ impl KdTreeBuilder for SahKdTreeBuilder { } fn find_best_split(&self, _: u32, parent: &KdBox) -> Option { - debug_assert!(parent.boundary.volume() > 0.0); + debug_assert!(!parent.boundary.is_empty()); debug_assert!(!parent.triangle_indices.is_empty()); - let min = parent.boundary.min(); - let max = parent.boundary.max(); - let min_by_snd = |a: (_, f32), b: (_, f32)| if a.1 <= b.1 { a } else { b }; let clipped_triangles = parent @@ -95,16 +92,12 @@ impl KdTreeBuilder for SahKdTreeBuilder { splits.dedup(); splits .par_iter() - .filter_map(|s| { - if s.distance > min[s.axis] && s.distance < max[s.axis] { - let plane = Aap { - axis: s.axis, - distance: s.distance, - }; - Some(self.split_and_calculate_cost(parent, plane, &clipped_triangles)) - } else { - None - } + .map(|s| { + let plane = Aap { + axis: s.axis, + distance: s.distance, + }; + self.split_and_calculate_cost(parent, plane, &clipped_triangles) }) .reduce_with(min_by_snd) .map(|a| a.0) @@ -151,7 +144,7 @@ mod tests { empty_factor: 0.8, triangles, }; - let tree = build_kdtree(builder, 10); + let tree = build_kdtree(builder, 6); let expected = KdNode::new_node( Aap::new_x(0.0), @@ -198,7 +191,7 @@ mod tests { empty_factor: 0.8, triangles, }; - let tree = build_kdtree(builder, 10); + let tree = build_kdtree(builder, 4); let expected = KdNode::new_node( Aap::new_x(0.0), diff --git a/kdtree/src/split.rs b/kdtree/src/split.rs index 41468c74..d6fa48b5 100644 --- a/kdtree/src/split.rs +++ b/kdtree/src/split.rs @@ -87,7 +87,7 @@ mod clip_triangle_tests { v1: Vector3::new(1.0, 0.0, 0.0), v2: Vector3::new(1.0, 1.0, 0.0), }; - let aabb = Aabb::from_extents(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(2.0, 1.0, 1.0)); + let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(2.0, 1.0, 1.0)); let actual = clip_triangle(&[triangle], &aabb, 0);