diff --git a/src/mathx.rs b/src/mathx.rs index b21a624..3b84795 100644 --- a/src/mathx.rs +++ b/src/mathx.rs @@ -1,4 +1,4 @@ -use glam::{FloatExt, Mat2, Mat3, Vec2}; +use glam::{FloatExt, Mat2, Mat3, Vec2, Vec3}; mod bounds { pub trait Pair {} @@ -93,6 +93,55 @@ where } } +/// Represents a 3×3 matrix decomposed as O^T D O, where O is orthogonal and D is diagonal. +/// +/// Not every matrix can be decomposed like this, only that of a symmetric bilinear function. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Decomp3 { + /// The orthogonal part. + /// + /// Using a non-orthogonal matrix will yield to incorrect results (but no UB). + pub ortho: Mat3, + + /// The diagonal part. + pub diag: Vec3, +} + +impl Decomp3 { + /// Computes the square of this, more efficiently than doing that with a matrix. + pub fn square(&self) -> Self { + Self { + ortho: self.ortho, + diag: self.diag * self.diag, + } + } + + /// Computes the inverse of this, more efficiently than doing that with a matrix. + pub fn inverse(&self) -> Self { + Self { + ortho: self.ortho, + diag: Vec3::splat(1.0) / self.diag, + } + } +} + +impl From for Mat3 { + fn from(value: Decomp3) -> Self { + value.ortho.transpose() * Mat3::from_diagonal(value.diag) * value.ortho + } +} + +impl std::ops::Mul for Decomp3 +where + Mat3: std::ops::Mul, +{ + type Output = >::Output; + + fn mul(self, rhs: T) -> Self::Output { + Mat3::from(self) * rhs + } +} + #[cfg(test)] mod tests { use super::*;