ndmath/
scalar.rs

1use std::ops::*;
2
3/// Trait for math with scalar numbers
4pub trait Scalar:
5    Copy
6    + PartialEq
7    + PartialOrd
8    + Add<Self, Output = Self>
9    + Sub<Self, Output = Self>
10    + Mul<Self, Output = Self>
11    + Div<Self, Output = Self>
12    + AddAssign<Self>
13    + SubAssign<Self>
14    + MulAssign<Self>
15    + DivAssign<Self>
16{
17    /// The value of 0
18    const ZERO: Self;
19    /// The value of 1
20    const ONE: Self;
21    /// The value of 2
22    const TWO: Self;
23    /// Get the absolute value of the number
24    fn abs(self) -> Self;
25    /// Get the max of this `Scalar` and another
26    ///
27    /// This function is named to not conflict with the
28    /// `Scalar`'s default `max` function
29    fn maxx(self, other: Self) -> Self {
30        if self > other {
31            self
32        } else {
33            other
34        }
35    }
36    /// Get the min of this `Scalar` and another
37    ///
38    /// This function is named to not conflict with the
39    /// `Scalar`'s default `min` function
40    fn minn(self, other: Self) -> Self {
41        if self < other {
42            self
43        } else {
44            other
45        }
46    }
47}
48
49macro_rules! scalar_unsigned_impl {
50    ($type:ty) => {
51        impl Scalar for $type {
52            const ZERO: Self = 0;
53            const ONE: Self = 1;
54            const TWO: Self = 2;
55            fn abs(self) -> Self {
56                self
57            }
58        }
59    };
60}
61
62macro_rules! scalar_signed_impl {
63    ($type:ty) => {
64        impl Scalar for $type {
65            const ZERO: Self = 0;
66            const ONE: Self = 1;
67            const TWO: Self = 2;
68            fn abs(self) -> Self {
69                self.abs()
70            }
71        }
72    };
73}
74
75macro_rules! scalar_float_impl {
76    ($type:ty) => {
77        impl Scalar for $type {
78            const ZERO: Self = 0.0;
79            const ONE: Self = 1.0;
80            const TWO: Self = 2.0;
81            fn abs(self) -> Self {
82                self.abs()
83            }
84        }
85    };
86}
87
88scalar_unsigned_impl!(u8);
89scalar_unsigned_impl!(u16);
90scalar_unsigned_impl!(u32);
91scalar_unsigned_impl!(u64);
92scalar_unsigned_impl!(u128);
93scalar_unsigned_impl!(usize);
94
95scalar_signed_impl!(i8);
96scalar_signed_impl!(i16);
97scalar_signed_impl!(i32);
98scalar_signed_impl!(i64);
99scalar_signed_impl!(i128);
100scalar_signed_impl!(isize);
101
102scalar_float_impl!(f32);
103scalar_float_impl!(f64);
104
105/// Trait for floating-point scalar numbers
106pub trait FloatingScalar: Scalar {
107    /// The value of Tau, or 2π
108    const TAU: Self;
109    /// The value of π
110    const PI: Self;
111    /// The epsilon value
112    const EPSILON: Self;
113    /// Get the sqare root of the scalar
114    fn sqrt(self) -> Self;
115    /// Square the scalar
116    fn square(self) -> Self {
117        self * self
118    }
119    /// Get the cosine
120    fn cos(self) -> Self;
121    /// Get the sine
122    fn sin(self) -> Self;
123    /// Get the tangent
124    fn tan(self) -> Self {
125        self.sin() / self.cos()
126    }
127    /// Get the four-quadrant arctangent
128    fn atan2(self, other: Self) -> Self;
129    /// Linear interpolate the scalar with another
130    fn lerp(self, other: Self, t: Self) -> Self {
131        (Self::ONE - t) * self + t * other
132    }
133    /// Get the unit vector corresponding to an angle in radians defined by the scalar
134    fn angle_as_vector(self) -> [Self; 2] {
135        [self.cos(), self.sin()]
136    }
137    /// Check if the value is within its epsilon range
138    fn is_zero(self) -> bool {
139        self.is_near_zero(Self::ONE)
140    }
141    /// Check if the value is within a multiple epsilon range
142    fn is_near_zero(self, n: Self) -> bool {
143        self.abs() < Self::EPSILON * n
144    }
145}
146
147macro_rules! floating_scalar_impl {
148    ($type:ty, $pi:expr, $epsilon:expr) => {
149        impl FloatingScalar for $type {
150            const PI: Self = $pi;
151            const TAU: Self = $pi * 2.0;
152            const EPSILON: Self = $epsilon;
153            fn sqrt(self) -> Self {
154                Self::sqrt(self)
155            }
156            fn cos(self) -> Self {
157                Self::cos(self)
158            }
159            fn sin(self) -> Self {
160                Self::sin(self)
161            }
162            fn atan2(self, other: Self) -> Self {
163                self.atan2(other)
164            }
165        }
166    };
167}
168
169floating_scalar_impl!(f32, std::f32::consts::PI, std::f32::EPSILON);
170floating_scalar_impl!(f64, std::f64::consts::PI, std::f64::EPSILON);