1use crate::CoordinateType;
9
10#[derive(Clone, Hash, PartialEq, Eq, Debug)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct Matrix3d<T: CoordinateType> {
19 pub m11: T,
21 pub m12: T,
23 pub m13: T,
25 pub m21: T,
27 pub m22: T,
29 pub m23: T,
31 pub m31: T,
33 pub m32: T,
35 pub m33: T,
37}
38
39impl<T> Matrix3d<T>
40where
41 T: CoordinateType,
42{
43 pub fn new([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]]: [[T; 3]; 3]) -> Self {
50 Matrix3d {
51 m11,
52 m12,
53 m13,
54 m21,
55 m22,
56 m23,
57 m31,
58 m32,
59 m33,
60 }
61 }
62
63 fn new_from_flat([m11, m12, m13, m21, m22, m23, m31, m32, m33]: [T; 9]) -> Self {
70 Matrix3d {
71 m11,
72 m12,
73 m13,
74 m21,
75 m22,
76 m23,
77 m31,
78 m32,
79 m33,
80 }
81 }
82
83 pub fn identity() -> Self {
85 #![allow(clippy::just_underscores_and_digits)]
86 let _0 = T::zero();
87 let _1 = T::one();
88 Self::new_from_flat([_1, _0, _0, _0, _1, _0, _0, _0, _1])
89 }
90
91 pub fn mul_scalar(&self, rhs: T) -> Self {
93 Matrix3d::new_from_flat([
94 self.m11 * rhs,
95 self.m12 * rhs,
96 self.m13 * rhs,
97 self.m21 * rhs,
98 self.m22 * rhs,
99 self.m23 * rhs,
100 self.m31 * rhs,
101 self.m32 * rhs,
102 self.m33 * rhs,
103 ])
104 }
105
106 pub fn add(&self, rhs: &Self) -> Self {
108 Matrix3d::new_from_flat([
109 self.m11 + rhs.m11,
110 self.m12 + rhs.m12,
111 self.m13 + rhs.m13,
112 self.m21 + rhs.m21,
113 self.m22 + rhs.m22,
114 self.m23 + rhs.m23,
115 self.m31 + rhs.m31,
116 self.m32 + rhs.m32,
117 self.m33 + rhs.m33,
118 ])
119 }
120
121 pub fn mul_column_vector(&self, rhs: &(T, T, T)) -> (T, T, T) {
123 (
124 self.m11 * rhs.0 + self.m12 * rhs.1 + self.m13 * rhs.2,
125 self.m21 * rhs.0 + self.m22 * rhs.1 + self.m23 * rhs.2,
126 self.m31 * rhs.0 + self.m32 * rhs.1 + self.m33 * rhs.2,
127 )
128 }
129
130 pub fn mul_matrix(&self, rhs: &Self) -> Self {
132 let a = self;
133 let b = rhs;
134 let c11 = a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31;
135 let c12 = a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32;
136 let c13 = a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33;
137 let c21 = a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31;
138 let c22 = a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32;
139 let c23 = a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33;
140 let c31 = a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31;
141 let c32 = a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32;
142 let c33 = a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33;
143 Self::new_from_flat([c11, c12, c13, c21, c22, c23, c31, c32, c33])
144 }
145
146 pub fn transpose(&self) -> Self {
148 Self::new_from_flat([
149 self.m11, self.m21, self.m31, self.m12, self.m22, self.m32, self.m13, self.m23,
150 self.m33,
151 ])
152 }
153
154 pub fn is_identity(&self) -> bool {
156 self == &Self::identity()
157 }
158
159 pub fn is_unitary(&self) -> bool {
161 self.mul_matrix(&self.transpose()).is_identity()
162 }
163
164 pub fn determinant(&self) -> T {
166 let a = self;
174 a.m11 * a.m22 * a.m33 - a.m11 * a.m23 * a.m32 - a.m12 * a.m21 * a.m33
175 + a.m12 * a.m23 * a.m31
176 + a.m13 * a.m21 * a.m32
177 - a.m13 * a.m22 * a.m31
178 }
179
180 pub fn try_inverse(&self) -> Option<Self> {
184 let a = self;
198
199 let det = a.determinant();
201 if !det.is_zero() {
202 Some(Self::new_from_flat([
203 (a.m22 * a.m33 - a.m23 * a.m32) / det,
204 (a.m13 * a.m32 - a.m12 * a.m33) / det,
205 (a.m12 * a.m23 - a.m13 * a.m22) / det,
206 (a.m23 * a.m31 - a.m21 * a.m33) / det,
207 (a.m11 * a.m33 - a.m13 * a.m31) / det,
208 (a.m13 * a.m21 - a.m11 * a.m23) / det,
209 (a.m21 * a.m32 - a.m22 * a.m31) / det,
210 (a.m12 * a.m31 - a.m11 * a.m32) / det,
211 (a.m11 * a.m22 - a.m12 * a.m21) / det,
212 ]))
213 } else {
214 None
215 }
216 }
217}
218
219impl<T: CoordinateType> Default for Matrix3d<T> {
220 fn default() -> Self {
221 Self::identity()
222 }
223}
224
225#[test]
226fn test_matrix_multiplication() {
227 let id: Matrix3d<i32> = Matrix3d::identity();
228 assert_eq!(id.mul_matrix(&id), id);
229}
230
231#[test]
232fn test_mul_column_vector() {
233 let id: Matrix3d<i32> = Matrix3d::identity();
234 let v = (1, 2, 3);
235 assert_eq!(id.mul_column_vector(&v), v);
236}
237
238#[test]
239fn test_inverse() {
240 let m = Matrix3d::new([[1.0, 4.0, 2.0], [1.0, 2.0, 4.0], [2.0, 0.0, 4.0]]);
241 let i = m.try_inverse().unwrap();
242 assert_eq!(m.mul_matrix(&i), Matrix3d::identity());
243 assert_eq!(i.mul_matrix(&m), Matrix3d::identity());
244}