nalgebra/geometry/
similarity_conversion.rs

1use num::Zero;
2
3use crate::ArrayStorage;
4use simba::scalar::{RealField, SubsetOf, SupersetOf};
5use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue};
6
7use crate::base::allocator::Allocator;
8use crate::base::dimension::{DimMin, DimNameAdd, DimNameSum, U1};
9use crate::base::{Const, DefaultAllocator, OMatrix, Scalar};
10
11use crate::geometry::{
12    AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation,
13};
14
15/*
16 * This file provides the following conversions:
17 * =============================================
18 *
19 * Similarity -> Similarity
20 * Similarity -> Transform
21 * Similarity -> Matrix (homogeneous)
22 */
23
24impl<T1, T2, R1, R2, const D: usize> SubsetOf<Similarity<T2, R2, D>> for Similarity<T1, R1, D>
25where
26    T1: RealField + SubsetOf<T2>,
27    T2: RealField + SupersetOf<T1>,
28    R1: AbstractRotation<T1, D> + SubsetOf<R2>,
29    R2: AbstractRotation<T2, D>,
30{
31    #[inline]
32    fn to_superset(&self) -> Similarity<T2, R2, D> {
33        Similarity::from_isometry(self.isometry.to_superset(), self.scaling().to_superset())
34    }
35
36    #[inline]
37    fn is_in_subset(sim: &Similarity<T2, R2, D>) -> bool {
38        crate::is_convertible::<_, Isometry<T1, R1, D>>(&sim.isometry)
39            && crate::is_convertible::<_, T1>(&sim.scaling())
40    }
41
42    #[inline]
43    fn from_superset_unchecked(sim: &Similarity<T2, R2, D>) -> Self {
44        Similarity::from_isometry(
45            sim.isometry.to_subset_unchecked(),
46            sim.scaling().to_subset_unchecked(),
47        )
48    }
49}
50
51impl<T1, T2, R, C, const D: usize> SubsetOf<Transform<T2, C, D>> for Similarity<T1, R, D>
52where
53    T1: RealField,
54    T2: RealField + SupersetOf<T1>,
55    C: SuperTCategoryOf<TAffine>,
56    R: AbstractRotation<T1, D>
57        + SubsetOf<OMatrix<T1, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>
58        + SubsetOf<OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>,
59    Const<D>: DimNameAdd<U1> + DimMin<Const<D>, Output = Const<D>>, // needed by .determinant()
60    DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
61    // + Allocator<D>
62    // + Allocator<T1, D>
63    // + Allocator<T1, D, D>
64    // + Allocator<D, D>
65    // + Allocator<D>,
66{
67    #[inline]
68    fn to_superset(&self) -> Transform<T2, C, D> {
69        Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
70    }
71
72    #[inline]
73    fn is_in_subset(t: &Transform<T2, C, D>) -> bool {
74        <Self as SubsetOf<_>>::is_in_subset(t.matrix())
75    }
76
77    #[inline]
78    fn from_superset_unchecked(t: &Transform<T2, C, D>) -> Self {
79        Self::from_superset_unchecked(t.matrix())
80    }
81}
82
83impl<T1, T2, R, const D: usize>
84    SubsetOf<OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>
85    for Similarity<T1, R, D>
86where
87    T1: RealField,
88    T2: RealField + SupersetOf<T1>,
89    R: AbstractRotation<T1, D>
90        + SubsetOf<OMatrix<T1, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>
91        + SubsetOf<OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>,
92    Const<D>: DimNameAdd<U1> + DimMin<Const<D>, Output = Const<D>>, // needed by .determinant()
93    DefaultAllocator: Allocator<Const<D>, Const<1>, Buffer<T1> = ArrayStorage<T1, D, 1>>
94        + Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
95{
96    #[inline]
97    fn to_superset(&self) -> OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
98        self.to_homogeneous().to_superset()
99    }
100
101    #[inline]
102    fn is_in_subset(m: &OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>) -> bool {
103        let mut rot = m.fixed_view::<D, D>(0, 0).clone_owned();
104        if rot
105            .fixed_columns_mut::<1>(0)
106            .try_normalize_mut(T2::zero())
107            .is_some()
108            && rot
109                .fixed_columns_mut::<1>(1)
110                .try_normalize_mut(T2::zero())
111                .is_some()
112            && rot
113                .fixed_columns_mut::<1>(2)
114                .try_normalize_mut(T2::zero())
115                .is_some()
116        {
117            // TODO: could we avoid explicit the computation of the determinant?
118            // (its sign is needed to see if the scaling factor is negative).
119            if rot.determinant() < T2::zero() {
120                rot.fixed_columns_mut::<1>(0).neg_mut();
121                rot.fixed_columns_mut::<1>(1).neg_mut();
122                rot.fixed_columns_mut::<1>(2).neg_mut();
123            }
124
125            let bottom = m.fixed_view::<1, D>(D, 0);
126            // Scalar types agree.
127            m.iter().all(|e| SupersetOf::<T1>::is_in_subset(e)) &&
128            // The normalized block part is a rotation.
129            // rot.is_special_orthogonal(T2::default_epsilon().sqrt()) &&
130            // The bottom row is (0, 0, ..., 1)
131            bottom.iter().all(|e| e.is_zero()) && m[(D, D)] == T2::one()
132        } else {
133            false
134        }
135    }
136
137    #[inline]
138    fn from_superset_unchecked(
139        m: &OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
140    ) -> Self {
141        let mut mm = m.clone_owned();
142        let na = mm.fixed_view_mut::<D, 1>(0, 0).normalize_mut();
143        let nb = mm.fixed_view_mut::<D, 1>(0, 1).normalize_mut();
144        let nc = mm.fixed_view_mut::<D, 1>(0, 2).normalize_mut();
145
146        let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness.
147
148        // TODO: could we avoid the explicit computation of the determinant?
149        // (its sign is needed to see if the scaling factor is negative).
150        if mm.fixed_view::<D, D>(0, 0).determinant() < T2::zero() {
151            mm.fixed_view_mut::<D, 1>(0, 0).neg_mut();
152            mm.fixed_view_mut::<D, 1>(0, 1).neg_mut();
153            mm.fixed_view_mut::<D, 1>(0, 2).neg_mut();
154            scale = -scale;
155        }
156
157        let t = m.fixed_view::<D, 1>(0, D).into_owned();
158        let t = Translation {
159            vector: crate::convert_unchecked(t),
160        };
161
162        Self::from_parts(
163            t,
164            crate::convert_unchecked(mm),
165            crate::convert_unchecked(scale),
166        )
167    }
168}
169
170impl<T: SimdRealField, R, const D: usize> From<Similarity<T, R, D>>
171    for OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
172where
173    Const<D>: DimNameAdd<U1>,
174    R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>>,
175    DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, // + Allocator<D>
176{
177    #[inline]
178    fn from(sim: Similarity<T, R, D>) -> Self {
179        sim.to_homogeneous()
180    }
181}
182
183impl<T: Scalar + Zero + PrimitiveSimdValue, R, const D: usize>
184    From<[Similarity<T::Element, R::Element, D>; 2]> for Similarity<T, R, D>
185where
186    T: From<[<T as SimdValue>::Element; 2]>,
187    R: SimdValue + AbstractRotation<T, D> + From<[<R as SimdValue>::Element; 2]>,
188    R::Element: AbstractRotation<T::Element, D>,
189    T::Element: Scalar + Zero + Copy,
190    R::Element: Scalar + Zero + Copy,
191{
192    #[inline]
193    fn from(arr: [Similarity<T::Element, R::Element, D>; 2]) -> Self {
194        let iso = Isometry::from([arr[0].isometry, arr[1].isometry]);
195        let scale = T::from([arr[0].scaling(), arr[1].scaling()]);
196
197        Self::from_isometry(iso, scale)
198    }
199}
200
201impl<T: Scalar + Zero + PrimitiveSimdValue, R, const D: usize>
202    From<[Similarity<T::Element, R::Element, D>; 4]> for Similarity<T, R, D>
203where
204    T: From<[<T as SimdValue>::Element; 4]>,
205    R: SimdValue + AbstractRotation<T, D> + From<[<R as SimdValue>::Element; 4]>,
206    R::Element: AbstractRotation<T::Element, D>,
207    T::Element: Scalar + Zero + Copy,
208    R::Element: Scalar + Zero + Copy,
209{
210    #[inline]
211    fn from(arr: [Similarity<T::Element, R::Element, D>; 4]) -> Self {
212        let iso = Isometry::from([
213            arr[0].isometry,
214            arr[1].isometry,
215            arr[2].isometry,
216            arr[3].isometry,
217        ]);
218        let scale = T::from([
219            arr[0].scaling(),
220            arr[1].scaling(),
221            arr[2].scaling(),
222            arr[3].scaling(),
223        ]);
224
225        Self::from_isometry(iso, scale)
226    }
227}
228
229impl<T: Scalar + Zero + PrimitiveSimdValue, R, const D: usize>
230    From<[Similarity<T::Element, R::Element, D>; 8]> for Similarity<T, R, D>
231where
232    T: From<[<T as SimdValue>::Element; 8]>,
233    R: SimdValue + AbstractRotation<T, D> + From<[<R as SimdValue>::Element; 8]>,
234    R::Element: AbstractRotation<T::Element, D>,
235    T::Element: Scalar + Zero + Copy,
236    R::Element: Scalar + Zero + Copy,
237{
238    #[inline]
239    fn from(arr: [Similarity<T::Element, R::Element, D>; 8]) -> Self {
240        let iso = Isometry::from([
241            arr[0].isometry,
242            arr[1].isometry,
243            arr[2].isometry,
244            arr[3].isometry,
245            arr[4].isometry,
246            arr[5].isometry,
247            arr[6].isometry,
248            arr[7].isometry,
249        ]);
250        let scale = T::from([
251            arr[0].scaling(),
252            arr[1].scaling(),
253            arr[2].scaling(),
254            arr[3].scaling(),
255            arr[4].scaling(),
256            arr[5].scaling(),
257            arr[6].scaling(),
258            arr[7].scaling(),
259        ]);
260
261        Self::from_isometry(iso, scale)
262    }
263}
264
265impl<T: Scalar + Zero + PrimitiveSimdValue, R, const D: usize>
266    From<[Similarity<T::Element, R::Element, D>; 16]> for Similarity<T, R, D>
267where
268    T: From<[<T as SimdValue>::Element; 16]>,
269    R: SimdValue + AbstractRotation<T, D> + From<[<R as SimdValue>::Element; 16]>,
270    R::Element: AbstractRotation<T::Element, D>,
271    T::Element: Scalar + Zero + Copy,
272    R::Element: Scalar + Zero + Copy,
273{
274    #[inline]
275    fn from(arr: [Similarity<T::Element, R::Element, D>; 16]) -> Self {
276        let iso = Isometry::from([
277            arr[0].isometry,
278            arr[1].isometry,
279            arr[2].isometry,
280            arr[3].isometry,
281            arr[4].isometry,
282            arr[5].isometry,
283            arr[6].isometry,
284            arr[7].isometry,
285            arr[8].isometry,
286            arr[9].isometry,
287            arr[10].isometry,
288            arr[11].isometry,
289            arr[12].isometry,
290            arr[13].isometry,
291            arr[14].isometry,
292            arr[15].isometry,
293        ]);
294        let scale = T::from([
295            arr[0].scaling(),
296            arr[1].scaling(),
297            arr[2].scaling(),
298            arr[3].scaling(),
299            arr[4].scaling(),
300            arr[5].scaling(),
301            arr[6].scaling(),
302            arr[7].scaling(),
303            arr[8].scaling(),
304            arr[9].scaling(),
305            arr[10].scaling(),
306            arr[11].scaling(),
307            arr[12].scaling(),
308            arr[13].scaling(),
309            arr[14].scaling(),
310            arr[15].scaling(),
311        ]);
312
313        Self::from_isometry(iso, scale)
314    }
315}