use std::fmt;
use rust_num::{one, Zero, zero};
use approx::ApproxEq;
use intersect::Intersect;
use num::{BaseFloat};
use point::{Point, Point3};
use ray::Ray3;
use vector::{Vector3, Vector4};
use vector::{Vector, EuclideanVector};
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Plane<S> {
pub n: Vector3<S>,
pub d: S,
}
impl<S: BaseFloat> Plane<S> {
pub fn new(n: Vector3<S>, d: S) -> Plane<S> {
Plane { n: n, d: d }
}
pub fn from_abcd(a: S, b: S, c: S, d: S) -> Plane<S> {
Plane { n: Vector3::new(a, b, c), d: d }
}
pub fn from_vector4(v: Vector4<S>) -> Plane<S> {
Plane { n: Vector3::new(v.x, v.y, v.z), d: v.w }
}
pub fn from_vector4_alt(v: Vector4<S>) -> Plane<S> {
Plane { n: Vector3::new(v.x, v.y, v.z), d: -v.w }
}
pub fn from_points(a: Point3<S>, b: Point3<S>, c: Point3<S>) -> Option<Plane<S>> {
let v0 = b.sub_p(&a);
let v1 = c.sub_p(&a);
let mut n = v0.cross(&v1);
if n.approx_eq(&zero()) { None }
else {
n.normalize_self();
let d = -a.dot(&n);
Some(Plane::new(n, d))
}
}
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
Plane { n: n, d: p.dot(&n) }
}
pub fn normalize(&self) -> Option<Plane<S>> {
if self.n.approx_eq(&zero()) { None }
else {
let denom = one::<S>() / self.n.length();
Some(Plane::new(self.n.mul_s(denom), self.d*denom))
}
}
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) {
fn intersection(&self) -> Option<Point3<S>> {
let (ref p, ref r) = *self;
let t = -(p.d + r.origin.dot(&p.n)) / r.direction.dot(&p.n);
if t < Zero::zero() { None }
else { Some(r.origin.add_v(&r.direction.mul_s(t))) }
}
}
impl<S: BaseFloat> Intersect<Option<Ray3<S>>> for (Plane<S>, Plane<S>) {
fn intersection(&self) -> Option<Ray3<S>> {
panic!("Not yet implemented");
}
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Plane<S>, Plane<S>) {
fn intersection(&self) -> Option<Point3<S>> {
panic!("Not yet implemented");
}
}
impl<S: BaseFloat + ApproxEq<S>>
ApproxEq<S> for Plane<S> {
#[inline]
fn approx_eq_eps(&self, other: &Plane<S>, epsilon: &S) -> bool {
self.n.approx_eq_eps(&other.n, epsilon) &&
self.d.approx_eq_eps(&other.d, epsilon)
}
}
impl<S: BaseFloat> fmt::Debug for Plane<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}x + {:?}y + {:?}z - {:?} = 0",
self.n.x, self.n.y, self.n.z, self.d)
}
}