mod v2d;
mod v3d;
use core::{
ops::{ Add, Sub, Mul, Div, Rem, Neg, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, Index, IndexMut },
f32::consts::FRAC_PI_2,
fmt::{ self, Debug, Display }
};
#[cfg(feature = "alloc")]
use alloc::{ vec::Vec, vec };
use crate::vectorized::Vectorized;
use crate::scalar::{ Scalar, FloatScalar, SignedScalar, IntScalar };
pub use v2d::{ Axis2, Vec2, Vectorized2D };
pub use v3d::{ Axis3, SignedAxis3, Vec3, Vectorized3D };
pub trait VectorAbstract<T: Scalar + Vectorized<T, V>, V: VectorAbstract<T, V>>
where
Self:
Vectorized<T, V> +
Clone + Copy + PartialEq + PartialOrd + Default + Display + Debug +
Add + Sub + Mul + Div + Rem + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign +
Add<Output = V> + Sub<Output = V> + Mul<Output = V> + Div<Output = V> + Rem<Output = V> +
Add<T, Output = V> + Sub<T, Output = V> + Mul<T, Output = V> + Div<T, Output = V> + Rem<T, Output = V>
{}
pub trait Vector<T: Scalar + Vectorized<T, V>, V: Vector<T, V, A>, A>: VectorAbstract<T, V> {
const ZERO: V;
const ONE: V;
fn identity(&self) -> V;
fn rank() -> usize;
#[cfg(feature = "alloc")]
fn to_vec(&self) -> Vec<T>;
fn sum(&self) -> T;
fn product(&self) -> T;
fn dot(&self, other: V) -> T;
fn average(&self) -> T {
self.sum() / T::from(Self::rank()).unwrap()
}
fn argmax(&self) -> A;
fn argmin(&self) -> A;
fn max<I: Vectorized<T, V>>(&self, other: I) -> V;
fn min<I: Vectorized<T, V>>(&self, other: I) -> V;
fn clamp<I: Vectorized<T, V>>(&self, min: I, max: I) -> V;
}
pub trait SignedVector<T: SignedScalar + Vectorized<T, V>, V: SignedVector<T, V, A, C>, A, C: Vectorized<T, V>>: Vector<T, V, A>
where
Self: Neg<Output = V> {
fn signum(&self) -> V;
fn abs(&self) -> V;
fn cross(&self, other: V) -> C;
}
pub trait IntVector<T: IntScalar<T> + Vectorized<T, V>, V: IntVector<T, V, A>, A>: Vector<T, V, A> {
fn pow<I: Vectorized<T, V>>(&self, pow: I) -> V;
fn log<I: Vectorized<T, V>>(&self, base: I) -> V;
}
pub trait FloatVector<T: FloatScalar + Vectorized<T, V>, V: FloatVector<T, V, A, C>, A, C: Vectorized<T, V>>: SignedVector<T, V, A, C> {
fn angle_to(&self, other: V) -> T {
let cross: C = self.cross(other);
match cross.attempt_get_scalar() {
Some(cross_scalar) => -cross_scalar.atan2(self.dot(other)),
None => -cross.dvec().length().atan2(self.dot(other))
}
}
fn to_radians(&self) -> V;
fn to_degrees(&self) -> V;
fn sin(&self) -> V;
fn cos(&self) -> V;
fn tan(&self) -> V;
fn asin(&self) -> V;
fn acos(&self) -> V;
fn atan(&self) -> V;
fn csc(&self) -> V {
T::one().dvec() / self.sin()
}
fn sec(&self) -> V {
T::one().dvec() / self.cos()
}
fn cot(&self) -> V {
T::one().dvec() / self.tan()
}
fn acsc(&self) -> V {
(T::one().dvec() / self.identity()).asin()
}
fn asec(&self) -> V {
(T::one().dvec() / self.identity()).acos()
}
fn acot(&self) -> V {
(T::one().dvec() / self.identity()).atan()
}
fn magnitude_squared(&self) -> T {
self.pow2().sum()
}
fn magnitude(&self) -> T {
self.magnitude_squared().sqrt()
}
fn length(&self) -> T {
self.magnitude()
}
fn inv_magnitude(&self) -> T {
self.identity().dot(self.identity()).inv_sqrt()
}
fn inv_length(&self) -> T {
self.inv_magnitude()
}
fn limit(&self, limit: T) -> V {
if self.magnitude() <= limit {
return self.identity();
}
let scale: T = limit / self.magnitude();
self.identity() * scale
}
fn normalized(&self) -> V {
self.identity() * self.inv_magnitude()
}
fn unit(&self) -> V {
self.normalized()
}
fn reflect(&self, normal: V) -> V {
let normals_normalized: V = normal.normalized();
let alignment: T = self.dot(normals_normalized);
self.identity() - (normals_normalized * alignment * T::from(2).unwrap())
}
fn bounce(&self, normal: V) -> V {
self.reflect(normal)
}
fn refract(&self, normal: V, refraction_index: T) -> V {
let normals_normalized: V = normal.normalized();
let alignment: T = self.dot(normals_normalized);
let discriminant: T = T::one() - refraction_index * refraction_index * (T::one() - alignment * alignment);
if discriminant < T::zero() {
T::zero().dvec()
} else { (self.identity() * refraction_index) - (normals_normalized * (refraction_index * alignment + discriminant.sqrt()))
}
}
fn direction_to(&self, other: V) -> V {
(other - self.identity()).normalized()
}
fn distance_squared_to(&self, other: V) -> T;
fn distance_to(&self, other: V) -> T {
self.distance_squared_to(other).sqrt()
}
fn move_towards(&self, target: V, delta: T) -> V {
let direction: V = self.direction_to(target);
let position: V = self.identity() + (direction * delta);
position.min(target)
}
fn lerp(&self, other: V, t: T) -> V {
let identity: V = self.identity();
identity + (other - identity) * t
}
fn smoothstep<I: Vectorized<T, V>>(&self, a: I, b: I) -> V;
fn bezier_derivative(&self, control_1: V, control_2: V, terminal: V, t: T) -> V;
fn bezier_sample(&self, control_1: V, control_2: V, terminal: V, t: T) -> V;
fn cubic_interpolate(&self, b: V, pre_a: V, post_b: V, weight: T) -> V;
fn cubic_interpolate_in_time(&self, b: V, pre_a: V, post_b: V, weight: T, b_t: T, pre_a_t: T, post_b_t: T) -> V;
fn slide(&self, normal: V) -> V {
self.identity() - (normal * self.dot(normal))
}
fn project(&self, other: V) -> V {
let scalar_projection: T = self.dot(other) / other.magnitude();
let unit: V = other.unit();
unit * scalar_projection
}
fn sqrt(&self) -> V;
fn inv_sqrt(&self) -> V {
T::one().dvec() / self.sqrt()
}
fn pow2(&self) -> V;
fn pow<I: Vectorized<T, V>>(&self, pow: I) -> V;
fn exp(&self) -> V {
T::E().dvec().pow(self.identity())
}
fn log<I: Vectorized<T, V>>(&self, base: I) -> V;
fn ln(&self) -> V {
self.log(T::E())
}
fn floor(&self) -> V;
fn ceil(&self) -> V;
fn round(&self) -> V;
fn snap_to(&self, multiple: V) -> V {
let diff: V = self.identity() % multiple;
self.identity() - diff
}
fn fract(&self) -> V {
self.identity() - self.floor()
}
fn approx_eq(&self, other: V) -> bool;
fn is_finite(&self) -> bool {
self.sum().is_finite() }
fn is_nan(&self) -> bool {
self.sum().is_nan()
}
fn is_normalized(&self) -> bool {
self.magnitude().approx_eq(T::one())
}
fn is_zero_approx(&self) -> bool {
self.approx_eq(T::zero().dvec())
}
}