use super::{Scalar, Vector, VectorIteratorExt};
use itertools::Itertools;
pub trait Spherical3d: Vector<Self::S, 3> {
type S: Scalar;
type Vec3: Vector<Self::S, 3>;
fn new(r: Self::S, phi: Self::S, theta: Self::S) -> Self {
Self::from_xyz(r, phi, theta)
}
fn r(&self) -> Self::S {
self.x()
}
fn phi(&self) -> Self::S {
self.y()
}
fn theta(&self) -> Self::S {
self.z()
}
fn cartesian(&self) -> Self::Vec3 {
let r = self.r();
let phi = self.phi();
let theta = self.theta();
let x = r * theta.sin() * phi.cos();
let y = r * theta.sin() * phi.sin();
let z = r * theta.cos();
Self::Vec3::from_xyz(x, y, z)
}
}
pub trait Vector3D: Vector<Self::S, 3> {
type S: Scalar;
type Spherical: Spherical3d<S = Self::S, Vec3 = Self>;
fn new(x: Self::S, y: Self::S, z: Self::S) -> Self;
fn to_array(&self) -> [Self::S; 3] {
[self.x(), self.y(), self.z()]
}
fn normal(&self, prev: Self, next: Self) -> Self {
(*self - prev).cross(&(next - prev))
}
fn cross(&self, other: &Self) -> Self;
fn tuple(&self) -> (Self::S, Self::S, Self::S) {
(self.x(), self.y(), self.z())
}
fn xyz(&self) -> Self {
Self::new(self.x(), self.y(), self.z())
}
fn xzy(&self) -> Self {
Self::new(self.x(), self.z(), self.y())
}
fn yxz(&self) -> Self {
Self::new(self.y(), self.x(), self.z())
}
fn yzx(&self) -> Self {
Self::new(self.y(), self.z(), self.x())
}
fn zxy(&self) -> Self {
Self::new(self.z(), self.x(), self.y())
}
fn zyx(&self) -> Self {
Self::new(self.z(), self.y(), self.x())
}
fn spherical(&self) -> Self::Spherical {
let r = self.length();
let phi = self.y().atan2(self.x());
let theta = if r == Self::S::ZERO {
Self::S::ZERO
} else {
(self.z() / r).acos()
};
Self::Spherical::new(r, phi, theta)
}
fn slerp(&self, other: &Self, t: Self::S) -> Self {
debug_assert!(
self.length() - Self::S::ONE < Self::S::EPS.sqrt(),
"slerp requires normalized vectors"
);
debug_assert!(
other.length() - Self::S::ONE < Self::S::EPS.sqrt(),
"slerp requires normalized vectors"
);
let mut dot = self.dot(other);
dot = dot.clamp(-Self::S::ONE, Self::S::ONE);
let theta = dot.acos();
if theta.abs() < Self::S::EPS.sqrt() {
return *self;
}
let sin_theta = theta.sin();
let st1 = ((Self::S::ONE - t) * theta).sin() / sin_theta;
let st2 = (t * theta).sin() / sin_theta;
*self * st1 + *other * st2
}
}
pub trait Vector3DIteratorExt<S: Scalar, V: Vector3D<S = S>>: Iterator<Item = V> {
fn normal(self) -> Self::Item
where
Self: Sized + ExactSizeIterator + Clone,
{
let normal = self
.circular_tuple_windows::<(_, _)>()
.map(|(a, b)| {
V::new(
(a.z() + b.z()) * (b.y() - a.y()),
(a.x() + b.x()) * (b.z() - a.z()),
(a.y() + b.y()) * (b.x() - a.x()),
)
})
.stable_sum();
normal * S::from(-0.5)
}
}
impl<I: Iterator<Item = V>, S: Scalar, V: Vector3D<S = S>> Vector3DIteratorExt<S, V> for I {}