use std::fmt;
use cgmath::{ApproxEq, BaseFloat};
use cgmath::Point3;
use cgmath::{Vector3, Vector4};
use cgmath::{EuclideanSpace, InnerSpace};
use cgmath::Zero;
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
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 - a;
let v1 = c - a;
let n = v0.cross(v1);
if ulps_eq!(n, &Vector3::zero()) {
None
} else {
let n = n.normalize();
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 ulps_eq!(self.n, &Vector3::zero()) {
None
} else {
let denom = S::one() / self.n.magnitude();
Some(Plane::new(self.n * denom, self.d * denom))
}
}
}
impl<S> ApproxEq for Plane<S>
where S: BaseFloat
{
type Epsilon = S::Epsilon;
#[inline]
fn default_epsilon() -> S::Epsilon {
S::default_epsilon()
}
#[inline]
fn default_max_relative() -> S::Epsilon {
S::default_max_relative()
}
#[inline]
fn default_max_ulps() -> u32 {
S::default_max_ulps()
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
Vector3::relative_eq(&self.n, &other.n, epsilon, max_relative) &&
S::relative_eq(&self.d, &other.d, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
Vector3::ulps_eq(&self.n, &other.n, epsilon, max_ulps) &&
S::ulps_eq(&self.d, &other.d, epsilon, max_ulps)
}
}
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)
}
}