use crate::Vec3;
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "speedy", derive(speedy::Writable, speedy::Readable))]
pub struct Plane3 {
pub normal: Vec3,
pub d: f32,
}
impl Plane3 {
pub const XY: Self = Self {
normal: Vec3::Z,
d: 0.0,
};
pub const YZ: Self = Self {
normal: Vec3::X,
d: 0.0,
};
pub const ZX: Self = Self {
normal: Vec3::Y,
d: 0.0,
};
#[inline]
pub fn from_normal_dist(normal: Vec3, d: f32) -> Self {
Self { normal, d }
}
#[inline]
pub fn from_normal_point(normal: Vec3, point: Vec3) -> Self {
Self {
normal,
d: -normal.dot(point),
}
}
#[inline]
#[must_use]
pub fn normalized(&self) -> Self {
let inv_len = self.normal.length_recip();
Self {
normal: self.normal * inv_len,
d: self.d * inv_len,
}
}
#[inline]
pub fn distance(&self, p: Vec3) -> f32 {
self.normal.dot(p) + self.d
}
pub fn intersect_ray(&self, origin: Vec3, dir: Vec3) -> (bool, f32) {
let denom = dir.dot(self.normal);
if denom == 0.0 {
(false, 0.0)
} else {
let t = -(origin.dot(self.normal) + self.d) / denom;
if t < 0.0 { (false, t) } else { (true, t) }
}
}
#[inline]
pub fn is_finite(&self) -> bool {
self.normal.is_finite() && self.d.is_finite()
}
#[inline]
pub fn as_vec4(&self) -> crate::Vec4 {
self.normal.extend(self.d)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_plane3() {
#![allow(clippy::float_cmp)]
let point = Vec3::new(2.0, 3.0, 4.0);
let p = Plane3::from_normal_point(Vec3::new(2.0, 0.0, 0.0), point);
assert_eq!(p.distance(point), 0.0);
let p = p.normalized();
assert_eq!(p.distance(point), 0.0);
}
}