1#![allow(unused_imports)]
6
7mod drot2;
8pub use drot2::*;
9
10#[cfg(not(feature = "f64"))]
11mod single;
12#[cfg(not(feature = "f64"))]
13pub use single::*;
14
15#[cfg(feature = "f64")]
16mod double;
17#[cfg(feature = "f64")]
18pub use double::*;
19
20use approx::abs_diff_ne;
21use bevy_math::{prelude::*, *};
22use bevy_shape::*;
23use glam_matrix_extras::{SymmetricDMat2, SymmetricDMat3, SymmetricMat2, SymmetricMat3};
24
25#[cfg(feature = "2d")]
29pub const DIM: usize = 2;
30
31#[cfg(feature = "3d")]
35pub const DIM: usize = 3;
36
37#[cfg(feature = "2d")]
46pub type RVector = RVec2;
47
48#[cfg(feature = "3d")]
57pub type RVector = RVec3;
58
59#[cfg(feature = "2d")]
63pub(crate) use bevy_math::Vec2 as Vector;
64
65#[cfg(feature = "3d")]
69pub(crate) use bevy_math::Vec3 as Vector;
70
71#[cfg(feature = "2d")]
75pub(crate) use bevy_math::IVec2 as IVector;
76
77#[cfg(feature = "3d")]
81pub(crate) use bevy_math::IVec3 as IVector;
82
83#[cfg(feature = "2d")]
87pub(crate) type Ray = Ray2d;
88
89#[cfg(feature = "3d")]
93pub(crate) type Ray = Ray3d;
94
95#[cfg(feature = "2d")]
99pub(crate) type Dir = Dir2;
100
101#[cfg(feature = "3d")]
105pub(crate) type Dir = Dir3;
106
107#[cfg(feature = "2d")]
111pub(crate) type AngularVector = f32;
112
113#[cfg(feature = "3d")]
117pub(crate) type AngularVector = Vector;
118
119#[cfg(feature = "2d")]
123pub(crate) type Rot = Rot2;
124
125#[cfg(feature = "3d")]
129pub(crate) type Rot = Quat;
130
131#[cfg(feature = "2d")]
135pub(crate) type Isometry = Isometry2d;
136
137#[cfg(feature = "3d")]
141pub(crate) type Isometry = Isometry3d;
142
143#[cfg(feature = "2d")]
148pub type SymmetricTensor = f32;
149
150#[cfg(feature = "3d")]
155pub type SymmetricTensor = SymmetricMat3;
156
157pub trait ToRealPrecision {
159 type Adjusted;
161
162 #[must_use]
164 fn real(&self) -> Self::Adjusted;
165}
166
167pub trait ToF32Precision {
169 type F32;
171
172 #[must_use]
174 fn f32(&self) -> Self::F32;
175}
176
177impl ToF32Precision for f32 {
178 type F32 = Self;
179 fn f32(&self) -> Self::F32 {
180 *self
181 }
182}
183
184impl ToF32Precision for f64 {
185 type F32 = f32;
186 fn f32(&self) -> Self::F32 {
187 *self as f32
188 }
189}
190
191impl ToF32Precision for DVec3 {
192 type F32 = Vec3;
193 fn f32(&self) -> Self::F32 {
194 self.as_vec3()
195 }
196}
197
198impl ToF32Precision for Vec3 {
199 type F32 = Self;
200 fn f32(&self) -> Self::F32 {
201 *self
202 }
203}
204
205impl ToF32Precision for DVec2 {
206 type F32 = Vec2;
207 fn f32(&self) -> Self::F32 {
208 self.as_vec2()
209 }
210}
211
212impl ToF32Precision for Vec2 {
213 type F32 = Self;
214 fn f32(&self) -> Self::F32 {
215 *self
216 }
217}
218
219impl ToF32Precision for Vec4 {
220 type F32 = Self;
221 fn f32(&self) -> Self::F32 {
222 *self
223 }
224}
225
226impl ToF32Precision for DRot2 {
227 type F32 = Rot2;
228 fn f32(&self) -> Self::F32 {
229 Rot2::from_sin_cos(self.sin as f32, self.cos as f32)
230 }
231}
232
233impl ToF32Precision for Rot2 {
234 type F32 = Self;
235 fn f32(&self) -> Self::F32 {
236 *self
237 }
238}
239
240impl ToF32Precision for DQuat {
241 type F32 = Quat;
242 fn f32(&self) -> Self::F32 {
243 self.as_quat()
244 }
245}
246
247impl ToF32Precision for Quat {
248 type F32 = Self;
249 fn f32(&self) -> Self::F32 {
250 *self
251 }
252}
253
254impl ToF32Precision for DMat2 {
255 type F32 = Mat2;
256 fn f32(&self) -> Self::F32 {
257 self.as_mat2()
258 }
259}
260
261impl ToF32Precision for Mat2 {
262 type F32 = Self;
263 fn f32(&self) -> Self::F32 {
264 *self
265 }
266}
267
268impl ToF32Precision for SymmetricDMat2 {
269 type F32 = SymmetricMat2;
270 fn f32(&self) -> Self::F32 {
271 SymmetricMat2 {
272 m00: self.m00 as f32,
273 m01: self.m01 as f32,
274 m11: self.m11 as f32,
275 }
276 }
277}
278
279impl ToF32Precision for SymmetricMat2 {
280 type F32 = Self;
281 fn f32(&self) -> Self::F32 {
282 *self
283 }
284}
285
286impl ToF32Precision for DMat3 {
287 type F32 = Mat3;
288 fn f32(&self) -> Self::F32 {
289 self.as_mat3()
290 }
291}
292
293impl ToF32Precision for Mat3 {
294 type F32 = Self;
295 fn f32(&self) -> Self::F32 {
296 *self
297 }
298}
299
300impl ToF32Precision for SymmetricDMat3 {
301 type F32 = SymmetricMat3;
302 fn f32(&self) -> Self::F32 {
303 SymmetricMat3 {
304 m00: self.m00 as f32,
305 m01: self.m01 as f32,
306 m02: self.m02 as f32,
307 m11: self.m11 as f32,
308 m12: self.m12 as f32,
309 m22: self.m22 as f32,
310 }
311 }
312}
313
314impl ToF32Precision for SymmetricMat3 {
315 type F32 = Self;
316 fn f32(&self) -> Self::F32 {
317 *self
318 }
319}
320
321#[cfg(feature = "2d")]
322pub(crate) fn cross(a: Vec2, b: Vec2) -> f32 {
323 a.perp_dot(b)
324}
325
326#[cfg(feature = "3d")]
327pub(crate) fn cross(a: Vec3, b: Vec3) -> Vec3 {
328 a.cross(b)
329}
330
331pub trait RecipOrZero {
333 fn recip_or_zero(self) -> Self;
336}
337
338impl RecipOrZero for f32 {
339 #[inline]
340 fn recip_or_zero(self) -> Self {
341 if self != 0.0 && self.is_finite() {
342 self.recip()
343 } else {
344 0.0
345 }
346 }
347}
348
349impl RecipOrZero for f64 {
350 #[inline]
351 fn recip_or_zero(self) -> Self {
352 if self != 0.0 && self.is_finite() {
353 self.recip()
354 } else {
355 0.0
356 }
357 }
358}
359
360impl RecipOrZero for Vec2 {
361 #[inline]
362 fn recip_or_zero(self) -> Self {
363 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
364 }
365}
366
367impl RecipOrZero for Vec3 {
368 #[inline]
369 fn recip_or_zero(self) -> Self {
370 Self::new(
371 self.x.recip_or_zero(),
372 self.y.recip_or_zero(),
373 self.z.recip_or_zero(),
374 )
375 }
376}
377
378impl RecipOrZero for DVec2 {
379 #[inline]
380 fn recip_or_zero(self) -> Self {
381 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
382 }
383}
384
385impl RecipOrZero for DVec3 {
386 #[inline]
387 fn recip_or_zero(self) -> Self {
388 Self::new(
389 self.x.recip_or_zero(),
390 self.y.recip_or_zero(),
391 self.z.recip_or_zero(),
392 )
393 }
394}
395
396pub trait MatExt {
398 type Real;
400
401 fn inverse_or_zero(self) -> Self;
404
405 fn is_isotropic(&self, epsilon: Self::Real) -> bool;
411}
412
413impl MatExt for Mat2 {
414 type Real = f32;
415
416 #[inline]
417 fn inverse_or_zero(self) -> Self {
418 if self.determinant() == 0.0 {
419 Self::ZERO
420 } else {
421 self.inverse()
422 }
423 }
424
425 #[inline]
426 fn is_isotropic(&self, epsilon: f32) -> bool {
427 let diag = Vec2::new(self.x_axis.x, self.y_axis.y);
429
430 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
432 return false;
433 }
434
435 let off_diag = [self.x_axis.y, self.y_axis.x];
437
438 off_diag.iter().all(|&x| x.abs() < epsilon)
440 }
441}
442
443impl MatExt for DMat2 {
444 type Real = f64;
445
446 #[inline]
447 fn inverse_or_zero(self) -> Self {
448 if self.determinant() == 0.0 {
449 Self::ZERO
450 } else {
451 self.inverse()
452 }
453 }
454
455 #[inline]
456 fn is_isotropic(&self, epsilon: f64) -> bool {
457 let diag = DVec2::new(self.x_axis.x, self.y_axis.y);
459
460 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
462 return false;
463 }
464
465 let off_diag = [self.x_axis.y, self.y_axis.x];
467
468 off_diag.iter().all(|&x| x.abs() < epsilon)
470 }
471}
472
473impl MatExt for SymmetricMat2 {
474 type Real = f32;
475
476 #[inline]
477 fn inverse_or_zero(self) -> Self {
478 if self.determinant() == 0.0 {
479 Self::ZERO
480 } else {
481 self.inverse()
482 }
483 }
484
485 #[inline]
486 fn is_isotropic(&self, epsilon: f32) -> bool {
487 let diag = Vec2::new(self.m00, self.m11);
489
490 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
492 return false;
493 }
494
495 self.m01.abs() < epsilon
497 }
498}
499
500impl MatExt for SymmetricDMat2 {
501 type Real = f64;
502
503 #[inline]
504 fn inverse_or_zero(self) -> Self {
505 if self.determinant() == 0.0 {
506 Self::ZERO
507 } else {
508 self.inverse()
509 }
510 }
511
512 #[inline]
513 fn is_isotropic(&self, epsilon: f64) -> bool {
514 let diag = DVec2::new(self.m00, self.m11);
516
517 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon) {
519 return false;
520 }
521
522 self.m01.abs() < epsilon
524 }
525}
526
527impl MatExt for Mat3 {
528 type Real = f32;
529
530 #[inline]
531 fn inverse_or_zero(self) -> Self {
532 if self.determinant() == 0.0 {
533 Self::ZERO
534 } else {
535 self.inverse()
536 }
537 }
538
539 #[inline]
540 fn is_isotropic(&self, epsilon: f32) -> bool {
541 let diag = Vec3::new(self.x_axis.x, self.y_axis.y, self.z_axis.z);
543
544 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
546 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
547 {
548 return false;
549 }
550
551 let off_diag = [
553 self.x_axis.y,
554 self.x_axis.z,
555 self.y_axis.x,
556 self.y_axis.z,
557 self.z_axis.x,
558 self.z_axis.y,
559 ];
560
561 off_diag.iter().all(|&x| x.abs() < epsilon)
563 }
564}
565
566impl MatExt for DMat3 {
567 type Real = f64;
568
569 #[inline]
570 fn inverse_or_zero(self) -> Self {
571 if self.determinant() == 0.0 {
572 Self::ZERO
573 } else {
574 self.inverse()
575 }
576 }
577
578 #[inline]
579 fn is_isotropic(&self, epsilon: f64) -> bool {
580 let diag = DVec3::new(self.x_axis.x, self.y_axis.y, self.z_axis.z);
582
583 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
585 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
586 {
587 return false;
588 }
589
590 let off_diag = [
592 self.x_axis.y,
593 self.x_axis.z,
594 self.y_axis.x,
595 self.y_axis.z,
596 self.z_axis.x,
597 self.z_axis.y,
598 ];
599
600 off_diag.iter().all(|&x| x.abs() < epsilon)
602 }
603}
604
605impl MatExt for SymmetricMat3 {
606 type Real = f32;
607
608 #[inline]
609 fn inverse_or_zero(self) -> Self {
610 if self.determinant() == 0.0 {
611 Self::ZERO
612 } else {
613 self.inverse()
614 }
615 }
616
617 #[inline]
618 fn is_isotropic(&self, epsilon: f32) -> bool {
619 let diag = Vec3::new(self.m00, self.m11, self.m22);
621
622 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
624 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
625 {
626 return false;
627 }
628
629 let off_diag = [self.m01, self.m02, self.m12];
631
632 off_diag.iter().all(|&x| x.abs() < epsilon)
634 }
635}
636
637impl MatExt for SymmetricDMat3 {
638 type Real = f64;
639
640 #[inline]
641 fn inverse_or_zero(self) -> Self {
642 if self.determinant() == 0.0 {
643 Self::ZERO
644 } else {
645 self.inverse()
646 }
647 }
648
649 #[inline]
650 fn is_isotropic(&self, epsilon: f64) -> bool {
651 let diag = DVec3::new(self.m00, self.m11, self.m22);
653
654 if abs_diff_ne!(diag.x, diag.y, epsilon = epsilon)
656 || abs_diff_ne!(diag.y, diag.z, epsilon = epsilon)
657 {
658 return false;
659 }
660
661 let off_diag = [self.m01, self.m02, self.m12];
663
664 off_diag.iter().all(|&x| x.abs() < epsilon)
666 }
667}
668
669#[allow(
671 dead_code,
672 reason = "Some internals need this, but only with specific features enabled."
673)]
674#[cfg(feature = "2d")]
675pub(crate) trait Rot2Ext {
676 fn chord_length(self) -> f32;
679
680 #[must_use]
683 fn add_angle_fast(&self, radians: f32) -> Self;
684}
685
686#[cfg(feature = "2d")]
687impl Rot2Ext for Rot2 {
688 #[inline]
689 fn chord_length(self) -> f32 {
690 (2.0 * (1.0 - self.cos)).max(0.0).sqrt()
698 }
699
700 #[inline]
701 fn add_angle_fast(&self, radians: f32) -> Self {
702 let (sin, cos) = (self.sin + radians * self.cos, self.cos - radians * self.sin);
703 let magnitude_squared = sin * sin + cos * cos;
704 let magnitude_recip = if magnitude_squared > 0.0 {
705 magnitude_squared.sqrt().recip()
706 } else {
707 0.0
708 };
709 Rot2::from_sin_cos(sin * magnitude_recip, cos * magnitude_recip)
710 }
711}
712
713#[cfg(feature = "3d")]
714pub(crate) trait QuatExt {
715 #[allow(
718 dead_code,
719 reason = "Some internals need this, but only with specific features enabled."
720 )]
721 fn chord_length(self) -> f32;
722
723 #[must_use]
727 fn fast_renormalize(self) -> Self;
728}
729
730#[cfg(feature = "3d")]
731impl QuatExt for Quat {
732 #[inline]
733 fn chord_length(self) -> f32 {
734 2.0 * self.xyz().length()
735 }
736
737 #[inline]
738 fn fast_renormalize(self) -> Self {
739 let length_squared = self.length_squared();
742 let approx_inv_length = 0.5 * (3.0 - length_squared);
743 self * approx_inv_length
744 }
745}
746
747#[allow(clippy::unnecessary_cast)]
748#[cfg(all(feature = "2d", any(feature = "parry-f32", feature = "parry-f64")))]
749pub(crate) fn pose_to_isometry(pose: &parry::math::Pose) -> Isometry2d {
750 let rotation = Rot2::from_sin_cos(pose.rotation.im as f32, pose.rotation.re as f32);
751 Isometry2d::new(pose.translation.f32(), rotation)
752}
753
754#[cfg(all(
755 feature = "default-collider",
756 any(feature = "parry-f32", feature = "parry-f64")
757))]
758use crate::prelude::*;
759
760#[cfg(all(
761 feature = "2d",
762 feature = "default-collider",
763 any(feature = "parry-f32", feature = "parry-f64")
764))]
765pub(crate) fn make_pose(
766 position: impl Into<Position>,
767 rotation: impl Into<Rot>,
768) -> parry::math::Pose2 {
769 let position: Position = position.into();
770 let rotation: Rot = rotation.into();
771 parry::math::Pose2::from_parts(
772 position.0,
773 parry::math::Rot2::from_cos_sin_unchecked(rotation.cos.real(), rotation.sin.real()),
774 )
775}
776
777#[cfg(all(
778 feature = "3d",
779 feature = "default-collider",
780 any(feature = "parry-f32", feature = "parry-f64")
781))]
782pub(crate) fn make_pose(
783 position: impl Into<Position>,
784 rotation: impl Into<Rot>,
785) -> parry::math::Pose3 {
786 let position: Position = position.into();
787 let rotation: Rot = rotation.into();
788 parry::math::Pose3::from_parts(position.0, rotation.real())
789}
790
791#[inline]
795#[must_use]
796pub fn orthonormal_basis_from_vec(axis: Vector) -> Rot {
797 #[cfg(feature = "2d")]
798 {
799 let normal = axis.perp();
800 orthonormal_basis([axis, normal])
801 }
802 #[cfg(feature = "3d")]
803 {
804 let (normal1, normal2) = axis.any_orthonormal_pair();
805 orthonormal_basis([axis, normal1, normal2])
806 }
807}
808
809#[inline]
813#[must_use]
814pub fn orthonormal_basis(axes: [Vector; DIM]) -> Rot {
815 #[cfg(feature = "2d")]
816 {
817 Rot2::from_sin_cos(axes[1].x, axes[0].x)
818 }
819 #[cfg(feature = "3d")]
820 {
821 let mat = Mat3::from_cols(axes[0], axes[1], axes[2]);
822 Quat::from_mat3(&mat)
823 }
824}
825
826#[inline(always)]
835#[must_use]
836pub fn next_down_vector(vec: RVector) -> Vector {
837 #[cfg(not(feature = "f64"))]
838 {
839 vec
840 }
841 #[cfg(feature = "f64")]
842 {
843 #[cfg(feature = "2d")]
844 {
845 let [x, y] = [vec.x as f32, vec.y as f32];
846 Vector::new(
847 if x as f64 <= vec.x { x } else { x.next_down() },
848 if y as f64 <= vec.y { y } else { y.next_down() },
849 )
850 }
851 #[cfg(feature = "3d")]
852 {
853 let [x, y, z] = [vec.x as f32, vec.y as f32, vec.z as f32];
854 Vector::new(
855 if x as f64 <= vec.x { x } else { x.next_down() },
856 if y as f64 <= vec.y { y } else { y.next_down() },
857 if z as f64 <= vec.z { z } else { z.next_down() },
858 )
859 }
860 }
861}
862
863#[inline(always)]
872#[must_use]
873pub fn next_up_vector(vec: RVector) -> Vector {
874 #[cfg(not(feature = "f64"))]
875 {
876 vec
877 }
878 #[cfg(feature = "f64")]
879 {
880 #[cfg(feature = "2d")]
881 {
882 let [x, y] = [vec.x as f32, vec.y as f32];
883 Vector::new(
884 if x as f64 >= vec.x { x } else { x.next_up() },
885 if y as f64 >= vec.y { y } else { y.next_up() },
886 )
887 }
888 #[cfg(feature = "3d")]
889 {
890 let [x, y, z] = [vec.x as f32, vec.y as f32, vec.z as f32];
891 Vector::new(
892 if x as f64 >= vec.x { x } else { x.next_up() },
893 if y as f64 >= vec.y { y } else { y.next_up() },
894 if z as f64 >= vec.z { z } else { z.next_up() },
895 )
896 }
897 }
898}