fey_math/
mat2.rs

1use crate::{Angle, Float, Mat3, Num, Signed, Vec2, impl_mat, vec2};
2
3pub type Mat2F = Mat2<f32>;
4
5/// A 2x2 column major matrix.
6#[repr(C)]
7#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
8pub struct Mat2<T> {
9    pub x_axis: Vec2<T>,
10    pub y_axis: Vec2<T>,
11}
12
13/// Create a [`Mat2`].
14#[inline]
15pub const fn mat2<T>(x_axis: Vec2<T>, y_axis: Vec2<T>) -> Mat2<T> {
16    Mat2 { x_axis, y_axis }
17}
18
19impl_mat!(
20    NAME = Mat2
21    SHORT = mat2
22    VEC_TY = Vec2
23    MUL_FN = mul_mat2
24    FIELDS = (x_axis, y_axis)
25    CONSTS = (X_AXIS, Y_AXIS)
26);
27
28impl<T: Copy> Mat2<T> {
29    /// Create from a 3x3 matrix, discarding the 2nd row and column.
30    #[inline]
31    pub fn from_mat3(m: &Mat3<T>) -> Self {
32        mat2(m.x_axis.xy(), m.y_axis.xy())
33    }
34
35    /// Transpose the matrix.
36    #[inline]
37    pub const fn transpose(&self) -> Self {
38        mat2(
39            vec2(self.x_axis.x, self.y_axis.x),
40            vec2(self.x_axis.y, self.y_axis.y),
41        )
42    }
43}
44
45impl<T: Num> Mat2<T> {
46    /// Returns the determinant.
47    #[inline]
48    pub fn determinant(&self) -> T {
49        self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x
50    }
51
52    /// Transforms a 2D vector.
53    #[inline]
54    pub fn transform_vec2(&self, rhs: Vec2<T>) -> Vec2<T> {
55        vec2(
56            self.x_axis.x * rhs.x + self.y_axis.x * rhs.y,
57            self.x_axis.y * rhs.x + self.y_axis.y * rhs.y,
58        )
59    }
60
61    /// Multiply by another matrix.
62    #[inline]
63    pub fn mul_mat2(&self, rhs: &Self) -> Self {
64        mat2(
65            self.transform_vec2(rhs.x_axis),
66            self.transform_vec2(rhs.y_axis),
67        )
68    }
69
70    /// Create a scaling matrix.
71    #[inline]
72    pub fn scale(scale: impl Into<Vec2<T>>) -> Self {
73        let scale = scale.into();
74        mat2(vec2(scale.x, T::ZERO), vec2(T::ZERO, scale.y))
75    }
76}
77
78impl<T: Signed> Mat2<T> {
79    /// Create a rotation matrix.
80    #[inline]
81    pub fn rotation(angle: impl Angle<T>) -> Self {
82        let (sin, cos) = angle.sin_cos();
83        mat2(vec2(cos, sin), vec2(-sin, cos))
84    }
85
86    /// Create a scale + rotation matrix.
87    #[inline]
88    pub fn scale_rotation(scale: impl Into<Vec2<T>>, angle: impl Angle<T>) -> Self {
89        let (sin, cos) = angle.sin_cos();
90        let scale = scale.into();
91        mat2(
92            vec2(cos * scale.x, sin * scale.x),
93            vec2(-sin * scale.y, cos * scale.y),
94        )
95    }
96}
97
98impl<T: Float> Mat2<T> {
99    /// Try to invert the matrix.
100    #[inline]
101    pub fn inverse(&self) -> Option<Self> {
102        let inv_det = {
103            let det = self.determinant();
104            if det == T::ZERO {
105                return None;
106            }
107            T::ONE / det
108        };
109        Some(mat2(
110            vec2(self.y_axis.y * inv_det, self.x_axis.y * -inv_det),
111            vec2(self.y_axis.x * -inv_det, self.x_axis.x * inv_det),
112        ))
113    }
114}