use std::fmt;
use cgmath::{EuclideanSpace, Point2, Point3};
use cgmath::{VectorSpace, Array, Vector2, Vector3};
use cgmath::{BaseNum, BaseFloat, ElementWise};
use {Ray2, Ray3, Plane};
use bound::{Bound, Relation};
use intersect::Intersect;
pub trait MinMax {
fn min(a: Self, b: Self) -> Self;
fn max(a: Self, b: Self) -> Self;
}
impl<S> MinMax for Point2<S>
where S: BaseNum
{
fn min(a: Point2<S>, b: Point2<S>) -> Point2<S> {
Point2::new(
a.x.partial_min(b.x),
a.y.partial_min(b.y)
)
}
fn max(a: Point2<S>, b: Point2<S>) -> Point2<S> {
Point2::new(
a.x.partial_max(b.x),
a.y.partial_max(b.y)
)
}
}
impl<S> MinMax for Point3<S>
where S: BaseNum
{
fn min(a: Point3<S>, b: Point3<S>) -> Point3<S> {
Point3::new(
a.x.partial_min(b.x),
a.y.partial_min(b.y),
a.z.partial_min(b.z)
)
}
fn max(a: Point3<S>, b: Point3<S>) -> Point3<S> {
Point3::new(
a.x.partial_max(b.x),
a.y.partial_max(b.y),
a.z.partial_max(b.z)
)
}
}
pub trait Aabb<S: BaseNum, V: VectorSpace<Scalar=S> + ElementWise + Array<Element=S>, P: EuclideanSpace<Scalar=S, Diff=V>>: Sized {
fn new(p1: P, p2: P) -> Self;
fn min(&self) -> P;
fn max(&self) -> P;
#[inline]
fn dim(&self) -> V { self.max() - self.min() }
#[inline]
fn volume(&self) -> S { self.dim().product() }
#[inline]
fn center(&self) -> P {
let two = S::one() + S::one();
self.min() + self.dim() / two
}
#[inline]
fn contains(&self, p: P) -> bool;
fn grow(&self, p: P) -> Self
where P: MinMax
{
Aabb::new(
MinMax::min(self.min(), p),
MinMax::max(self.max(), p)
)
}
fn add_v(&self, v: V) -> Self {
Aabb::new(self.min() + v, self.max() + v)
}
fn mul_s(&self, s: S) -> Self {
Aabb::new(self.min() * s, self.max() * s)
}
fn mul_v(&self, v: V) -> Self {
let min = P::from_vec(self.min().to_vec().mul_element_wise(v));
let max = P::from_vec(self.max().to_vec().mul_element_wise(v));
Aabb::new(min, max)
}
}
#[derive(Copy, Clone, PartialEq)]
pub struct Aabb2<S> {
pub min: Point2<S>,
pub max: Point2<S>,
}
impl<S: BaseNum> Aabb2<S> {
#[inline]
pub fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> {
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)),
}
}
#[inline]
pub fn to_corners(&self) -> [Point2<S>; 4] {
[self.min,
Point2::new(self.max.x, self.min.y),
Point2::new(self.min.x, self.max.y),
self.max]
}
}
impl<S: BaseNum> Aabb<S, Vector2<S>, Point2<S>> for Aabb2<S> {
#[inline]
fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> { Aabb2::new(p1, p2) }
#[inline]
fn min(&self) -> Point2<S> { self.min }
#[inline]
fn max(&self) -> Point2<S> { self.max }
#[inline]
fn contains(&self, p: Point2<S>) -> bool {
let v_min = p - self.min();
let v_max = self.max() - p;
v_min.x >= S::zero() && v_min.y >= S::zero() &&
v_max.x > S::zero() && v_max.y > S::zero()
}
}
impl<S: BaseNum> fmt::Debug for Aabb2<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{:?} - {:?}]", self.min, self.max)
}
}
#[derive(Copy, Clone, PartialEq)]
pub struct Aabb3<S> {
pub min: Point3<S>,
pub max: Point3<S>,
}
impl<S: BaseNum> Aabb3<S> {
#[inline]
pub fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> {
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)),
}
}
#[inline]
pub fn to_corners(&self) -> [Point3<S>; 8] {
[self.min,
Point3::new(self.max.x, self.min.y, self.min.z),
Point3::new(self.min.x, self.max.y, self.min.z),
Point3::new(self.max.x, self.max.y, self.min.z),
Point3::new(self.min.x, self.min.y, self.max.z),
Point3::new(self.max.x, self.min.y, self.max.z),
Point3::new(self.min.x, self.max.y, self.max.z),
self.max]
}
}
impl<S: BaseNum> Aabb<S, Vector3<S>, Point3<S>> for Aabb3<S> {
#[inline]
fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> { Aabb3::new(p1, p2) }
#[inline]
fn min(&self) -> Point3<S> { self.min }
#[inline]
fn max(&self) -> Point3<S> { self.max }
#[inline]
fn contains(&self, p: Point3<S>) -> bool {
let v_min = p - self.min();
let v_max = self.max() - p;
v_min.x >= S::zero() && v_min.y >= S::zero() && v_min.z >= S::zero() &&
v_max.x > S::zero() && v_max.y > S::zero() && v_max.z > S::zero()
}
}
impl<S: BaseNum> fmt::Debug for Aabb3<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{:?} - {:?}]", self.min, self.max)
}
}
impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Aabb2<S>) {
fn intersection(&self) -> Option<Point2<S>> {
let (ref ray, ref aabb) = *self;
let mut tmin = S::neg_infinity();
let mut tmax = S::infinity();
if ray.direction.x != S::zero() {
let tx1 = (aabb.min.x - ray.origin.x) / ray.direction.x;
let tx2 = (aabb.max.x - ray.origin.x) / ray.direction.x;
tmin = tmin.max(tx1.min(tx2));
tmax = tmax.min(tx1.max(tx2));
}
if ray.direction.y != S::zero() {
let ty1 = (aabb.min.y - ray.origin.y) / ray.direction.y;
let ty2 = (aabb.max.y - ray.origin.y) / ray.direction.y;
tmin = tmin.max(ty1.min(ty2));
tmax = tmax.min(ty1.max(ty2));
}
if tmin < S::zero() && tmax < S::zero() {
None
}
else if tmax >= tmin {
if tmin >= S::zero() {
Some(Point2::new(ray.origin.x + ray.direction.x * tmin,
ray.origin.y + ray.direction.y * tmin))
}
else {
Some(Point2::new(ray.origin.x + ray.direction.x * tmax,
ray.origin.y + ray.direction.y * tmax))
}
}
else {
None
}
}
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Ray3<S>, Aabb3<S>) {
fn intersection(&self) -> Option<Point3<S>> {
let (ref ray, ref aabb) = *self;
let mut tmin = S::neg_infinity();
let mut tmax = S::infinity();
if ray.direction.x != S::zero() {
let tx1 = (aabb.min.x - ray.origin.x) / ray.direction.x;
let tx2 = (aabb.max.x - ray.origin.x) / ray.direction.x;
tmin = tmin.max(tx1.min(tx2));
tmax = tmax.min(tx1.max(tx2));
}
if ray.direction.y != S::zero() {
let ty1 = (aabb.min.y - ray.origin.y) / ray.direction.y;
let ty2 = (aabb.max.y - ray.origin.y) / ray.direction.y;
tmin = tmin.max(ty1.min(ty2));
tmax = tmax.min(ty1.max(ty2));
}
if ray.direction.z != S::zero() {
let tz1 = (aabb.min.z - ray.origin.z) / ray.direction.z;
let tz2 = (aabb.max.z - ray.origin.z) / ray.direction.z;
tmin = tmin.max(tz1.min(tz2));
tmax = tmax.min(tz1.max(tz2));
}
if tmin < S::zero() && tmax < S::zero() {
None
}
else if tmax >= tmin {
if tmin >= S::zero() {
Some(Point3::new(ray.origin.x + ray.direction.x * tmin,
ray.origin.y + ray.direction.y * tmin,
ray.origin.z + ray.direction.z * tmin))
}
else {
Some(Point3::new(ray.origin.x + ray.direction.x * tmax,
ray.origin.y + ray.direction.y * tmax,
ray.origin.z + ray.direction.z * tmax))
}
}
else {
None
}
}
}
impl<S: BaseFloat + 'static> Bound<S> for Aabb3<S> {
fn relate_plane(self, plane: Plane<S>) -> Relation {
let corners = self.to_corners();
let first = corners[0].relate_plane(plane);
for p in corners[1..].iter() {
if p.relate_plane(plane) != first {
return Relation::Cross;
}
}
first
}
}