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}