use Plane;
use cgmath::Matrix4;
use cgmath::BaseFloat;
use cgmath::{EuclideanSpace, Point3};
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
#[repr(u8)]
pub enum Relation {
In,
Cross,
Out,
}
pub trait Bound<S: BaseFloat + 'static>: Sized + Copy {
fn relate_plane(self, Plane<S>) -> Relation;
fn relate_clip_space(self, projection: Matrix4<S>) -> Relation {
use frustum::Frustum;
match Frustum::from_matrix4(projection) {
Some(f) => f.contains(self),
None => Relation::Cross,
}
}
}
impl<S: BaseFloat + 'static> Bound<S> for Point3<S> {
fn relate_plane(self, plane: Plane<S>) -> Relation {
let dist = self.dot(plane.n);
if dist > plane.d {
Relation::In
} else if dist < plane.d {
Relation::Out
} else {
Relation::Cross
}
}
fn relate_clip_space(self, projection: Matrix4<S>) -> Relation {
use std::cmp::Ordering::*;
let p = projection * self.to_homogeneous();
match (p.x.abs().partial_cmp(&p.w),
p.y.abs().partial_cmp(&p.w),
p.z.abs().partial_cmp(&p.w)) {
(Some(Less), Some(Less), Some(Less)) => Relation::In,
(Some(Greater), _, _) |
(_, Some(Greater), _) |
(_, _, Some(Greater)) => Relation::Out,
_ => Relation::Cross,
}
}
}