1#![allow(dead_code)]
7
8#[allow(dead_code)]
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct Mat2 {
12 pub m: [[f32; 2]; 2],
13}
14
15#[allow(dead_code)]
17pub fn mat2(a: f32, b: f32, c: f32, d: f32) -> Mat2 {
18 Mat2 {
19 m: [[a, b], [c, d]],
20 }
21}
22
23#[allow(dead_code)]
25pub fn mat2_identity() -> Mat2 {
26 mat2(1.0, 0.0, 0.0, 1.0)
27}
28
29#[allow(dead_code)]
31pub fn mat2_zero() -> Mat2 {
32 mat2(0.0, 0.0, 0.0, 0.0)
33}
34
35#[allow(dead_code)]
37pub fn mat2_det(m: &Mat2) -> f32 {
38 m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0]
39}
40
41#[allow(dead_code)]
43pub fn mat2_inverse(m: &Mat2) -> Option<Mat2> {
44 let det = mat2_det(m);
45 if det.abs() < 1e-10 {
46 return None;
47 }
48 let inv_det = 1.0 / det;
49 Some(mat2(
50 m.m[1][1] * inv_det,
51 -m.m[0][1] * inv_det,
52 -m.m[1][0] * inv_det,
53 m.m[0][0] * inv_det,
54 ))
55}
56
57#[allow(dead_code)]
59pub fn mat2_transpose(m: &Mat2) -> Mat2 {
60 mat2(m.m[0][0], m.m[1][0], m.m[0][1], m.m[1][1])
61}
62
63#[allow(dead_code)]
65pub fn mat2_mul(a: &Mat2, b: &Mat2) -> Mat2 {
66 mat2(
67 a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[1][0],
68 a.m[0][0] * b.m[0][1] + a.m[0][1] * b.m[1][1],
69 a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[1][0],
70 a.m[1][0] * b.m[0][1] + a.m[1][1] * b.m[1][1],
71 )
72}
73
74#[allow(dead_code)]
76pub fn mat2_add(a: &Mat2, b: &Mat2) -> Mat2 {
77 mat2(
78 a.m[0][0] + b.m[0][0],
79 a.m[0][1] + b.m[0][1],
80 a.m[1][0] + b.m[1][0],
81 a.m[1][1] + b.m[1][1],
82 )
83}
84
85#[allow(dead_code)]
87pub fn mat2_scale(m: &Mat2, s: f32) -> Mat2 {
88 mat2(m.m[0][0] * s, m.m[0][1] * s, m.m[1][0] * s, m.m[1][1] * s)
89}
90
91#[allow(dead_code)]
93pub fn mat2_mul_vec(m: &Mat2, v: [f32; 2]) -> [f32; 2] {
94 [
95 m.m[0][0] * v[0] + m.m[0][1] * v[1],
96 m.m[1][0] * v[0] + m.m[1][1] * v[1],
97 ]
98}
99
100#[allow(dead_code)]
102pub fn mat2_rotation(theta: f32) -> Mat2 {
103 let c = theta.cos();
104 let s = theta.sin();
105 mat2(c, -s, s, c)
106}
107
108#[allow(dead_code)]
110pub fn mat2_trace(m: &Mat2) -> f32 {
111 m.m[0][0] + m.m[1][1]
112}
113
114#[allow(dead_code)]
116pub fn mat2_approx_eq(a: &Mat2, b: &Mat2, eps: f32) -> bool {
117 (a.m[0][0] - b.m[0][0]).abs() < eps
118 && (a.m[0][1] - b.m[0][1]).abs() < eps
119 && (a.m[1][0] - b.m[1][0]).abs() < eps
120 && (a.m[1][1] - b.m[1][1]).abs() < eps
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use std::f32::consts::PI;
127
128 #[test]
129 fn test_identity_det() {
130 let id = mat2_identity();
131 assert!((mat2_det(&id) - 1.0).abs() < 1e-5);
132 }
133
134 #[test]
135 fn test_zero_det() {
136 let z = mat2_zero();
137 assert_eq!(mat2_det(&z), 0.0);
138 }
139
140 #[test]
141 fn test_inverse() {
142 let m = mat2(2.0, 1.0, 5.0, 3.0);
143 let inv = mat2_inverse(&m).expect("should succeed");
144 let prod = mat2_mul(&m, &inv);
145 assert!(mat2_approx_eq(&prod, &mat2_identity(), 1e-5));
146 }
147
148 #[test]
149 fn test_singular_inverse() {
150 let m = mat2(1.0, 2.0, 2.0, 4.0);
151 assert!(mat2_inverse(&m).is_none());
152 }
153
154 #[test]
155 fn test_mul_identity() {
156 let m = mat2(3.0, 7.0, 2.0, 5.0);
157 let id = mat2_identity();
158 let result = mat2_mul(&m, &id);
159 assert!(mat2_approx_eq(&result, &m, 1e-5));
160 }
161
162 #[test]
163 fn test_transpose() {
164 let m = mat2(1.0, 2.0, 3.0, 4.0);
165 let t = mat2_transpose(&m);
166 assert!((t.m[0][1] - 3.0).abs() < 1e-5);
167 assert!((t.m[1][0] - 2.0).abs() < 1e-5);
168 }
169
170 #[test]
171 fn test_mul_vec() {
172 let m = mat2(1.0, 0.0, 0.0, 2.0);
173 let v = mat2_mul_vec(&m, [3.0, 4.0]);
174 assert!((v[0] - 3.0).abs() < 1e-5);
175 assert!((v[1] - 8.0).abs() < 1e-5);
176 }
177
178 #[test]
179 fn test_rotation_matrix() {
180 let r = mat2_rotation(PI / 2.0);
181 let v = mat2_mul_vec(&r, [1.0, 0.0]);
182 assert!(v[0].abs() < 1e-5);
183 assert!((v[1] - 1.0).abs() < 1e-5);
184 }
185
186 #[test]
187 fn test_trace() {
188 let m = mat2(3.0, 1.0, 2.0, 5.0);
189 assert!((mat2_trace(&m) - 8.0).abs() < 1e-5);
190 }
191
192 #[test]
193 fn test_scale() {
194 let m = mat2_identity();
195 let s = mat2_scale(&m, 3.0);
196 assert!((s.m[0][0] - 3.0).abs() < 1e-5);
197 assert!((s.m[1][1] - 3.0).abs() < 1e-5);
198 }
199}