bb_geometry/linear_algebra/matrix3x3/
mod.rs

1use crate::linear_algebra::EPSILON;
2use std::ops::{Index, IndexMut, Mul, Sub};
3
4/// Represents a 3x3 linear_algebra with f32 values in row-major order.
5///
6/// Internal representation is `[[f32; 3]; 3]`.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct Matrix3x3 {
9    /// The linear_algebra data stored as an array of arrays (rows).
10    data: [[f32; 3]; 3],
11}
12
13impl Matrix3x3 {
14    /// Creates a new 3x3 linear_algebra from the provided 2D array data.
15    ///
16    /// The data should be in row-major order: `data[row][column]`.
17    ///
18    /// # Example
19    /// ```
20    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
21    /// let linear_algebra = Matrix3x3::new([
22    ///     [1.0, 2.0, 3.0],
23    ///     [4.0, 5.0, 6.0],
24    ///     [7.0, 8.0, 9.0],
25    /// ]);
26    /// assert_eq!(linear_algebra.get(0, 1), 2.0);
27    /// ```
28    pub fn new(data: [[f32; 3]; 3]) -> Self {
29        Self { data }
30    }
31
32    /// Creates an identity linear_algebra (1.0 on the diagonal, 0.0 elsewhere).
33    ///
34    /// # Example
35    /// ```
36    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
37    /// let identity = Matrix3x3::identity();
38    /// assert_eq!(identity.get(0, 0), 1.0);
39    /// assert_eq!(identity.get(1, 1), 1.0);
40    /// assert_eq!(identity.get(0, 1), 0.0);
41    /// ```
42    pub fn identity() -> Self {
43        Self {
44            data: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
45        }
46    }
47
48    /// Creates a zero linear_algebra (all elements are 0.0).
49    ///
50    /// # Example
51    /// ```
52    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
53    /// let zero = Matrix3x3::zero();
54    /// assert_eq!(zero.get(1, 2), 0.0);
55    /// ```
56    pub fn zero() -> Self {
57        Self {
58            data: [[0.0; 3]; 3], // Use array initializer
59        }
60    }
61
62    /// Gets the value at the specified row and column using a method call.
63    ///
64    /// Prefer using the index operator `linear_algebra[(row, col)]` for more idiomatic access.
65    ///
66    /// # Panics
67    /// Panics if `row` or `col` are out of bounds (>= 3).
68    ///
69    /// # Example
70    /// ```
71    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
72    /// let linear_algebra = Matrix3x3::identity();
73    /// assert_eq!(linear_algebra.get(1, 1), 1.0);
74    /// ```
75    #[inline]
76    pub fn get(&self, row: usize, col: usize) -> f32 {
77        assert!(row < 3, "Row index out of bounds: {}", row);
78        assert!(col < 3, "Column index out of bounds: {}", col);
79        self.data[row][col]
80    }
81
82    /// Sets the value at the specified row and column using a method call.
83    ///
84    /// Prefer using the mutable index operator `linear_algebra[(row, col)] = value`
85    /// for more idiomatic modification.
86    ///
87    /// # Panics
88    /// Panics if `row` or `col` are out of bounds (>= 3).
89    ///
90    /// # Example
91    /// ```
92    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
93    /// let mut linear_algebra = Matrix3x3::zero();
94    /// linear_algebra.set(2, 1, 5.0);
95    /// assert_eq!(linear_algebra.get(2, 1), 5.0);
96    /// ```
97    #[inline]
98    pub fn set(&mut self, row: usize, col: usize, value: f32) {
99        assert!(row < 3, "Row index out of bounds: {}", row);
100        assert!(col < 3, "Column index out of bounds: {}", col);
101        self.data[row][col] = value;
102    }
103
104    /// Returns the transpose of the linear_algebra.
105    ///
106    /// The element at `(row, col)` in the original linear_algebra becomes
107    /// the element at `(col, row)` in the transposed linear_algebra.
108    /// Does not modify the original linear_algebra.
109    ///
110    /// # Example
111    /// ```
112    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
113    /// let linear_algebra = Matrix3x3::new([
114    ///     [1.0, 2.0, 3.0],
115    ///     [4.0, 5.0, 6.0],
116    ///     [7.0, 8.0, 9.0],
117    /// ]);
118    /// let transposed = linear_algebra.transpose();
119    /// assert_eq!(transposed.get(0, 1), 4.0); // linear_algebra.get(1, 0)
120    /// assert_eq!(transposed.get(1, 0), 2.0); // linear_algebra.get(0, 1)
121    /// assert_eq!(transposed.get(2, 1), 6.0); // linear_algebra.get(1, 2)
122    /// ```
123    pub fn transpose(&self) -> Self {
124        let mut result_data = [[0.0f32; 3]; 3];
125        for i in 0..3 {
126            for j in 0..3 {
127                result_data[j][i] = self.data[i][j]; // Swap indices
128            }
129        }
130        Self { data: result_data }
131    }
132
133    /// Performs linear_algebra multiplication: `self * other`.
134    ///
135    /// This method delegates to the `*` operator implementation provided by `Mul`.
136    /// Does not modify the original matrices.
137    ///
138    /// # Example
139    /// ```
140    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
141    /// let a = Matrix3x3::new([
142    ///     [1.0, 2.0, 0.0],
143    ///     [3.0, 4.0, 0.0],
144    ///     [0.0, 0.0, 1.0],
145    /// ]);
146    /// let b = Matrix3x3::new([
147    ///     [5.0, 6.0, 0.0],
148    ///     [7.0, 8.0, 0.0],
149    ///     [0.0, 0.0, 1.0],
150    /// ]);
151    /// let result = a.multiply(&b);
152    /// // 1*5 + 2*7 = 19
153    /// assert_eq!(result.get(0, 0), 19.0);
154    /// // 1*6 + 2*8 = 22
155    /// assert_eq!(result.get(0, 1), 22.0);
156    /// // 3*5 + 4*7 = 15 + 28 = 43
157    /// assert_eq!(result.get(1, 0), 43.0);
158    /// // 3*6 + 4*8 = 18 + 32 = 50
159    /// assert_eq!(result.get(1, 1), 50.0);
160    /// ```
161    #[inline]
162    pub fn multiply(&self, other: &Self) -> Self {
163        // Delegate to the Mul trait implementation
164        self * other
165    }
166
167    /// Checks if a linear_algebra has components not exceeding EPSILON.
168    ///
169    /// # Example
170    /// ```
171    /// use crate::bb_geometry::linear_algebra::matrix3x3::*;
172    /// use crate::bb_geometry::linear_algebra::EPSILON;
173    /// let zero_matrix = Matrix3x3::zero();
174    /// let matrix_with_epsilon_entries = Matrix3x3::new([[EPSILON, EPSILON, 0.0], [0.0, 0.0, 0.0], [0.0, EPSILON, 0.0]]);
175    /// let matrix_with_entry_exceeding_epsilon = Matrix3x3::new([[EPSILON, 1.1* EPSILON, 0.0], [0.0, 0.0, 0.0], [0.0, EPSILON, 0.0]]);
176    ///
177    /// let zero_matrix_is_almost_zero = zero_matrix.is_almost_zero();
178    /// let matrix_with_epsilon_entries_almost_zero = matrix_with_epsilon_entries.is_almost_zero();
179    /// let matrix_with_entry_exceeding_epsilon_is_not_almost_zero = !matrix_with_entry_exceeding_epsilon.is_almost_zero();
180    ///
181    /// assert!(zero_matrix_is_almost_zero);
182    /// assert!(matrix_with_epsilon_entries_almost_zero);
183    /// assert!(matrix_with_entry_exceeding_epsilon_is_not_almost_zero);
184    /// ```
185    pub fn is_almost_zero(&self) -> bool {
186        self.data
187            .iter()
188            .all(|row| row.iter().all(|&value| value.abs() <= EPSILON))
189    }
190}
191
192// --- Trait Implementations ---
193
194/// Allows accessing linear_algebra elements using tuple indexing `linear_algebra[(row, col)]`.
195///
196/// # Panics
197/// Panics if `row` or `col` are out of bounds (>= 3).
198///
199/// # Example
200/// ```
201/// use crate::bb_geometry::linear_algebra::matrix3x3::*;
202/// let linear_algebra = Matrix3x3::new([
203///     [1.0, 2.0, 3.0],
204///     [4.0, 5.0, 6.0],
205///     [7.0, 8.0, 9.0],
206/// ]);
207/// assert_eq!(linear_algebra[(1, 2)], 6.0);
208/// ```
209impl Index<(usize, usize)> for Matrix3x3 {
210    type Output = f32;
211
212    #[inline]
213    fn index(&self, index: (usize, usize)) -> &Self::Output {
214        assert!(index.0 < 3, "Row index out of bounds: {}", index.0);
215        assert!(index.1 < 3, "Column index out of bounds: {}", index.1);
216        &self.data[index.0][index.1]
217    }
218}
219
220/// Allows mutating linear_algebra elements using tuple indexing `linear_algebra[(row, col)] = value`.
221///
222/// # Panics
223/// Panics if `row` or `col` are out of bounds (>= 3).
224///
225/// # Example
226/// ```
227/// use crate::bb_geometry::linear_algebra::matrix3x3::*;
228/// let mut linear_algebra = Matrix3x3::zero();
229/// linear_algebra[(2, 1)] = 99.0;
230/// assert_eq!(linear_algebra[(2, 1)], 99.0);
231/// ```
232impl IndexMut<(usize, usize)> for Matrix3x3 {
233    #[inline]
234    fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
235        assert!(index.0 < 3, "Row index out of bounds: {}", index.0);
236        assert!(index.1 < 3, "Column index out of bounds: {}", index.1);
237        &mut self.data[index.0][index.1]
238    }
239}
240
241/// Implements linear_algebra multiplication using the `*` operator (`&Matrix3x3 * &Matrix3x3`).
242///
243/// This is often the most convenient way to perform linear_algebra multiplication.
244///
245/// # Example
246/// ```
247/// use crate::bb_geometry::linear_algebra::matrix3x3::*;
248/// let a = Matrix3x3::identity();
249/// let b = Matrix3x3::new([
250///     [1.0, 2.0, 3.0],
251///     [4.0, 5.0, 6.0],
252///     [7.0, 8.0, 9.0],
253/// ]);
254/// let result = &a * &b; // Multiplying by identity returns the original
255/// assert_eq!(result, b);
256///
257/// let c = Matrix3x3::new([
258///     [2.0, 0.0, 0.0],
259///     [0.0, 3.0, 0.0],
260///     [0.0, 0.0, 1.0],
261/// ]);
262/// let scaled_b = &b * &c; // Scale columns of b
263/// assert_eq!(scaled_b[(0, 0)], 2.0); // 1*2
264/// assert_eq!(scaled_b[(1, 1)], 15.0); // 5*3
265/// assert_eq!(scaled_b[(2, 2)], 9.0); // 9*1
266/// ```
267impl Mul<&Matrix3x3> for &Matrix3x3 {
268    type Output = Matrix3x3;
269
270    fn mul(self, rhs: &Matrix3x3) -> Self::Output {
271        let mut result_data = [[0.0f32; 3]; 3];
272        for i in 0..3 {
273            // Result row
274            for j in 0..3 {
275                // Result column
276                let mut sum = 0.0;
277                for k in 0..3 {
278                    // Inner dimension K
279                    // Accessing via internal data:
280                    sum += self.data[i][k] * rhs.data[k][j];
281                }
282                result_data[i][j] = sum;
283            }
284        }
285        Matrix3x3 { data: result_data }
286    }
287}
288
289// Optional: Implement multiplication for owned values as well, typically by delegating
290impl Mul<Matrix3x3> for Matrix3x3 {
291    type Output = Matrix3x3;
292
293    #[inline]
294    fn mul(self, rhs: Matrix3x3) -> Self::Output {
295        // Delegate to the reference implementation
296        &self * &rhs
297    }
298}
299
300impl Mul<&Matrix3x3> for Matrix3x3 {
301    type Output = Matrix3x3;
302
303    #[inline]
304    fn mul(self, rhs: &Matrix3x3) -> Self::Output {
305        &self * rhs
306    }
307}
308
309impl Mul<Matrix3x3> for &Matrix3x3 {
310    type Output = Matrix3x3;
311
312    #[inline]
313    fn mul(self, rhs: Matrix3x3) -> Self::Output {
314        self * &rhs
315    }
316}
317
318impl Sub<&Matrix3x3> for &Matrix3x3 {
319    type Output = Matrix3x3;
320    #[inline]
321    fn sub(self, rhs: &Matrix3x3) -> Self::Output {
322        Matrix3x3::new([
323            [
324                self[(0, 0)] - rhs[(0, 0)],
325                self[(0, 1)] - rhs[(0, 1)],
326                self[(0, 2)] - rhs[(0, 2)],
327            ],
328            [
329                self[(1, 0)] - rhs[(1, 0)],
330                self[(1, 1)] - rhs[(1, 1)],
331                self[(1, 2)] - rhs[(1, 2)],
332            ],
333            [
334                self[(2, 0)] - rhs[(2, 0)],
335                self[(2, 1)] - rhs[(2, 1)],
336                self[(2, 2)] - rhs[(2, 2)],
337            ],
338        ])
339    }
340}
341
342impl Sub<Matrix3x3> for Matrix3x3 {
343    type Output = Matrix3x3;
344    #[inline]
345    fn sub(self, rhs: Matrix3x3) -> Self::Output {
346        &self - &rhs
347    }
348}
349
350impl Sub<&Matrix3x3> for Matrix3x3 {
351    type Output = Matrix3x3;
352    #[inline]
353    fn sub(self, rhs: &Matrix3x3) -> Self::Output {
354        &self - rhs
355    }
356}
357
358impl Sub<Matrix3x3> for &Matrix3x3 {
359    type Output = Matrix3x3;
360    #[inline]
361    fn sub(self, rhs: Matrix3x3) -> Self::Output {
362        self - &rhs
363    }
364}