#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Mat2 {
pub m: [[f32; 2]; 2],
}
pub fn mat2_identity() -> Mat2 {
Mat2 {
m: [[1.0, 0.0], [0.0, 1.0]],
}
}
pub fn mat2_mul(a: &Mat2, b: &Mat2) -> Mat2 {
Mat2 {
m: [
[
a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[1][0],
a.m[0][0] * b.m[0][1] + a.m[0][1] * b.m[1][1],
],
[
a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[1][0],
a.m[1][0] * b.m[0][1] + a.m[1][1] * b.m[1][1],
],
],
}
}
pub fn mat2_det(m: &Mat2) -> f32 {
m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0]
}
pub fn mat2_inverse(m: &Mat2) -> Option<Mat2> {
let det = mat2_det(m);
if det.abs() < 1e-9 {
return None;
}
let inv_det = 1.0 / det;
Some(Mat2 {
m: [
[m.m[1][1] * inv_det, -m.m[0][1] * inv_det],
[-m.m[1][0] * inv_det, m.m[0][0] * inv_det],
],
})
}
pub fn mat2_inv(m: &Mat2) -> Option<Mat2> {
mat2_inverse(m)
}
pub fn mat2_transform(m: &Mat2, v: [f32; 2]) -> [f32; 2] {
[
m.m[0][0] * v[0] + m.m[0][1] * v[1],
m.m[1][0] * v[0] + m.m[1][1] * v[1],
]
}
pub fn mat2_mul_vec2(a: &Mat2, v: [f32; 2]) -> [f32; 2] {
mat2_transform(a, v)
}
pub fn mat2_transpose(m: &Mat2) -> Mat2 {
Mat2 {
m: [[m.m[0][0], m.m[1][0]], [m.m[0][1], m.m[1][1]]],
}
}
pub fn mat2_from_angle(angle_rad: f32) -> Mat2 {
let c = angle_rad.cos();
let s = angle_rad.sin();
Mat2 {
m: [[c, -s], [s, c]],
}
}
pub fn mat2_scale(sx: f32, sy: f32) -> Mat2 {
Mat2 {
m: [[sx, 0.0], [0.0, sy]],
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::FRAC_PI_2;
const EPS: f32 = 1e-5;
#[test]
fn test_identity() {
let id = mat2_identity();
assert_eq!(id.m, [[1.0, 0.0], [0.0, 1.0]]);
}
#[test]
fn test_mul_identity() {
let id = mat2_identity();
let a = Mat2 {
m: [[2.0, 3.0], [4.0, 5.0]],
};
let r = mat2_mul(&id, &a);
assert!((r.m[0][0] - 2.0).abs() < EPS);
assert!((r.m[1][1] - 5.0).abs() < EPS);
}
#[test]
fn test_mul() {
let a = Mat2 {
m: [[1.0, 2.0], [3.0, 4.0]],
};
let b = Mat2 {
m: [[5.0, 6.0], [7.0, 8.0]],
};
let r = mat2_mul(&a, &b);
assert!((r.m[0][0] - 19.0).abs() < EPS);
assert!((r.m[0][1] - 22.0).abs() < EPS);
assert!((r.m[1][0] - 43.0).abs() < EPS);
assert!((r.m[1][1] - 50.0).abs() < EPS);
}
#[test]
fn test_det_identity() {
let id = mat2_identity();
assert!((mat2_det(&id) - 1.0).abs() < EPS);
}
#[test]
fn test_det_zero() {
let m = Mat2 {
m: [[1.0, 2.0], [2.0, 4.0]],
};
assert!(mat2_det(&m).abs() < EPS);
}
#[test]
fn test_inv_identity() {
let id = mat2_identity();
let inv = mat2_inverse(&id).expect("should succeed");
assert!((inv.m[0][0] - 1.0).abs() < EPS);
assert!((inv.m[1][1] - 1.0).abs() < EPS);
}
#[test]
fn test_inv_singular() {
let m = Mat2 {
m: [[1.0, 2.0], [2.0, 4.0]],
};
assert!(mat2_inverse(&m).is_none());
}
#[test]
fn test_from_angle_90() {
let r = mat2_from_angle(FRAC_PI_2);
let v = mat2_mul_vec2(&r, [1.0, 0.0]);
assert!((v[0] - 0.0).abs() < 1e-5);
assert!((v[1] - 1.0).abs() < 1e-5);
}
#[test]
fn test_scale() {
let s = mat2_scale(2.0, 3.0);
let v = mat2_mul_vec2(&s, [1.0, 1.0]);
assert!((v[0] - 2.0).abs() < EPS);
assert!((v[1] - 3.0).abs() < EPS);
}
}