use super::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Plane3<T> {
pub normal: Vec3<T>,
pub distance: T,
}
#[allow(non_snake_case)]
#[inline]
pub const fn Plane3<T>(normal: Vec3<T>, distance: T) -> Plane3<T> {
Plane3 { normal, distance }
}
#[cfg(feature = "dataview")]
unsafe impl<T: dataview::Pod> dataview::Pod for Plane3<T> {}
impl<T> Plane3<T> {
#[inline]
pub const fn new(normal: Vec3<T>, distance: T) -> Plane3<T> {
Plane3 { normal, distance }
}
#[inline]
pub fn point(normal: Vec3<T>, pt: Point3<T>) -> Plane3<T> where T: Float {
let distance = normal.dot(pt);
Plane3 { normal, distance }
}
#[inline]
pub fn triangle(pt1: Point3<T>, pt2: Point3<T>, pt3: Point3<T>) -> Plane3<T> where T: Float {
let normal = (pt2 - pt1).cross(pt3 - pt1).norm();
let distance = normal.dot(pt1);
Plane3 { normal, distance }
}
}
impl<T: ops::Neg> ops::Neg for Plane3<T> {
type Output = Plane3<T::Output>;
#[inline]
fn neg(self) -> Plane3<T::Output> {
Plane3 {
normal: -self.normal,
distance: -self.distance,
}
}
}
impl<T: Float> Plane3<T> {
#[inline]
pub fn distance(&self, pt: Point3<T>) -> T {
self.normal.dot(pt) + self.distance
}
#[inline]
pub fn project(&self, pt: Point3<T>) -> Point3<T> {
pt - self.normal * self.distance(pt)
}
}
impl<T: Float> Trace3<T> for Plane3<T> {
#[inline]
fn inside(&self, pt: Point3<T>) -> bool {
self.distance(pt) >= T::ZERO
}
fn trace(&self, ray: &Ray3<T>) -> Option<Hit3<T>> {
let denom = self.normal.dot(ray.direction);
if denom == T::ZERO {
return None;
}
let distance = -self.distance(ray.origin) / denom;
if !(distance > ray.distance.min && distance <= ray.distance.max) {
return None;
}
let point = ray.at(distance);
let (normal, side) = if denom < T::ZERO {
(self.normal, HitSide::Entry)
}
else {
(-self.normal, HitSide::Exit)
};
Some(Hit3 { point, distance, normal, index: 0, side })
}
}