Utility methods for AA boxes

This commit is contained in:
Risto Saarelma 2014-01-31 20:02:42 +02:00
parent 304151d2f7
commit 6ac1f09750
2 changed files with 89 additions and 16 deletions

View file

@ -15,12 +15,48 @@
//! Axis-aligned bounding boxes //! Axis-aligned bounding boxes
use point::{Point2, Point3}; use point::{Point, Point2, Point3};
use vector::{Vector, Vec2, Vec3};
use array::build;
use std::num::{zero, one};
use std::iter::Iterator;
pub trait Aabb
<
S: Primitive,
V: Vector<S, Slice>,
P: Point<S, V, Slice>,
Slice
> {
fn new(p1: &P, p2: &P) -> Self;
fn min<'a>(&'a self) -> &'a P;
fn max<'a>(&'a self) -> &'a P;
#[inline] fn dim(&self) -> V { self.max().sub_p(self.min()) }
#[inline] fn volume(&self) -> S { self.dim().comp_mul() }
#[inline] fn center(&self) -> P {
let two = one::<S>() + one::<S>();
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 {
p.sub_p(self.min()).iter().all(|x| *x >= zero::<S>()) &&
self.max().sub_p(p).iter().all(|x| *x > zero::<S>())
}
// Returns a new AABB that is grown to include the given point.
fn grow(&self, p: &P) -> Self {
let mn : P = build(|i| self.min().i(i).min(p.i(i)));
let mx : P = build(|i| self.max().i(i).max(p.i(i)));
Aabb::new(&mn, &mx)
}
}
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
pub struct Aabb2<S> { pub struct Aabb2<S> {
min: Point2<S>, mn: Point2<S>,
max: Point2<S>, mx: Point2<S>,
} }
impl<S: Num + Orderable> Aabb2<S> { impl<S: Num + Orderable> Aabb2<S> {
@ -28,16 +64,22 @@ impl<S: Num + Orderable> Aabb2<S> {
#[inline] #[inline]
pub fn new(p1: &Point2<S>, p2: &Point2<S>) -> Aabb2<S> { pub fn new(p1: &Point2<S>, p2: &Point2<S>) -> Aabb2<S> {
Aabb2 { Aabb2 {
min: Point2::new(p1.x.min(&p2.x), p1.y.min(&p2.y)), mn: Point2::new(p1.x.min(&p2.x), p1.y.min(&p2.y)),
max: Point2::new(p1.x.max(&p2.x), p1.y.max(&p2.y)), mx: Point2::new(p1.x.max(&p2.x), p1.y.max(&p2.y)),
} }
} }
} }
impl<S: Primitive> Aabb<S, Vec2<S>, Point2<S>, [S, ..2]> for Aabb2<S> {
fn new(p1: &Point2<S>, p2: &Point2<S>) -> Aabb2<S> { Aabb2::new(p1, p2) }
#[inline] fn min<'a>(&'a self) -> &'a Point2<S> { &self.mn }
#[inline] fn max<'a>(&'a self) -> &'a Point2<S> { &self.mx }
}
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
pub struct Aabb3<S> { pub struct Aabb3<S> {
min: Point3<S>, mn: Point3<S>,
max: Point3<S>, mx: Point3<S>,
} }
impl<S: Num + Orderable> Aabb3<S> { impl<S: Num + Orderable> Aabb3<S> {
@ -45,8 +87,14 @@ impl<S: Num + Orderable> Aabb3<S> {
#[inline] #[inline]
pub fn new(p1: &Point3<S>, p2: &Point3<S>) -> Aabb3<S> { pub fn new(p1: &Point3<S>, p2: &Point3<S>) -> Aabb3<S> {
Aabb3 { Aabb3 {
min: Point3::new(p1.x.min(&p2.x), p1.y.min(&p2.y), p1.z.min(&p2.z)), mn: Point3::new(p1.x.min(&p2.x), p1.y.min(&p2.y), p1.z.min(&p2.z)),
max: Point3::new(p1.x.max(&p2.x), p1.y.max(&p2.y), p1.z.max(&p2.z)), mx: Point3::new(p1.x.max(&p2.x), p1.y.max(&p2.y), p1.z.max(&p2.z)),
} }
} }
} }
impl<S: Primitive> Aabb<S, Vec3<S>, Point3<S>, [S, ..3]> for Aabb3<S> {
fn new(p1: &Point3<S>, p2: &Point3<S>) -> Aabb3<S> { Aabb3::new(p1, p2) }
#[inline] fn min<'a>(&'a self) -> &'a Point3<S> { &self.mn }
#[inline] fn max<'a>(&'a self) -> &'a Point3<S> { &self.mx }
}

View file

@ -1,13 +1,38 @@
use cgmath::aabb::{Aabb2, Aabb3}; use cgmath::aabb::*;
use cgmath::point::{Point2, Point3}; use cgmath::point::{Point2, Point3};
use cgmath::vector::{Vec2, Vec3};
#[test] #[test]
fn test_aabb() { fn test_aabb() {
let aabb = Aabb2::new(&Point2::new(-20f64, 30f64), &Point2::new(10f64, -10f64)); let aabb = Aabb2::new(&Point2::new(-20, 30), &Point2::new(10, -10));
assert_eq!(aabb.min, Point2::new(-20f64, -10f64)); assert_eq!(aabb.min(), &Point2::new(-20, -10));
assert_eq!(aabb.max, Point2::new(10f64, 30f64)); assert_eq!(aabb.max(), &Point2::new(10, 30));
assert_eq!(aabb.dim(), Vec2::new(30, 40));
assert_eq!(aabb.volume(), 30 * 40);
assert_eq!(aabb.center(), Point2::new(-5, 10));
let aabb = Aabb3::new(&Point3::new(-20f64, 30f64, 0f64), &Point3::new(10f64, -10f64, -5f64)); assert!(aabb.contains(&Point2::new(0, 0)));
assert_eq!(aabb.min, Point3::new(-20f64, -10f64, -5f64)); assert!(!aabb.contains(&Point2::new(-50, -50)));
assert_eq!(aabb.max, Point3::new(10f64, 30f64, 0f64)); assert!(!aabb.contains(&Point2::new(50, 50)));
assert_eq!(aabb.grow(&Point2::new(0, 0)), aabb);
assert_eq!(aabb.grow(&Point2::new(100, 100)),
Aabb2::new(&Point2::new(-20, -10), &Point2::new(100, 100)));
assert_eq!(aabb.grow(&Point2::new(-100, -100)),
Aabb2::new(&Point2::new(-100, -100), &Point2::new(10, 30)));
let aabb = Aabb3::new(&Point3::new(-20, 30, 5), &Point3::new(10, -10, -5));
assert_eq!(aabb.min(), &Point3::new(-20, -10, -5));
assert_eq!(aabb.max(), &Point3::new(10, 30, 5));
assert_eq!(aabb.dim(), Vec3::new(30, 40, 10));
assert_eq!(aabb.volume(), 30 * 40 * 10);
assert_eq!(aabb.center(), Point3::new(-5, 10, 0));
assert!(aabb.contains(&Point3::new(0, 0, 0)));
assert!(!aabb.contains(&Point3::new(-100, 0, 0)));
assert!(!aabb.contains(&Point3::new(100, 0, 0)));
assert!(aabb.contains(&Point3::new(9, 29, -1)));
assert!(!aabb.contains(&Point3::new(10, 30, 5)));
assert!(aabb.contains(&Point3::new(-20, -10, -5)));
assert!(!aabb.contains(&Point3::new(-21, -11, -6)));
} }