use num::Zero; use simba::scalar::{RealField, SubsetOf, SupersetOf}; use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimMin, DimNameAdd, DimNameSum, U1}; use crate::base::{Const, DefaultAllocator, OMatrix, Scalar}; use crate::geometry::{ AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, }; /* * This file provides the following conversions: * ============================================= * * Similarity -> Similarity * Similarity -> Transform * Similarity -> Matrix (homogeneous) */ impl SubsetOf> for Similarity where T1: RealField + SubsetOf, T2: RealField + SupersetOf, R1: AbstractRotation + SubsetOf, R2: AbstractRotation, { #[inline] fn to_superset(&self) -> Similarity { Similarity::from_isometry(self.isometry.to_superset(), self.scaling().to_superset()) } #[inline] fn is_in_subset(sim: &Similarity) -> bool { crate::is_convertible::<_, Isometry>(&sim.isometry) && crate::is_convertible::<_, T1>(&sim.scaling()) } #[inline] fn from_superset_unchecked(sim: &Similarity) -> Self { Similarity::from_isometry( sim.isometry.to_subset_unchecked(), sim.scaling().to_subset_unchecked(), ) } } impl SubsetOf> for Similarity where T1: RealField, T2: RealField + SupersetOf, C: SuperTCategoryOf, R: AbstractRotation + SubsetOf, U1>, DimNameSum, U1>>> + SubsetOf, U1>, DimNameSum, U1>>>, Const: DimNameAdd + DimMin, Output = Const>, // needed by .determinant() DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + Allocator, U1>, DimNameSum, U1>> + Allocator, U1>, DimNameSum, U1>>, // + Allocator<(usize, usize), D> // + Allocator // + Allocator // + Allocator // + Allocator, { #[inline] fn to_superset(&self) -> Transform { Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } impl SubsetOf, U1>, DimNameSum, U1>>> for Similarity where T1: RealField, T2: RealField + SupersetOf, R: AbstractRotation + SubsetOf, U1>, DimNameSum, U1>>> + SubsetOf, U1>, DimNameSum, U1>>>, Const: DimNameAdd + DimMin, Output = Const>, // needed by .determinant() DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + Allocator, U1>, DimNameSum, U1>> + Allocator, U1>, DimNameSum, U1>>, // + Allocator<(usize, usize), D> // + Allocator // + Allocator // + Allocator // + Allocator { #[inline] fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { self.to_homogeneous().to_superset() } #[inline] fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { let mut rot = m.fixed_slice::(0, 0).clone_owned(); if rot .fixed_columns_mut::<1>(0) .try_normalize_mut(T2::zero()) .is_some() && rot .fixed_columns_mut::<1>(1) .try_normalize_mut(T2::zero()) .is_some() && rot .fixed_columns_mut::<1>(2) .try_normalize_mut(T2::zero()) .is_some() { // TODO: could we avoid explicit the computation of the determinant? // (its sign is needed to see if the scaling factor is negative). if rot.determinant() < T2::zero() { rot.fixed_columns_mut::<1>(0).neg_mut(); rot.fixed_columns_mut::<1>(1).neg_mut(); rot.fixed_columns_mut::<1>(2).neg_mut(); } let bottom = m.fixed_slice::<1, D>(D, 0); // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && // The normalized block part is a rotation. // rot.is_special_orthogonal(T2::default_epsilon().sqrt()) && // The bottom row is (0, 0, ..., 1) bottom.iter().all(|e| e.is_zero()) && m[(D, D)] == T2::one() } else { false } } #[inline] fn from_superset_unchecked( m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { let mut mm = m.clone_owned(); let na = mm.fixed_slice_mut::(0, 0).normalize_mut(); let nb = mm.fixed_slice_mut::(0, 1).normalize_mut(); let nc = mm.fixed_slice_mut::(0, 2).normalize_mut(); let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness. // TODO: could we avoid the explicit computation of the determinant? // (its sign is needed to see if the scaling factor is negative). if mm.fixed_slice::(0, 0).determinant() < T2::zero() { mm.fixed_slice_mut::(0, 0).neg_mut(); mm.fixed_slice_mut::(0, 1).neg_mut(); mm.fixed_slice_mut::(0, 2).neg_mut(); scale = -scale; } let t = m.fixed_slice::(0, D).into_owned(); let t = Translation { vector: crate::convert_unchecked(t), }; Self::from_parts( t, crate::convert_unchecked(mm), crate::convert_unchecked(scale), ) } } impl From> for OMatrix, U1>, DimNameSum, U1>> where Const: DimNameAdd, R: SubsetOf, U1>, DimNameSum, U1>>>, DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, // + Allocator { #[inline] fn from(sim: Similarity) -> Self { sim.to_homogeneous() } } impl From<[Similarity; 2]> for Similarity where T: From<[::Element; 2]>, R: SimdValue + AbstractRotation + From<[::Element; 2]>, R::Element: AbstractRotation, T::Element: Scalar + Zero + Copy, R::Element: Scalar + Zero + Copy, { #[inline] fn from(arr: [Similarity; 2]) -> Self { let iso = Isometry::from([arr[0].isometry, arr[1].isometry]); let scale = T::from([arr[0].scaling(), arr[1].scaling()]); Self::from_isometry(iso, scale) } } impl From<[Similarity; 4]> for Similarity where T: From<[::Element; 4]>, R: SimdValue + AbstractRotation + From<[::Element; 4]>, R::Element: AbstractRotation, T::Element: Scalar + Zero + Copy, R::Element: Scalar + Zero + Copy, { #[inline] fn from(arr: [Similarity; 4]) -> Self { let iso = Isometry::from([ arr[0].isometry, arr[1].isometry, arr[2].isometry, arr[3].isometry, ]); let scale = T::from([ arr[0].scaling(), arr[1].scaling(), arr[2].scaling(), arr[3].scaling(), ]); Self::from_isometry(iso, scale) } } impl From<[Similarity; 8]> for Similarity where T: From<[::Element; 8]>, R: SimdValue + AbstractRotation + From<[::Element; 8]>, R::Element: AbstractRotation, T::Element: Scalar + Zero + Copy, R::Element: Scalar + Zero + Copy, { #[inline] fn from(arr: [Similarity; 8]) -> Self { let iso = Isometry::from([ arr[0].isometry, arr[1].isometry, arr[2].isometry, arr[3].isometry, arr[4].isometry, arr[5].isometry, arr[6].isometry, arr[7].isometry, ]); let scale = T::from([ arr[0].scaling(), arr[1].scaling(), arr[2].scaling(), arr[3].scaling(), arr[4].scaling(), arr[5].scaling(), arr[6].scaling(), arr[7].scaling(), ]); Self::from_isometry(iso, scale) } } impl From<[Similarity; 16]> for Similarity where T: From<[::Element; 16]>, R: SimdValue + AbstractRotation + From<[::Element; 16]>, R::Element: AbstractRotation, T::Element: Scalar + Zero + Copy, R::Element: Scalar + Zero + Copy, { #[inline] fn from(arr: [Similarity; 16]) -> Self { let iso = Isometry::from([ arr[0].isometry, arr[1].isometry, arr[2].isometry, arr[3].isometry, arr[4].isometry, arr[5].isometry, arr[6].isometry, arr[7].isometry, arr[8].isometry, arr[9].isometry, arr[10].isometry, arr[11].isometry, arr[12].isometry, arr[13].isometry, arr[14].isometry, arr[15].isometry, ]); let scale = T::from([ arr[0].scaling(), arr[1].scaling(), arr[2].scaling(), arr[3].scaling(), arr[4].scaling(), arr[5].scaling(), arr[6].scaling(), arr[7].scaling(), arr[8].scaling(), arr[9].scaling(), arr[10].scaling(), arr[11].scaling(), arr[12].scaling(), arr[13].scaling(), arr[14].scaling(), arr[15].scaling(), ]); Self::from_isometry(iso, scale) } }