lina/mat/
linear.rs

1use std::{array, fmt, ops, marker::PhantomData};
2use bytemuck::{Pod, Zeroable};
3
4use crate::{Point, Scalar, Vector, Float, cross, HcMatrix, HcPoint, Space, WorldSpace, dot, Dir};
5
6
7/// A linear transformatin matrix with `C` columns and `R` rows. Represents a
8/// linear transformation on cartesian coordinates from `Src` to `Dst`.
9///
10/// This type does not implement `ops::Index[Mut]`. Instead, there are two main
11/// ways to access elements. Use whatever you prefer, but keep in mind that
12/// code is read more often than it is written, so the first option is likely
13/// better as it avoids ambiguity.
14/// - [`Self::row`] and [`Self::col`]: `matrix.row(2).col(0)`
15/// - [`Self::elem`]: `matrix.elem(2, 0)`
16///
17///
18/// # Matrices as transformations
19///
20/// Matrices in computer graphics are usually used to represent and carry out
21/// *transformations*. In its simplest form, a matrix can represent a
22/// *linear* transformation, which includes rotation and scaling, but *not*
23/// translation. This is what this type represents.
24///
25/// To represent non-linear transformations (translations & projections), one
26/// needs to use [homogeneous coordinates][hc-wiki]. To represent such a
27/// transformation, use [`HcMatrix`].
28///
29/// To learn more about this whole topic, I strongly recommend watching
30/// [3blue1brown's series "Essence of Linear Algebra"][3b1b-lina], in particular
31/// [Chapter 3: Linear transformations and matrices][3b1b-transform].
32///
33///
34/// ## Transforming a point or vector
35///
36/// Mathematically, to apply a transformation to a vector/point, you multiply
37/// the matrix with the vector/point: `matrix * vec`. The relevant operator is
38/// defined, so you can just do that in Rust as well. Alternatively, you can
39/// use [`Matrix::transform`], which does exactly the same.
40///
41///
42/// ## Combining transformations
43///
44/// Oftentimes you want to apply multiple transformations to a set of points or
45/// vectors. You can save processing time by combining all transformation
46/// matrices into a single matrix. That's the beauty and convenience of
47/// representing transformations as matrix: it's always possible to combine all
48/// of them into a single matrix.
49///
50/// Mathematically, this composition is *matrix multiplication*: `A * B` results
51/// in a matrix that represents the combined transformation of *first* `B`,
52/// *then* `A`. Matrix multiplication is not commutative, i.e. the order of
53/// operands matters. And it's also in an non-intuitive order, with the
54/// rightmost transformation being applied first. For that reason, you can also
55/// use [`Matrix::and_then`] instead of the overloaded operator `*`. Use what
56/// you think is easier to read.
57///
58///
59/// [3b1b-lina]: https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab
60/// [3b1b-transform]: https://www.youtube.com/watch?v=kYB8IZa5AuE
61/// [hc-wiki]: https://en.wikipedia.org/wiki/Homogeneous_coordinates#Use_in_computer_graphics_and_computer_vision
62///
63///
64/// ## `fmt::Debug` output
65///
66/// Setting the alternative flag `#` for debug output is recommended to have a
67/// properly formatted matrix. In order to avoid ambiguity when using
68/// single-line mode, a `row<i>` is prefixed to each row.
69///
70/// ```
71/// use lina::Mat3;
72///
73/// let m = <Mat3<_>>::from_rows([
74///     [1, 2, 3],
75///     [4, 5, 6],
76///     [7, 8, 9],
77/// ]);
78///
79/// // Formatting without `#` alternate flag (one line)
80/// assert_eq!(
81///     format!("{m:?}"),
82///     "Matrix [row0 [1, 2, 3], row1 [4, 5, 6], row2 [7, 8, 9]]",
83/// );
84///
85/// // Formatting with `#` alternate flag (multi line)
86/// assert_eq!(format!("{m:#?}"), concat!(
87///     "Matrix [\n",
88///     "    [1, 2, 3],\n",
89///     "    [4, 5, 6],\n",
90///     "    [7, 8, 9],\n",
91///     "]",
92/// ));
93/// ```
94#[repr(transparent)]
95pub struct Matrix<
96    T: Scalar,
97    const C: usize,
98    const R: usize,
99    Src: Space = WorldSpace,
100    Dst: Space = WorldSpace,
101>(pub(super) [[T; R]; C], PhantomData<(Src, Dst)>);
102
103pub(super) type MatrixStorage<T, const C: usize, const R: usize> = [[T; R]; C];
104
105/// A 3×3 linear transformation matrix.
106pub type Mat3<T, Src = WorldSpace, Dst = WorldSpace> = Matrix<T, 3, 3, Src, Dst>;
107/// A 2×2 linear transformation matrix.
108pub type Mat2<T, Src = WorldSpace, Dst = WorldSpace> = Matrix<T, 2, 2, Src, Dst>;
109
110/// A 3×3 linear transformation matrix with `f32` elements.
111pub type Mat3f<Src = WorldSpace, Dst = WorldSpace> = Mat3<f32, Src, Dst>;
112
113/// A 2×2 linear transformation matrix with `f32` elements.
114pub type Mat2f<Src = WorldSpace, Dst = WorldSpace> = Mat2<f32, Src, Dst>;
115
116
117impl<T: Scalar, const C: usize, const R: usize, Src: Space, Dst: Space> Matrix<T, C, R, Src, Dst> {
118    fn new_impl(data: [[T; R]; C]) -> Self {
119        Self(data, PhantomData)
120    }
121
122    /// Returns a matrix with all elements being zero.
123    pub fn zero() -> Self {
124        Self::new_impl([[T::zero(); R]; C])
125    }
126
127    /// Returns a matrix with the specified rows. This is opposite of the memory
128    /// layout (which is column-major), but using this constructor usually
129    /// leads to easier-to-read code as the element order matches code order.
130    ///
131    /// ```
132    /// use lina::{Matrix, vec3};
133    ///
134    /// let m = <Matrix<_, 3, 2>>::from_rows([
135    ///     [1, 2, 3],
136    ///     [4, 5, 6],
137    /// ]);
138    ///
139    ///
140    /// assert_eq!(m.row(0).to_array(), [1, 2, 3]);
141    /// assert_eq!(m.row(1).to_array(), [4, 5, 6]);
142    /// ```
143    pub fn from_rows<V>(rows: [V; R]) -> Self
144    where
145        V: Into<[T; C]>,
146    {
147        let mut out = Self::zero();
148        for (i, row) in IntoIterator::into_iter(rows).enumerate() {
149            out.set_row(i, row);
150        }
151        out
152    }
153
154    /// Returns a matrix with the specified columns. This matches the memory
155    /// layout but is usually more difficult to read in code. Consider using
156    /// [`Matrix::from_rows`] instead.
157    ///
158    /// ```
159    /// use lina::{Matrix, vec2};
160    ///
161    /// let m = <Matrix<_, 2, 3>>::from_cols([
162    ///     [1, 2, 3],
163    ///     [4, 5, 6],
164    /// ]);
165    ///
166    ///
167    /// assert_eq!(m.row(0).to_array(), [1, 4]);
168    /// assert_eq!(m.row(1).to_array(), [2, 5]);
169    /// assert_eq!(m.row(2).to_array(), [3, 6]);
170    /// ```
171    pub fn from_cols<V>(cols: [V; C]) -> Self
172    where
173        V: Into<[T; R]>,
174    {
175        Self::new_impl(cols.map(|v| v.into()))
176    }
177
178    /// Returns the column with index `idx`.
179    pub fn col(&self, index: usize) -> Col<'_, T, C, R> {
180        Col {
181            matrix: &self.0,
182            index,
183        }
184    }
185
186    /// Sets the column with index `idx` to the given values.
187    ///
188    /// ```
189    /// use lina::{Mat3, vec3};
190    ///
191    /// let mut mat = <Mat3<_>>::identity();
192    /// mat.set_col(1, vec3(2, 4, 6));
193    ///
194    /// assert_eq!(mat, Mat3::from_rows([
195    ///     [1, 2, 0],
196    ///     [0, 4, 0],
197    ///     [0, 6, 1],
198    /// ]));
199    /// ```
200    pub fn set_col(&mut self, idx: usize, v: impl Into<[T; R]>) {
201        self.0[idx] = v.into().into();
202    }
203
204    /// Returns the row with index `idx`.
205    pub fn row(&self, index: usize) -> Row<'_, T, C, R> {
206        Row {
207            matrix: &self.0,
208            index,
209        }
210    }
211
212    /// Sets the row with index `idx` to the given values.
213    ///
214    /// ```
215    /// use lina::{Mat3, vec3};
216    ///
217    /// let mut mat = <Mat3<_>>::identity();
218    /// mat.set_row(1, vec3(2, 4, 6));
219    ///
220    /// assert_eq!(mat, Mat3::from_rows([
221    ///     [1, 0, 0],
222    ///     [2, 4, 6],
223    ///     [0, 0, 1],
224    /// ]));
225    /// ```
226    pub fn set_row(&mut self, idx: usize, v: impl Into<[T; C]>) {
227        let v = v.into();
228        for i in 0..C {
229            self.0[i][idx] = v[i];
230        }
231    }
232
233    /// Returns the element at the given (row, column). Panics if either index
234    /// is out of bounds.
235    ///
236    /// ```
237    /// use lina::{Mat3, vec3};
238    ///
239    /// let mat = <Mat3<_>>::from_rows([
240    ///     [1, 0, 8],
241    ///     [0, 9, 0],
242    ///     [0, 7, 1],
243    /// ]);
244    ///
245    /// assert_eq!(mat.elem(1, 1), 9);
246    /// assert_eq!(mat.elem(0, 2), 8);
247    /// assert_eq!(mat.elem(2, 1), 7);
248    ///
249    /// ```
250    pub fn elem(&self, row: usize, col: usize) -> T {
251        self.0[col][row]
252    }
253
254    /// Overwrites the element in the given (row, column) with the given value.
255    /// Panics if `row` or `col` is out of bounds.
256    ///
257    /// ```
258    /// use lina::{Mat3, vec3};
259    ///
260    /// let mut mat = <Mat3<_>>::identity();
261    /// mat.set_elem(1, 1, 9);
262    /// mat.set_elem(0, 2, 8);
263    /// mat.set_elem(2, 1, 7);
264    ///
265    /// assert_eq!(mat, Mat3::from_rows([
266    ///     [1, 0, 8],
267    ///     [0, 9, 0],
268    ///     [0, 7, 1],
269    /// ]));
270    /// ```
271    pub fn set_elem(&mut self, row: usize, col: usize, value: T) {
272        self.0[col][row] = value;
273    }
274
275    /// Returns an iterator over all entries of this matrix, in column-major order.
276    ///
277    /// ```
278    /// let m = <lina::Matrix<_, 2, 3>>::from_rows([
279    ///     [1, 2],
280    ///     [3, 4],
281    ///     [5, 6],
282    /// ]);
283    /// let mut it = m.iter();
284    ///
285    /// assert_eq!(it.next(), Some(1));
286    /// assert_eq!(it.next(), Some(3));
287    /// assert_eq!(it.next(), Some(5));
288    /// assert_eq!(it.next(), Some(2));
289    /// assert_eq!(it.next(), Some(4));
290    /// assert_eq!(it.next(), Some(6));
291    /// assert_eq!(it.next(), None);
292    /// ```
293    pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
294        self.0.iter().flat_map(|col| col).copied()
295    }
296
297    /// Returns the transposed version of this matrix (swapping rows and
298    /// columns). You have to specify the source and target spaces of the
299    /// returned matrix manually as it's likely different from `self`, but
300    /// cannot be inferred.
301    ///
302    /// ```
303    /// use lina::{Matrix, WorldSpace};
304    ///
305    /// let m = <Matrix<_, 3, 2>>::from_rows([
306    ///     [1, 2, 3],
307    ///     [4, 5, 6],
308    /// ]);
309    /// let t = m.transposed::<WorldSpace, WorldSpace>();
310    ///
311    /// assert_eq!(t, Matrix::from_rows([
312    ///     [1, 4],
313    ///     [2, 5],
314    ///     [3, 6],
315    /// ]));
316    /// ```
317    #[must_use = "does not transpose in-place"]
318    pub fn transposed<NewSrc: Space, NewDst: Space>(&self) -> Matrix<T, R, C, NewSrc, NewDst> {
319        Matrix::from_rows(self.0)
320    }
321
322    /// Reinterprets this matrix to be a transformation into the space `New`.
323    pub fn with_target_space<New: Space>(self) -> Matrix<T, C, R, Src, New> {
324        Matrix::new_impl(self.0)
325    }
326
327    /// Reinterprets this matrix to be a transformation from the space `New`.
328    pub fn with_source_space<New: Space>(self) -> Matrix<T, C, R, New, Dst> {
329        Matrix::new_impl(self.0)
330    }
331
332    /// Reinterprets this matrix to be a transformation from the space `NewSrc`
333    /// into the space `NewDst`.
334    pub fn with_spaces<NewSrc: Space, NewDst: Space>(self) -> Matrix<T, C, R, NewSrc, NewDst> {
335        Matrix::new_impl(self.0)
336    }
337
338    /// Transforms the given point or vector with this matrix (numerically just
339    /// a simple matrix-vector-multiplication).
340    ///
341    /// This function accepts `C`-dimensional [`Point`]s, [`Vector`]s and
342    /// [`HcPoint`]s. For the latter, only its `coords` part are transformed
343    /// with the `weight` untouched. To be clear: as this matrix represents a
344    /// linear transformation in cartesian coordinates, no perspective divide
345    /// is performed. Use [`HcMatrix`] if you want to represent non-linear
346    /// transformations.
347    ///
348    /// Instead of using this function, you can also use the `*` operator
349    /// overload, if you prefer. It does exactly the same.
350    pub fn transform<'a, X>(&'a self, x: X) -> <&'a Self as ops::Mul<X>>::Output
351    where
352        &'a Self: ops::Mul<X>,
353    {
354        self * x
355    }
356
357    /// Combines the transformations of two matrices into a single
358    /// transformation matrix. First the transformation of `self` is applied,
359    /// then the one of `second`. In the language of math, this is just matrix
360    /// multiplication: `second * self`. You can also use the overloaded `*`
361    /// operator instead, but this method exists for those who find the matrix
362    /// multiplication order unintuitive and this method call easier to read.
363    ///
364    /// ```
365    /// use lina::Mat2;
366    ///
367    /// // Rotation by 90° counter clock wise.
368    /// let rotate = <Mat2<_>>::from_rows([
369    ///     [0, -1],
370    ///     [1,  0],
371    /// ]);
372    ///
373    /// // Scale x-axis by 2, y-axis by 3.
374    /// let scale = <Mat2<_>>::from_rows([
375    ///     [2, 0],
376    ///     [0, 3],
377    /// ]);
378    ///
379    /// assert_eq!(rotate.and_then(scale), Mat2::from_rows([
380    ///     [0, -2],
381    ///     [3,  0],
382    /// ]));
383    /// assert_eq!(scale.and_then(rotate), Mat2::from_rows([
384    ///     [0, -3],
385    ///     [2,  0],
386    /// ]));
387    /// ```
388    pub fn and_then<const R2: usize, Dst2: Space>(
389        self,
390        second: Matrix<T, R, R2, Dst, Dst2>,
391    ) -> Matrix<T, C, R2, Src, Dst2> {
392        second * self
393    }
394
395    /// Returns the homogeneous version of this matrix by first adding one row
396    /// and one column, all filled with 0s, except the element in the bottom
397    /// right corner, which is a 1.
398    ///
399    /// ```
400    /// use lina::{Mat2, HcMat2};
401    ///
402    /// let linear = <Mat2<_>>::from_rows([
403    ///     [1, 2],
404    ///     [3, 4],
405    /// ]);
406    ///
407    /// assert_eq!(linear.to_homogeneous(), <HcMat2<_>>::from_rows([
408    ///     [1, 2, 0],
409    ///     [3, 4, 0],
410    ///     [0, 0, 1],
411    /// ]));
412    /// ```
413    pub fn to_homogeneous(&self) -> HcMatrix<T, C, R, Src, Dst> {
414        HcMatrix::from_parts(*self, Vector::zero(), Vector::zero(), T::one())
415    }
416
417    /// Applies the given function to each element and returns the resulting new
418    /// matrix.
419    ///
420    /// ```
421    /// use lina::{Mat2, vec2};
422    ///
423    /// let mat = <Mat2<_>>::identity().map(|e: i32| e + 1);
424    ///
425    /// assert_eq!(mat, Mat2::from_rows([
426    ///     [2, 1],
427    ///     [1, 2],
428    /// ]));
429    /// ```
430    pub fn map<U: Scalar, F: FnMut(T) -> U>(&self, mut f: F) -> Matrix<U, C, R, Src, Dst> {
431        Matrix::new_impl(self.0.map(|col| col.map(&mut f)))
432    }
433
434    /// Pairs up the same elements from `self` and `other`, applies the given
435    /// function to each and returns the resulting matrix. Useful for
436    /// element-wise operations.
437    ///
438    /// ```
439    /// use lina::{Mat3f, vec3};
440    ///
441    /// let a = <Mat3f>::from_rows([
442    ///     [1.0, 2.0, 3.0],
443    ///     [4.0, 5.0, 6.0],
444    ///     [7.0, 8.0, 9.0],
445    /// ]);
446    /// let b = Mat3f::identity();
447    /// let c = a.zip_map(&b, |elem_a, elem_b| elem_a * elem_b);   // element-wise multiplication
448    ///
449    /// assert_eq!(c, Mat3f::from_rows([
450    ///     [1.0, 0.0, 0.0],
451    ///     [0.0, 5.0, 0.0],
452    ///     [0.0, 0.0, 9.0],
453    /// ]));
454    /// ```
455    pub fn zip_map<U, O, F>(
456        &self,
457        other: &Matrix<U, C, R, Src, Dst>,
458        mut f: F,
459    ) -> Matrix<O, C, R, Src, Dst>
460    where
461        U: Scalar,
462        O: Scalar,
463        F: FnMut(T, U) -> O,
464    {
465        Matrix::new_impl(array::from_fn(|i| array::from_fn(|j| f(self.0[i][j], other.0[i][j]))))
466    }
467
468    /// Returns a byte slice of this matrix, representing the raw column-major
469    /// data. Useful to pass to graphics APIs.
470    pub fn as_bytes(&self) -> &[u8] {
471        bytemuck::bytes_of(self)
472    }
473}
474
475impl<T: Scalar, const N: usize, Src: Space, Dst: Space> Matrix<T, N, N, Src, Dst> {
476    /// Returns the identity matrix with all elements 0, except the diagonal
477    /// which is all 1.
478    ///
479    /// ```
480    /// use lina::{Mat3f, vec3};
481    ///
482    /// let mat = <Mat3f>::identity();
483    /// assert_eq!(mat, Mat3f::from_rows([
484    ///     [1.0, 0.0, 0.0],
485    ///     [0.0, 1.0, 0.0],
486    ///     [0.0, 0.0, 1.0],
487    /// ]));
488    /// ```
489    pub fn identity() -> Self {
490        Self::from_diagonal([T::one(); N])
491    }
492
493    /// Returns a matrix with the given diagonal and all other elements set to 0.
494    ///
495    /// ```
496    /// use lina::Mat3;
497    ///
498    /// let mat = <Mat3<_>>::from_diagonal([1, 2, 3]);
499    ///
500    /// assert_eq!(mat, Mat3::from_rows([
501    ///     [1, 0, 0],
502    ///     [0, 2, 0],
503    ///     [0, 0, 3],
504    /// ]));
505    /// ```
506    pub fn from_diagonal(v: impl Into<[T; N]>) -> Self {
507        let mut m = Self::zero();
508        m.set_diagonal(v);
509        m
510    }
511
512    /// Returns the diagonal of this matrix.
513    ///
514    /// ```
515    /// use lina::Mat3;
516    ///
517    /// let mat = <Mat3<_>>::from_rows([
518    ///     [1, 2, 3],
519    ///     [4, 5, 6],
520    ///     [7, 8, 9],
521    /// ]);
522    /// assert_eq!(mat.diagonal(), [1, 5, 9]);
523    /// ```
524    pub fn diagonal(&self) -> [T; N] {
525        array::from_fn(|i| self.0[i][i])
526    }
527
528    /// Sets the diagonal to the given values.
529    ///
530    /// ```
531    /// use lina::Mat3;
532    ///
533    /// let mut mat = <Mat3<_>>::from_rows([
534    ///     [1, 2, 3],
535    ///     [4, 5, 6],
536    ///     [7, 8, 9],
537    /// ]);
538    /// mat.set_diagonal([2, 1, 0]);
539    ///
540    /// assert_eq!(mat, Mat3::from_rows([
541    ///     [2, 2, 3],
542    ///     [4, 1, 6],
543    ///     [7, 8, 0],
544    /// ]));
545    /// ```
546    pub fn set_diagonal(&mut self, v: impl Into<[T; N]>) {
547        let v = v.into();
548        for i in 0..N {
549            self.0[i][i] = v[i];
550        }
551    }
552
553    /// Checks whether this matrix is *symmetric*, i.e. whether transposing
554    /// does *not* change the matrix.
555    ///
556    /// ```
557    /// use lina::{Mat3f, Mat2};
558    ///
559    /// assert!(<Mat3f>::identity().is_symmetric());
560    /// assert!(!<Mat2<_>>::from_rows([[1, 2], [3, 4]]).is_symmetric());
561    /// ```
562    pub fn is_symmetric(&self) -> bool {
563        for c in 1..N {
564            for r in 0..c {
565                if self.0[c][r] != self.0[r][c] {
566                    return false;
567                }
568            }
569        }
570
571        true
572    }
573
574    /// Returns the *trace* of the matrix, i.e. the sum of all elements on the
575    /// diagonal.
576    ///
577    /// ```
578    /// use lina::{Mat2, Mat3f};
579    ///
580    /// assert_eq!(<Mat3f>::identity().trace(), 3.0);
581    /// assert_eq!(<Mat2<_>>::from_rows([[1, 2], [3, 4]]).trace(), 5);
582    /// ```
583    pub fn trace(&self) -> T {
584        self.diagonal().as_ref().iter().fold(T::zero(), |a, b| a + *b)
585    }
586}
587
588impl<T: Float, Src: Space, Dst: Space> Matrix<T, 1, 1, Src, Dst> {
589    #[doc = include_str!("determinant_docs.md")]
590    pub fn determinant(&self) -> T {
591        self.0[0][0]
592    }
593
594    #[doc = include_str!("inverted_docs.md")]
595    pub fn inverted(&self) -> Option<Matrix<T, 1, 1, Dst, Src>> {
596        let det = self.determinant();
597        if det.is_zero() {
598            return None;
599        }
600
601        Some(Matrix::identity() / det)
602    }
603}
604
605impl<T: Float, Src: Space, Dst: Space> Matrix<T, 2, 2, Src, Dst> {
606    #[doc = include_str!("determinant_docs.md")]
607    pub fn determinant(&self) -> T {
608        self.0[0][0] * self.0[1][1] - self.0[0][1] * self.0[1][0]
609    }
610
611    #[doc = include_str!("inverted_docs.md")]
612    pub fn inverted(&self) -> Option<Matrix<T, 2, 2, Dst, Src>> {
613        let det = self.determinant();
614        if det.is_zero() {
615            return None;
616        }
617
618        let m = Self::from_rows([
619            [ self.row(1).col(1), -self.row(0).col(1)],
620            [-self.row(1).col(0),  self.row(0).col(0)],
621        ]);
622        Some(m.with_spaces() / det)
623    }
624}
625
626impl<T: Float, Src: Space, Dst: Space> Matrix<T, 3, 3, Src, Dst> {
627    #[doc = include_str!("determinant_docs.md")]
628    pub fn determinant(&self) -> T {
629        T::zero()
630            + self.0[0][0] * (self.0[1][1] * self.0[2][2] - self.0[2][1] * self.0[1][2])
631            + self.0[1][0] * (self.0[2][1] * self.0[0][2] - self.0[0][1] * self.0[2][2])
632            + self.0[2][0] * (self.0[0][1] * self.0[1][2] - self.0[1][1] * self.0[0][2])
633    }
634
635    #[doc = include_str!("inverted_docs.md")]
636    pub fn inverted(&self) -> Option<Matrix<T, 3, 3, Dst, Src>> {
637        let det = self.determinant();
638        if det.is_zero() {
639            return None;
640        }
641
642        let calc_row = |col_a, col_b| cross::<_, WorldSpace>(
643            self.col(col_a).to_vec(),
644            self.col(col_b).to_vec()
645        );
646
647        let m = Self::from_rows([
648            calc_row(1, 2),
649            calc_row(2, 0),
650            calc_row(0, 1),
651        ]);
652        Some(m.with_spaces() / det)
653    }
654}
655
656impl<T: Float, Src: Space, Dst: Space> Matrix<T, 4, 4, Src, Dst> {
657    #[doc = include_str!("determinant_docs.md")]
658    pub fn determinant(&self) -> T {
659        super::inv4::det(&self.0)
660    }
661
662    #[doc = include_str!("inverted_docs.md")]
663    pub fn inverted(&self) -> Option<Matrix<T, 4, 4, Dst, Src>> {
664        super::inv4::inv(&self.0).map(Matrix::new_impl)
665    }
666}
667
668
669// =============================================================================================
670// ===== Non-mathematical trait impls
671// =============================================================================================
672
673/// The inner array implements `Zeroable` and `Matrix` is just a newtype wrapper
674/// around that array with `repr(transparent)`.
675unsafe impl<
676    T: Scalar + Zeroable,
677    const C: usize,
678    const R: usize,
679    Src: Space,
680    Dst: Space,
681> Zeroable for Matrix<T, C, R, Src, Dst> {}
682
683/// The struct is marked as `repr(transparent)` so is guaranteed to have the
684/// same layout as `[[T; R]; C]`. And `bytemuck` itself has an impl for arrays
685/// where `T: Pod`.
686unsafe impl<
687    T: Scalar + Pod,
688    const C: usize,
689    const R: usize,
690    Src: Space,
691    Dst: Space,
692> Pod for Matrix<T, C, R, Src, Dst> {}
693
694impl<
695    T: Scalar,
696    const C: usize,
697    const R: usize,
698    Src: Space,
699    Dst: Space,
700> fmt::Debug for Matrix<T, C, R, Src, Dst> {
701    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
702        write!(f, "Matrix ")?;
703        super::debug_matrix_impl(f, C, R, |r, c| self.elem(r, c))
704    }
705}
706
707
708// =============================================================================================
709// ===== Mathematical trait impls
710// =============================================================================================
711
712super::shared_trait_impls!(Matrix);
713super::impl_scalar_mul!(Matrix => f32, f64, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
714
715
716// =============================================================================================
717// ===== Matrix * matrix multiplication (composition)
718// =============================================================================================
719
720/// `matrix * matrix` multiplication. You can also use [`Matrix::and_then`].
721impl<
722    T: Scalar,
723    const C: usize,
724    const R: usize,
725    const S: usize,
726    Src: Space,
727    Mid: Space,
728    Dst: Space,
729> ops::Mul<Matrix<T, C, S, Src, Mid>> for Matrix<T, S, R, Mid, Dst> {
730    type Output = Matrix<T, C, R, Src, Dst>;
731    fn mul(self, rhs: Matrix<T, C, S, Src, Mid>) -> Self::Output {
732        // This is the straight-forward n³ algorithm. Using more sophisticated
733        // algorithms with sub cubic runtime is not worth it for small
734        // matrices. However, this can certainly be micro-optimized. In
735        // particular, using SSE seems like a good idea, but "requires" all
736        // columns to be properly aligned in memory.
737        //
738        // TODO: try to optimize
739        let mut out = Self::Output::zero();
740        for c in 0..C {
741            for r in 0..R {
742                for s in 0..S {
743                    out.0[c][r] += self.0[s][r] * rhs.0[c][s];
744                }
745            }
746        }
747        out
748    }
749}
750
751
752// =============================================================================================
753// ===== Matrix * vector multiplication (transformations)
754// =============================================================================================
755
756/// See [`Matrix::transform`].
757impl<
758    T: Scalar,
759    const C: usize,
760    const R: usize,
761    Src: Space,
762    Dst: Space,
763> ops::Mul<Vector<T, C, Src>> for &Matrix<T, C, R, Src, Dst> {
764    type Output = Vector<T, R, Dst>;
765    fn mul(self, rhs: Vector<T, C, Src>) -> Self::Output {
766        array::from_fn(|row| dot(self.row(row), rhs)).into()
767    }
768}
769
770/// See [`Matrix::transform`].
771impl<
772    T: Scalar,
773    const C: usize,
774    const R: usize,
775    Src: Space,
776    Dst: Space,
777> ops::Mul<Dir<T, C, Src>> for &Matrix<T, C, R, Src, Dst> {
778    type Output = Vector<T, R, Dst>;
779    fn mul(self, rhs: Dir<T, C, Src>) -> Self::Output {
780        array::from_fn(|row| dot(self.row(row), rhs.to_unit_vec())).into()
781    }
782}
783
784/// See [`Matrix::transform`].
785impl<
786    T: Scalar,
787    const C: usize,
788    const R: usize,
789    Src: Space,
790    Dst: Space,
791> ops::Mul<Point<T, C, Src>> for &Matrix<T, C, R, Src, Dst> {
792    type Output = Point<T, R, Dst>;
793    fn mul(self, rhs: Point<T, C, Src>) -> Self::Output {
794        (self * rhs.to_vec()).to_point()
795    }
796}
797
798/// See [`Matrix::transform`].
799impl<
800    T: Scalar,
801    const C: usize,
802    const R: usize,
803    Src: Space,
804    Dst: Space,
805> ops::Mul<HcPoint<T, C, Src>> for &Matrix<T, C, R, Src, Dst> {
806    type Output = HcPoint<T, R, Dst>;
807    fn mul(self, rhs: HcPoint<T, C, Src>) -> Self::Output {
808        HcPoint::new(self * Vector::from(rhs.coords), rhs.weight)
809    }
810}
811
812
813// =============================================================================================
814// ===== `Row` and `Col` proxies
815// =============================================================================================
816
817/// Proxy type representing one row of a matrix.
818#[derive(Clone, Copy)]
819pub struct Row<'a, T: Scalar, const C: usize, const R: usize> {
820    matrix: &'a MatrixStorage<T, C, R>,
821    index: usize,
822}
823
824impl<'a, T: Scalar, const C: usize, const R: usize> Row<'a, T, C, R> {
825    /// Indexes into this row with the given column index, returning the element.
826    pub fn col(self, col: usize) -> T {
827        self.matrix[col][self.index]
828    }
829
830    /// Returns this row as array.
831    pub fn to_array(self) -> [T; C] {
832        self.into()
833    }
834
835    /// Returns this row as vector.
836    pub fn to_vec<S: Space>(self) -> Vector<T, C, S> {
837        self.into()
838    }
839
840    /// Returns this row as point.
841    pub fn to_point<S: Space>(self) -> Point<T, C, S> {
842        self.into()
843    }
844}
845
846/// Proxy type representing one column of a matrix.
847#[derive(Clone, Copy)]
848pub struct Col<'a, T: Scalar, const C: usize, const R: usize> {
849    matrix: &'a MatrixStorage<T, C, R>,
850    index: usize,
851}
852
853impl<'a, T: Scalar, const C: usize, const R: usize> Col<'a, T, C, R> {
854    /// Indexes into this column with the given row index, returning the element.
855    pub fn row(self, row: usize) -> T {
856        self.matrix[self.index][row]
857    }
858
859    /// Returns this column as array.
860    pub fn to_array(self) -> [T; R] {
861        self.into()
862    }
863
864    /// Returns this column as vector.
865    pub fn to_vec<S: Space>(self) -> Vector<T, R, S> {
866        self.into()
867    }
868
869    /// Returns this column as point.
870    pub fn to_point<S: Space>(self) -> Point<T, R, S> {
871        self.into()
872    }
873}
874
875impl<'a, T: Scalar, const C: usize, const R: usize> From<Row<'a, T, C, R>> for [T; C] {
876    fn from(src: Row<'a, T, C, R>) -> Self {
877        array::from_fn(|i| src.matrix[i][src.index])
878    }
879}
880impl<
881    'a,
882    T: Scalar,
883    const C: usize,
884    const R: usize,
885    S: Space,
886> From<Row<'a, T, C, R>> for Vector<T, C, S> {
887    fn from(src: Row<'a, T, C, R>) -> Self {
888        src.to_array().into()
889    }
890}
891impl<
892    'a,
893    T: Scalar,
894    const C: usize,
895    const R: usize,
896    S: Space,
897> From<Row<'a, T, C, R>> for Point<T, C, S> {
898    fn from(src: Row<'a, T, C, R>) -> Self {
899        src.to_array().into()
900    }
901}
902impl<'a, T: Scalar, const C: usize, const R: usize> fmt::Debug for Row<'a, T, C, R> {
903    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
904        crate::util::debug_list_one_line(&self.to_array(), f)
905    }
906}
907
908impl<'a, T: Scalar, const C: usize, const R: usize> From<Col<'a, T, C, R>> for [T; R] {
909    fn from(src: Col<'a, T, C, R>) -> Self {
910        src.matrix[src.index]
911    }
912}
913impl<
914    'a,
915    T: Scalar,
916    const C: usize,
917    const R: usize,
918    S: Space,
919> From<Col<'a, T, C, R>> for Vector<T, R, S> {
920    fn from(src: Col<'a, T, C, R>) -> Self {
921        src.to_array().into()
922    }
923}
924impl<
925    'a,
926    T: Scalar,
927    const C: usize,
928    const R: usize,
929    S: Space,
930> From<Col<'a, T, C, R>> for Point<T, R, S> {
931    fn from(src: Col<'a, T, C, R>) -> Self {
932        src.to_array().into()
933    }
934}
935impl<'a, T: Scalar, const C: usize, const R: usize> fmt::Debug for Col<'a, T, C, R> {
936    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
937        crate::util::debug_list_one_line(&self.to_array(), f)
938
939    }
940}