1#[cfg(feature = "f32")]
6mod single;
7#[cfg(feature = "f32")]
8pub use single::*;
9
10#[cfg(feature = "f64")]
11mod double;
12#[cfg(feature = "f64")]
13pub use double::*;
14
15use bevy_math::{prelude::*, *};
16
17#[cfg(feature = "2d")]
19pub const DIM: usize = 2;
20#[cfg(feature = "3d")]
22pub const DIM: usize = 3;
23
24#[cfg(feature = "2d")]
26pub(crate) use bevy_math::Vec2 as VectorF32;
27
28#[cfg(feature = "3d")]
30pub(crate) use bevy_math::Vec3 as VectorF32;
31
32#[cfg(feature = "2d")]
34pub(crate) type Ray = Ray2d;
35#[cfg(feature = "3d")]
37pub(crate) type Ray = Ray3d;
38
39#[cfg(feature = "2d")]
42pub(crate) type Dir = Dir2;
43#[cfg(feature = "3d")]
45pub(crate) type Dir = Dir3;
46
47pub trait AdjustPrecision {
49 type Adjusted;
51 fn adjust_precision(&self) -> Self::Adjusted;
53}
54
55pub trait AsF32 {
57 type F32;
59 fn f32(&self) -> Self::F32;
61}
62
63impl AsF32 for DVec3 {
64 type F32 = Vec3;
65 fn f32(&self) -> Self::F32 {
66 self.as_vec3()
67 }
68}
69
70impl AsF32 for Vec3 {
71 type F32 = Self;
72 fn f32(&self) -> Self::F32 {
73 *self
74 }
75}
76
77impl AsF32 for DVec2 {
78 type F32 = Vec2;
79 fn f32(&self) -> Self::F32 {
80 self.as_vec2()
81 }
82}
83
84impl AsF32 for Vec2 {
85 type F32 = Self;
86 fn f32(&self) -> Self::F32 {
87 *self
88 }
89}
90
91impl AsF32 for Vec4 {
92 type F32 = Self;
93 fn f32(&self) -> Self::F32 {
94 *self
95 }
96}
97
98impl AsF32 for DQuat {
99 type F32 = Quat;
100 fn f32(&self) -> Self::F32 {
101 self.as_quat()
102 }
103}
104
105impl AsF32 for Quat {
106 type F32 = Self;
107 fn f32(&self) -> Self::F32 {
108 *self
109 }
110}
111
112impl AsF32 for DMat2 {
113 type F32 = Mat2;
114 fn f32(&self) -> Self::F32 {
115 self.as_mat2()
116 }
117}
118
119impl AsF32 for Mat2 {
120 type F32 = Self;
121 fn f32(&self) -> Self::F32 {
122 *self
123 }
124}
125
126impl AsF32 for DMat3 {
127 type F32 = Mat3;
128 fn f32(&self) -> Self::F32 {
129 self.as_mat3()
130 }
131}
132
133impl AsF32 for Mat3 {
134 type F32 = Self;
135 fn f32(&self) -> Self::F32 {
136 *self
137 }
138}
139
140#[cfg(feature = "2d")]
141pub(crate) fn cross(a: Vector, b: Vector) -> Scalar {
142 a.perp_dot(b)
143}
144
145#[cfg(feature = "3d")]
146pub(crate) fn cross(a: Vector, b: Vector) -> Vector {
147 a.cross(b)
148}
149
150pub trait RecipOrZero {
152 fn recip_or_zero(self) -> Self;
155}
156
157impl RecipOrZero for f32 {
158 #[inline]
159 fn recip_or_zero(self) -> Self {
160 if self != 0.0 && self.is_finite() {
161 self.recip()
162 } else {
163 0.0
164 }
165 }
166}
167
168impl RecipOrZero for f64 {
169 #[inline]
170 fn recip_or_zero(self) -> Self {
171 if self != 0.0 && self.is_finite() {
172 self.recip()
173 } else {
174 0.0
175 }
176 }
177}
178
179impl RecipOrZero for Vec2 {
180 #[inline]
181 fn recip_or_zero(self) -> Self {
182 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
183 }
184}
185
186impl RecipOrZero for Vec3 {
187 #[inline]
188 fn recip_or_zero(self) -> Self {
189 Self::new(
190 self.x.recip_or_zero(),
191 self.y.recip_or_zero(),
192 self.z.recip_or_zero(),
193 )
194 }
195}
196
197impl RecipOrZero for DVec2 {
198 #[inline]
199 fn recip_or_zero(self) -> Self {
200 Self::new(self.x.recip_or_zero(), self.y.recip_or_zero())
201 }
202}
203
204impl RecipOrZero for DVec3 {
205 #[inline]
206 fn recip_or_zero(self) -> Self {
207 Self::new(
208 self.x.recip_or_zero(),
209 self.y.recip_or_zero(),
210 self.z.recip_or_zero(),
211 )
212 }
213}
214
215pub trait MatExt {
217 fn inverse_or_zero(self) -> Self;
220}
221
222impl MatExt for Mat2 {
223 #[inline]
224 fn inverse_or_zero(self) -> Self {
225 if self.determinant() == 0.0 {
226 Self::ZERO
227 } else {
228 self.inverse()
229 }
230 }
231}
232
233impl MatExt for DMat2 {
234 #[inline]
235 fn inverse_or_zero(self) -> Self {
236 if self.determinant() == 0.0 {
237 Self::ZERO
238 } else {
239 self.inverse()
240 }
241 }
242}
243
244impl MatExt for Mat3 {
245 #[inline]
246 fn inverse_or_zero(self) -> Self {
247 if self.determinant() == 0.0 {
248 Self::ZERO
249 } else {
250 self.inverse()
251 }
252 }
253}
254
255impl MatExt for DMat3 {
256 #[inline]
257 fn inverse_or_zero(self) -> Self {
258 if self.determinant() == 0.0 {
259 Self::ZERO
260 } else {
261 self.inverse()
262 }
263 }
264}
265
266#[expect(clippy::unnecessary_cast)]
267#[cfg(all(feature = "2d", any(feature = "parry-f32", feature = "parry-f64")))]
268pub(crate) fn na_iso_to_iso(isometry: &parry::math::Isometry<Scalar>) -> Isometry2d {
269 Isometry2d::new(
270 Vector::from(isometry.translation).f32(),
271 Rot2::from_sin_cos(isometry.rotation.im as f32, isometry.rotation.re as f32),
272 )
273}
274
275#[cfg(all(
276 feature = "default-collider",
277 any(feature = "parry-f32", feature = "parry-f64")
278))]
279use crate::prelude::*;
280#[cfg(all(
281 feature = "default-collider",
282 any(feature = "parry-f32", feature = "parry-f64")
283))]
284use parry::math::Isometry;
285
286#[cfg(all(
287 feature = "2d",
288 feature = "default-collider",
289 any(feature = "parry-f32", feature = "parry-f64")
290))]
291pub(crate) fn make_isometry(
292 position: impl Into<Position>,
293 rotation: impl Into<Rotation>,
294) -> Isometry<Scalar> {
295 let position: Position = position.into();
296 let rotation: Rotation = rotation.into();
297 Isometry::<Scalar>::new(position.0.into(), rotation.into())
298}
299
300#[cfg(all(
301 feature = "3d",
302 feature = "default-collider",
303 any(feature = "parry-f32", feature = "parry-f64")
304))]
305pub(crate) fn make_isometry(
306 position: impl Into<Position>,
307 rotation: impl Into<Rotation>,
308) -> Isometry<Scalar> {
309 let position: Position = position.into();
310 let rotation: Rotation = rotation.into();
311 Isometry::<Scalar>::new(position.0.into(), rotation.to_scaled_axis().into())
312}
313
314#[inline]
322#[must_use]
323#[cfg(feature = "3d")]
324pub fn skew_symmetric_mat3(v: Vector3) -> Matrix3 {
325 Matrix3::from_cols_array(&[0.0, v.z, -v.y, -v.z, 0.0, v.x, v.y, -v.x, 0.0])
326}