From 4b7e8f7fab2c3a69a697ed104bfc54d431887f48 Mon Sep 17 00:00:00 2001 From: Robert Sheehy Date: Tue, 8 Apr 2025 08:01:28 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AAUnittests=20for=20Aabb=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/geometry/aabb.rs | 127 ++++++++++++++++++++++++++++++++++++++++--- src/geometry/axis.rs | 33 ++++++++++- 2 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/geometry/aabb.rs b/src/geometry/aabb.rs index 9d21048..4ab2b03 100644 --- a/src/geometry/aabb.rs +++ b/src/geometry/aabb.rs @@ -75,10 +75,7 @@ impl Aabb { let t0 = (axis_interval.min - ray_origin[axis_index]) * adinv; let t1 = (axis_interval.max - ray_origin[axis_index]) * adinv; - let (t0, t1) = match t0 < t1 { - true => (t0, t1), - false => (t1, t0), - }; + let (t0, t1) = if t0 < t1 { (t0, t1) } else { (t1, t0) }; t_min = t_min.max(t0); t_max = t_max.min(t1); @@ -105,9 +102,9 @@ impl Aabb { pub fn vertices(&self) -> impl Iterator> { iproduct!( - [self.x.max, self.x.min].into_iter(), - [self.y.max, self.y.min].into_iter(), - [self.z.max, self.z.min].into_iter() + [self.x.max, self.x.min], + [self.y.max, self.y.min], + [self.z.max, self.z.min] ) .map(|(x, y, z)| Vector3::new(x, y, z)) } @@ -119,3 +116,119 @@ impl Add> for Aabb { Aabb::new(self.x + offset.x, self.y + offset.y, self.z + offset.z) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_aabb_new() { + let x = Interval::new(0.0, 1.0); + let y = Interval::new(0.0, 1.0); + let z = Interval::new(0.0, 1.0); + let aabb = Aabb::new(x, y, z); + + assert_eq!(aabb.x.min, 0.0); + assert_eq!(aabb.x.max, 1.0); + assert_eq!(aabb.y.min, 0.0); + assert_eq!(aabb.y.max, 1.0); + assert_eq!(aabb.z.min, 0.0); + assert_eq!(aabb.z.max, 1.0); + } + + #[test] + fn test_aabb_from_points() { + let a = Vector3::new(1.0, 2.0, 3.0); + let b = Vector3::new(4.0, 5.0, 6.0); + let aabb = Aabb::from_points(a, b); + + assert_eq!(aabb.x.min, 1.0); + assert_eq!(aabb.x.max, 4.0); + assert_eq!(aabb.y.min, 2.0); + assert_eq!(aabb.y.max, 5.0); + assert_eq!(aabb.z.min, 3.0); + assert_eq!(aabb.z.max, 6.0); + } + + #[test] + fn test_aabb_from_boxes() { + let a = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let b = Aabb::from_points(Vector3::new(1.0, 1.0, 1.0), Vector3::new(2.0, 5.0, 2.0)); + let combined = Aabb::from_boxes(&a, &b); + + assert_eq!(combined.x.min, 0.0); + assert_eq!(combined.x.max, 2.0); + assert_eq!(combined.y.min, 0.0); + assert_eq!(combined.y.max, 5.0); + assert_eq!(combined.z.min, 0.0); + assert_eq!(combined.z.max, 2.0); + } + + #[test] + fn test_aabb_longest_axis() { + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 2.0, 3.0)); + assert_eq!(aabb.longest_axis(), Axis::Z); + + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(5.0, 2.0, 3.0)); + assert_eq!(aabb.longest_axis(), Axis::X); + + let aabb = Aabb::from_points(Vector3::new(0.0, 10.0, 0.0), Vector3::new(5.0, 2.0, 3.0)); + assert_eq!(aabb.longest_axis(), Axis::Y); + } + + #[test] + fn test_aabb_hit() { + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let ray = Ray::new( + Vector3::new(-1.0, 0.5, 0.5), + Vector3::new(1.0, 0.0, 0.0), + 1.0, + ); + let interval = Interval::new(0.0, 10.0); + + assert!(aabb.hit(&ray, &interval)); + } + + #[test] + fn test_aabb_no_hit() { + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let ray = Ray::new( + Vector3::new(-1.0, 2.0, 2.0), + Vector3::new(1.0, 0.0, 0.0), + 1.0, + ); + let interval = Interval::new(0.0, 10.0); + + assert!(!aabb.hit(&ray, &interval)); + } + + #[test] + fn test_aabb_vertices() { + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let vertices: Vec<_> = aabb.vertices().collect(); + + assert_eq!(vertices.len(), 8); + assert!(vertices.contains(&Vector3::new(0.0, 0.0, 0.0))); + assert!(vertices.contains(&Vector3::new(1.0, 0.0, 0.0))); + assert!(vertices.contains(&Vector3::new(0.0, 1.0, 0.0))); + assert!(vertices.contains(&Vector3::new(1.0, 1.0, 0.0))); + assert!(vertices.contains(&Vector3::new(0.0, 0.0, 1.0))); + assert!(vertices.contains(&Vector3::new(1.0, 0.0, 1.0))); + assert!(vertices.contains(&Vector3::new(0.0, 1.0, 1.0))); + assert!(vertices.contains(&Vector3::new(1.0, 1.0, 1.0))); + } + + #[test] + fn test_aabb_add_vector() { + let aabb = Aabb::from_points(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let offset = Vector3::new(1.0, 2.0, 3.0); + let translated = aabb + offset; + + assert_eq!(translated.x.min, 1.0); + assert_eq!(translated.x.max, 2.0); + assert_eq!(translated.y.min, 2.0); + assert_eq!(translated.y.max, 3.0); + assert_eq!(translated.z.min, 3.0); + assert_eq!(translated.z.max, 4.0); + } +} diff --git a/src/geometry/axis.rs b/src/geometry/axis.rs index 9ed5940..c2cec85 100644 --- a/src/geometry/axis.rs +++ b/src/geometry/axis.rs @@ -1,7 +1,7 @@ use crate::geometry::aabb::Aabb; use serde::Deserialize; -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, PartialEq)] pub enum Axis { #[serde(rename = "x")] X = 0, @@ -24,3 +24,34 @@ impl Axis { } } } +#[cfg(test)] +mod tests { + use super::*; + use nalgebra::Vector3; + + #[test] + fn test_axis_as_index() { + assert_eq!(Axis::X.as_index(), 0); + assert_eq!(Axis::Y.as_index(), 1); + assert_eq!(Axis::Z.as_index(), 2); + } + + #[test] + fn test_axis_compare_bboxes() { + let a = Aabb::from_points(Vector3::new(1.0, 2.0, 3.0), Vector3::new(2.0, 3.0, 4.0)); + let b = Aabb::from_points(Vector3::new(0.0, -2.0, 10.0), Vector3::new(2.0, 5.0, 11.0)); + + assert_eq!( + Axis::X.compare_bboxes(&a, &b), + Some(std::cmp::Ordering::Greater) + ); + assert_eq!( + Axis::Y.compare_bboxes(&a, &b), + Some(std::cmp::Ordering::Greater) + ); + assert_eq!( + Axis::Z.compare_bboxes(&a, &b), + Some(std::cmp::Ordering::Less) + ); + } +}