1use crate::{f64::math, swizzles::*, DMat3, DVec2, Mat2};
4use core::fmt;
5use core::iter::{Product, Sum};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8#[inline(always)]
10#[must_use]
11pub const fn dmat2(x_axis: DVec2, y_axis: DVec2) -> DMat2 {
12 DMat2::from_cols(x_axis, y_axis)
13}
14
15#[derive(Clone, Copy)]
17#[cfg_attr(feature = "cuda", repr(align(16)))]
18#[repr(C)]
19pub struct DMat2 {
20 pub x_axis: DVec2,
21 pub y_axis: DVec2,
22}
23
24impl DMat2 {
25 pub const ZERO: Self = Self::from_cols(DVec2::ZERO, DVec2::ZERO);
27
28 pub const IDENTITY: Self = Self::from_cols(DVec2::X, DVec2::Y);
30
31 pub const NAN: Self = Self::from_cols(DVec2::NAN, DVec2::NAN);
33
34 #[allow(clippy::too_many_arguments)]
35 #[inline(always)]
36 #[must_use]
37 const fn new(m00: f64, m01: f64, m10: f64, m11: f64) -> Self {
38 Self {
39 x_axis: DVec2::new(m00, m01),
40 y_axis: DVec2::new(m10, m11),
41 }
42 }
43
44 #[inline(always)]
46 #[must_use]
47 pub const fn from_cols(x_axis: DVec2, y_axis: DVec2) -> Self {
48 Self { x_axis, y_axis }
49 }
50
51 #[inline]
55 #[must_use]
56 pub const fn from_cols_array(m: &[f64; 4]) -> Self {
57 Self::new(m[0], m[1], m[2], m[3])
58 }
59
60 #[inline]
63 #[must_use]
64 pub const fn to_cols_array(&self) -> [f64; 4] {
65 [self.x_axis.x, self.x_axis.y, self.y_axis.x, self.y_axis.y]
66 }
67
68 #[inline]
72 #[must_use]
73 pub const fn from_cols_array_2d(m: &[[f64; 2]; 2]) -> Self {
74 Self::from_cols(DVec2::from_array(m[0]), DVec2::from_array(m[1]))
75 }
76
77 #[inline]
80 #[must_use]
81 pub const fn to_cols_array_2d(&self) -> [[f64; 2]; 2] {
82 [self.x_axis.to_array(), self.y_axis.to_array()]
83 }
84
85 #[doc(alias = "scale")]
87 #[inline]
88 #[must_use]
89 pub const fn from_diagonal(diagonal: DVec2) -> Self {
90 Self::new(diagonal.x, 0.0, 0.0, diagonal.y)
91 }
92
93 #[inline]
96 #[must_use]
97 pub fn from_scale_angle(scale: DVec2, angle: f64) -> Self {
98 let (sin, cos) = math::sin_cos(angle);
99 Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y)
100 }
101
102 #[inline]
104 #[must_use]
105 pub fn from_angle(angle: f64) -> Self {
106 let (sin, cos) = math::sin_cos(angle);
107 Self::new(cos, sin, -sin, cos)
108 }
109
110 #[inline]
112 #[must_use]
113 pub fn from_mat3(m: DMat3) -> Self {
114 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
115 }
116
117 #[inline]
124 #[must_use]
125 pub fn from_mat3_minor(m: DMat3, i: usize, j: usize) -> Self {
126 match (i, j) {
127 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
128 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
129 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
130 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
131 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
132 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
133 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
134 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
135 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
136 _ => panic!("index out of bounds"),
137 }
138 }
139
140 #[inline]
146 #[must_use]
147 pub const fn from_cols_slice(slice: &[f64]) -> Self {
148 Self::new(slice[0], slice[1], slice[2], slice[3])
149 }
150
151 #[inline]
157 pub fn write_cols_to_slice(self, slice: &mut [f64]) {
158 slice[0] = self.x_axis.x;
159 slice[1] = self.x_axis.y;
160 slice[2] = self.y_axis.x;
161 slice[3] = self.y_axis.y;
162 }
163
164 #[inline]
170 #[must_use]
171 pub fn col(&self, index: usize) -> DVec2 {
172 match index {
173 0 => self.x_axis,
174 1 => self.y_axis,
175 _ => panic!("index out of bounds"),
176 }
177 }
178
179 #[inline]
185 pub fn col_mut(&mut self, index: usize) -> &mut DVec2 {
186 match index {
187 0 => &mut self.x_axis,
188 1 => &mut self.y_axis,
189 _ => panic!("index out of bounds"),
190 }
191 }
192
193 #[inline]
199 #[must_use]
200 pub fn row(&self, index: usize) -> DVec2 {
201 match index {
202 0 => DVec2::new(self.x_axis.x, self.y_axis.x),
203 1 => DVec2::new(self.x_axis.y, self.y_axis.y),
204 _ => panic!("index out of bounds"),
205 }
206 }
207
208 #[inline]
211 #[must_use]
212 pub fn is_finite(&self) -> bool {
213 self.x_axis.is_finite() && self.y_axis.is_finite()
214 }
215
216 #[inline]
218 #[must_use]
219 pub fn is_nan(&self) -> bool {
220 self.x_axis.is_nan() || self.y_axis.is_nan()
221 }
222
223 #[inline]
225 #[must_use]
226 pub fn transpose(&self) -> Self {
227 Self {
228 x_axis: DVec2::new(self.x_axis.x, self.y_axis.x),
229 y_axis: DVec2::new(self.x_axis.y, self.y_axis.y),
230 }
231 }
232
233 #[inline]
235 #[must_use]
236 pub fn determinant(&self) -> f64 {
237 self.x_axis.x * self.y_axis.y - self.x_axis.y * self.y_axis.x
238 }
239
240 #[inline]
248 #[must_use]
249 pub fn inverse(&self) -> Self {
250 let inv_det = {
251 let det = self.determinant();
252 glam_assert!(det != 0.0);
253 det.recip()
254 };
255 Self::new(
256 self.y_axis.y * inv_det,
257 self.x_axis.y * -inv_det,
258 self.y_axis.x * -inv_det,
259 self.x_axis.x * inv_det,
260 )
261 }
262
263 #[inline]
265 #[must_use]
266 pub fn mul_vec2(&self, rhs: DVec2) -> DVec2 {
267 #[allow(clippy::suspicious_operation_groupings)]
268 DVec2::new(
269 (self.x_axis.x * rhs.x) + (self.y_axis.x * rhs.y),
270 (self.x_axis.y * rhs.x) + (self.y_axis.y * rhs.y),
271 )
272 }
273
274 #[inline]
276 #[must_use]
277 pub fn mul_mat2(&self, rhs: &Self) -> Self {
278 Self::from_cols(self.mul(rhs.x_axis), self.mul(rhs.y_axis))
279 }
280
281 #[inline]
283 #[must_use]
284 pub fn add_mat2(&self, rhs: &Self) -> Self {
285 Self::from_cols(self.x_axis.add(rhs.x_axis), self.y_axis.add(rhs.y_axis))
286 }
287
288 #[inline]
290 #[must_use]
291 pub fn sub_mat2(&self, rhs: &Self) -> Self {
292 Self::from_cols(self.x_axis.sub(rhs.x_axis), self.y_axis.sub(rhs.y_axis))
293 }
294
295 #[inline]
297 #[must_use]
298 pub fn mul_scalar(&self, rhs: f64) -> Self {
299 Self::from_cols(self.x_axis.mul(rhs), self.y_axis.mul(rhs))
300 }
301
302 #[inline]
304 #[must_use]
305 pub fn div_scalar(&self, rhs: f64) -> Self {
306 let rhs = DVec2::splat(rhs);
307 Self::from_cols(self.x_axis.div(rhs), self.y_axis.div(rhs))
308 }
309
310 #[inline]
320 #[must_use]
321 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
322 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
323 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
324 }
325
326 #[inline]
328 #[must_use]
329 pub fn abs(&self) -> Self {
330 Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
331 }
332
333 #[inline]
334 pub fn as_mat2(&self) -> Mat2 {
335 Mat2::from_cols(self.x_axis.as_vec2(), self.y_axis.as_vec2())
336 }
337}
338
339impl Default for DMat2 {
340 #[inline]
341 fn default() -> Self {
342 Self::IDENTITY
343 }
344}
345
346impl Add<DMat2> for DMat2 {
347 type Output = Self;
348 #[inline]
349 fn add(self, rhs: Self) -> Self::Output {
350 self.add_mat2(&rhs)
351 }
352}
353
354impl AddAssign<DMat2> for DMat2 {
355 #[inline]
356 fn add_assign(&mut self, rhs: Self) {
357 *self = self.add_mat2(&rhs);
358 }
359}
360
361impl Sub<DMat2> for DMat2 {
362 type Output = Self;
363 #[inline]
364 fn sub(self, rhs: Self) -> Self::Output {
365 self.sub_mat2(&rhs)
366 }
367}
368
369impl SubAssign<DMat2> for DMat2 {
370 #[inline]
371 fn sub_assign(&mut self, rhs: Self) {
372 *self = self.sub_mat2(&rhs);
373 }
374}
375
376impl Neg for DMat2 {
377 type Output = Self;
378 #[inline]
379 fn neg(self) -> Self::Output {
380 Self::from_cols(self.x_axis.neg(), self.y_axis.neg())
381 }
382}
383
384impl Mul<DMat2> for DMat2 {
385 type Output = Self;
386 #[inline]
387 fn mul(self, rhs: Self) -> Self::Output {
388 self.mul_mat2(&rhs)
389 }
390}
391
392impl MulAssign<DMat2> for DMat2 {
393 #[inline]
394 fn mul_assign(&mut self, rhs: Self) {
395 *self = self.mul_mat2(&rhs);
396 }
397}
398
399impl Mul<DVec2> for DMat2 {
400 type Output = DVec2;
401 #[inline]
402 fn mul(self, rhs: DVec2) -> Self::Output {
403 self.mul_vec2(rhs)
404 }
405}
406
407impl Mul<DMat2> for f64 {
408 type Output = DMat2;
409 #[inline]
410 fn mul(self, rhs: DMat2) -> Self::Output {
411 rhs.mul_scalar(self)
412 }
413}
414
415impl Mul<f64> for DMat2 {
416 type Output = Self;
417 #[inline]
418 fn mul(self, rhs: f64) -> Self::Output {
419 self.mul_scalar(rhs)
420 }
421}
422
423impl MulAssign<f64> for DMat2 {
424 #[inline]
425 fn mul_assign(&mut self, rhs: f64) {
426 *self = self.mul_scalar(rhs);
427 }
428}
429
430impl Div<DMat2> for f64 {
431 type Output = DMat2;
432 #[inline]
433 fn div(self, rhs: DMat2) -> Self::Output {
434 rhs.div_scalar(self)
435 }
436}
437
438impl Div<f64> for DMat2 {
439 type Output = Self;
440 #[inline]
441 fn div(self, rhs: f64) -> Self::Output {
442 self.div_scalar(rhs)
443 }
444}
445
446impl DivAssign<f64> for DMat2 {
447 #[inline]
448 fn div_assign(&mut self, rhs: f64) {
449 *self = self.div_scalar(rhs);
450 }
451}
452
453impl Sum<Self> for DMat2 {
454 fn sum<I>(iter: I) -> Self
455 where
456 I: Iterator<Item = Self>,
457 {
458 iter.fold(Self::ZERO, Self::add)
459 }
460}
461
462impl<'a> Sum<&'a Self> for DMat2 {
463 fn sum<I>(iter: I) -> Self
464 where
465 I: Iterator<Item = &'a Self>,
466 {
467 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
468 }
469}
470
471impl Product for DMat2 {
472 fn product<I>(iter: I) -> Self
473 where
474 I: Iterator<Item = Self>,
475 {
476 iter.fold(Self::IDENTITY, Self::mul)
477 }
478}
479
480impl<'a> Product<&'a Self> for DMat2 {
481 fn product<I>(iter: I) -> Self
482 where
483 I: Iterator<Item = &'a Self>,
484 {
485 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
486 }
487}
488
489impl PartialEq for DMat2 {
490 #[inline]
491 fn eq(&self, rhs: &Self) -> bool {
492 self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis)
493 }
494}
495
496#[cfg(not(target_arch = "spirv"))]
497impl AsRef<[f64; 4]> for DMat2 {
498 #[inline]
499 fn as_ref(&self) -> &[f64; 4] {
500 unsafe { &*(self as *const Self as *const [f64; 4]) }
501 }
502}
503
504#[cfg(not(target_arch = "spirv"))]
505impl AsMut<[f64; 4]> for DMat2 {
506 #[inline]
507 fn as_mut(&mut self) -> &mut [f64; 4] {
508 unsafe { &mut *(self as *mut Self as *mut [f64; 4]) }
509 }
510}
511
512impl fmt::Debug for DMat2 {
513 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
514 fmt.debug_struct(stringify!(DMat2))
515 .field("x_axis", &self.x_axis)
516 .field("y_axis", &self.y_axis)
517 .finish()
518 }
519}
520
521impl fmt::Display for DMat2 {
522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523 if let Some(p) = f.precision() {
524 write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
525 } else {
526 write!(f, "[{}, {}]", self.x_axis, self.y_axis)
527 }
528 }
529}