1use core::iter::Sum;
2use core::ops::*;
3#[cfg(feature = "f64")]
4use glam::{DVec2, DVec3};
5use glam::{Vec2, Vec3};
6
7#[cfg(feature = "bevy_reflect")]
8use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize, std_traits::ReflectDefault};
9
10#[cfg(feature = "f64")]
11use crate::{DMat23, SymmetricDMat2, SymmetricDMat3};
12#[cfg(feature = "f32")]
13use crate::{Mat23, SymmetricMat2, SymmetricMat3};
14
15macro_rules! symmetric_mat5s {
16 ($($n:ident => $symmetricm2t:ident, $symmetricm3t:ident, $m23t:ident, $v2t:ident, $v3t:ident, $t:ident),+) => {
17 $(
18 #[derive(Clone, Copy, PartialEq)]
41 #[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
42 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43 #[cfg_attr(
44 all(feature = "bevy_reflect", feature = "serde"),
45 reflect(Debug, Default, PartialEq, Serialize, Deserialize)
46 )]
47 pub struct $n {
48 pub a: $symmetricm3t,
51 pub b: $m23t,
53 pub d: $symmetricm2t,
56 }
57
58 impl $n {
59 pub const ZERO: Self = Self::new(
61 $symmetricm3t::ZERO,
62 $m23t::ZERO,
63 $symmetricm2t::ZERO,
64 );
65
66 pub const IDENTITY: Self = Self::new(
69 $symmetricm3t::IDENTITY,
70 $m23t::ZERO,
71 $symmetricm2t::IDENTITY,
72 );
73
74 pub const NAN: Self = Self::new(
76 $symmetricm3t::NAN,
77 $m23t::NAN,
78 $symmetricm2t::NAN,
79 );
80
81 #[inline(always)]
90 #[must_use]
91 pub const fn new(
92 a: $symmetricm3t,
93 b: $m23t,
94 d: $symmetricm2t,
95 ) -> Self {
96 Self { a, b, d }
97 }
98
99 #[inline]
101 #[must_use]
102 pub fn from_outer_product(v1: $v3t, v2: $v2t) -> Self {
103 Self::new(
104 $symmetricm3t::from_outer_product(v1),
105 $m23t::from_outer_product(v2, v1),
106 $symmetricm2t::from_outer_product(v2),
107 )
108 }
109
110 #[inline]
113 #[must_use]
114 pub fn is_finite(&self) -> bool {
115 self.a.is_finite() && self.b.is_finite() && self.d.is_finite()
116 }
117
118 #[inline]
120 #[must_use]
121 pub fn is_nan(&self) -> bool {
122 self.a.is_nan() || self.b.is_nan() || self.d.is_nan()
123 }
124
125 #[inline]
129 #[must_use]
130 pub fn inverse(&self) -> Self {
131 let inv_d = self.d.inverse();
132 let bt_inv_d = inv_d.mul(self.b);
133 let bt_inv_d_b = $symmetricm3t::complete_mat23_sandwich(&bt_inv_d, &self.b);
134
135 let res_a = self.a.sub(bt_inv_d_b).inverse();
136 let neg_res_bt = bt_inv_d.mul(res_a);
137 let res_d = $symmetricm2t::complete_mat23_sandwich(&bt_inv_d, &neg_res_bt).add(inv_d);
138
139 Self::new(res_a, -neg_res_bt, res_d)
140 }
141
142 #[inline]
144 #[must_use]
145 pub fn inverse_or_zero(&self) -> Self {
146 let inverse = self.inverse();
148 if inverse.is_finite() {
149 inverse
150 } else {
151 Self::ZERO
152 }
153 }
154
155 #[inline]
157 #[must_use]
158 pub fn abs(&self) -> Self {
159 Self::new(self.a.abs(), self.b.abs(), self.d.abs())
160 }
161
162 #[inline]
164 #[must_use]
165 pub fn mul_vec5(&self, rhs1: $v3t, rhs2: $v2t) -> ($v3t, $v2t) {
166 let res1 = $v3t::new(
167 rhs1.x * self.a.m00 + rhs1.y * self.a.m01 + rhs1.z * self.a.m02 + rhs2.dot(self.b.col(0)),
168 rhs1.x * self.a.m01 + rhs1.y * self.a.m11 + rhs1.z * self.a.m12 + rhs2.dot(self.b.col(1)),
169 rhs1.x * self.a.m02 + rhs1.y * self.a.m12 + rhs1.z * self.a.m22 + rhs2.dot(self.b.col(2)),
170 );
171 let res2 = $v2t::new(
172 rhs1.dot(self.b.row(0)) + rhs2.x * self.d.m00 + rhs2.y * self.d.m01,
173 rhs1.dot(self.b.row(1)) + rhs2.x * self.d.m01 + rhs2.y * self.d.m11,
174 );
175 (res1, res2)
176 }
177
178 #[inline]
180 #[must_use]
181 pub fn add_symmetric_mat5(&self, rhs: &Self) -> Self {
182 self.add(rhs)
183 }
184
185 #[inline]
187 #[must_use]
188 pub fn sub_symmetric_mat5(&self, rhs: &Self) -> Self {
189 self.sub(rhs)
190 }
191
192 #[inline]
194 #[must_use]
195 pub fn mul_scalar(&self, rhs: $t) -> Self {
196 Self::new(
197 self.a.mul_scalar(rhs),
198 self.b.mul_scalar(rhs),
199 self.d.mul_scalar(rhs),
200 )
201 }
202
203 #[inline]
205 #[must_use]
206 pub fn div_scalar(&self, rhs: $t) -> Self {
207 Self::new(
208 self.a.div_scalar(rhs),
209 self.b.div_scalar(rhs),
210 self.d.div_scalar(rhs),
211 )
212 }
213 }
214
215 impl Default for $n {
216 #[inline(always)]
217 fn default() -> Self {
218 Self::IDENTITY
219 }
220 }
221
222 impl Add for $n {
223 type Output = Self;
224 #[inline]
225 fn add(self, rhs: Self) -> Self::Output {
226 Self::new(self.a.add(rhs.a), self.b.add(rhs.b), self.d.add(rhs.d))
227 }
228 }
229
230 impl Add<&Self> for $n {
231 type Output = Self;
232 #[inline]
233 fn add(self, rhs: &Self) -> Self::Output {
234 self.add(*rhs)
235 }
236 }
237
238 impl Add<Self> for &$n {
239 type Output = $n;
240 #[inline]
241 fn add(self, rhs: Self) -> Self::Output {
242 (*self).add(rhs)
243 }
244 }
245
246 impl Add<&Self> for &$n {
247 type Output = $n;
248 #[inline]
249 fn add(self, rhs: &Self) -> Self::Output {
250 (*self).add(*rhs)
251 }
252 }
253
254 impl AddAssign for $n {
255 #[inline]
256 fn add_assign(&mut self, rhs: Self) {
257 *self = self.add(rhs);
258 }
259 }
260
261 impl AddAssign<&Self> for $n {
262 #[inline]
263 fn add_assign(&mut self, rhs: &Self) {
264 self.add_assign(*rhs);
265 }
266 }
267
268 impl Sub for $n {
269 type Output = Self;
270 #[inline]
271 fn sub(self, rhs: Self) -> Self::Output {
272 Self::new(self.a.sub(rhs.a), self.b.sub(rhs.b), self.d.sub(rhs.d))
273 }
274 }
275
276 impl Sub<&Self> for $n {
277 type Output = Self;
278 #[inline]
279 fn sub(self, rhs: &Self) -> Self::Output {
280 self.sub(*rhs)
281 }
282 }
283
284 impl Sub<Self> for &$n {
285 type Output = $n;
286 #[inline]
287 fn sub(self, rhs: Self) -> Self::Output {
288 (*self).sub(rhs)
289 }
290 }
291
292 impl Sub<&Self> for &$n {
293 type Output = $n;
294 #[inline]
295 fn sub(self, rhs: &Self) -> Self::Output {
296 (*self).sub(*rhs)
297 }
298 }
299
300 impl SubAssign for $n {
301 #[inline]
302 fn sub_assign(&mut self, rhs: Self) {
303 *self = self.sub(rhs);
304 }
305 }
306
307 impl SubAssign<&Self> for $n {
308 #[inline]
309 fn sub_assign(&mut self, rhs: &Self) {
310 self.sub_assign(*rhs);
311 }
312 }
313
314 impl Neg for $n {
315 type Output = Self;
316 #[inline]
317 fn neg(self) -> Self::Output {
318 Self::new(-self.a, -self.b, -self.d)
319 }
320 }
321
322 impl Neg for &$n {
323 type Output = $n;
324 #[inline]
325 fn neg(self) -> Self::Output {
326 (*self).neg()
327 }
328 }
329
330 impl Mul<$n> for $t {
331 type Output = $n;
332 #[inline]
333 fn mul(self, rhs: $n) -> Self::Output {
334 rhs.mul_scalar(self)
335 }
336 }
337
338 impl Mul<&$n> for $t {
339 type Output = $n;
340 #[inline]
341 fn mul(self, rhs: &$n) -> Self::Output {
342 self.mul(*rhs)
343 }
344 }
345
346 impl Mul<$n> for &$t {
347 type Output = $n;
348 #[inline]
349 fn mul(self, rhs: $n) -> Self::Output {
350 (*self).mul(rhs)
351 }
352 }
353
354 impl Mul<&$n> for &$t {
355 type Output = $n;
356 #[inline]
357 fn mul(self, rhs: &$n) -> Self::Output {
358 (*self).mul(*rhs)
359 }
360 }
361
362 impl Mul<$t> for $n {
363 type Output = Self;
364 #[inline]
365 fn mul(self, rhs: $t) -> Self::Output {
366 self.mul_scalar(rhs)
367 }
368 }
369
370 impl Mul<&$t> for $n {
371 type Output = Self;
372 #[inline]
373 fn mul(self, rhs: &$t) -> Self::Output {
374 self.mul(*rhs)
375 }
376 }
377
378 impl Mul<$t> for &$n {
379 type Output = $n;
380 #[inline]
381 fn mul(self, rhs: $t) -> Self::Output {
382 (*self).mul(rhs)
383 }
384 }
385
386 impl Mul<&$t> for &$n {
387 type Output = $n;
388 #[inline]
389 fn mul(self, rhs: &$t) -> Self::Output {
390 (*self).mul(*rhs)
391 }
392 }
393
394 impl MulAssign<$t> for $n {
395 #[inline]
396 fn mul_assign(&mut self, rhs: $t) {
397 *self = self.mul(rhs);
398 }
399 }
400
401 impl MulAssign<&$t> for $n {
402 #[inline]
403 fn mul_assign(&mut self, rhs: &$t) {
404 self.mul_assign(*rhs);
405 }
406 }
407
408 impl Div<$n> for $t {
409 type Output = $n;
410 #[inline]
411 fn div(self, rhs: $n) -> Self::Output {
412 rhs.div_scalar(self)
413 }
414 }
415
416 impl Div<&$n> for $t {
417 type Output = $n;
418 #[inline]
419 fn div(self, rhs: &$n) -> Self::Output {
420 self.div(*rhs)
421 }
422 }
423
424 impl Div<$n> for &$t {
425 type Output = $n;
426 #[inline]
427 fn div(self, rhs: $n) -> Self::Output {
428 (*self).div(rhs)
429 }
430 }
431
432 impl Div<&$n> for &$t {
433 type Output = $n;
434 #[inline]
435 fn div(self, rhs: &$n) -> Self::Output {
436 (*self).div(*rhs)
437 }
438 }
439
440 impl Div<$t> for $n {
441 type Output = Self;
442 #[inline]
443 fn div(self, rhs: $t) -> Self::Output {
444 self.div_scalar(rhs)
445 }
446 }
447
448 impl Div<&$t> for $n {
449 type Output = Self;
450 #[inline]
451 fn div(self, rhs: &$t) -> Self::Output {
452 self.div(*rhs)
453 }
454 }
455
456 impl Div<$t> for &$n {
457 type Output = $n;
458 #[inline]
459 fn div(self, rhs: $t) -> Self::Output {
460 (*self).div(rhs)
461 }
462 }
463
464 impl Div<&$t> for &$n {
465 type Output = $n;
466 #[inline]
467 fn div(self, rhs: &$t) -> Self::Output {
468 (*self).div(*rhs)
469 }
470 }
471
472 impl DivAssign<$t> for $n {
473 #[inline]
474 fn div_assign(&mut self, rhs: $t) {
475 *self = self.div(rhs);
476 }
477 }
478
479 impl DivAssign<&$t> for $n {
480 #[inline]
481 fn div_assign(&mut self, rhs: &$t) {
482 self.div_assign(*rhs);
483 }
484 }
485
486 impl Sum<$n> for $n {
487 fn sum<I: Iterator<Item = $n>>(iter: I) -> Self {
488 iter.fold(Self::ZERO, Self::add)
489 }
490 }
491
492 impl<'a> Sum<&'a $n> for $n {
493 fn sum<I: Iterator<Item = &'a $n>>(iter: I) -> Self {
494 iter.fold(Self::ZERO, |a, &b| a.add(b))
495 }
496 }
497
498 #[cfg(feature = "approx")]
499 impl approx::AbsDiffEq for $n {
500 type Epsilon = $t;
501
502 #[inline]
503 fn default_epsilon() -> Self::Epsilon {
504 $t::default_epsilon()
505 }
506
507 #[inline]
508 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
509 self.a.abs_diff_eq(&other.a, epsilon)
510 && self.b.abs_diff_eq(&other.b, epsilon)
511 && self.d.abs_diff_eq(&other.d, epsilon)
512 }
513 }
514
515 #[cfg(feature = "approx")]
516 impl approx::RelativeEq for $n {
517 #[inline]
518 fn default_max_relative() -> Self::Epsilon {
519 $t::default_max_relative()
520 }
521
522 #[inline]
523 fn relative_eq(
524 &self,
525 other: &Self,
526 epsilon: Self::Epsilon,
527 max_relative: Self::Epsilon,
528 ) -> bool {
529 self.a.relative_eq(&other.a, epsilon, max_relative)
530 && self.b.relative_eq(&other.b, epsilon, max_relative)
531 && self.d.relative_eq(&other.d, epsilon, max_relative)
532 }
533 }
534
535 #[cfg(feature = "approx")]
536 impl approx::UlpsEq for $n {
537 #[inline]
538 fn default_max_ulps() -> u32 {
539 $t::default_max_ulps()
540 }
541
542 #[inline]
543 fn ulps_eq(
544 &self,
545 other: &Self,
546 epsilon: Self::Epsilon,
547 max_ulps: u32,
548 ) -> bool {
549 self.a.ulps_eq(&other.a, epsilon, max_ulps)
550 && self.b.ulps_eq(&other.b, epsilon, max_ulps)
551 && self.d.ulps_eq(&other.d, epsilon, max_ulps)
552 }
553 }
554
555 impl core::fmt::Debug for $n {
556 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
557 f.debug_struct(stringify!($n))
558 .field("a", &self.a)
559 .field("b", &self.b)
560 .field("d", &self.d)
561 .finish()
562 }
563 }
564
565 impl core::fmt::Display for $n {
566 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
567 if let Some(p) = f.precision() {
568 write!(
569 f,
570 r#"[
571 [{:.*}, {:.*}, {:.*}, {:.*}, {:.*}],
572 [{:.*}, {:.*}, {:.*}, {:.*}, {:.*}],
573 [{:.*}, {:.*}, {:.*}, {:.*}, {:.*}],
574 [{:.*}, {:.*}, {:.*}, {:.*}, {:.*}],
575 [{:.*}, {:.*}, {:.*}, {:.*}, {:.*}],
576]"#,
577 p, self.a.m00, p, self.a.m01, p, self.a.m02, p, self.b.x_axis.x, p, self.b.x_axis.y,
578 p, self.a.m01, p, self.a.m11, p, self.a.m12, p, self.b.y_axis.x, p, self.b.y_axis.y,
579 p, self.a.m02, p, self.a.m12, p, self.a.m22, p, self.b.z_axis.x, p, self.b.z_axis.y,
580 p, self.b.x_axis.x, p, self.b.y_axis.x, p, self.b.z_axis.x, p, self.d.m00, p, self.d.m01,
581 p, self.b.x_axis.y, p, self.b.y_axis.y, p, self.b.z_axis.y, p, self.d.m01, p, self.d.m11,
582 )
583 } else {
584 write!(
585 f,
586 r#"[
587 [{}, {}, {}, {}, {}],
588 [{}, {}, {}, {}, {}],
589 [{}, {}, {}, {}, {}],
590 [{}, {}, {}, {}, {}],
591 [{}, {}, {}, {}, {}],
592]"#,
593 self.a.m00, self.a.m01, self.a.m02, self.b.x_axis.x, self.b.x_axis.y,
594 self.a.m01, self.a.m11, self.a.m12, self.b.y_axis.x, self.b.y_axis.y,
595 self.a.m02, self.a.m12, self.a.m22, self.b.z_axis.x, self.b.z_axis.y,
596 self.b.x_axis.x, self.b.y_axis.x, self.b.z_axis.x, self.d.m00, self.d.m01,
597 self.b.x_axis.y, self.b.y_axis.y, self.b.z_axis.y, self.d.m01, self.d.m11,
598 )
599 }
600 }
601 }
602 )+
603 }
604}
605
606#[cfg(feature = "f32")]
607symmetric_mat5s!(SymmetricMat5 => SymmetricMat2, SymmetricMat3, Mat23, Vec2, Vec3, f32);
608
609#[cfg(feature = "f64")]
610symmetric_mat5s!(SymmetricDMat5 => SymmetricDMat2, SymmetricDMat3, DMat23, DVec2, DVec3, f64);
611
612#[cfg(all(feature = "f32", feature = "f64"))]
613impl SymmetricMat5 {
614 #[inline]
616 #[must_use]
617 pub fn as_symmetric_dmat5(&self) -> SymmetricDMat5 {
618 SymmetricDMat5 {
619 a: self.a.as_symmetric_dmat3(),
620 b: self.b.as_dmat23(),
621 d: self.d.as_symmetric_dmat2(),
622 }
623 }
624}
625
626#[cfg(all(feature = "f32", feature = "f64"))]
627impl SymmetricDMat5 {
628 #[inline]
630 #[must_use]
631 pub fn as_symmetric_mat5(&self) -> SymmetricMat5 {
632 SymmetricMat5 {
633 a: self.a.as_symmetric_mat3(),
634 b: self.b.as_mat23(),
635 d: self.d.as_symmetric_mat2(),
636 }
637 }
638}
639
640#[cfg(test)]
641mod tests {
642 use approx::assert_relative_eq;
643 use glam::{Vec2, Vec3, vec2, vec3};
644
645 use crate::{Mat23, SymmetricMat2, SymmetricMat3, SymmetricMat5};
646
647 #[test]
648 fn mul_vec5() {
649 let mat = SymmetricMat5::from_outer_product(Vec3::new(1.0, 2.0, 3.0), Vec2::new(4.0, 5.0));
650
651 let (res1, res2) = mat.mul_vec5(Vec3::new(1.0, 2.0, 3.0), Vec2::new(4.0, 5.0));
652
653 assert_eq!(res1, vec3(55.0, 110.0, 165.0));
654 assert_eq!(res2, vec2(220.0, 275.0));
655 }
656
657 #[test]
658 fn inverse() {
659 let a = SymmetricMat3::new(1.0, 6.0, 7.0, 2.0, 10.0, 3.0);
660 let b = Mat23::from_cols(vec2(8.0, 9.0), vec2(11.0, 12.0), vec2(13.0, 14.0));
661 let d = SymmetricMat2::new(4.0, 15.0, 5.0);
662 let mat = SymmetricMat5 { a, b, d };
663
664 let x1 = Vec3::new(1.0, 2.0, 3.0);
666 let x2 = Vec2::new(4.0, 5.0);
667
668 let (rhs1, rhs2) = mat.mul_vec5(x1, x2);
670
671 let (sol1, sol2) = mat.inverse().mul_vec5(rhs1, rhs2);
673
674 assert_relative_eq!(sol1, x1, epsilon = 1e-5);
676 assert_relative_eq!(sol2, x2, epsilon = 1e-5);
677 }
678}