use std::fmt;
use cgmath::prelude::*;
use cgmath::{BaseFloat, Point3, Vector3, Vector4};
#[derive(Copy, Clone, PartialEq)]
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, d }
}
pub fn from_abcd(a: S, b: S, c: S, d: S) -> Plane<S> {
Plane {
n: Vector3::new(a, b, c),
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 dis = -a.dot(n);
Some(Plane::new(n, dis))
}
}
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
Plane { 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: 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
)
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
#[repr(u8)]
pub enum PlaneRelation {
In,
Cross,
Out,
}
pub trait PlaneBound<S: BaseFloat>: fmt::Debug {
fn relate(&self, plane: Plane<S>) -> PlaneRelation;
}
impl<S: BaseFloat> PlaneBound<S> for Point3<S> {
fn relate(&self, plane: Plane<S>) -> PlaneRelation {
let dist = self.dot(plane.n);
if dist > plane.d {
PlaneRelation::In
} else if dist < plane.d {
PlaneRelation::Out
} else {
PlaneRelation::Cross
}
}
}