//! Module containing the bounding box struct. use math::Number; macro_rules! make_bounding_box { ($name: ident, $vector: ident, $size: expr) => { use math::vector::$vector; /// Represents a bounding box. #[derive(Clone)] pub struct $name { min: $vector, max: $vector, } impl $name { /// Creates a bounding box from its min and max coordinates. pub fn new(min: $vector, max: $vector) -> $name { $name { min: min, max: max, } } /// Enlarges the bounding box so it contains the point passed as parameter. pub fn add_point(&mut self, point: &$vector) { for i in 0..$size { if point[i] < self.min[i] { self.min[i] = point[i]; } if point[i] > self.max[i] { self.max[i] = point[i]; } } } /// Returns the minimum value of the bounding box. pub fn min(&self) -> $vector { self.min } /// Returns the maximum value of the bounding box. pub fn max(&self) -> $vector { self.max } /// Returns a mut ref to the min. pub fn min_mut(&mut self) -> &mut $vector { &mut self.min } /// Returns a mut ref to the max. pub fn max_mut(&mut self) -> &mut $vector { &mut self.max } } impl $name { /// Scales a bounding box from its center. pub fn scale(&mut self, factor: T) { let diag = self.max - self.min; self.min -= diag * factor; self.max += diag * factor; } /// Returns the intersection between two bounding boxes. pub fn intersection(&self, other: &$name) -> $name { let mut ret = self.clone(); for i in 0..$size { if ret.min()[i] < other.min()[i] { ret.min_mut()[i] = other.min()[i]; } if ret.max()[i] > other.max()[i] { ret.max_mut()[i] = other.max()[i]; } } ret } } } } make_bounding_box!(BoundingBox2, Vector2, 2); make_bounding_box!(BoundingBox3, Vector3, 3); make_bounding_box!(BoundingBox4, Vector4, 4); #[cfg(test)] mod tests { macro_rules! assert_delta { ($x:expr, $y:expr, $d:expr) => { if !($x - $y < $d || $y - $x < $d) { panic!(); } } } use math::vector::Vector2; use math::bounding_box::BoundingBox2; use math::vector::Vector3; use math::bounding_box::BoundingBox3; #[test] fn initialization() { use std::f64::{MIN, MAX}; let mut bounding_box = BoundingBox2::new( Vector2::new(MAX, MAX), Vector2::new(MIN, MIN), ); let v1 = Vector2::new(10.0, 20.0); bounding_box.add_point(&v1); assert_delta!(bounding_box.min().x(), v1.x(), 0.01); assert_delta!(bounding_box.min().y(), v1.y(), 0.01); assert_delta!(bounding_box.max().x(), v1.x(), 0.01); assert_delta!(bounding_box.max().y(), v1.y(), 0.01); let v2 = Vector2::new(20.0, 10.0); assert_delta!(bounding_box.min().x(), v1.x(), 0.01); assert_delta!(bounding_box.min().y(), v2.y(), 0.01); assert_delta!(bounding_box.max().x(), v1.x(), 0.01); assert_delta!(bounding_box.max().y(), v2.y(), 0.01); } #[test] fn intersection() { let b1 = BoundingBox3::new( Vector3::new(0, 0, 0), Vector3::new(2, 2, 2), ); let b2 = BoundingBox3::new( Vector3::new(1, 1, 1), Vector3::new(3, 3, 3), ); let b = b1.intersection(&b2); assert_eq!(b.min().x(), 1); assert_eq!(b.min().y(), 1); assert_eq!(b.min().z(), 1); assert_eq!(b.max().x(), 2); assert_eq!(b.max().y(), 2); assert_eq!(b.max().z(), 2); } }