glm/mat/
sqmat.rs

1//
2// GLSL Mathematics for Rust.
3//
4// Copyright (c) 2015, 2025 The glm-rs authors.
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22// THE SOFTWARE.
23
24use num_traits::One;
25
26use crate::basenum::BaseFloat;
27use crate::vec::vec::{Vector2, Vector3, Vector4};
28
29use super::mat::*;
30use super::traits::{GenMat, GenSquareMat};
31
32impl<T: BaseFloat> One for Matrix2<T> {
33    #[inline]
34    fn one() -> Matrix2<T> {
35        let y = T::one();
36        let l = T::zero();
37        Matrix2::new(Vector2::new(y, l), Vector2::new(l, y))
38    }
39}
40
41impl<T: BaseFloat> GenSquareMat<T, Vector2<T>> for Matrix2<T> {
42    #[inline(always)]
43    fn determinant(&self) -> T {
44        self[0][0] * self[1][1] - self[0][1] * self[1][0]
45    }
46    #[inline]
47    fn inverse(&self) -> Option<Matrix2<T>> {
48        let det = self.determinant();
49        let ling = T::zero();
50        if det.is_approx_eq(&ling) {
51            None
52        } else {
53            let inv_det = det.recip();
54            let m = Matrix2::new(
55                Vector2::new(self[1][1] * inv_det, -self[0][1] * inv_det),
56                Vector2::new(-self[1][0] * inv_det, self[0][0] * inv_det),
57            );
58            Some(m)
59        }
60    }
61}
62
63impl<T: BaseFloat> One for Matrix3<T> {
64    #[inline]
65    fn one() -> Matrix3<T> {
66        let y = T::one();
67        let l = T::zero();
68        Matrix3::new(
69            Vector3::new(y, l, l),
70            Vector3::new(l, y, l),
71            Vector3::new(l, l, y),
72        )
73    }
74}
75
76impl<T: BaseFloat> GenSquareMat<T, Vector3<T>> for Matrix3<T> {
77    #[inline]
78    fn determinant(&self) -> T {
79        self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2])
80            - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2])
81            + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2])
82    }
83    #[inline]
84    fn inverse(&self) -> Option<Matrix3<T>> {
85        let det = self.determinant();
86        let ling = T::zero();
87        if det.is_approx_eq(&ling) {
88            None
89        } else {
90            let inv_det = det.recip();
91            let r11 = self[1][1] * self[2][2] - self[2][1] * self[1][2];
92            let r12 = self[2][0] * self[1][2] - self[1][0] * self[2][2];
93            let r13 = self[1][0] * self[2][1] - self[2][0] * self[1][1];
94            let r21 = self[2][1] * self[0][2] - self[0][1] * self[2][2];
95            let r22 = self[0][0] * self[2][2] - self[2][0] * self[0][2];
96            let r23 = self[2][0] * self[0][1] - self[0][0] * self[2][1];
97            let r31 = self[0][1] * self[1][2] - self[1][1] * self[0][2];
98            let r32 = self[1][0] * self[0][2] - self[0][0] * self[1][2];
99            let r33 = self[0][0] * self[1][1] - self[1][0] * self[0][1];
100            let m = Matrix3::new(
101                Vector3::new(r11 * inv_det, r21 * inv_det, r31 * inv_det),
102                Vector3::new(r12 * inv_det, r22 * inv_det, r32 * inv_det),
103                Vector3::new(r13 * inv_det, r23 * inv_det, r33 * inv_det),
104            );
105            Some(m)
106        }
107    }
108}
109
110impl<T: BaseFloat> One for Matrix4<T> {
111    #[inline]
112    fn one() -> Matrix4<T> {
113        let y = T::one();
114        let l = T::zero();
115        Matrix4::new(
116            Vector4::new(y, l, l, l),
117            Vector4::new(l, y, l, l),
118            Vector4::new(l, l, y, l),
119            Vector4::new(l, l, l, y),
120        )
121    }
122}
123
124impl<T: BaseFloat> GenSquareMat<T, Vector4<T>> for Matrix4<T> {
125    #[inline]
126    #[rustfmt::skip]
127    fn determinant(&self) -> T {
128        self[0][0] * (
129            self[1][1] * self[2][2] * self[3][3] +
130            self[2][1] * self[3][2] * self[1][3] +
131            self[3][1] * self[1][2] * self[2][3] -
132            self[3][1] * self[2][2] * self[1][3] -
133            self[1][1] * self[3][2] * self[2][3] -
134            self[2][1] * self[1][2] * self[3][3]
135        ) -
136        self[1][0] * (
137            self[0][1] * self[2][2] * self[3][3] +
138            self[2][1] * self[3][2] * self[0][3] +
139            self[3][1] * self[0][2] * self[2][3] -
140            self[3][1] * self[2][2] * self[0][3] -
141            self[0][1] * self[3][2] * self[2][3] -
142            self[2][1] * self[0][2] * self[3][3]
143        ) +
144        self[2][0] * (
145            self[0][1] * self[1][2] * self[3][3] +
146            self[1][1] * self[3][2] * self[0][3] +
147            self[3][1] * self[0][2] * self[1][3] -
148            self[3][1] * self[1][2] * self[0][3] -
149            self[0][1] * self[3][2] * self[1][3] -
150            self[1][1] * self[0][2] * self[3][3]
151        ) -
152        self[3][0] * (
153            self[0][1] * self[1][2] * self[2][3] +
154            self[1][1] * self[2][2] * self[0][3] +
155            self[2][1] * self[0][2] * self[1][3] -
156            self[2][1] * self[1][2] * self[0][3] -
157            self[0][1] * self[2][2] * self[1][3] -
158            self[1][1] * self[0][2] * self[2][3]
159        )
160    }
161    #[inline]
162    fn inverse(&self) -> Option<Matrix4<T>> {
163        let det = self.determinant();
164        let ling = T::zero();
165        if det.is_approx_eq(&ling) {
166            None
167        } else {
168            let inv_det = det.recip();
169            let tr = self.transpose();
170            let cf = |i, j| -> T {
171                let mat = match i {
172                    0 => Matrix3::new(tr.c1.truncate(j), tr.c2.truncate(j), tr.c3.truncate(j)),
173                    1 => Matrix3::new(tr.c0.truncate(j), tr.c2.truncate(j), tr.c3.truncate(j)),
174                    2 => Matrix3::new(tr.c0.truncate(j), tr.c1.truncate(j), tr.c3.truncate(j)),
175                    3 => Matrix3::new(tr.c0.truncate(j), tr.c1.truncate(j), tr.c2.truncate(j)),
176                    _ => unreachable!(),
177                };
178                let d = mat.determinant() * inv_det;
179                if (i + j) & 1 == 1 {
180                    -d
181                } else {
182                    d
183                }
184            };
185            let m = Matrix4::new(
186                Vector4::new(cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3)),
187                Vector4::new(cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3)),
188                Vector4::new(cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3)),
189                Vector4::new(cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3)),
190            );
191            Some(m)
192        }
193    }
194}
195
196#[cfg(test)]
197mod test {
198    use num_traits::{One, Zero};
199
200    use crate::*;
201
202    #[test]
203    fn test_determinant() {
204        let m2 = mat2(4., 5., 6., 7.);
205        assert_eq!(m2.determinant(), -2.);
206        assert_eq!(Mat3::one().determinant(), 1.);
207        let m4 = mat4(
208            1., 0., 4., 0., 2., 1., 2., 1., 3., 2., 3., 1., 4., 3., 0., 0.,
209        );
210        assert_eq!(m4.determinant(), -7.);
211        assert_eq!((m4 * m4).determinant(), 49.);
212        assert_eq!(Mat4::one().determinant(), 1.);
213    }
214
215    #[test]
216    fn test_inverse_mat2() {
217        let yi = Mat2::one();
218        assert!(yi.inverse().is_some());
219        assert!(DMat2::zero().inverse().is_none());
220        let mat = mat2(1., 3., 2., 4.);
221        let inv = mat.inverse().unwrap();
222        assert_close_to!(mat * inv, yi, 0.000001);
223        assert_close_to!(inv * mat, yi, 0.000001);
224        let m2 = mat2(1., 2., 2., 4.);
225        assert!(m2.inverse().is_none());
226    }
227
228    #[test]
229    fn test_inverse_mat3() {
230        let yi = Mat3::one();
231        assert!(yi.inverse().is_some());
232        assert_eq!(yi.inverse().unwrap(), yi);
233        assert!(DMat3::zero().inverse().is_none());
234        let mat = mat3(5., 7., 11., -6., 9., 2., 1., 13., 0.);
235        let inv = mat.inverse().unwrap();
236        assert_close_to!(mat * inv, yi, 0.000001);
237        assert_close_to!(inv * mat, yi, 0.000001);
238    }
239
240    #[test]
241    #[rustfmt::skip]
242    fn test_inverse_mat4() {
243        let mat = mat4(
244            1., 0., 4., 0.,
245            2., 1., 2., 1.,
246            3., 2., 3., 1.,
247            4., 3., 0., 0.,
248        );
249        let invm = mat4(
250            3./7., 12./7., -12./7., 4./7.,
251            -4./7., -16./7., 16./7., -3./7.,
252            1./7., -3./7., 3./7., -1./7.,
253            -4./7., 5./7., 2./7., -3./7.,
254        );
255        assert_approx_eq!(mat.inverse().unwrap(), invm);
256        assert_close_to!(mat.inverse().unwrap().inverse().unwrap(), mat, 0.000001);
257        assert!(Mat4::one().inverse().is_some());
258    }
259}