#[cfg(feature = "dim3")]
use crate::math::Real;
use crate::math::Vector;
use crate::utils::{CopySign, SimdRealCopy};
use na::{Vector2, Vector3};
pub trait OrthonormalBasis: Sized {
type Basis;
fn orthonormal_basis(self) -> Self::Basis;
fn orthonormal_vector(self) -> Self;
}
impl<N: SimdRealCopy> OrthonormalBasis for Vector2<N> {
type Basis = [Vector2<N>; 1];
fn orthonormal_basis(self) -> [Vector2<N>; 1] {
[Vector2::new(-self.y, self.x)]
}
fn orthonormal_vector(self) -> Vector2<N> {
Vector2::new(-self.y, self.x)
}
}
impl<N: SimdRealCopy + CopySign<N>> OrthonormalBasis for Vector3<N> {
type Basis = [Vector3<N>; 2];
fn orthonormal_basis(self) -> [Vector3<N>; 2] {
let sign = self.z.copy_sign_to(N::one());
let a = -N::one() / (sign + self.z);
let b = self.x * self.y * a;
[
Vector3::new(
N::one() + sign * self.x * self.x * a,
sign * b,
-sign * self.x,
),
Vector3::new(b, sign + self.y * self.y * a, -self.y),
]
}
fn orthonormal_vector(self) -> Vector3<N> {
let sign = self.z.copy_sign_to(N::one());
let a = -N::one() / (sign + self.z);
let b = self.x * self.y * a;
Vector3::new(b, sign + self.y * self.y * a, -self.y)
}
}
#[cfg(feature = "dim2")]
impl OrthonormalBasis for Vector {
type Basis = [Vector; 1];
fn orthonormal_basis(self) -> [Vector; 1] {
[Vector::new(-self.y, self.x)]
}
fn orthonormal_vector(self) -> Vector {
Vector::new(-self.y, self.x)
}
}
#[cfg(feature = "dim3")]
impl OrthonormalBasis for Vector {
type Basis = [Vector; 2];
fn orthonormal_basis(self) -> [Vector; 2] {
let sign = Real::copysign(1.0, self.z);
let a = -1.0 / (sign + self.z);
let b = self.x * self.y * a;
[
Vector::new(1.0 + sign * self.x * self.x * a, sign * b, -sign * self.x),
Vector::new(b, sign + self.y * self.y * a, -self.y),
]
}
fn orthonormal_vector(self) -> Vector {
let sign = Real::copysign(1.0, self.z);
let a = -1.0 / (sign + self.z);
let b = self.x * self.y * a;
Vector::new(b, sign + self.y * self.y * a, -self.y)
}
}