use std::cmp; use std::f64; use i_bound::BoundType; use i_bound::IBound; use i_shape::ShapeType; #[derive(Debug, Clone)] pub struct AxisAlignedBBox { pub _bound_lower: [f64; 3], pub _bound_upper: [f64; 3], } #[derive(Debug, Clone)] pub enum Axis { X, Y, Z, } impl AxisAlignedBBox { pub fn init(shape_type: ShapeType, vals: &[f64]) -> AxisAlignedBBox { match shape_type { ShapeType::Ray => { assert!(vals.len() == 6); let mut bounds = [(0f64, 0f64); 3]; for i in 0..3 { let b = if vals[3 + i] > 0f64 { (vals[i], f64::INFINITY) } else if vals[3 + i] < 0f64 { (f64::NEG_INFINITY, vals[i]) } else { (vals[i], vals[i]) }; bounds[i] = b; } AxisAlignedBBox { _bound_lower: [bounds[0].0, bounds[1].0, bounds[2].0], _bound_upper: [bounds[0].1, bounds[1].1, bounds[2].1], } } ShapeType::Point => { assert!(vals.len() == 3); AxisAlignedBBox { _bound_lower: [vals[0], vals[1], vals[2]], _bound_upper: [vals[0], vals[1], vals[2]], } } ShapeType::Sphere => { assert!(vals.len() == 4); AxisAlignedBBox { _bound_lower: [vals[0] - vals[3], vals[1] - vals[3], vals[2] - vals[3]], _bound_upper: [vals[0] + vals[3], vals[1] + vals[3], vals[2] + vals[3]], } } ShapeType::Plane => { assert!(vals.len() == 6); AxisAlignedBBox { _bound_lower: [f64::NEG_INFINITY; 3], _bound_upper: [f64::INFINITY; 3], } } ShapeType::Box => { assert!(vals.len() == 4); AxisAlignedBBox { _bound_lower: [vals[0] - vals[3], vals[1] - vals[3], vals[2] - vals[3]], _bound_upper: [vals[0] + vals[3], vals[1] + vals[3], vals[2] + vals[3]], } } ShapeType::Rect => { assert!(vals.len() == 6); AxisAlignedBBox { _bound_lower: [vals[0], vals[1], vals[2]], _bound_upper: [vals[3], vals[4], vals[5]], } } ShapeType::Frustum => { unimplemented!(); } _ => { unimplemented!(); } } } pub fn get_longest_axis(&self) -> (Axis, f64) { let dx = (Axis::X, self._bound_upper[0] - self._bound_lower[0]); let dy = (Axis::Y, self._bound_upper[1] - self._bound_lower[1]); let dz = (Axis::Z, self._bound_upper[2] - self._bound_lower[2]); let longest = [dx, dy, dz] .iter() .cloned() .max_by(|x, y| { if x.1 < y.1 { cmp::Ordering::Less } else if x.1 < y.1 { cmp::Ordering::Greater } else { cmp::Ordering::Equal } }) .unwrap(); longest } } impl IBound for AxisAlignedBBox { fn get_type(&self) -> BoundType { BoundType::AxisAlignBox } fn intersect(&self, other: &dyn IBound) -> bool { match other.get_type() { BoundType::AxisAlignBox => { let a_bounds = self.get_bound_data(); let b_bounds = other.get_bound_data(); let a_lower = &a_bounds[0..3]; let a_upper = &a_bounds[3..6]; let b_lower = &b_bounds[0..3]; let b_upper = &b_bounds[3..6]; for i in 0..3 { if a_lower[i] > b_upper[i] || a_upper[i] < b_lower[i] { return false; } } return true; } _ => { unimplemented!(); } } } fn get_shortest_separation(&self, _other: &dyn IBound) -> f64 { unimplemented!(); } fn get_bound_data(&self) -> [f64; 32] { let mut arr = [0f64; 32]; for i in 0..3 { arr[i] = self._bound_lower[i]; } for i in 0..3 { arr[i + 3] = self._bound_upper[i]; } arr } fn get_union(&mut self, bounds: &[&dyn IBound]) { self._bound_lower = [f64::INFINITY; 3]; self._bound_upper = [f64::NEG_INFINITY; 3]; for i in bounds { match i.get_type() { BoundType::AxisAlignBox => (), _ => { unimplemented!(); } } let b = i.get_bound_data(); let b_lower = &b[0..3]; let b_upper = &b[3..6]; for j in 0..3 { self._bound_lower[j] = self._bound_lower[j].min(b_lower[j]); self._bound_upper[j] = self._bound_upper[j].max(b_upper[j]); } } } fn get_centroid(&self) -> [f64; 3] { match self.get_type() { BoundType::AxisAlignBox => { let b = self.get_bound_data(); let b_lower = &b[0..3]; let b_upper = &b[3..6]; return [ (b_lower[0] + b_upper[0]) / 2f64, (b_lower[1] + b_upper[1]) / 2f64, (b_lower[2] + b_upper[2]) / 2f64, ]; } _ => { unimplemented!(); } } } } impl Default for AxisAlignedBBox { fn default() -> AxisAlignedBBox { AxisAlignedBBox { _bound_lower: [f64::NEG_INFINITY; 3], _bound_upper: [f64::INFINITY; 3], } } }