Skip to main content

care_game/
math.rs

1use nalgebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4};
2
3#[cfg(not(feature = "f64"))]
4/// Floating point type used by the library
5pub type Fl = f32;
6#[cfg(not(feature = "f64"))]
7pub use std::f32 as std_fl;
8#[cfg(feature = "f64")]
9/// Floating point type used by the library
10pub type Fl = f64;
11#[cfg(feature = "f64")]
12pub use std::f64 as std_fl;
13
14/// Trait for numbers
15pub trait IntoFl {
16    /// Convert into a float
17    fn into_fl(self) -> Fl;
18}
19
20macro_rules! impl_into_fl {
21    ($ty:ident) => {
22        impl IntoFl for $ty {
23            fn into_fl(self) -> Fl {
24                self as Fl
25            }
26        }
27    };
28}
29
30impl_into_fl!(f32);
31impl_into_fl!(f64);
32impl_into_fl!(u8);
33impl_into_fl!(i8);
34impl_into_fl!(u16);
35impl_into_fl!(i16);
36impl_into_fl!(u32);
37impl_into_fl!(i32);
38impl_into_fl!(u64);
39impl_into_fl!(i64);
40impl_into_fl!(u128);
41impl_into_fl!(i128);
42impl_into_fl!(usize);
43impl_into_fl!(isize);
44
45#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
46/// A vector of 2 floating point numbers
47pub struct Vec2(pub Vector2<Fl>);
48#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
49/// A vector of 3 floating point numbers
50pub struct Vec3(pub Vector3<Fl>);
51#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
52/// A vector of 4 floating point numbers
53pub struct Vec4(pub Vector4<Fl>);
54#[derive(Debug, Clone, PartialEq, PartialOrd)]
55/// A 2x2 matrix of floating point numbers
56pub struct Mat2(pub Matrix2<Fl>);
57#[derive(Debug, Clone, PartialEq, PartialOrd)]
58/// A 3x3 matrix of floating point numbers
59pub struct Mat3(pub Matrix3<Fl>);
60#[derive(Debug, Clone, PartialEq, PartialOrd)]
61/// A 4x4 matrix of floating point numbers
62pub struct Mat4(pub Matrix4<Fl>);
63
64macro_rules! impl_vec_n {
65    ( $vec:ident, $inner:ident; $( $name:ident: $ty_name:ident ),* ) => {
66        impl $vec {
67            #[inline(always)]
68            /// Create a vector from a set of numbers
69            pub fn new( $($name: impl IntoFl,)* ) -> Self {
70                Self($inner::new( $($name.into_fl(),)* ))
71            }
72            $(
73                #[inline(always)]
74                /// Access a component of this vector
75                pub fn $name(&self) -> Fl {
76                    self.0.$name
77                }
78            )*
79        }
80        impl<$($ty_name: IntoFl,)*> From<($($ty_name,)*)> for $vec {
81            #[inline(always)]
82            /// Convert from a tuple of numbers to a vector
83            fn from(($($name,)*): ($($ty_name,)*)) -> Self {
84                Self::new($($name,)*)
85            }
86        }
87
88        impl ::std::ops::Add<$vec> for $vec {
89            type Output = $vec;
90
91            #[inline(always)]
92            /// Add two vectors (component-wise)
93            fn add(self, rhs: Self) -> Self::Output {
94                Self::new($(self.$name() + rhs.$name(),)*)
95            }
96        }
97
98        impl ::std::ops::Sub<$vec> for $vec {
99            type Output = $vec;
100
101            #[inline(always)]
102            /// Subtract two vectors (component-wise)
103            fn sub(self, rhs: Self) -> Self::Output {
104                Self::new($(self.$name() - rhs.$name(),)*)
105            }
106        }
107
108        impl ::std::ops::Mul<$vec> for $vec {
109            type Output = $vec;
110
111            #[inline(always)]
112            /// Multiply two vectors (component-wise)
113            fn mul(self, rhs: Self) -> Self::Output {
114                Self::new($(self.$name() * rhs.$name(),)*)
115            }
116        }
117
118        impl ::std::ops::Mul<Fl> for $vec {
119            type Output = $vec;
120
121            #[inline(always)]
122            /// Multiply a vector with a number
123            fn mul(self, rhs: Fl) -> Self::Output {
124                Self(self.0 * rhs)
125            }
126        }
127
128        impl ::std::ops::Div<$vec> for $vec {
129            type Output = $vec;
130
131            #[inline(always)]
132            /// Divide two vectors (component-wise)
133            fn div(self, rhs: Self) -> Self::Output {
134                Self::new($(self.$name() / rhs.$name(),)*)
135            }
136        }
137
138        impl ::std::ops::Div<Fl> for $vec {
139            type Output = $vec;
140
141            #[inline(always)]
142            /// Divide a vector by a number
143            fn div(self, rhs: Fl) -> Self::Output {
144                Self(self.0 / rhs)
145            }
146        }
147    };
148}
149
150impl_vec_n!(Vec2, Vector2; x: T, y: U);
151impl_vec_n!(Vec3, Vector3; x: T, y: U, z: V);
152impl_vec_n!(Vec4, Vector4; x: T, y: U, z: V, w: W);
153
154impl Mat4 {
155    /// 4x4 identity matrix
156    pub fn ident() -> Self {
157        Mat4(Matrix4::identity())
158    }
159}
160
161impl std::ops::Mul<Vec3> for &Mat4 {
162    type Output = Vec3;
163
164    fn mul(self, rhs: Vec3) -> Self::Output {
165        Vec3((self.0 * Vector4::new(rhs.0.x, rhs.0.y, rhs.0.z, 1.0)).xyz())
166    }
167}
168
169impl std::ops::Mul<Vec4> for &Mat4 {
170    type Output = Vec4;
171
172    fn mul(self, rhs: Vec4) -> Self::Output {
173        Vec4(self.0 * rhs.0)
174    }
175}
176
177impl Mat3 {
178    /// 3x3 identity matrix
179    pub fn ident() -> Self {
180        Mat3(Matrix3::identity())
181    }
182}
183
184impl std::ops::Mul<Vec2> for &Mat3 {
185    type Output = Vec2;
186
187    fn mul(self, rhs: Vec2) -> Self::Output {
188        Vec2((self.0 * Vector3::new(rhs.0.x, rhs.0.y, 1.0)).xy())
189    }
190}
191
192impl std::ops::Mul<Vec3> for &Mat3 {
193    type Output = Vec3;
194
195    fn mul(self, rhs: Vec3) -> Self::Output {
196        Vec3(self.0 * rhs.0)
197    }
198}
199
200impl Mat2 {
201    /// 2x2 identity matrix
202    pub fn ident() -> Self {
203        Mat2(Matrix2::identity())
204    }
205    /// Create a new matrix from the 4 components, column major
206    pub fn new(x1: impl IntoFl, y1: impl IntoFl, x2: impl IntoFl, y2: impl IntoFl) -> Self {
207        Mat2(Matrix2::new(
208            x1.into_fl(),
209            y1.into_fl(),
210            x2.into_fl(),
211            y2.into_fl(),
212        ))
213    }
214}
215
216impl Vec2 {
217    #[inline]
218    /// Return a version of this vector that has been rotated by `rotation` radians clockwise
219    pub fn rotated(&self, rotation: Fl) -> Self {
220        let (s, c) = (rotation.sin(), rotation.cos());
221        Self::new(self.0.x * c + self.0.y * s, self.0.y * c - self.0.x * s)
222    }
223    /// Return a version of this vector that's been rotated by 90 degrees clockwise
224    pub fn tangent(&self) -> Self {
225        Self::new(self.0.y, -self.0.x)
226    }
227    /// Return the euclidian length (l1 norm) of this vector
228    pub fn length(&self) -> Fl {
229        (self.0.x.powi(2) + self.0.y.powi(2)).sqrt()
230    }
231    /// Return the euclidian length (l1 norm) of this vector
232    pub fn normalize_or(&self, other: Vec2) -> Self {
233        if self.length() <= 0.000001 {
234            other
235        } else {
236            *self / self.length()
237        }
238    }
239}
240
241impl std::ops::Mul<Vec2> for &Mat2 {
242    type Output = Vec2;
243
244    fn mul(self, rhs: Vec2) -> Self::Output {
245        Vec2(self.0 * rhs.0)
246    }
247}
248
249/// Good set of default imports
250pub mod prelude {
251    pub use super::Fl;
252    pub use super::Mat2;
253    pub use super::Mat3;
254    pub use super::Mat4;
255    pub use super::Vec2;
256    pub use super::Vec3;
257    pub use super::Vec4;
258}