ruby_math/algebra/mat/
mat2d.rs

1#![allow(dead_code)]
2
3use std::{
4    fmt::Display,
5    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
6};
7
8use crate::algebra::{vec2d, Mat2f, Mat3d, Mat4d, Vec2d};
9
10#[derive(Clone, Copy, PartialEq, Debug)]
11pub struct Mat2d {
12    x_axis: Vec2d,
13    y_axis: Vec2d,
14}
15
16pub fn mat2d(m00: f64, m01: f64, m10: f64, m11: f64) -> Mat2d {
17    Mat2d::from_array([m00, m01, m10, m11])
18}
19
20impl Display for Mat2d {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        write!(
23            f,
24            "Mat2d({}, {} | {}, {})",
25            self.x_axis.x(),
26            self.x_axis.y(),
27            self.y_axis.x(),
28            self.y_axis.y()
29        )
30    }
31}
32
33impl Default for Mat2d {
34    fn default() -> Self {
35        Self {
36            x_axis: Vec2d::default(),
37            y_axis: Vec2d::default(),
38        }
39    }
40}
41
42impl Add<Mat2d> for Mat2d {
43    type Output = Mat2d;
44
45    fn add(self, rhs: Mat2d) -> Self::Output {
46        Mat2d::new(self.x_axis + rhs.x_axis, self.y_axis + rhs.y_axis)
47    }
48}
49
50impl Add<f64> for Mat2d {
51    type Output = Mat2d;
52
53    fn add(self, rhs: f64) -> Self::Output {
54        Mat2d::new(self.x_axis + rhs, self.y_axis + rhs)
55    }
56}
57
58impl Add<Mat2d> for f64 {
59    type Output = Mat2d;
60
61    fn add(self, rhs: Mat2d) -> Self::Output {
62        Mat2d::new(self + rhs.x_axis, self + rhs.y_axis)
63    }
64}
65
66impl AddAssign<Mat2d> for Mat2d {
67    fn add_assign(&mut self, rhs: Mat2d) {
68        *self = *self + rhs;
69    }
70}
71
72impl AddAssign<f64> for Mat2d {
73    fn add_assign(&mut self, rhs: f64) {
74        *self = *self + rhs;
75    }
76}
77
78impl Sub<Mat2d> for Mat2d {
79    type Output = Mat2d;
80
81    fn sub(self, rhs: Mat2d) -> Self::Output {
82        Mat2d::new(self.x_axis - rhs.x_axis, self.y_axis - rhs.y_axis)
83    }
84}
85
86impl Sub<f64> for Mat2d {
87    type Output = Mat2d;
88
89    fn sub(self, rhs: f64) -> Self::Output {
90        Mat2d::new(self.x_axis - rhs, self.y_axis - rhs)
91    }
92}
93
94impl Sub<Mat2d> for f64 {
95    type Output = Mat2d;
96
97    fn sub(self, rhs: Mat2d) -> Self::Output {
98        Mat2d::new(self - rhs.x_axis, self - rhs.y_axis)
99    }
100}
101
102impl SubAssign<Mat2d> for Mat2d {
103    fn sub_assign(&mut self, rhs: Mat2d) {
104        *self = *self - rhs;
105    }
106}
107
108impl SubAssign<f64> for Mat2d {
109    fn sub_assign(&mut self, rhs: f64) {
110        *self = *self - rhs;
111    }
112}
113
114impl Mul<Mat2d> for Mat2d {
115    type Output = Mat2d;
116
117    fn mul(self, rhs: Mat2d) -> Self::Output {
118        let m00 = self.x_axis.dot(vec2d(rhs[0][0], rhs[1][0]));
119        let m01 = self.x_axis.dot(vec2d(rhs[0][1], rhs[1][1]));
120        let m10 = self.y_axis.dot(vec2d(rhs[0][0], rhs[1][0]));
121        let m11 = self.y_axis.dot(vec2d(rhs[0][1], rhs[1][1]));
122        Mat2d::new(vec2d(m00, m01), vec2d(m10, m11))
123    }
124}
125
126impl Mul<Vec2d> for Mat2d {
127    type Output = Vec2d;
128
129    fn mul(self, rhs: Vec2d) -> Self::Output {
130        let v0 = self.x_axis.dot(rhs);
131        let v1 = self.y_axis.dot(rhs);
132        vec2d(v0, v1)
133    }
134}
135
136impl Mul<f64> for Mat2d {
137    type Output = Mat2d;
138
139    fn mul(self, rhs: f64) -> Self::Output {
140        Mat2d::new(self.x_axis * rhs, self.y_axis * rhs)
141    }
142}
143
144impl Mul<Mat2d> for f64 {
145    type Output = Mat2d;
146
147    fn mul(self, rhs: Mat2d) -> Self::Output {
148        Mat2d::new(self * rhs.x_axis, self * rhs.y_axis)
149    }
150}
151
152impl MulAssign<Mat2d> for Mat2d {
153    fn mul_assign(&mut self, rhs: Mat2d) {
154        *self = *self * rhs;
155    }
156}
157
158impl MulAssign<f64> for Mat2d {
159    fn mul_assign(&mut self, rhs: f64) {
160        *self = *self * rhs;
161    }
162}
163
164impl Div<f64> for Mat2d {
165    type Output = Mat2d;
166
167    fn div(self, rhs: f64) -> Self::Output {
168        Mat2d::new(self.x_axis / rhs, self.y_axis / rhs)
169    }
170}
171
172impl DivAssign<f64> for Mat2d {
173    fn div_assign(&mut self, rhs: f64) {
174        *self = *self / rhs;
175    }
176}
177
178impl Index<usize> for Mat2d {
179    type Output = Vec2d;
180
181    fn index(&self, index: usize) -> &Self::Output {
182        match index {
183            0 => &self.x_axis,
184            1 => &self.y_axis,
185            _ => panic!("`rmath::algebra::Mat2d::index`: index out of bounds."),
186        }
187    }
188}
189
190impl IndexMut<usize> for Mat2d {
191    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
192        match index {
193            0 => &mut self.x_axis,
194            1 => &mut self.y_axis,
195            _ => panic!("`rmath::algebra::Mat2d::index_mut`: index out of bounds."),
196        }
197    }
198}
199
200impl Mat2d {
201    pub fn new(x_axis: Vec2d, y_axis: Vec2d) -> Self {
202        Self { x_axis, y_axis }
203    }
204
205    pub fn zero() -> Self {
206        Self::new(vec2d(0.0, 0.0), vec2d(0.0, 0.0))
207    }
208
209    pub fn identity() -> Self {
210        Self::new(vec2d(1.0, 0.0), vec2d(0.0, 1.0))
211    }
212}
213
214impl Mat2d {
215    pub fn col(&self, index: usize) -> Vec2d {
216        match index {
217            0 => vec2d(self[0][0], self[1][0]),
218            1 => vec2d(self[0][1], self[1][1]),
219            _ => panic!("`rmath::algebra::Mat2d::col`: index out of bounds."),
220        }
221    }
222
223    pub fn row(&self, index: usize) -> Vec2d {
224        match index {
225            0 => self.x_axis,
226            1 => self.y_axis,
227            _ => panic!("`rmath::algebra::Mat2d::row`: index out of bounds."),
228        }
229    }
230
231    pub fn is_nan(&self) -> bool {
232        self.x_axis.is_nan() || self.y_axis.is_nan()
233    }
234
235    pub fn is_infinite(&self) -> bool {
236        self.x_axis.is_infinite() || self.y_axis.is_infinite()
237    }
238
239    pub fn is_finite(&self) -> bool {
240        self.x_axis.is_finite() && self.y_axis.is_finite()
241    }
242
243    pub fn transpose(&self) -> Self {
244        let (m00, m01) = self.x_axis.to_tuple();
245        let (m10, m11) = self.y_axis.to_tuple();
246        Self::new(vec2d(m00, m10), vec2d(m01, m11))
247    }
248
249    pub fn determinant(&self) -> f64 {
250        let (m00, m01) = self.x_axis.to_tuple();
251        let (m10, m11) = self.y_axis.to_tuple();
252        m00 * m11 - m01 * m10
253    }
254
255    pub fn inverse(&self) -> Self {
256        let det = self.determinant();
257        ruby_assert!(!(det.abs() < f64::EPSILON));
258
259        let inv_det = det.recip();
260        let a00 = self[1][1];
261        let a01 = -self[1][0];
262        let a10 = -self[0][1];
263        let a11 = self[0][0];
264
265        Self::new(vec2d(a00, a10), vec2d(a01, a11)).mul(inv_det)
266    }
267
268    pub fn try_inverse(&self) -> Option<Self> {
269        let det = self.determinant();
270        if det.abs() < f64::EPSILON {
271            return None;
272        }
273
274        let inv_det = det.recip();
275        let a00 = self[1][1];
276        let a01 = -self[1][0];
277        let a10 = -self[0][1];
278        let a11 = self[0][0];
279
280        Some(Self::new(vec2d(a00, a10), vec2d(a01, a11)).mul(inv_det))
281    }
282}
283
284impl From<Mat3d> for Mat2d {
285    fn from(m: Mat3d) -> Self {
286        mat2d(m[0][0], m[0][1], m[1][0], m[1][1])
287    }
288}
289
290impl From<Mat4d> for Mat2d {
291    fn from(m: Mat4d) -> Self {
292        mat2d(m[0][0], m[0][1], m[1][0], m[1][1])
293    }
294}
295
296impl Mat2d {
297    pub fn from_array(m: [f64; 4]) -> Self {
298        Self::new(vec2d(m[0], m[1]), vec2d(m[2], m[3]))
299    }
300
301    pub fn from_array_2d(m: [[f64; 2]; 2]) -> Self {
302        Self::new(vec2d(m[0][0], m[0][1]), vec2d(m[1][0], m[1][1]))
303    }
304
305    pub fn from_diagonal(diagonal: Vec2d) -> Self {
306        Self::new(vec2d(diagonal.x(), 0.0), vec2d(0.0, diagonal.y()))
307    }
308}
309
310impl Mat2d {
311    pub fn to_array(self) -> [f64; 4] {
312        [self[0][0], self[0][1], self[1][0], self[1][1]]
313    }
314
315    pub fn to_array_2d(self) -> [[f64; 2]; 2] {
316        [[self[0][0], self[0][1]], [self[1][0], self[1][1]]]
317    }
318
319    pub fn to_mat3d(self) -> Mat3d {
320        Mat3d::from(self)
321    }
322
323    pub fn to_mat4d(self) -> Mat4d {
324        Mat4d::from(self)
325    }
326
327    pub fn to_mat2f(self) -> Mat2f {
328        Mat2f::new(self.x_axis.to_vec2f(), self.y_axis.to_vec2f())
329    }
330}