#![no_std]
#![deny(missing_docs)]
use scalars::{InverseTrigonometry, One, Sqrt};
pub use vector_space::*;
pub trait DotProduct<T = Self>: VectorSpace {
type Output;
fn dot(&self, other: &T) -> <Self as DotProduct<T>>::Output;
fn scalar(&self, other: &T) -> <Self as DotProduct<T>>::Output {
self.dot(other)
}
}
impl DotProduct for f32 {
type Output = Self;
fn dot(&self, other: &Self) -> Self {
*self * *other
}
}
impl DotProduct for f64 {
type Output = Self;
fn dot(&self, other: &Self) -> Self {
*self * *other
}
}
pub trait InnerSpace: DotProduct<Output = <Self as VectorSpace>::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.dot(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.dot(&dir.normalize())
}
#[inline]
fn normalized_project(self, dir: Self) -> Self {
let scalar = self.dot(&dir);
dir * scalar
}
#[inline]
fn project(self, dir: Self) -> Self {
let ratio = self.dot(&dir) / dir.magnitude2();
dir * ratio
}
#[inline]
fn normalized_reject(self, dir: Self) -> Self {
let scalar = self.dot(&dir);
let proj = dir * scalar;
self - proj
}
#[inline]
fn reject(self, dir: Self) -> Self {
let ratio = self.dot(&dir) / dir.magnitude2();
self - dir * ratio
}
#[inline]
fn normalized_reflect(self, dir: Self) -> Self {
let scalar = self.dot(&dir);
let proj = dir * scalar;
proj * (Self::Scalar::one() + Self::Scalar::one()) - self
}
#[inline]
fn reflect(self, dir: Self) -> Self {
let ratio = self.dot(&dir) / dir.magnitude2();
dir * ratio * (Self::Scalar::one() + Self::Scalar::one()) - self
}
}
impl<T: DotProduct<Output = Self::Scalar>> InnerSpace for T {}
pub fn distance<T: AffineSpace>(a: T, b: T) -> <T::Diff as VectorSpace>::Scalar
where
T::Diff: InnerSpace,
{
(b - a).magnitude()
}
pub fn distance2<T: AffineSpace>(a: T, b: T) -> <T::Diff as VectorSpace>::Scalar
where
T::Diff: InnerSpace,
{
(b - a).magnitude2()
}
pub fn direction<T: AffineSpace>(a: T, b: T) -> T::Diff
where
T::Diff: InnerSpace,
{
(b - a).normalize()
}