use std::ops::{Add, Div, Mul, Neg, Sub};
use super::point::PgaPoint;
use super::line::PgaLine;
#[repr(C, align(16))]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "vulkan", derive(bytemuck::Pod, bytemuck::Zeroable))]
pub struct PgaPlane {
pub d: f32, pub a: f32, pub b: f32, pub c: f32, }
impl Default for PgaPlane {
#[inline(always)]
fn default() -> Self {
Self::xy()
}
}
impl PgaPlane {
#[inline(always)]
pub const fn new(a: f32, b: f32, c: f32, d: f32) -> Self {
Self { d, a, b, c }
}
#[inline]
pub fn from_point_normal(point: &[f32; 3], normal: &[f32; 3]) -> Self {
let d = -(normal[0] * point[0] + normal[1] * point[1] + normal[2] * point[2]);
Self::new(normal[0], normal[1], normal[2], d)
}
#[inline(always)]
pub const fn yz() -> Self {
Self::new(1.0, 0.0, 0.0, 0.0)
}
#[inline(always)]
pub const fn xz() -> Self {
Self::new(0.0, 1.0, 0.0, 0.0)
}
#[inline(always)]
pub const fn xy() -> Self {
Self::new(0.0, 0.0, 1.0, 0.0)
}
#[inline(always)]
pub const fn infinity() -> Self {
Self { d: 1.0, a: 0.0, b: 0.0, c: 0.0 }
}
#[inline(always)]
pub const fn normal(&self) -> [f32; 3] {
[self.a, self.b, self.c]
}
#[inline(always)]
pub fn norm_sq(&self) -> f32 {
self.a * self.a + self.b * self.b + self.c * self.c
}
#[inline(always)]
pub fn norm(&self) -> f32 {
self.norm_sq().sqrt()
}
#[inline]
pub fn normalized(&self) -> Self {
let n = self.norm();
if n > 1e-12 {
let inv = 1.0 / n;
Self {
d: self.d * inv,
a: self.a * inv,
b: self.b * inv,
c: self.c * inv,
}
} else {
*self
}
}
#[inline]
pub fn distance_to_point(&self, p: &PgaPoint) -> f32 {
let norm_plane = self.normalized();
let pt = p.to_euclidean();
norm_plane.a * pt[0] + norm_plane.b * pt[1] + norm_plane.c * pt[2] + norm_plane.d
}
#[inline]
pub fn reflect_point(&self, p: &PgaPoint) -> PgaPoint {
let n = self.normalized();
let [x, y, z] = p.to_euclidean();
let signed_dist = n.a * x + n.b * y + n.c * z + n.d;
let factor = 2.0 * signed_dist;
PgaPoint::new(
x - factor * n.a,
y - factor * n.b,
z - factor * n.c,
)
}
#[inline]
pub fn reflect_plane(&self, other: &Self) -> Self {
let n = self.normalized();
let o = other.normalized();
let dot = n.a * o.a + n.b * o.b + n.c * o.c;
let factor = 2.0 * dot;
Self::new(
factor * n.a - o.a,
factor * n.b - o.b,
factor * n.c - o.c,
factor * n.d - o.d,
)
}
#[inline]
pub fn meet(&self, other: &Self) -> PgaLine {
let vx = self.b * other.c - self.c * other.b;
let vy = self.c * other.a - self.a * other.c;
let vz = self.a * other.b - self.b * other.a;
let mx = self.d * other.a - other.d * self.a;
let my = self.d * other.b - other.d * self.b;
let mz = self.d * other.c - other.d * self.c;
PgaLine::from_direction_and_moment([vx, vy, vz], [mx, my, mz])
}
}
impl Neg for PgaPlane {
type Output = Self;
#[inline(always)]
fn neg(self) -> Self {
Self {
d: -self.d,
a: -self.a,
b: -self.b,
c: -self.c,
}
}
}
impl Add for PgaPlane {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self {
Self {
d: self.d + rhs.d,
a: self.a + rhs.a,
b: self.b + rhs.b,
c: self.c + rhs.c,
}
}
}
impl Sub for PgaPlane {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: Self) -> Self {
Self {
d: self.d - rhs.d,
a: self.a - rhs.a,
b: self.b - rhs.b,
c: self.c - rhs.c,
}
}
}
impl Mul<f32> for PgaPlane {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: f32) -> Self {
Self {
d: self.d * rhs,
a: self.a * rhs,
b: self.b * rhs,
c: self.c * rhs,
}
}
}
impl Div<f32> for PgaPlane {
type Output = Self;
#[inline(always)]
fn div(self, rhs: f32) -> Self {
let inv = 1.0 / rhs;
Self {
d: self.d * inv,
a: self.a * inv,
b: self.b * inv,
c: self.c * inv,
}
}
}