use crate::VectorSpace;
use num_traits::{One, real::Real};
pub trait InnerSpace: VectorSpace {
fn scalar(&self, other: &Self) -> Self::Scalar;
#[inline]
fn magnitude2(&self) -> Self::Scalar {
self.scalar(self)
}
#[inline]
fn magnitude(&self) -> Self::Scalar {
self.magnitude2().sqrt()
}
#[inline]
fn normalize(self) -> Self {
let mag = self.magnitude();
self / mag
}
#[inline]
fn angle(&self, other: &Self) -> Self::Scalar {
(self.scalar(other) / (self.magnitude() * other.magnitude())).acos()
}
#[inline]
fn with_magnitude(self, magnitude: Self::Scalar) -> Self {
let mag = self.magnitude();
self * (magnitude / mag)
}
#[inline]
fn with_direction(self, dir: Self) -> Self {
dir * self.magnitude()
}
#[inline]
fn query_axis(&self, dir: Self) -> Self::Scalar {
self.scalar(&dir.normalize())
}
#[inline]
fn normalized_project(self, dir: Self) -> Self {
let scalar = self.scalar(&dir);
dir * scalar
}
#[inline]
fn project(self, dir: Self) -> Self {
self.normalized_project(dir.normalize())
}
#[inline]
fn normalized_reject(self, dir: Self) -> Self {
let scalar = self.scalar(&dir);
let proj = dir * scalar;
self - proj
}
#[inline]
fn reject(self, dir: Self) -> Self {
self.normalized_reject(dir.normalize())
}
#[inline]
fn normalized_reflect(self, dir: Self) -> Self {
let scalar = self.scalar(&dir);
let proj = dir * scalar;
proj * (Self::Scalar::one() + Self::Scalar::one()) - self
}
#[inline]
fn reflect(self, dir: Self) -> Self {
self.normalized_reflect(dir.normalize())
}
}
impl InnerSpace for f32 {
fn scalar(&self, other: &Self) -> Self {
self * other
}
}
impl InnerSpace for f64 {
fn scalar(&self, other: &Self) -> Self {
self * other
}
}