use crate::{matrix, quat, vector};
pub trait IsSquared<const D: usize, const D2: usize> {}
impl IsSquared<2, 4> for [(); 2] {}
impl IsSquared<3, 9> for [(); 3] {}
impl IsSquared<4, 16> for [(); 4] {}
pub trait Num:
Copy
+ PartialEq
+ PartialOrd
+ std::fmt::Display
+ std::fmt::Debug
+ std::ops::Neg<Output = Self>
+ num_traits::Num
+ num_traits::ConstOne
+ num_traits::ConstZero
+ num_traits::FromPrimitive
{
}
impl<T> Num for T where
T: Copy
+ PartialEq
+ PartialOrd
+ std::fmt::Display
+ std::fmt::Debug
+ std::ops::Neg<Output = Self>
+ num_traits::Num
+ num_traits::ConstOne
+ num_traits::ConstZero
+ num_traits::FromPrimitive
{
}
pub trait Float: Num + num_traits::Float {
fn frac(n: i32, d: u32) -> Self {
Self::from_i32(n).unwrap() / Self::from_u32(d).unwrap()
}
}
impl<T> Float for T where T: Num + num_traits::Float {}
pub trait ArrayBasic:
Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default + PartialEq<Self>
{
}
impl<T> ArrayBasic for T where
T: Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default + PartialEq<Self>
{
}
pub trait ArrayRef<F, const D:usize>:
std::convert::AsRef<[F; D]> + std::convert::AsMut<[F; D]> + std::ops::Deref<Target = [F;D]>
+ std::ops::DerefMut
{
}
impl<T, F, const D: usize> ArrayRef<F, D> for T where
T: std::convert::AsRef<[F; D]> + std::convert::AsMut<[F; D]>
+ std::ops::Deref<Target = [F; D]>
+ std::ops::DerefMut
{
}
pub trait ArrayIndex<F>: std::ops::Index<usize, Output = F> + std::ops::IndexMut<usize> {}
impl<T, F> ArrayIndex<F> for T where
T: std::ops::Index<usize, Output = F> + std::ops::IndexMut<usize>
{
}
pub trait ArrayConvert<F, const D: usize>:
std::convert::From<[F; D]>
+ for<'a> std::convert::From<&'a [F; D]>
+ for<'a> std::convert::TryFrom<&'a [F]>
+ for<'a> std::convert::TryFrom<Vec<F>>
+ std::convert::Into<[F; D]>
{
}
impl<T, F, const D: usize> ArrayConvert<F, D> for T where
T: std::convert::From<[F; D]>
+ for<'a> std::convert::From<&'a [F; D]>
+ for<'a> std::convert::TryFrom<&'a [F]>
+ for<'a> std::convert::TryFrom<Vec<F>>
+ std::convert::Into<[F; D]>
{
}
pub trait ArrayAddSubNeg<F, const D: usize>:
Sized
+ std::ops::Neg<Output = Self>
+ std::ops::Add<Self, Output = Self>
+ for<'a> std::ops::Add<&'a [F; D], Output = Self>
+ for<'a> std::ops::Add<&'a Self, Output = Self>
+ std::ops::AddAssign<Self>
+ for<'a> std::ops::AddAssign<&'a [F; D]>
+ std::ops::Sub<Self, Output = Self>
+ for<'a> std::ops::Sub<&'a [F; D], Output = Self>
+ for<'a> std::ops::Sub<&'a Self, Output = Self>
+ std::ops::SubAssign<Self>
+ for<'a> std::ops::SubAssign<&'a [F; D]>
{
}
impl<T, F, const D: usize> ArrayAddSubNeg<F, D> for T where
T: Sized
+ std::ops::Neg<Output = Self>
+ std::ops::Add<Self, Output = Self>
+ for<'a> std::ops::Add<&'a [F; D], Output = Self>
+ for<'a> std::ops::Add<&'a Self, Output = Self>
+ std::ops::AddAssign<Self>
+ for<'a> std::ops::AddAssign<&'a [F; D]>
+ std::ops::Sub<Self, Output = Self>
+ for<'a> std::ops::Sub<&'a [F; D], Output = Self>
+ for<'a> std::ops::Sub<&'a Self, Output = Self>
+ std::ops::SubAssign<Self>
+ for<'a> std::ops::SubAssign<&'a [F; D]>
{
}
pub trait ArrayScale<F>:
std::ops::Mul<F, Output = Self>
+ std::ops::MulAssign<F>
+ std::ops::Div<F, Output = Self>
+ std::ops::DivAssign<F>
{
}
impl<T, F> ArrayScale<F> for T where
T: std::ops::Mul<F, Output = Self>
+ std::ops::MulAssign<F>
+ std::ops::Div<F, Output = Self>
+ std::ops::DivAssign<F>
{
}
#[allow(dead_code)]
pub trait ArrayMulDiv<F, const D: usize>:
Sized
+ std::ops::Mul<Self, Output = Self>
+ for<'a> std::ops::Mul<&'a [F; 4], Output = Self>
+ for<'a> std::ops::Mul<&'a Self, Output = Self>
+ std::ops::MulAssign<Self>
+ for<'a> std::ops::MulAssign<&'a [F; 4]>
+ std::ops::Div<Self, Output = Self>
+ for<'a> std::ops::Div<&'a [F; 4], Output = Self>
+ for<'a> std::ops::Div<&'a Self, Output = Self>
+ std::ops::DivAssign<Self>
+ for<'a> std::ops::DivAssign<&'a [F; 4]>
{
}
impl<T, F, const D: usize> ArrayMulDiv<F, D> for T where
T: Sized
+ std::ops::Mul<Self, Output = Self>
+ for<'a> std::ops::Mul<&'a [F; 4], Output = Self>
+ for<'a> std::ops::Mul<&'a Self, Output = Self>
+ std::ops::MulAssign<Self>
+ for<'a> std::ops::MulAssign<&'a [F; 4]>
+ std::ops::Div<Self, Output = Self>
+ for<'a> std::ops::Div<&'a [F; 4], Output = Self>
+ for<'a> std::ops::Div<&'a Self, Output = Self>
+ std::ops::DivAssign<Self>
+ for<'a> std::ops::DivAssign<&'a [F; 4]>
{
}
pub trait QuatMulDiv<F, const D: usize>:
Sized
+ std::ops::Mul<Self, Output = Self>
+ for<'a> std::ops::Mul<&'a Self, Output = Self>
+ std::ops::MulAssign<Self>
+ std::ops::Div<Self, Output = Self>
+ for<'a> std::ops::Div<&'a Self, Output = Self>
+ std::ops::DivAssign<Self>
{
}
impl<T, F, const D: usize> QuatMulDiv<F, D> for T where
T: Sized
+ std::ops::Mul<Self, Output = Self>
+ for<'a> std::ops::Mul<&'a Self, Output = Self>
+ std::ops::MulAssign<Self>
+ std::ops::Div<Self, Output = Self>
+ for<'a> std::ops::Div<&'a Self, Output = Self>
+ std::ops::DivAssign<Self>
{
}
pub trait Vector<F: Float, const D: usize>:
ArrayBasic
+ ArrayRef<F, D> + ArrayIndex<F>
+ ArrayConvert<F, D>
+ ArrayAddSubNeg<F, D>
+ ArrayScale<F>
{
fn is_zero(&self) -> bool {
!self.deref().iter().any(|f| !f.is_zero())
}
#[must_use]
fn mix<A>(self, other: A, t: F) -> Self
where
A: std::ops::Deref<Target = [F; D]>,
{
vector::mix(self.deref(), other.deref(), t).into()
}
fn dot(&self, other: &[F; D]) -> F {
vector::dot(self.deref(), other)
}
fn reduce_sum(&self) -> F {
let mut r = F::zero();
for d in self.deref() {
r = r + *d
}
r
}
#[inline]
fn length_sq(&self) -> F {
self.dot(self)
}
#[inline]
fn length(&self) -> F {
self.length_sq().sqrt()
}
#[inline]
fn distance_sq(&self, other: &[F; D]) -> F {
(*self - other).length_sq()
}
#[inline]
fn distance(&self, other: &[F; D]) -> F {
self.distance_sq(other).sqrt()
}
#[inline]
#[must_use]
fn normalize(mut self) -> Self {
let l = self.length();
if l < F::epsilon() {
self = Self::default()
} else {
self /= l
}
self
}
fn rotate_around(mut self, pivot: &Self, angle: F, c0: usize, c1: usize) -> Self {
let (s, c) = angle.sin_cos();
let dx = self[c0] - pivot[c0];
let dy = self[c1] - pivot[c1];
let x1 = c * dx - s * dy;
let y1 = c * dy + s * dx;
self[c0] = x1 + pivot[c0];
self[c1] = y1 + pivot[c1];
self
}
#[must_use]
fn cross_product(&self, other: &[F; 3]) -> Self
where
Self: From<[F; 3]>,
Self: AsRef<[F; 3]>, {
vector::cross_product3(self.as_ref(), other).into()
}
#[must_use]
fn apply_q3<Q>(&self, q: &Q) -> Self
where
Q: Quaternion<F>,
Self: From<[F; 3]>, Self: AsRef<[F; 3]>, {
quat::apply3(q.deref(), self.as_ref()).into()
}
#[must_use]
fn apply_q4<Q>(&self, q: &Q) -> Self
where
Q: Quaternion<F>,
Self: From<[F; 4]>,
Self: AsRef<[F; 4]>, {
quat::apply4(q.deref(), self.as_ref()).into()
}
fn transformed_by_m<const D2: usize>(&mut self, m: &[F; D2]) -> &mut Self
where
[(); D]: IsSquared<D, D2>,
{
*self = matrix::multiply::<F, D2, D, D, D, D, 1>(m, self.deref()).into();
self
}
#[must_use]
fn uniform_dist_sphere3(x: [F; 2], map: bool) -> Self
where
Self: From<[F; 3]>,
{
(vector::uniform_dist_sphere3(x, map)).into()
}
}
pub trait Vector2<F: Float>: Vector<F, 2> {}
impl<F, V> Vector2<F> for V
where
F: Float,
V: Vector<F, 2>,
{
}
pub trait Vector3<F: Float>: Vector<F, 3> {}
impl<F, V> Vector3<F> for V
where
F: Float,
V: Vector<F, 3>,
{
}
pub trait Vector4<F: Float>: Vector<F, 4> {}
impl<F, V> Vector4<F> for V
where
F: Float,
V: Vector<F, 4>,
{
}
pub trait SqMatrix<F: Float, const D: usize, const D2: usize>:
ArrayBasic
+ ArrayRef<F, D2>
+ ArrayIndex<F>
+ ArrayConvert<F, D2>
+ ArrayAddSubNeg<F, D2>
+ ArrayScale<F>
+ std::ops::Mul<Output = Self>
+ std::ops::MulAssign
{
fn identity() -> Self {
matrix::identity::<F, D2, D>().into()
}
fn is_zero(&self) -> bool {
vector::is_zero(self.deref())
}
fn set_zero(&mut self) -> &mut Self {
vector::set_zero(self.deref_mut());
self
}
fn transpose(&self) -> Self;
fn determinant(&self) -> F;
fn inverse(&self) -> Self;
fn transform<T>(&self, v: &T) -> T
where
T: std::ops::Deref<Target = [F; D]>,
T: From<[F; D]>;
}
pub trait SqMatrix2<F: Float>: SqMatrix<F, 2, 4> {}
impl<F, M> SqMatrix2<F> for M
where
F: Float,
M: SqMatrix<F, 2, 4>,
{
}
pub trait SqMatrix3<F: Float>: SqMatrix<F, 3, 9> {}
impl<F, M> SqMatrix3<F> for M
where
F: Float,
M: SqMatrix<F, 3, 9>,
{
}
pub trait SqMatrix4<F: Float>: SqMatrix<F, 4, 16> {
fn perspective(fov: F, aspect: F, near: F, far: F) -> Self {
matrix::perspective4(fov, aspect, near, far).into()
}
fn look_at(eye: &[F; 3], center: &[F; 3], up: &[F; 3]) -> Self {
matrix::look_at4(eye, center, up).into()
}
fn translate3(&mut self, by: &[F; 3]) {
self[3] = self[3] + by[0];
self[7] = self[7] + by[1];
self[11] = self[11] + by[2];
}
fn translate4(&mut self, by: &[F; 4]) {
self[3] = self[3] + by[0];
self[7] = self[7] + by[1];
self[11] = self[11] + by[2];
}
}
impl<F, M> SqMatrix4<F> for M
where
F: Float,
M: SqMatrix<F, 4, 16>,
{
}
pub trait Quaternion<F: Float>:
ArrayBasic
+ ArrayRef<F, 4>
+ ArrayIndex<F>
+ ArrayConvert<F, 4>
+ ArrayAddSubNeg<F, 4>
+ QuatMulDiv<F, 4>
+ ArrayScale<F>
{
#[must_use]
fn of_rijk(r: F, i: F, j: F, k: F) -> Self;
#[must_use]
#[inline]
fn conjugate(self) -> Self {
let (r, i, j, k) = self.as_rijk();
Self::of_rijk(r, -i, -j, -k)
}
#[must_use]
fn of_axis_angle(axis: &[F; 3], angle: F) -> Self {
quat::of_axis_angle(axis, angle).into()
}
#[inline]
#[must_use]
fn rotate_x(self, angle: F) -> Self {
quat::rotate_x(self.as_ref(), angle).into()
}
#[inline]
#[must_use]
fn rotate_y(self, angle: F) -> Self {
quat::rotate_y(self.as_ref(), angle).into()
}
#[inline]
#[must_use]
fn rotate_z(self, angle: F) -> Self {
quat::rotate_z(self.as_ref(), angle).into()
}
#[must_use]
fn look_at(dirn: &[F; 3], up: &[F; 3]) -> Self {
quat::look_at(dirn, up).into()
}
#[must_use]
fn rotation_of_vec_to_vec(a: &[F; 3], b: &[F; 3]) -> Self {
quat::rotation_of_vec_to_vec(a, b).into()
}
fn mapping_vector_pair_to_vector_pair(
(di_m, dj_m): (&[F; 3], &[F; 3]),
(di_c, dj_c): (&[F; 3], &[F; 3]),
) -> Self {
let z_axis: [F; 3] = [F::zero(), F::zero(), F::one()];
let qi_c = Self::rotation_of_vec_to_vec(di_c, &z_axis);
let qi_m = Self::rotation_of_vec_to_vec(di_m, &z_axis);
let dj_c_rotated = quat::apply3(&qi_c, dj_c);
let dj_m_rotated = quat::apply3(&qi_m, dj_m);
let theta_dj_m = dj_m_rotated[0].atan2(dj_m_rotated[1]);
let theta_dj_c = dj_c_rotated[0].atan2(dj_c_rotated[1]);
let theta = theta_dj_m - theta_dj_c;
let theta_div_2 = theta / (F::one() + F::one());
let cos_2theta = theta_div_2.cos();
let sin_2theta = theta_div_2.sin();
let q_z = Self::of_rijk(cos_2theta, F::zero(), F::zero(), sin_2theta);
qi_c.conjugate() * q_z * qi_m
}
#[must_use]
fn weighted_average_pair(&self, w_a: F, qb: &Self, w_b: F) -> Self {
quat::weighted_average_pair(self.as_ref(), w_a, qb.as_ref(), w_b).into()
}
#[must_use]
fn weighted_average_many<A: Into<[F; 4]>, I: Iterator<Item = (F, A)>>(value_iter: I) -> Self {
let value_iter = value_iter.map(|(w, v)| (w, v.into()));
quat::weighted_average_many(value_iter).into()
}
fn as_rijk(&self) -> (F, F, F, F);
fn as_axis_angle<V: From<[F; 3]>>(&self) -> (V, F) {
let (axis, angle) = quat::as_axis_angle(self.as_ref());
(axis.into(), angle)
}
fn set_zero(&mut self) {
*self = [F::zero(); 4].into();
}
#[must_use]
fn mix(self, other: &[F; 4], t: F) -> Self {
vector::mix(self.deref(), other, t).into()
}
fn dot(self, other: &Self) -> F {
vector::dot(self.deref(), other.deref())
}
fn length_sq(&self) -> F {
self.dot(self)
}
fn length(&self) -> F {
self.length_sq().sqrt()
}
fn distance_sq(&self, other: &Self) -> F {
quat::distance_sq(self, other)
}
fn distance(&self, other: &Self) -> F {
self.distance_sq(other).sqrt()
}
#[must_use]
fn normalize(mut self) -> Self {
let l = self.length();
if l < F::epsilon() {
self.set_zero()
} else {
self /= l
}
self
}
#[must_use]
fn of_rotation3<M>(rotation: &M) -> Self
where
M: SqMatrix3<F>;
fn set_rotation3<M>(&self, m: &mut M)
where
M: SqMatrix3<F>;
fn set_rotation4<M>(&self, m: &mut M)
where
M: SqMatrix4<F>;
#[must_use]
fn apply3<T>(&self, other: &T) -> T
where
T: std::ops::Deref<Target = [F; 3]>,
T: From<[F; 3]>,
{
quat::apply3(self.deref(), other.deref()).into()
}
#[must_use]
fn apply3_arr(&self, other: &[F; 3]) -> [F; 3] {
quat::apply3(self.deref(), other)
}
#[must_use]
fn apply4<T>(&self, other: &T) -> T
where
T: std::ops::Deref<Target = [F; 4]>,
T: From<[F; 4]>,
{
quat::apply4(self.deref(), other.deref()).into()
}
#[must_use]
fn apply4_arr(&self, other: &[F; 4]) -> [F; 4] {
quat::apply4(self.deref(), other)
}
}
pub trait Transform<F, V3, Q>:
Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default
where
F: Float,
V3: Vector<F, 3>,
Q: Quaternion<F>,
{
fn of_trs(t: V3, r: Q, s: F) -> Self;
fn scale(&self) -> F;
fn translation(&self) -> V3;
fn rotation(&self) -> Q;
#[must_use]
fn inverse(&self) -> Self;
fn invert(&mut self);
fn as_mat<M: SqMatrix4<F>>(&self) -> M;
}
pub trait Vector3D<Scalar: Float> {
type Vec2: Vector<Scalar, 2>;
type Vec3: Vector<Scalar, 3>;
type Vec4: Vector<Scalar, 4>;
}
pub trait Geometry3D<Scalar: Float> {
type Vec3: Vector<Scalar, 3>;
type Vec4: Vector<Scalar, 4>;
type Mat3: SqMatrix3<Scalar>;
type Mat4: SqMatrix4<Scalar>;
type Quat: Quaternion<Scalar>;
type Trans: Transform<Scalar, Self::Vec3, Self::Quat>;
}
pub trait Geometry2D<Scalar: Float> {
type Vec2: Vector<Scalar, 2>;
type Mat2: SqMatrix<Scalar, 2, 4>;
}