use crate::Vec3;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Plane {
pub normal: Vec3,
pub d: f32,
}
impl Plane {
#[inline]
pub fn from_normal_point(normal: Vec3, point: Vec3) -> Self {
let normal = normal.normalize();
Self {
normal,
d: -normal.dot(point),
}
}
#[inline]
pub const fn from_normal_d(normal: Vec3, d: f32) -> Self {
Self { normal, d }
}
#[inline]
pub fn distance_to_point(&self, point: Vec3) -> f32 {
self.normal.dot(point) + self.d
}
#[inline]
pub fn project_point(&self, point: Vec3) -> Vec3 {
let dist = self.distance_to_point(point);
point - self.normal * dist
}
#[inline]
pub fn is_point_in_front(&self, point: Vec3) -> bool {
self.distance_to_point(point) > 0.0
}
#[inline]
pub fn normalize(self) -> Self {
let len = self.normal.length();
if len > 0.0 {
Self {
normal: self.normal / len,
d: self.d / len,
}
} else {
self
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plane_from_normal_point() {
let normal = Vec3::Z;
let point = Vec3::new(0.0, 0.0, 5.0);
let plane = Plane::from_normal_point(normal, point);
assert!((plane.distance_to_point(point)).abs() < 0.0001);
}
#[test]
fn test_plane_project_point() {
let plane = Plane::from_normal_point(Vec3::Z, Vec3::ZERO);
let point = Vec3::new(1.0, 2.0, 5.0);
let projected = plane.project_point(point);
assert!((projected.z).abs() < 0.0001);
}
}