use super::generated::types::{Bivector, Rotor, Vector};
use crate::scalar::Float;
impl<T: Float> Vector<T> {
#[inline]
pub fn dot(self, other: Self) -> T {
self.x() * other.x() + self.y() * other.y()
}
#[inline]
pub fn perp(&self) -> Self {
Self::new(-self.y(), self.x())
}
}
impl<T: Float> Bivector<T> {
#[inline]
pub fn unit() -> Self {
Self::unit_b()
}
#[inline]
pub fn value(&self) -> T {
self.b()
}
}
impl<T: Float> Rotor<T> {
#[inline]
pub fn from_angle(angle: T) -> Self {
let half = angle / T::TWO;
Self::new_unchecked(half.cos(), -half.sin())
}
#[inline]
pub fn from_vectors(a: Vector<T>, b: Vector<T>) -> Self {
let angle_a = a.y().atan2(a.x());
let angle_b = b.y().atan2(b.x());
let angle = angle_b - angle_a;
Self::from_angle(angle)
}
#[inline]
pub fn compose(&self, other: Self) -> Self {
other * *self
}
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
Self::new_unchecked(
self.s() * (T::one() - t) + other.s() * t,
self.b() * (T::one() - t) + other.b() * t,
)
.normalize()
}
#[inline]
pub fn slerp(&self, other: Self, t: T) -> Self {
let dot = self.s() * other.s() + self.b() * other.b();
let dot = if dot > T::one() {
T::one()
} else if dot < -T::one() {
-T::one()
} else {
dot
};
let theta = dot.acos();
let sin_theta = theta.sin();
if sin_theta.abs() < T::epsilon() {
return self.lerp(other, t);
}
let s1 = ((T::one() - t) * theta).sin() / sin_theta;
let s2 = (t * theta).sin() / sin_theta;
Self::new_unchecked(
self.s() * s1 + other.s() * s2,
self.b() * s1 + other.b() * s2,
)
}
#[inline]
pub fn angle(&self) -> T {
T::atan2(-self.b(), self.s()) * T::TWO
}
#[inline]
pub fn with_dilation(angle: T, dilation: T) -> Self {
let half = angle / T::TWO;
let scale = dilation.sqrt();
Self::new_unchecked(scale * half.cos(), -scale * half.sin())
}
#[inline]
pub fn dilation_factor(&self) -> T {
self.norm_squared()
}
}