Skip to main content

rsm_lib/
mat2.rs

1use num_traits::{
2    NumAssign, Float
3};
4
5use std::slice::{
6    Iter,
7    IterMut
8};
9
10use std::ops::{
11    Neg, Add, Sub, Mul, Div,
12    Index, IndexMut
13};
14
15use crate::vec2::Vec2;
16
17use std::fmt;
18
19#[derive(Debug, Default, Copy, Clone, PartialEq)]
20pub struct Mat2<T> (
21    pub Vec2<T>,
22    pub Vec2<T>,
23);
24
25impl<T> Mat2<T>
26where
27    T: NumAssign + Copy,
28{
29    /// Creates a new 2x2 matrix from two column vectors.
30    ///
31    /// # Parameters
32    /// - `col0`: The first column of the matrix.
33    /// - `col1`: The second column of the matrix.
34    ///
35    /// # Returns
36    /// Returns a new `Mat2` instance with the specified columns.
37    ///
38    /// # Examples
39    /// ```
40    /// let col0 = Vec2::new(1.0, 2.0);
41    /// let col1 = Vec2::new(3.0, 4.0);
42    /// let matrix = Mat2::new(&col0, &col1);
43    /// ```
44    #[inline]
45    pub fn new(col0: &Vec2<T>, col1: &Vec2<T>) -> Self {
46        Self(col0.clone(), col1.clone())
47    }
48
49    /// Creates a 2x2 zero matrix.
50    ///
51    /// This method returns a matrix with all elements set to zero.
52    ///
53    /// # Returns
54    /// Returns a `Mat2` instance with all elements as zero.
55    ///
56    /// # Examples
57    /// ```
58    /// let matrix = Mat2::zero();
59    /// ```
60    #[inline]
61    pub fn zero() -> Self {
62        Self(
63            Vec2::zero(),
64            Vec2::zero(),
65        )
66    }
67
68    /// Creates a 2x2 identity matrix.
69    ///
70    /// The identity matrix has ones on the diagonal and zeros elsewhere. It is the multiplicative identity 
71    /// for matrix multiplication.
72    ///
73    /// # Returns
74    /// Returns a `Mat2` instance with ones on the diagonal and zeros elsewhere.
75    ///
76    /// # Examples
77    /// ```
78    /// let matrix = Mat2::identity();
79    /// ```
80    #[inline]
81    pub fn identity() -> Self {
82        Self(
83            Vec2::new(T::one(), T::zero()),
84            Vec2::new(T::zero(), T::one()),
85        )
86    }
87
88    /// Transposes the matrix.
89    ///
90    /// The transpose of a matrix is obtained by swapping its rows and columns.
91    ///
92    /// # Returns
93    /// Returns a new `Mat2` instance that is the transpose of the original matrix.
94    ///
95    /// # Examples
96    /// ```
97    /// let matrix = Mat2::identity();
98    /// let transposed = matrix.transpose();
99    /// ```
100    #[inline]
101    pub fn transpose(&self) -> Self {
102        Self(
103            Vec2::new(self.0.x, self.1.x),
104            Vec2::new(self.0.y, self.1.y),
105        )
106    }
107
108    /// Computes the determinant of the matrix.
109    ///
110    /// The determinant is a scalar value that can be used to determine if the matrix is invertible. 
111    /// For a 2x2 matrix, the determinant is computed as:
112    ///
113    /// `det = (a00 * a11 - a01 * a10)`
114    ///
115    /// # Returns
116    /// Returns the determinant of the matrix.
117    ///
118    /// # Examples
119    /// ```
120    /// let matrix = Mat2::new(&Vec2::new(1.0, 2.0), &Vec2::new(3.0, 4.0));
121    /// let det = matrix.determinant();
122    /// assert_eq!(det, -2.0);
123    /// ```
124    pub fn determinant(&self) -> T {
125        self.0.x * self.1.y - self.0.y * self.1.x
126    }
127
128    /// Computes the trace of the matrix.
129    ///
130    /// The trace of a matrix is the sum of its diagonal elements. For a 2x2 matrix, the trace is computed as:
131    ///
132    /// `trace = a00 + a11`
133    ///
134    /// # Returns
135    /// Returns the trace of the matrix.
136    ///
137    /// # Examples
138    /// ```
139    /// let matrix = Mat2::new(&Vec2::new(1.0, 2.0), &Vec2::new(3.0, 4.0));
140    /// let trace = matrix.trace();
141    /// assert_eq!(trace, 5.0);
142    /// ```
143    pub fn trace(&self) -> T {
144        self.0.x + self.1.y
145    }
146
147    /// Multiplies this matrix with another 2x2 matrix.
148    ///
149    /// Matrix multiplication is performed using the formula:
150    ///
151    /// ```
152    /// C[0][0] = A[0][0] * B[0][0] + A[1][0] * B[0][1]
153    /// C[0][1] = A[0][1] * B[0][0] + A[1][1] * B[0][1]
154    /// C[1][0] = A[0][0] * B[1][0] + A[1][0] * B[1][1]
155    /// C[1][1] = A[0][1] * B[1][0] + A[1][1] * B[1][1]
156    /// ```
157    ///
158    /// # Parameters
159    /// - `other`: The matrix to multiply with.
160    ///
161    /// # Returns
162    /// Returns a new `Mat2` instance that is the result of the matrix multiplication.
163    ///
164    /// # Examples
165    /// ```
166    /// let a = Mat2::new(&Vec2::new(1.0, 2.0), &Vec2::new(3.0, 4.0));
167    /// let b = Mat2::new(&Vec2::new(5.0, 6.0), &Vec2::new(7.0, 8.0));
168    /// let c = a.mul(&b);
169    /// assert_eq!(c.0, Vec2::new(19.0, 22.0));
170    /// assert_eq!(c.1, Vec2::new(43.0, 50.0));
171    /// ```
172    pub fn mul(&self, other: &Self) -> Self {
173        let col0 = Vec2::new(
174            self.0.x * other.0.x + self.1.x * other.0.y,
175            self.0.y * other.0.x + self.1.y * other.0.y,
176        );
177        let col1 = Vec2::new(
178            self.0.x * other.1.x + self.1.x * other.1.y,
179            self.0.y * other.1.x + self.1.y * other.1.y,
180        );
181        Self::new(&col0, &col1)
182    }
183
184    /// Scales the matrix by a given 2D vector.
185    ///
186    /// This method scales the matrix by multiplying its elements according to the given scale vector. 
187    /// The scaling affects only the diagonal elements of the matrix.
188    ///
189    /// # Parameters
190    /// - `scale`: The 2D vector to scale the matrix by.
191    ///
192    /// # Examples
193    /// ```
194    /// let mut matrix = Mat2::identity();
195    /// matrix.scale(Vec2::new(2.0, 3.0));
196    /// assert_eq!(matrix.0, Vec2::new(2.0, 0.0));
197    /// assert_eq!(matrix.1, Vec2::new(0.0, 3.0));
198    /// ```
199    #[inline]
200    pub fn scale(&mut self, scale: Vec2<T>) {
201        self.0.x *= scale.x;
202        self.1.y *= scale.y;
203    }
204}
205
206impl<T> Mat2<T>
207where
208    T: NumAssign + Float,
209{
210    /// Applies a rotation transformation to the matrix by the specified angle.
211    ///
212    /// This method performs a rotation of the matrix elements by an angle, effectively rotating
213    /// the coordinate system represented by the matrix. The rotation is applied using a counter-clockwise
214    /// rotation matrix. The rotation is applied to the matrix as follows:
215    ///
216    /// ```
217    /// R = [ c -s ]
218    ///     [ s  c ]
219    /// ```
220    /// where `c = cos(angle)` and `s = sin(angle)`.
221    ///
222    /// # Parameters
223    /// - `angle`: The angle of rotation in radians. Positive values rotate counter-clockwise,
224    ///   and negative values rotate clockwise.
225    ///
226    /// # Examples
227    /// ```
228    /// let mut matrix = Mat2::identity();
229    /// matrix.rotation(0.5); // Rotate by 0.5 radians
230    /// assert_eq!(matrix[0][0], 0.8775825618903728); // cos(0.5)
231    /// assert_eq!(matrix[0][1], -0.479425538604203); // -sin(0.5)
232    /// assert_eq!(matrix[1][0], 0.479425538604203); // sin(0.5)
233    /// assert_eq!(matrix[1][1], 0.8775825618903728); // cos(0.5)
234    /// ```
235    pub fn rotation(&mut self, angle: T) {
236        let c = angle.cos();
237        let s = angle.sin();
238
239        let new_x0 = c * self[0][0] - s * self[1][0];
240        let new_x1 = c * self[0][1] - s * self[1][1];
241
242        let new_y0 = s * self[0][0] + c * self[1][0];
243        let new_y1 = s * self[0][1] + c * self[1][1];
244
245        self[0][0] = new_x0;
246        self[0][1] = new_x1;
247
248        self[1][0] = new_y0;
249        self[1][1] = new_y1;
250    }
251}
252
253impl<T> fmt::Display for Mat2<T>
254where
255    T: fmt::Display,
256{
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        writeln!(f, "[{}, {}]", self.0, self.1)
259    }
260}
261
262impl<T> Index<usize> for Mat2<T> {
263    type Output = Vec2<T>;
264
265    #[inline]
266    fn index(&self, index: usize) -> &Self::Output {
267        match index {
268            0 => &self.0,
269            1 => &self.1,
270            _ => panic!("Index out of bounds for Mat2"),
271        }
272    }
273}
274
275impl<T> IndexMut<usize> for Mat2<T> {
276    #[inline]
277    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
278        match index {
279            0 => &mut self.0,
280            1 => &mut self.1,
281            _ => panic!("Index out of bounds for Mat2"),
282        }
283    }
284}
285
286impl<'a, T> IntoIterator for &'a Mat2<T>
287where
288    T: NumAssign + Copy
289{
290    type Item = &'a Vec2<T>;
291    type IntoIter = Iter<'a, Vec2<T>>;
292
293    #[inline]
294    fn into_iter(self) -> Self::IntoIter {
295        let slice: &[Vec2<T>; 2] = unsafe { std::mem::transmute(self) };
296        slice.iter()
297    }
298}
299
300impl<'a, T> IntoIterator for &'a mut Mat2<T>
301where
302    T: NumAssign + Copy
303{
304    type Item = &'a mut Vec2<T>;
305    type IntoIter = IterMut<'a, Vec2<T>>;
306
307    #[inline]
308    fn into_iter(self) -> Self::IntoIter {
309        let slice: &mut [Vec2<T>; 2] = unsafe { std::mem::transmute(self) };
310        slice.iter_mut()
311    }
312}
313
314impl<T> Neg for Mat2<T>
315where
316    T: NumAssign + Copy + Neg<Output = T>,
317{
318    type Output = Self;
319
320    fn neg(self) -> Self::Output {
321        Self (
322            -self.0,
323            -self.1
324        )
325    }
326}
327
328impl<T> Add<Mat2<T>> for Mat2<T>
329where
330    T: NumAssign + Copy,
331{
332    type Output = Self;
333
334    fn add(self, other: Self) -> Self {
335        Self (
336            self.0 + other.0,
337            self.1 + other.1
338        )
339    }
340}
341
342impl<T> Sub<Mat2<T>> for Mat2<T>
343where
344    T: NumAssign + Copy,
345{
346    type Output = Self;
347
348    fn sub(self, other: Self) -> Self {
349        Self (
350            self.0 - other.0,
351            self.1 - other.1
352        )
353    }
354}
355
356impl<T> Mul<Mat2<T>> for Mat2<T>
357where
358    T: NumAssign + Copy,
359{
360    type Output = Mat2<T>;
361
362    #[inline]
363    fn mul(self, other: Mat2<T>) -> Mat2<T> {
364        Self::mul(&self, &other)
365    }
366}
367
368impl<T> Mul<T> for Mat2<T>
369where
370    T: NumAssign + Copy,
371{
372    type Output = Self;
373
374    fn mul(self, scalar: T) -> Self {
375        Self (
376            self.0 * scalar,
377            self.1 * scalar
378        )
379    }
380}
381
382impl<T> Div<T> for Mat2<T>
383where
384    T: NumAssign + Copy,
385{
386    type Output = Self;
387
388    fn div(self, scalar: T) -> Self {
389        Self (
390            self.0 / scalar,
391            self.1 / scalar
392        )
393    }
394}