1use crate::math::Real;
4use na::{
5 Matrix1, Matrix2, Matrix3, RowVector2, Scalar, SimdRealField, UnitComplex, UnitQuaternion,
6 Vector1, Vector2, Vector3,
7};
8use parry::utils::SdpMatrix3;
9use std::ops::IndexMut;
10
11#[cfg(feature = "simd-is-enabled")]
12use crate::{
13 math::{SIMD_WIDTH, SimdReal},
14 num::Zero,
15};
16
17pub trait SimdRealCopy: SimdRealField<Element = Real> + Copy {}
21impl SimdRealCopy for Real {}
22#[cfg(feature = "simd-is-enabled")]
23impl SimdRealCopy for SimdReal {}
24
25const INV_EPSILON: Real = 1.0e-20;
26
27pub(crate) fn inv(val: Real) -> Real {
28 if (-INV_EPSILON..=INV_EPSILON).contains(&val) {
29 0.0
30 } else {
31 1.0 / val
32 }
33}
34
35pub(crate) fn simd_inv<N: SimdRealCopy>(val: N) -> N {
36 let eps = N::splat(INV_EPSILON);
37 N::zero().select(val.simd_gt(-eps) & val.simd_lt(eps), N::one() / val)
38}
39
40pub trait SimdSign<Rhs>: Sized {
42 fn copy_sign_to(self, to: Rhs) -> Rhs;
45}
46
47impl SimdSign<Real> for Real {
48 fn copy_sign_to(self, to: Self) -> Self {
49 const MINUS_ZERO: Real = -0.0;
50 let signbit = MINUS_ZERO.to_bits();
51 Real::from_bits((signbit & self.to_bits()) | ((!signbit) & to.to_bits()))
52 }
53}
54
55impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector2<N>> for N {
56 fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
57 Vector2::new(self.copy_sign_to(to.x), self.copy_sign_to(to.y))
58 }
59}
60
61impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector3<N>> for N {
62 fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
63 Vector3::new(
64 self.copy_sign_to(to.x),
65 self.copy_sign_to(to.y),
66 self.copy_sign_to(to.z),
67 )
68 }
69}
70
71impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector2<N>> for Vector2<N> {
72 fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
73 Vector2::new(self.x.copy_sign_to(to.x), self.y.copy_sign_to(to.y))
74 }
75}
76
77impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector3<N>> for Vector3<N> {
78 fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
79 Vector3::new(
80 self.x.copy_sign_to(to.x),
81 self.y.copy_sign_to(to.y),
82 self.z.copy_sign_to(to.z),
83 )
84 }
85}
86
87#[cfg(feature = "simd-is-enabled")]
88impl SimdSign<SimdReal> for SimdReal {
89 fn copy_sign_to(self, to: SimdReal) -> SimdReal {
90 to.simd_copysign(self)
91 }
92}
93
94pub trait SimdBasis: Sized {
96 type Basis;
98 fn orthonormal_basis(self) -> Self::Basis;
100 fn orthonormal_vector(self) -> Self;
102}
103
104impl<N: SimdRealCopy> SimdBasis for Vector2<N> {
105 type Basis = [Vector2<N>; 1];
106 fn orthonormal_basis(self) -> [Vector2<N>; 1] {
107 [Vector2::new(-self.y, self.x)]
108 }
109 fn orthonormal_vector(self) -> Vector2<N> {
110 Vector2::new(-self.y, self.x)
111 }
112}
113
114impl<N: SimdRealCopy + SimdSign<N>> SimdBasis for Vector3<N> {
115 type Basis = [Vector3<N>; 2];
116 fn orthonormal_basis(self) -> [Vector3<N>; 2] {
119 let sign = self.z.copy_sign_to(N::one());
120 let a = -N::one() / (sign + self.z);
121 let b = self.x * self.y * a;
122
123 [
124 Vector3::new(
125 N::one() + sign * self.x * self.x * a,
126 sign * b,
127 -sign * self.x,
128 ),
129 Vector3::new(b, sign + self.y * self.y * a, -self.y),
130 ]
131 }
132
133 fn orthonormal_vector(self) -> Vector3<N> {
134 let sign = self.z.copy_sign_to(N::one());
135 let a = -N::one() / (sign + self.z);
136 let b = self.x * self.y * a;
137 Vector3::new(b, sign + self.y * self.y * a, -self.y)
138 }
139}
140
141pub(crate) trait SimdCrossMatrix: Sized {
142 type CrossMat;
143 type CrossMatTr;
144
145 fn gcross_matrix(self) -> Self::CrossMat;
146 fn gcross_matrix_tr(self) -> Self::CrossMatTr;
147}
148
149impl<N: SimdRealCopy> SimdCrossMatrix for Vector3<N> {
150 type CrossMat = Matrix3<N>;
151 type CrossMatTr = Matrix3<N>;
152
153 #[inline]
154 #[rustfmt::skip]
155 fn gcross_matrix(self) -> Self::CrossMat {
156 Matrix3::new(
157 N::zero(), -self.z, self.y,
158 self.z, N::zero(), -self.x,
159 -self.y, self.x, N::zero(),
160 )
161 }
162
163 #[inline]
164 #[rustfmt::skip]
165 fn gcross_matrix_tr(self) -> Self::CrossMatTr {
166 Matrix3::new(
167 N::zero(), self.z, -self.y,
168 -self.z, N::zero(), self.x,
169 self.y, -self.x, N::zero(),
170 )
171 }
172}
173
174impl<N: SimdRealCopy> SimdCrossMatrix for Vector2<N> {
175 type CrossMat = RowVector2<N>;
176 type CrossMatTr = Vector2<N>;
177
178 #[inline]
179 fn gcross_matrix(self) -> Self::CrossMat {
180 RowVector2::new(-self.y, self.x)
181 }
182 #[inline]
183 fn gcross_matrix_tr(self) -> Self::CrossMatTr {
184 Vector2::new(-self.y, self.x)
185 }
186}
187impl SimdCrossMatrix for Real {
188 type CrossMat = Matrix2<Real>;
189 type CrossMatTr = Matrix2<Real>;
190
191 #[inline]
192 fn gcross_matrix(self) -> Matrix2<Real> {
193 Matrix2::new(0.0, -self, self, 0.0)
194 }
195
196 #[inline]
197 fn gcross_matrix_tr(self) -> Matrix2<Real> {
198 Matrix2::new(0.0, self, -self, 0.0)
199 }
200}
201
202#[cfg(feature = "simd-is-enabled")]
203impl SimdCrossMatrix for SimdReal {
204 type CrossMat = Matrix2<SimdReal>;
205 type CrossMatTr = Matrix2<SimdReal>;
206
207 #[inline]
208 fn gcross_matrix(self) -> Matrix2<SimdReal> {
209 Matrix2::new(SimdReal::zero(), -self, self, SimdReal::zero())
210 }
211
212 #[inline]
213 fn gcross_matrix_tr(self) -> Matrix2<SimdReal> {
214 Matrix2::new(SimdReal::zero(), self, -self, SimdReal::zero())
215 }
216}
217
218pub(crate) trait SimdCross<Rhs>: Sized {
219 type Result;
220 fn gcross(&self, rhs: Rhs) -> Self::Result;
221}
222
223impl SimdCross<Vector3<Real>> for Vector3<Real> {
224 type Result = Self;
225
226 fn gcross(&self, rhs: Vector3<Real>) -> Self::Result {
227 self.cross(&rhs)
228 }
229}
230
231impl SimdCross<Vector2<Real>> for Vector2<Real> {
232 type Result = Real;
233
234 fn gcross(&self, rhs: Vector2<Real>) -> Self::Result {
235 self.x * rhs.y - self.y * rhs.x
236 }
237}
238
239impl SimdCross<Vector2<Real>> for Real {
240 type Result = Vector2<Real>;
241
242 fn gcross(&self, rhs: Vector2<Real>) -> Self::Result {
243 Vector2::new(-rhs.y * *self, rhs.x * *self)
244 }
245}
246
247pub(crate) trait SimdDot<Rhs>: Sized {
248 type Result;
249 fn gdot(&self, rhs: Rhs) -> Self::Result;
250}
251
252impl<N: SimdRealCopy> SimdDot<Vector3<N>> for Vector3<N> {
253 type Result = N;
254
255 fn gdot(&self, rhs: Vector3<N>) -> Self::Result {
256 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
257 }
258}
259
260impl<N: SimdRealCopy> SimdDot<Vector2<N>> for Vector2<N> {
261 type Result = N;
262
263 fn gdot(&self, rhs: Vector2<N>) -> Self::Result {
264 self.x * rhs.x + self.y * rhs.y
265 }
266}
267
268impl<N: SimdRealCopy> SimdDot<Vector1<N>> for N {
269 type Result = N;
270
271 fn gdot(&self, rhs: Vector1<N>) -> Self::Result {
272 *self * rhs.x
273 }
274}
275
276impl<N: SimdRealCopy> SimdDot<N> for N {
277 type Result = N;
278
279 fn gdot(&self, rhs: N) -> Self::Result {
280 *self * rhs
281 }
282}
283
284impl<N: SimdRealCopy> SimdDot<N> for Vector1<N> {
285 type Result = N;
286
287 fn gdot(&self, rhs: N) -> Self::Result {
288 self.x * rhs
289 }
290}
291
292#[cfg(feature = "simd-is-enabled")]
293impl SimdCross<Vector3<SimdReal>> for Vector3<SimdReal> {
294 type Result = Vector3<SimdReal>;
295
296 fn gcross(&self, rhs: Self) -> Self::Result {
297 self.cross(&rhs)
298 }
299}
300
301#[cfg(feature = "simd-is-enabled")]
302impl SimdCross<Vector2<SimdReal>> for SimdReal {
303 type Result = Vector2<SimdReal>;
304
305 fn gcross(&self, rhs: Vector2<SimdReal>) -> Self::Result {
306 Vector2::new(-rhs.y * *self, rhs.x * *self)
307 }
308}
309
310#[cfg(feature = "simd-is-enabled")]
311impl SimdCross<Vector2<SimdReal>> for Vector2<SimdReal> {
312 type Result = SimdReal;
313
314 fn gcross(&self, rhs: Self) -> Self::Result {
315 let yx = Vector2::new(rhs.y, rhs.x);
316 let prod = self.component_mul(&yx);
317 prod.x - prod.y
318 }
319}
320
321pub trait SimdQuat<N> {
323 type Result;
325
326 fn diff_conj1_2(&self, rhs: &Self) -> Self::Result;
328}
329
330impl<N: SimdRealCopy> SimdQuat<N> for UnitComplex<N> {
331 type Result = Matrix1<N>;
332
333 fn diff_conj1_2(&self, rhs: &Self) -> Self::Result {
334 let two: N = N::splat(2.0);
335 Matrix1::new((self.im * rhs.im + self.re * rhs.re) * two)
336 }
337}
338
339impl<N: SimdRealCopy> SimdQuat<N> for UnitQuaternion<N> {
340 type Result = Matrix3<N>;
341
342 fn diff_conj1_2(&self, rhs: &Self) -> Self::Result {
343 let half = N::splat(0.5);
344 let v1 = self.imag();
345 let v2 = rhs.imag();
346 let w1 = self.w;
347 let w2 = rhs.w;
348
349 (v1 * v2.transpose() + Matrix3::from_diagonal_element(w1 * w2)
351 - (v1 * w2 + v2 * w1).cross_matrix()
352 + v1.cross_matrix() * v2.cross_matrix())
353 * half
354 }
355}
356
357pub(crate) trait SimdAngularInertia<N> {
358 type AngVector;
359 type AngMatrix;
360 fn inverse(&self) -> Self;
361 fn transform_vector(&self, pt: Self::AngVector) -> Self::AngVector;
362 fn into_matrix(self) -> Self::AngMatrix;
363}
364
365impl<N: SimdRealCopy> SimdAngularInertia<N> for N {
366 type AngVector = N;
367 type AngMatrix = N;
368
369 fn inverse(&self) -> Self {
370 simd_inv(*self)
371 }
372
373 fn transform_vector(&self, pt: N) -> N {
374 pt * *self
375 }
376
377 fn into_matrix(self) -> Self::AngMatrix {
378 self
379 }
380}
381
382impl<N: SimdRealCopy> SimdAngularInertia<N> for SdpMatrix3<N> {
383 type AngVector = Vector3<N>;
384 type AngMatrix = Matrix3<N>;
385
386 fn inverse(&self) -> Self {
387 let minor_m12_m23 = self.m22 * self.m33 - self.m23 * self.m23;
388 let minor_m11_m23 = self.m12 * self.m33 - self.m13 * self.m23;
389 let minor_m11_m22 = self.m12 * self.m23 - self.m13 * self.m22;
390
391 let determinant =
392 self.m11 * minor_m12_m23 - self.m12 * minor_m11_m23 + self.m13 * minor_m11_m22;
393
394 if determinant.is_zero() {
395 Self::zero()
396 } else {
397 SdpMatrix3 {
398 m11: minor_m12_m23 / determinant,
399 m12: -minor_m11_m23 / determinant,
400 m13: minor_m11_m22 / determinant,
401 m22: (self.m11 * self.m33 - self.m13 * self.m13) / determinant,
402 m23: (self.m13 * self.m12 - self.m23 * self.m11) / determinant,
403 m33: (self.m11 * self.m22 - self.m12 * self.m12) / determinant,
404 }
405 }
406 }
407
408 fn transform_vector(&self, v: Vector3<N>) -> Vector3<N> {
409 let x = self.m11 * v.x + self.m12 * v.y + self.m13 * v.z;
410 let y = self.m12 * v.x + self.m22 * v.y + self.m23 * v.z;
411 let z = self.m13 * v.x + self.m23 * v.y + self.m33 * v.z;
412 Vector3::new(x, y, z)
413 }
414
415 #[rustfmt::skip]
416 fn into_matrix(self) -> Matrix3<N> {
417 Matrix3::new(
418 self.m11, self.m12, self.m13,
419 self.m12, self.m22, self.m23,
420 self.m13, self.m23, self.m33,
421 )
422 }
423}
424
425#[derive(Clone, Debug, PartialEq, Eq)]
428pub(crate) struct FlushToZeroDenormalsAreZeroFlags {
429 original_flags: u32,
430}
431
432impl FlushToZeroDenormalsAreZeroFlags {
433 #[cfg(not(all(
434 not(feature = "enhanced-determinism"),
435 any(target_arch = "x86_64", target_arch = "x86"),
436 target_feature = "sse"
437 )))]
438 pub fn flush_denormal_to_zero() -> Self {
439 Self { original_flags: 0 }
440 }
441
442 #[cfg(all(
443 not(feature = "enhanced-determinism"),
444 any(target_arch = "x86", target_arch = "x86_64"),
445 target_feature = "sse"
446 ))]
447 #[allow(deprecated)] pub fn flush_denormal_to_zero() -> Self {
449 unsafe {
450 #[cfg(target_arch = "x86")]
451 use std::arch::x86::{_MM_FLUSH_ZERO_ON, _mm_getcsr, _mm_setcsr};
452 #[cfg(target_arch = "x86_64")]
453 use std::arch::x86_64::{_MM_FLUSH_ZERO_ON, _mm_getcsr, _mm_setcsr};
454
455 let original_flags = _mm_getcsr();
459 _mm_setcsr(original_flags | _MM_FLUSH_ZERO_ON | (1 << 6));
460 Self { original_flags }
461 }
462 }
463}
464
465#[cfg(all(
466 not(feature = "enhanced-determinism"),
467 any(target_arch = "x86", target_arch = "x86_64"),
468 target_feature = "sse"
469))]
470impl Drop for FlushToZeroDenormalsAreZeroFlags {
471 #[allow(deprecated)] fn drop(&mut self) {
473 #[cfg(target_arch = "x86")]
474 unsafe {
475 std::arch::x86::_mm_setcsr(self.original_flags)
476 }
477 #[cfg(target_arch = "x86_64")]
478 unsafe {
479 std::arch::x86_64::_mm_setcsr(self.original_flags)
480 }
481 }
482}
483
484#[derive(Clone, Debug, PartialEq, Eq)]
489pub(crate) struct DisableFloatingPointExceptionsFlags {
490 #[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
491 original_flags: [u8; 256],
497}
498
499#[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
500extern "C" {
501 fn feholdexcept(env: *mut std::ffi::c_void);
502 fn fesetenv(env: *const std::ffi::c_void);
503}
504
505impl DisableFloatingPointExceptionsFlags {
506 #[cfg(not(feature = "debug-disable-legitimate-fe-exceptions"))]
507 #[allow(dead_code)]
508 pub fn disable_floating_point_exceptions() -> Self {
510 Self {}
511 }
512
513 #[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
514 pub fn disable_floating_point_exceptions() -> Self {
516 unsafe {
517 let mut original_flags = [0; 256];
518 feholdexcept(original_flags.as_mut_ptr() as *mut _);
519 Self { original_flags }
520 }
521 }
522}
523
524#[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
525impl Drop for DisableFloatingPointExceptionsFlags {
526 fn drop(&mut self) {
527 unsafe {
528 fesetenv(self.original_flags.as_ptr() as *const _);
529 }
530 }
531}
532
533pub(crate) fn select_other<T: PartialEq>(pair: (T, T), elt: T) -> T {
534 if pair.0 == elt { pair.1 } else { pair.0 }
535}
536
537pub trait IndexMut2<I>: IndexMut<I> {
539 fn index_mut2(&mut self, i: usize, j: usize) -> (&mut Self::Output, &mut Self::Output);
543
544 #[inline]
548 fn index_mut_const(&mut self, i: usize, j: usize) -> (&mut Self::Output, &Self::Output) {
549 let (a, b) = self.index_mut2(i, j);
550 (a, &*b)
551 }
552}
553
554impl<T> IndexMut2<usize> for Vec<T> {
555 #[inline]
556 fn index_mut2(&mut self, i: usize, j: usize) -> (&mut T, &mut T) {
557 assert!(i != j, "Unable to index the same element twice.");
558 assert!(i < self.len() && j < self.len(), "Index out of bounds.");
559
560 unsafe {
561 let a = &mut *(self.get_unchecked_mut(i) as *mut _);
562 let b = &mut *(self.get_unchecked_mut(j) as *mut _);
563 (a, b)
564 }
565 }
566}
567
568impl<T> IndexMut2<usize> for [T] {
569 #[inline]
570 fn index_mut2(&mut self, i: usize, j: usize) -> (&mut T, &mut T) {
571 assert!(i != j, "Unable to index the same element twice.");
572 assert!(i < self.len() && j < self.len(), "Index out of bounds.");
573
574 unsafe {
575 let a = &mut *(self.get_unchecked_mut(i) as *mut _);
576 let b = &mut *(self.get_unchecked_mut(j) as *mut _);
577 (a, b)
578 }
579 }
580}
581
582pub fn smallest_abs_diff_between_sin_angles<N: SimdRealCopy>(a: N, b: N) -> N {
584 let s_err = a - b;
586 let sgn = s_err.simd_signum();
587 let s_err_complement = s_err - sgn * N::splat(2.0);
588 let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
589 s_err.select(s_err_is_smallest, s_err_complement)
590}
591
592pub fn smallest_abs_diff_between_angles<N: SimdRealCopy>(a: N, b: N) -> N {
594 let s_err = a - b;
596 let sgn = s_err.simd_signum();
597 let s_err_complement = s_err - sgn * N::simd_two_pi();
598 let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
599 s_err.select(s_err_is_smallest, s_err_complement)
600}
601
602#[cfg(feature = "simd-nightly")]
603#[inline(always)]
604pub(crate) fn transmute_to_wide(val: [std::simd::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
605 unsafe { std::mem::transmute(val) }
606}
607
608#[cfg(feature = "simd-stable")]
609#[inline(always)]
610pub(crate) fn transmute_to_wide(val: [wide::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
611 val
612}
613
614#[cfg(feature = "serde-serialize")]
616pub mod serde {
617 use serde::{Deserialize, Serialize};
618 use std::iter::FromIterator;
619
620 pub fn serialize_to_vec_tuple<
625 'a,
626 S: serde::Serializer,
627 T: IntoIterator<Item = (&'a K, &'a V)>,
628 K: Serialize + 'a,
629 V: Serialize + 'a,
630 >(
631 target: T,
632 s: S,
633 ) -> Result<S::Ok, S::Error> {
634 let container: Vec<_> = target.into_iter().collect();
635 serde::Serialize::serialize(&container, s)
636 }
637
638 pub fn deserialize_from_vec_tuple<
643 'de,
644 D: serde::Deserializer<'de>,
645 T: FromIterator<(K, V)>,
646 K: Deserialize<'de>,
647 V: Deserialize<'de>,
648 >(
649 d: D,
650 ) -> Result<T, D::Error> {
651 let hashmap_as_vec: Vec<(K, V)> = Deserialize::deserialize(d)?;
652 Ok(T::from_iter(hashmap_as_vec))
653 }
654
655 #[cfg(test)]
656 mod test {
657 use std::collections::HashMap;
658
659 #[test]
662 fn serde_json_hashmap() {
663 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
664 struct Test {
665 #[cfg_attr(
666 feature = "serde-serialize",
667 serde(
668 serialize_with = "crate::utils::serde::serialize_to_vec_tuple",
669 deserialize_with = "crate::utils::serde::deserialize_from_vec_tuple"
670 )
671 )]
672 pub map: HashMap<usize, String>,
673 }
674
675 let s = Test {
676 map: [(42, "Forty-Two".to_string())].into(),
677 };
678 let j = serde_json::to_string(&s).unwrap();
679 assert_eq!(&j, "{\"map\":[[42,\"Forty-Two\"]]}");
680 let p: Test = serde_json::from_str(&j).unwrap();
681 assert_eq!(&p, &s);
682 }
683 }
684}