use std::fmt;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct BoundingBox {
pub x0: usize,
pub y0: usize,
pub z0: usize,
pub x1: usize,
pub y1: usize,
pub z1: usize,
}
#[derive(Debug, Fail)]
#[fail(display = "expansion outside domain: {} expanded by {}", bbox, distance)]
pub struct ExpansionOutsideDomainError {
bbox: BoundingBox,
distance: usize,
}
impl fmt::Display for BoundingBox {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Box: ({}, {}, {}) - ({}, {}, {})",
self.x0, self.y0, self.z0, self.x1, self.y1, self.z1
)
}
}
impl BoundingBox {
pub fn new(x0: usize, y0: usize, z0: usize, x1: usize, y1: usize, z1: usize) -> BoundingBox {
BoundingBox {
x0,
y0,
z0,
x1,
y1,
z1,
}
}
pub fn intersects(&self, rhs: &BoundingBox) -> bool {
!(self.x0 > rhs.x1
|| rhs.x0 > self.x1
|| self.y0 > rhs.y1
|| rhs.y0 > self.y1
|| self.z0 > rhs.z1
|| rhs.z0 > self.z1)
}
pub fn inside(&self, rhs: &BoundingBox) -> bool {
self.x0 >= rhs.x0
&& self.y0 >= rhs.y0
&& self.z0 >= rhs.z0
&& self.x1 < rhs.x1
&& self.y1 < rhs.y1
&& self.z1 < rhs.z1
}
pub fn expanded(&self, distance: usize) -> Result<BoundingBox, ExpansionOutsideDomainError> {
if distance > self.x0 || distance > self.y0 || distance > self.z0 {
Err(ExpansionOutsideDomainError {
bbox: *self,
distance,
})
} else {
Ok(BoundingBox::new(
self.x0 - distance,
self.y0 - distance,
self.z0 - distance,
self.x1 + distance,
self.y1 + distance,
self.z1 + distance,
))
}
}
}
#[cfg(test)]
mod tests {
use world::boundingbox::BoundingBox;
#[test]
fn test_inside() {
let outer = BoundingBox::new(0, 0, 0, 10, 10, 10);
let inner = BoundingBox::new(0, 0, 0, 9, 9, 9);
assert!(inner.inside(&outer));
assert!(!outer.inside(&inner));
}
#[test]
fn test_inside_not() {
let outer = BoundingBox::new(0, 0, 0, 10, 10, 10);
let inner = BoundingBox::new(0, 0, 0, 10, 10, 10);
assert!(!inner.inside(&outer));
assert!(!outer.inside(&inner));
}
#[test]
fn test_intersects() {
let first = BoundingBox::new(0, 0, 0, 4, 4, 4);
let second = BoundingBox::new(2, 2, 2, 5, 5, 5);
assert!(first.intersects(&second));
assert!(second.intersects(&first));
}
#[test]
fn test_intersects_not() {
let first = BoundingBox::new(0, 0, 0, 4, 4, 4);
let second = BoundingBox::new(5, 0, 0, 6, 3, 3);
assert!(!first.intersects(&second));
assert!(!second.intersects(&first));
}
#[test]
fn test_expanded() {
let first = BoundingBox::new(3, 3, 3, 4, 4, 4);
let expected = BoundingBox::new(0, 0, 0, 7, 7, 7);
assert_eq!(first.expanded(3).unwrap(), expected);
assert!(first.expanded(4).is_err());
}
}