1#![allow(unused_imports)]
6
7#[cfg(feature = "f32")]
8mod single;
9use approx::abs_diff_ne;
10use glam_matrix_extras::{SymmetricDMat2, SymmetricDMat3, SymmetricMat2, SymmetricMat3};
11#[cfg(feature = "f32")]
12pub use single::*;
13
14#[cfg(feature = "f64")]
15mod double;
16#[cfg(feature = "f64")]
17pub use double::*;
18
19use bevy_math::{prelude::*, *};
20
21#[cfg(feature = "2d")]
23pub const DIM: usize = 2;
24#[cfg(feature = "3d")]
26pub const DIM: usize = 3;
27
28#[cfg(feature = "2d")]
30pub(crate) use bevy_math::Vec2 as VectorF32;
31
32#[cfg(feature = "3d")]
34pub(crate) use bevy_math::Vec3 as VectorF32;
35
36#[cfg(feature = "2d")]
38pub(crate) use bevy_math::IVec2 as IVector;
39
40#[cfg(feature = "3d")]
42pub(crate) use bevy_math::IVec3 as IVector;
43
44#[cfg(feature = "2d")]
46pub(crate) type Ray = Ray2d;
47
48#[cfg(feature = "3d")]
50pub(crate) type Ray = Ray3d;
51
52#[cfg(feature = "2d")]
55pub(crate) type Dir = Dir2;
56
57#[cfg(feature = "3d")]
59pub(crate) type Dir = Dir3;
60
61#[cfg(feature = "2d")]
63pub(crate) type AngularVector = Scalar;
64
65#[cfg(feature = "3d")]
67pub(crate) type AngularVector = Vector;
68
69#[cfg(feature = "2d")]
74pub(crate) type SymmetricTensor = Scalar;
75
76#[cfg(feature = "3d")]
81pub(crate) type SymmetricTensor = SymmetricMatrix;
82
83#[cfg(feature = "2d")]
85pub(crate) type Rot = crate::physics_transform::Rotation;
86
87#[cfg(feature = "3d")]
89pub(crate) type Rot = Quaternion;
90
91#[cfg(feature = "2d")]
93pub(crate) type Isometry = Isometry2d;
94
95#[cfg(feature = "3d")]
97pub(crate) type Isometry = Isometry3d;
98
99pub trait AdjustPrecision {
101 type Adjusted;
103 fn adjust_precision(&self) -> Self::Adjusted;
105}
106
107pub trait AsF32 {
109 type F32;
111 fn f32(&self) -> Self::F32;
113}
114
115impl AsF32 for DVec3 {
116 type F32 = Vec3;
117 fn f32(&self) -> Self::F32 {
118 self.as_vec3()
119 }
120}
121
122impl AsF32 for Vec3 {
123 type F32 = Self;
124 fn f32(&self) -> Self::F32 {
125 *self
126 }
127}
128
129impl AsF32 for DVec2 {
130 type F32 = Vec2;
131 fn f32(&self) -> Self::F32 {
132 self.as_vec2()
133 }
134}
135
136impl AsF32 for Vec2 {
137 type F32 = Self;
138 fn f32(&self) -> Self::F32 {
139 *self
140 }
141}
142
143impl AsF32 for Vec4 {
144 type F32 = Self;
145 fn f32(&self) -> Self::F32 {
146 *self
147 }
148}
149
150impl AsF32 for DQuat {
151 type F32 = Quat;
152 fn f32(&self) -> Self::F32 {
153 self.as_quat()
154 }
155}
156
157impl AsF32 for Quat {
158 type F32 = Self;
159 fn f32(&self) -> Self::F32 {
160 *self
161 }
162}
163
164impl AsF32 for DMat2 {
165 type F32 = Mat2;
166 fn f32(&self) -> Self::F32 {
167 self.as_mat2()
168 }
169}
170
171impl AsF32 for Mat2 {
172 type F32 = Self;
173 fn f32(&self) -> Self::F32 {
174 *self
175 }
176}
177
178impl AsF32 for SymmetricDMat2 {
179 type F32 = SymmetricMat2;
180 fn f32(&self) -> Self::F32 {
181 SymmetricMat2 {
182 m00: self.m00 as f32,
183 m01: self.m01 as f32,
184 m11: self.m11 as f32,
185 }
186 }
187}
188
189impl AsF32 for SymmetricMat2 {
190 type F32 = Self;
191 fn f32(&self) -> Self::F32 {
192 *self
193 }
194}
195
196impl AsF32 for DMat3 {
197 type F32 = Mat3;
198 fn f32(&self) -> Self::F32 {
199 self.as_mat3()
200 }
201}
202
203impl AsF32 for Mat3 {
204 type F32 = Self;
205 fn f32(&self) -> Self::F32 {
206 *self
207 }
208}
209
210impl AsF32 for SymmetricDMat3 {
211 type F32 = SymmetricMat3;
212 fn f32(&self) -> Self::F32 {
213 SymmetricMat3 {
214 m00: self.m00 as f32,
215 m01: self.m01 as f32,
216 m02: self.m02 as f32,
217 m11: self.m11 as f32,
218 m12: self.m12 as f32,
219 m22: self.m22 as f32,
220 }
221 }
222}
223
224impl AsF32 for SymmetricMat3 {
225 type F32 = Self;
226 fn f32(&self) -> Self::F32 {
227 *self
228 }
229}
230
231#[cfg(feature = "2d")]
232pub(crate) fn cross(a: Vector, b: Vector) -> Scalar {
233 a.perp_dot(b)
234}
235
236#[cfg(feature = "3d")]
237pub(crate) fn cross(a: Vector, b: Vector) -> Vector {
238 a.cross(b)
239}
240
241pub trait RecipOrZero {
243 fn recip_or_zero(self) -> Self;
246}
247
248impl RecipOrZero for f32 {
249 #[inline]
250 fn recip_or_zero(self) -> Self {
251 if self != 0.0 && self.is_finite() {
252 self.recip()
253 } else {
254 0.0
255 }
256 }
257}
258
259impl RecipOrZero for f64 {
260 #[inline]
261 fn recip_or_zero(self) -> Self {
262 if self != 0.0 && self.is_finite() {
263 self.recip()
264 } else {
265 0.0
266 }
267 }
268}
269
270impl RecipOrZero for Vec2 {
271 #[inline]
272 fn recip_or_zero(self) -> Self {
273 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
274 }
275}
276
277impl RecipOrZero for Vec3 {
278 #[inline]
279 fn recip_or_zero(self) -> Self {
280 Self::new(
281 self.x.recip_or_zero(),
282 self.y.recip_or_zero(),
283 self.z.recip_or_zero(),
284 )
285 }
286}
287
288impl RecipOrZero for DVec2 {
289 #[inline]
290 fn recip_or_zero(self) -> Self {
291 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
292 }
293}
294
295impl RecipOrZero for DVec3 {
296 #[inline]
297 fn recip_or_zero(self) -> Self {
298 Self::new(
299 self.x.recip_or_zero(),
300 self.y.recip_or_zero(),
301 self.z.recip_or_zero(),
302 )
303 }
304}
305
306pub trait MatExt {
308 type Scalar;
310
311 fn inverse_or_zero(self) -> Self;
314
315 fn is_isotropic(&self, epsilon: Self::Scalar) -> bool;
321}
322
323impl MatExt for Mat2 {
324 type Scalar = f32;
325
326 #[inline]
327 fn inverse_or_zero(self) -> Self {
328 if self.determinant() == 0.0 {
329 Self::ZERO
330 } else {
331 self.inverse()
332 }
333 }
334
335 #[inline]
336 fn is_isotropic(&self, epsilon: f32) -> bool {
337 let diag = Vec2::new(self.x_axis.x, self.y_axis.y);
339
340 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
342 return false;
343 }
344
345 let off_diag = [self.x_axis.y, self.y_axis.x];
347
348 off_diag.iter().all(|&x| x.abs() < epsilon)
350 }
351}
352
353impl MatExt for DMat2 {
354 type Scalar = f64;
355
356 #[inline]
357 fn inverse_or_zero(self) -> Self {
358 if self.determinant() == 0.0 {
359 Self::ZERO
360 } else {
361 self.inverse()
362 }
363 }
364
365 #[inline]
366 fn is_isotropic(&self, epsilon: f64) -> bool {
367 let diag = DVec2::new(self.x_axis.x, self.y_axis.y);
369
370 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
372 return false;
373 }
374
375 let off_diag = [self.x_axis.y, self.y_axis.x];
377
378 off_diag.iter().all(|&x| x.abs() < epsilon)
380 }
381}
382
383impl MatExt for SymmetricMat2 {
384 type Scalar = f32;
385
386 #[inline]
387 fn inverse_or_zero(self) -> Self {
388 if self.determinant() == 0.0 {
389 Self::ZERO
390 } else {
391 self.inverse()
392 }
393 }
394
395 #[inline]
396 fn is_isotropic(&self, epsilon: f32) -> bool {
397 let diag = Vec2::new(self.m00, self.m11);
399
400 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
402 return false;
403 }
404
405 self.m01.abs() < epsilon
407 }
408}
409
410impl MatExt for SymmetricDMat2 {
411 type Scalar = f64;
412
413 #[inline]
414 fn inverse_or_zero(self) -> Self {
415 if self.determinant() == 0.0 {
416 Self::ZERO
417 } else {
418 self.inverse()
419 }
420 }
421
422 #[inline]
423 fn is_isotropic(&self, epsilon: f64) -> bool {
424 let diag = DVec2::new(self.m00, self.m11);
426
427 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
429 return false;
430 }
431
432 self.m01.abs() < epsilon
434 }
435}
436
437impl MatExt for Mat3 {
438 type Scalar = f32;
439
440 #[inline]
441 fn inverse_or_zero(self) -> Self {
442 if self.determinant() == 0.0 {
443 Self::ZERO
444 } else {
445 self.inverse()
446 }
447 }
448
449 #[inline]
450 fn is_isotropic(&self, epsilon: f32) -> bool {
451 let diag = Vec3::new(self.x_axis.x, self.y_axis.y, self.z_axis.z);
453
454 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
456 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
457 {
458 return false;
459 }
460
461 let off_diag = [
463 self.x_axis.y,
464 self.x_axis.z,
465 self.y_axis.x,
466 self.y_axis.z,
467 self.z_axis.x,
468 self.z_axis.y,
469 ];
470
471 off_diag.iter().all(|&x| x.abs() < epsilon)
473 }
474}
475
476impl MatExt for DMat3 {
477 type Scalar = f64;
478
479 #[inline]
480 fn inverse_or_zero(self) -> Self {
481 if self.determinant() == 0.0 {
482 Self::ZERO
483 } else {
484 self.inverse()
485 }
486 }
487
488 #[inline]
489 fn is_isotropic(&self, epsilon: f64) -> bool {
490 let diag = DVec3::new(self.x_axis.x, self.y_axis.y, self.z_axis.z);
492
493 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
495 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
496 {
497 return false;
498 }
499
500 let off_diag = [
502 self.x_axis.y,
503 self.x_axis.z,
504 self.y_axis.x,
505 self.y_axis.z,
506 self.z_axis.x,
507 self.z_axis.y,
508 ];
509
510 off_diag.iter().all(|&x| x.abs() < epsilon)
512 }
513}
514
515impl MatExt for SymmetricMat3 {
516 type Scalar = f32;
517
518 #[inline]
519 fn inverse_or_zero(self) -> Self {
520 if self.determinant() == 0.0 {
521 Self::ZERO
522 } else {
523 self.inverse()
524 }
525 }
526
527 #[inline]
528 fn is_isotropic(&self, epsilon: f32) -> bool {
529 let diag = Vec3::new(self.m00, self.m11, self.m22);
531
532 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
534 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
535 {
536 return false;
537 }
538
539 let off_diag = [self.m01, self.m02, self.m12];
541
542 off_diag.iter().all(|&x| x.abs() < epsilon)
544 }
545}
546
547impl MatExt for SymmetricDMat3 {
548 type Scalar = f64;
549
550 #[inline]
551 fn inverse_or_zero(self) -> Self {
552 if self.determinant() == 0.0 {
553 Self::ZERO
554 } else {
555 self.inverse()
556 }
557 }
558
559 #[inline]
560 fn is_isotropic(&self, epsilon: f64) -> bool {
561 let diag = DVec3::new(self.m00, self.m11, self.m22);
563
564 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
566 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
567 {
568 return false;
569 }
570
571 let off_diag = [self.m01, self.m02, self.m12];
573
574 off_diag.iter().all(|&x| x.abs() < epsilon)
576 }
577}
578
579#[allow(clippy::unnecessary_cast)]
580#[cfg(all(feature = "2d", any(feature = "parry-f32", feature = "parry-f64")))]
581pub(crate) fn na_iso_to_iso(isometry: &parry::math::Isometry<Scalar>) -> Isometry2d {
582 Isometry2d::new(
583 Vector::from(isometry.translation).f32(),
584 Rot2::from_sin_cos(isometry.rotation.im as f32, isometry.rotation.re as f32),
585 )
586}
587
588#[cfg(all(
589 feature = "default-collider",
590 any(feature = "parry-f32", feature = "parry-f64")
591))]
592use crate::prelude::*;
593
594#[cfg(all(
595 feature = "2d",
596 feature = "default-collider",
597 any(feature = "parry-f32", feature = "parry-f64")
598))]
599pub(crate) fn make_isometry(
600 position: impl Into<Position>,
601 rotation: impl Into<Rotation>,
602) -> parry::math::Isometry<Scalar> {
603 let position: Position = position.into();
604 let rotation: Rotation = rotation.into();
605 parry::math::Isometry::<Scalar>::new(position.0.into(), rotation.into())
606}
607
608#[cfg(all(
609 feature = "3d",
610 feature = "default-collider",
611 any(feature = "parry-f32", feature = "parry-f64")
612))]
613pub(crate) fn make_isometry(
614 position: impl Into<Position>,
615 rotation: impl Into<Rotation>,
616) -> parry::math::Isometry<Scalar> {
617 let position: Position = position.into();
618 let rotation: Rotation = rotation.into();
619 parry::math::Isometry::<Scalar>::new(position.0.into(), rotation.to_scaled_axis().into())
620}
621
622#[inline]
630#[must_use]
631#[cfg(feature = "3d")]
632pub fn skew_symmetric_mat3(v: Vector3) -> Matrix3 {
633 Matrix3::from_cols_array(&[0.0, v.z, -v.y, -v.z, 0.0, v.x, v.y, -v.x, 0.0])
634}
635
636#[inline]
640#[must_use]
641pub fn orthonormal_basis_from_vec(axis: Vector) -> Rot {
642 #[cfg(feature = "2d")]
643 {
644 let normal = axis.perp();
645 orthonormal_basis([axis, normal])
646 }
647 #[cfg(feature = "3d")]
648 {
649 let (normal1, normal2) = axis.any_orthonormal_pair();
650 orthonormal_basis([axis, normal1, normal2])
651 }
652}
653
654#[inline]
658#[must_use]
659pub fn orthonormal_basis(axes: [Vector; DIM]) -> Rot {
660 #[cfg(feature = "2d")]
661 {
662 let mat = Matrix2::from_cols(axes[0], axes[1]);
663 crate::physics_transform::Rotation::from(mat)
664 }
665 #[cfg(feature = "3d")]
666 {
667 let mat = Matrix3::from_cols(axes[0], axes[1], axes[2]);
668 Quaternion::from_mat3(&mat)
669 }
670}