1mod angular_inertia_ops;
4mod component_mul;
5mod copysign;
6mod cross_product;
7mod cross_product_matrix;
8mod dot_product;
9mod fp_flags;
10mod index_mut2;
11mod matrix_column;
12mod orthonormal_basis;
13mod pos_ops;
14mod rotation_ops;
15mod scalar_type;
16mod simd_real_copy;
17mod simd_select;
18
19pub use component_mul::ComponentMul;
20pub use copysign::CopySign;
21pub use index_mut2::IndexMut2;
22pub use matrix_column::MatrixColumn;
23pub use orthonormal_basis::OrthonormalBasis;
24pub use pos_ops::PoseOps;
25pub use rotation_ops::RotationOps;
26pub use scalar_type::ScalarType;
27pub use simd_real_copy::SimdRealCopy;
28pub use simd_select::SimdSelect;
29
30pub use angular_inertia_ops::AngularInertiaOps;
31pub use cross_product::CrossProduct;
32pub use cross_product_matrix::CrossProductMatrix;
33pub use dot_product::{DotProduct, SimdLength};
34pub(crate) use fp_flags::{DisableFloatingPointExceptionsFlags, FlushToZeroDenormalsAreZeroFlags};
35
36#[cfg(feature = "simd-is-enabled")]
37use crate::math::SIMD_WIDTH;
38use crate::math::{Real, SimdVector, Vector};
39#[cfg(feature = "dim2")]
40use na::Matrix2;
41#[cfg(feature = "dim3")]
42use na::Matrix3;
43
44#[cfg(feature = "dim2")]
46pub const DIM_MINUS_ONE: usize = 1;
47#[cfg(feature = "dim3")]
49pub const DIM_MINUS_ONE: usize = 2;
50
51pub fn try_normalize_and_get_length(v: Vector, threshold: Real) -> Option<(Vector, Real)> {
56 let len = v.length();
57 if len > threshold {
58 Some((v / len, len))
59 } else {
60 None
61 }
62}
63
64#[inline]
66pub fn vect_to_na(v: Vector) -> SimdVector<Real> {
67 v.into()
68}
69
70use crate::math::Matrix;
71
72#[cfg(feature = "dim2")]
74#[inline]
75pub fn mat_to_na(m: Matrix) -> Matrix2<Real> {
76 m.into()
77}
78
79#[cfg(feature = "dim3")]
81#[inline]
82pub fn mat_to_na(m: Matrix) -> Matrix3<Real> {
83 Matrix3::new(
84 m.x_axis.x, m.y_axis.x, m.z_axis.x, m.x_axis.y, m.y_axis.y, m.z_axis.y, m.x_axis.z,
85 m.y_axis.z, m.z_axis.z,
86 )
87}
88
89const INV_EPSILON: Real = 1.0e-20;
90
91pub(crate) fn inv(val: Real) -> Real {
92 if (-INV_EPSILON..=INV_EPSILON).contains(&val) {
93 0.0
94 } else {
95 1.0 / val
96 }
97}
98
99pub(crate) fn simd_inv<N: SimdRealCopy>(val: N) -> N {
100 let eps = N::splat(INV_EPSILON);
101 N::zero().select(val.simd_gt(-eps) & val.simd_lt(eps), N::one() / val)
102}
103
104pub(crate) fn select_other<T: PartialEq>(pair: (T, T), elt: T) -> T {
105 if pair.0 == elt { pair.1 } else { pair.0 }
106}
107
108pub fn smallest_abs_diff_between_sin_angles<N: SimdRealCopy>(a: N, b: N) -> N {
110 let s_err = a - b;
112 let sgn = s_err.simd_signum();
113 let s_err_complement = s_err - sgn * N::splat(2.0);
114 let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
115 s_err.select(s_err_is_smallest, s_err_complement)
116}
117
118pub fn smallest_abs_diff_between_angles<N: SimdRealCopy>(a: N, b: N) -> N {
120 let s_err = a - b;
122 let sgn = s_err.simd_signum();
123 let s_err_complement = s_err - sgn * N::simd_two_pi();
124 let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
125 s_err.select(s_err_is_smallest, s_err_complement)
126}
127
128#[cfg(feature = "simd-nightly")]
129#[inline(always)]
130pub(crate) fn transmute_to_wide(val: [std::simd::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
131 unsafe { std::mem::transmute(val) }
132}
133
134#[cfg(feature = "simd-stable")]
135#[inline(always)]
136pub(crate) fn transmute_to_wide(val: [wide::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
137 val
138}
139
140#[cfg(feature = "serde-serialize")]
142pub mod serde {
143 use serde::{Deserialize, Serialize};
144 use std::iter::FromIterator;
145
146 pub fn serialize_to_vec_tuple<
151 'a,
152 S: serde::Serializer,
153 T: IntoIterator<Item = (&'a K, &'a V)>,
154 K: Serialize + 'a,
155 V: Serialize + 'a,
156 >(
157 target: T,
158 s: S,
159 ) -> Result<S::Ok, S::Error> {
160 let container: Vec<_> = target.into_iter().collect();
161 serde::Serialize::serialize(&container, s)
162 }
163
164 pub fn deserialize_from_vec_tuple<
169 'de,
170 D: serde::Deserializer<'de>,
171 T: FromIterator<(K, V)>,
172 K: Deserialize<'de>,
173 V: Deserialize<'de>,
174 >(
175 d: D,
176 ) -> Result<T, D::Error> {
177 let hashmap_as_vec: Vec<(K, V)> = Deserialize::deserialize(d)?;
178 Ok(T::from_iter(hashmap_as_vec))
179 }
180
181 #[cfg(test)]
182 mod test {
183 use std::collections::HashMap;
184
185 #[test]
188 fn serde_json_hashmap() {
189 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
190 struct Test {
191 #[cfg_attr(
192 feature = "serde-serialize",
193 serde(
194 serialize_with = "crate::utils::serde::serialize_to_vec_tuple",
195 deserialize_with = "crate::utils::serde::deserialize_from_vec_tuple"
196 )
197 )]
198 pub map: HashMap<usize, String>,
199 }
200
201 let s = Test {
202 map: [(42, "Forty-Two".to_string())].into(),
203 };
204 let j = serde_json::to_string(&s).unwrap();
205 assert_eq!(&j, "{\"map\":[[42,\"Forty-Two\"]]}");
206 let p: Test = serde_json::from_str(&j).unwrap();
207 assert_eq!(&p, &s);
208 }
209 }
210}