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}