use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Scalar:
Add<Self, Output = Self>
+ Copy
+ PartialEq
+ PartialOrd
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Div<Self, Output = Self>
{
const ZERO: Self;
const ONE: Self;
const TWO: Self;
fn abs(self) -> Self;
fn maxx(self, other: Self) -> Self {
if self > other {
self
} else {
other
}
}
fn minn(self, other: Self) -> Self {
if self < other {
self
} else {
other
}
}
}
macro_rules! scalar_unsigned_impl {
($type:ty) => {
impl Scalar for $type {
const ZERO: Self = 0;
const ONE: Self = 1;
const TWO: Self = 2;
fn abs(self) -> Self {
self
}
}
};
}
macro_rules! scalar_signed_impl {
($type:ty) => {
impl Scalar for $type {
const ZERO: Self = 0;
const ONE: Self = 1;
const TWO: Self = 2;
fn abs(self) -> Self {
self.abs()
}
}
};
}
macro_rules! scalar_float_impl {
($type:ty) => {
impl Scalar for $type {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
fn abs(self) -> Self {
self.abs()
}
}
};
}
scalar_unsigned_impl!(u8);
scalar_unsigned_impl!(u16);
scalar_unsigned_impl!(u32);
scalar_unsigned_impl!(u64);
scalar_unsigned_impl!(u128);
scalar_unsigned_impl!(usize);
scalar_signed_impl!(i8);
scalar_signed_impl!(i16);
scalar_signed_impl!(i32);
scalar_signed_impl!(i64);
scalar_signed_impl!(i128);
scalar_signed_impl!(isize);
scalar_float_impl!(f32);
scalar_float_impl!(f64);
pub trait FloatingScalar: Scalar + Mul<Output = Self> + Neg<Output = Self> {
const TAU: Self;
const PI: Self;
const EPSILON: Self;
fn sqrt(self) -> Self;
fn square(self) -> Self {
self * self
}
fn cos(self) -> Self;
fn sin(self) -> Self;
fn tan(self) -> Self {
self.sin() / self.cos()
}
fn atan2(self, other: Self) -> Self;
fn lerp(self, other: Self, t: Self) -> Self {
(Self::ONE - t) * self + t * other
}
fn angle_as_vector(self) -> [Self; 2] {
[self.cos(), self.sin()]
}
fn is_zero(self) -> bool {
self.is_near_zero(Self::ONE)
}
fn is_near_zero(self, n: Self) -> bool {
self.abs() < Self::EPSILON * n
}
}
macro_rules! floating_scalar_impl {
($type:ty, $pi:expr, $epsilon:expr) => {
impl FloatingScalar for $type {
const PI: Self = $pi;
const TAU: Self = $pi * 2.0;
const EPSILON: Self = $epsilon;
fn sqrt(self) -> Self {
Self::sqrt(self)
}
fn cos(self) -> Self {
Self::cos(self)
}
fn sin(self) -> Self {
Self::sin(self)
}
fn atan2(self, other: Self) -> Self {
self.atan2(other)
}
}
};
}
floating_scalar_impl!(f32, std::f32::consts::PI, std::f32::EPSILON);
floating_scalar_impl!(f64, std::f64::consts::PI, std::f64::EPSILON);