// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, // refer to the AUTHORS file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Axis-aligned bounding boxes //! //! An AABB is a geometric object which encompasses a set of points and is not //! rotated. It is either a rectangle or a rectangular prism (depending on the //! dimension) where the slope of every line is either 0 or undefined. These //! are useful for very cheap collision detection. use point::{Point, Point2, Point3}; use vector::{Vector, Vector2, Vector3}; use num::BaseNum; use std::fmt; use std::num::{zero, one}; pub trait Aabb, P: Point> { /// Create a new AABB using two points as opposing corners. fn new(p1: P, p2: P) -> Self; /// Return a shared reference to the point nearest to (-inf, -inf). fn min<'a>(&'a self) -> &'a P; /// Return a shared reference to the point nearest to (inf, inf). fn max<'a>(&'a self) -> &'a P; /// Return the dimensions of this AABB. #[inline] fn dim(&self) -> V { self.max().sub_p(self.min()) } /// Return the volume this AABB encloses. #[inline] fn volume(&self) -> S { self.dim().comp_mul() } /// Return the center point of this AABB. #[inline] fn center(&self) -> P { let two = one::() + one::(); self.min().add_v(&self.dim().div_s(two)) } /// Tests whether a point is cointained in the box, inclusive for min corner /// and exclusive for the max corner. #[inline] fn contains(&self, p: &P) -> bool; /// Returns a new AABB that is grown to include the given point. fn grow(&self, p: &P) -> Self { let min = self.min().min(p); let max = self.max().max(p); Aabb::new(min, max) } /// Add a vector to every point in the AABB, returning a new AABB. fn add_v(&self, v: &V) -> Self { Aabb::new(self.min().add_v(v), self.max().add_v(v)) } /// Multiply every point in the AABB by a scalar, returning a new AABB. fn mul_s(&self, s: S) -> Self { Aabb::new(self.min().mul_s(s.clone()), self.max().mul_s(s.clone())) } /// Multiply every point in the AABB by a vector, returning a new AABB. fn mul_v(&self, v: &V) -> Self { let min : P = Point::from_vec(&self.min().to_vec().mul_v(v)); let max : P = Point::from_vec(&self.max().to_vec().mul_v(v)); Aabb::new(min, max) } } /// A two-dimensional AABB, aka a rectangle. #[deriving(Clone, PartialEq)] pub struct Aabb2 { pub min: Point2, pub max: Point2, } impl Aabb2 { /// Construct a new axis-aligned bounding box from two points. #[inline] pub fn new(p1: Point2, p2: Point2) -> Aabb2 { Aabb2 { min: Point2::new(p1.x.partial_min(p2.x), p1.y.partial_min(p2.y)), max: Point2::new(p1.x.partial_max(p2.x), p1.y.partial_max(p2.y)), } } } impl Aabb, Point2> for Aabb2 { #[inline] fn new(p1: Point2, p2: Point2) -> Aabb2 { Aabb2::new(p1, p2) } #[inline] fn min<'a>(&'a self) -> &'a Point2 { &self.min } #[inline] fn max<'a>(&'a self) -> &'a Point2 { &self.max } #[inline] fn contains(&self, p: &Point2) -> bool { let v_min = p.sub_p(self.min()); let v_max = self.max().sub_p(p); v_min.x >= zero() && v_min.y >= zero() && v_max.x > zero() && v_max.y > zero() } } impl fmt::Show for Aabb2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{} - {}]", self.min, self.max) } } /// A three-dimensional AABB, aka a rectangular prism. #[deriving(Clone, PartialEq)] pub struct Aabb3 { pub min: Point3, pub max: Point3, } impl Aabb3 { /// Construct a new axis-aligned bounding box from two points. #[inline] pub fn new(p1: Point3, p2: Point3) -> Aabb3 { Aabb3 { min: Point3::new(p1.x.partial_min(p2.x), p1.y.partial_min(p2.y), p1.z.partial_min(p2.z)), max: Point3::new(p1.x.partial_max(p2.x), p1.y.partial_max(p2.y), p1.z.partial_max(p2.z)), } } } impl Aabb, Point3> for Aabb3 { #[inline] fn new(p1: Point3, p2: Point3) -> Aabb3 { Aabb3::new(p1, p2) } #[inline] fn min<'a>(&'a self) -> &'a Point3 { &self.min } #[inline] fn max<'a>(&'a self) -> &'a Point3 { &self.max } #[inline] fn contains(&self, p: &Point3) -> bool { let v_min = p.sub_p(self.min()); let v_max = self.max().sub_p(p); v_min.x >= zero() && v_min.y >= zero() && v_min.z >= zero() && v_max.x > zero() && v_max.y > zero() && v_max.z > zero() } } impl fmt::Show for Aabb3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{} - {}]", self.min, self.max) } }