batbox_la/mat/_4x4/
extra.rs

1use super::*;
2
3impl<T: Copy> mat4<T> {
4    /// Get transposed matrix.
5    ///
6    /// # Examples
7    /// ```
8    /// # use batbox_la::*;
9    /// let matrix = mat4::translate(vec3(1, 2, 3));
10    /// let matrix_transposed = matrix.transpose();
11    /// for i in 0..4 {
12    ///     for j in 0..4 {
13    ///         assert_eq!(matrix[(i, j)], matrix_transposed[(j, i)]);
14    ///     }
15    /// }
16    /// ```
17    pub fn transpose(self) -> Self {
18        let mut result = self;
19        for i in 0..4 {
20            for j in 0..4 {
21                result[(i, j)] = self[(j, i)];
22            }
23        }
24        result
25    }
26}
27
28impl<T: Num> mat4<T> {
29    /// Construct a transformation matrix with given orts
30    ///
31    /// # Examples
32    /// ```
33    /// # use batbox_la::*;
34    /// let e1 = vec3(1.0, 2.0, 3.0);
35    /// let e2 = vec3(3.0, 4.0, 5.0);
36    /// let e3 = vec3(5.0, 6.0, -1.0);
37    /// let m = mat4::from_orts(e1, e2, e3);
38    /// assert_eq!(vec3(1.0, 0.0, 0.0).transform(m), e1);
39    /// assert_eq!(vec3(0.0, 1.0, 0.0).transform(m), e2);
40    /// assert_eq!(vec3(0.0, 0.0, 1.0).transform(m), e3);
41    /// let v = vec3(2.0, 3.0, 4.0);
42    /// assert_eq!(v.transform(m), e1 * v.x + e2 * v.y + e3 * v.z);
43    /// ```
44    pub fn from_orts(x: vec3<T>, y: vec3<T>, z: vec3<T>) -> Self {
45        mat4::new([
46            [x.x, y.x, z.x, T::ZERO],
47            [x.y, y.y, z.y, T::ZERO],
48            [x.z, y.z, z.z, T::ZERO],
49            [T::ZERO, T::ZERO, T::ZERO, T::ONE],
50        ])
51    }
52}
53
54impl<T: Float> mat4<T> {
55    /// Get inverse matrix.
56    ///
57    /// # Examples
58    /// ```
59    /// # use batbox_la::*;
60    /// let matrix = mat4::<f64>::rotate_x(Angle::from_radians(0.123));
61    /// let matrix_inv = matrix.inverse();
62    /// let mult = matrix * matrix_inv;
63    /// for i in 0..4 {
64    ///     for j in 0..4 {
65    ///         assert!((mult[(i, j)] - if i == j { 1.0 } else { 0.0 }).abs() < 1e-5);
66    ///     }
67    /// }
68    /// ```
69    pub fn inverse(self) -> Self {
70        let b00 = self[(0, 0)] * self[(1, 1)] - self[(1, 0)] * self[(0, 1)];
71        let b01 = self[(0, 0)] * self[(2, 1)] - self[(2, 0)] * self[(0, 1)];
72        let b02 = self[(0, 0)] * self[(3, 1)] - self[(3, 0)] * self[(0, 1)];
73        let b03 = self[(1, 0)] * self[(2, 1)] - self[(2, 0)] * self[(1, 1)];
74        let b04 = self[(1, 0)] * self[(3, 1)] - self[(3, 0)] * self[(1, 1)];
75        let b05 = self[(2, 0)] * self[(3, 1)] - self[(3, 0)] * self[(2, 1)];
76        let b06 = self[(0, 2)] * self[(1, 3)] - self[(1, 2)] * self[(0, 3)];
77        let b07 = self[(0, 2)] * self[(2, 3)] - self[(2, 2)] * self[(0, 3)];
78        let b08 = self[(0, 2)] * self[(3, 3)] - self[(3, 2)] * self[(0, 3)];
79        let b09 = self[(1, 2)] * self[(2, 3)] - self[(2, 2)] * self[(1, 3)];
80        let b10 = self[(1, 2)] * self[(3, 3)] - self[(3, 2)] * self[(1, 3)];
81        let b11 = self[(2, 2)] * self[(3, 3)] - self[(3, 2)] * self[(2, 3)];
82
83        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
84
85        if det == T::ZERO {
86            Self::identity()
87        } else {
88            mat4::new([
89                [
90                    self[(1, 1)] * b11 - self[(2, 1)] * b10 + self[(3, 1)] * b09,
91                    self[(2, 1)] * b08 - self[(0, 1)] * b11 - self[(3, 1)] * b07,
92                    self[(0, 1)] * b10 - self[(1, 1)] * b08 + self[(3, 1)] * b06,
93                    self[(1, 1)] * b07 - self[(0, 1)] * b09 - self[(2, 1)] * b06,
94                ],
95                [
96                    self[(2, 0)] * b10 - self[(1, 0)] * b11 - self[(3, 0)] * b09,
97                    self[(0, 0)] * b11 - self[(2, 0)] * b08 + self[(3, 0)] * b07,
98                    self[(1, 0)] * b08 - self[(0, 0)] * b10 - self[(3, 0)] * b06,
99                    self[(0, 0)] * b09 - self[(1, 0)] * b07 + self[(2, 0)] * b06,
100                ],
101                [
102                    self[(1, 3)] * b05 - self[(2, 3)] * b04 + self[(3, 3)] * b03,
103                    self[(2, 3)] * b02 - self[(0, 3)] * b05 - self[(3, 3)] * b01,
104                    self[(0, 3)] * b04 - self[(1, 3)] * b02 + self[(3, 3)] * b00,
105                    self[(1, 3)] * b01 - self[(0, 3)] * b03 - self[(2, 3)] * b00,
106                ],
107                [
108                    self[(2, 2)] * b04 - self[(1, 2)] * b05 - self[(3, 2)] * b03,
109                    self[(0, 2)] * b05 - self[(2, 2)] * b02 + self[(3, 2)] * b01,
110                    self[(1, 2)] * b02 - self[(0, 2)] * b04 - self[(3, 2)] * b00,
111                    self[(0, 2)] * b03 - self[(1, 2)] * b01 + self[(2, 2)] * b00,
112                ],
113            ]) / det
114        }
115    }
116}
117
118#[test]
119fn test_mat_inverse_random() {
120    fn check(m: mat4<f64>) {
121        let m_inv = m.inverse();
122        let mul = m * m_inv;
123        assert!(mul.approx_eq(&mat4::identity()));
124    }
125    // Random generated test cases
126    check(mat4::new([
127        [8.7, 3.6, 6.5, 6.5],
128        [7.4, 5.8, 8.6, 2.6],
129        [1.8, 8.3, 6.6, 4.9],
130        [2.1, 3.4, 3.5, 8.8],
131    ]));
132    check(mat4::new([
133        [9.6, 0.6, 5.4, 3.2],
134        [0.5, 0.1, 5.4, 6.6],
135        [2.0, 3.8, 0.0, 1.4],
136        [6.6, 2.9, 4.3, 9.3],
137    ]));
138    check(mat4::new([
139        [6.1, 1.7, 2.7, 3.6],
140        [1.8, 2.5, 7.8, 7.1],
141        [2.6, 9.5, 1.5, 8.0],
142        [6.5, 6.5, 5.9, 7.2],
143    ]));
144    check(mat4::new([
145        [8.4, 1.0, 6.4, 0.0],
146        [1.6, 1.1, 1.5, 4.0],
147        [5.5, 1.2, 0.6, 8.3],
148        [9.1, 9.7, 8.7, 0.8],
149    ]));
150    check(mat4::new([
151        [0.6, 5.7, 0.2, 7.1],
152        [3.5, 1.7, 6.4, 1.6],
153        [2.0, 3.4, 4.1, 5.0],
154        [7.3, 5.9, 8.9, 3.0],
155    ]));
156    check(mat4::new([
157        [1.9, 1.4, 4.0, 3.7],
158        [7.8, 8.2, 9.1, 1.3],
159        [3.2, 4.4, 3.9, 2.5],
160        [7.1, 7.3, 3.5, 5.0],
161    ]));
162    check(mat4::new([
163        [6.0, 7.0, 4.0, 0.6],
164        [0.9, 8.7, 6.2, 6.0],
165        [0.2, 4.6, 3.7, 0.2],
166        [8.4, 6.2, 7.6, 2.8],
167    ]));
168    check(mat4::new([
169        [5.1, 9.6, 4.6, 4.5],
170        [1.5, 9.2, 2.3, 9.4],
171        [5.6, 7.6, 0.4, 2.9],
172        [0.6, 0.5, 4.3, 4.6],
173    ]));
174    check(mat4::new([
175        [3.0, 5.7, 8.6, 2.1],
176        [6.2, 7.2, 0.1, 6.7],
177        [5.3, 5.9, 5.8, 2.1],
178        [9.4, 9.9, 9.8, 5.8],
179    ]));
180    check(mat4::new([
181        [4.3, 8.4, 2.0, 6.2],
182        [2.3, 9.0, 4.6, 5.8],
183        [5.5, 1.2, 8.8, 1.6],
184        [4.5, 9.3, 4.8, 1.5],
185    ]));
186}