use num::Zero; use alga::general::{AbstractMagma, AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, AbstractModule, Module, Real, Inverse, Multiplicative, Additive, Identity, Id}; use alga::linear::{Transformation, AffineTransformation, Similarity, Isometry, DirectIsometry, OrthogonalTransformation, VectorSpace, FiniteDimVectorSpace, NormedSpace, Rotation, ProjectiveTransformation}; use core::ColumnVector; use core::storage::OwnedStorage; use core::allocator::{Allocator, OwnedAllocator}; use core::dimension::{U1, U3, U4}; use geometry::{PointBase, QuaternionBase, UnitQuaternionBase}; impl Identity for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn identity() -> Self { Self::identity() } } impl Identity for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn identity() -> Self { Self::zero() } } impl AbstractMagma for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } impl AbstractMagma for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self + rhs } } impl Inverse for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn inverse(&self) -> Self { -self } } macro_rules! impl_structures( ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( impl $marker<$operator> for $Quaternion where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { } )*} ); impl_structures!( QuaternionBase; AbstractSemigroup, AbstractMonoid, AbstractSemigroup, AbstractQuasigroup, AbstractMonoid, AbstractLoop, AbstractGroup, AbstractGroupAbelian ); /* * * Vector space. * */ impl AbstractModule for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { type AbstractRing = N; #[inline] fn multiply_by(&self, n: N) -> Self { self * n } } impl Module for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { type Ring = N; } impl VectorSpace for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { type Field = N; } impl FiniteDimVectorSpace for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn dimension() -> usize { 4 } #[inline] fn canonical_basis_element(i: usize) -> Self { Self::from_vector(ColumnVector::canonical_basis_element(i)) } #[inline] fn dot(&self, other: &Self) -> N { self.coords.dot(&other.coords) } #[inline] unsafe fn component_unchecked(&self, i: usize) -> &N { self.coords.component_unchecked(i) } #[inline] unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut N { self.coords.component_unchecked_mut(i) } } impl NormedSpace for QuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn norm_squared(&self) -> N { self.coords.norm_squared() } #[inline] fn norm(&self) -> N { self.as_vector().norm() } #[inline] fn normalize(&self) -> Self { let v = self.coords.normalize(); Self::from_vector(v) } #[inline] fn normalize_mut(&mut self) -> N { self.coords.normalize_mut() } #[inline] fn try_normalize(&self, min_norm: N) -> Option { if let Some(v) = self.coords.try_normalize(min_norm) { Some(Self::from_vector(v)) } else { None } } #[inline] fn try_normalize_mut(&mut self, min_norm: N) -> Option { self.coords.try_normalize_mut(min_norm) } } /* * * Implementations for UnitQuaternionBase. * */ impl Identity for UnitQuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn identity() -> Self { Self::identity() } } impl AbstractMagma for UnitQuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } impl Inverse for UnitQuaternionBase where N: Real, S: OwnedStorage, S::Alloc: OwnedAllocator { #[inline] fn inverse(&self) -> Self { self.inverse() } #[inline] fn inverse_mut(&mut self) { self.inverse_mut() } } impl_structures!( UnitQuaternionBase; AbstractSemigroup, AbstractQuasigroup, AbstractMonoid, AbstractLoop, AbstractGroup ); impl Transformation> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator, SB::Alloc: OwnedAllocator { #[inline] fn transform_point(&self, pt: &PointBase) -> PointBase { self * pt } #[inline] fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { self * v } } impl ProjectiveTransformation> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator, SB::Alloc: OwnedAllocator { #[inline] fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } #[inline] fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { self.inverse() * v } } impl AffineTransformation> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator, SB::Alloc: OwnedAllocator { type Rotation = Self; type NonUniformScaling = Id; type Translation = Id; #[inline] fn decompose(&self) -> (Id, Self, Id, Self) { (Id::new(), self.clone(), Id::new(), Self::identity()) } #[inline] fn append_translation(&self, _: &Self::Translation) -> Self { self.clone() } #[inline] fn prepend_translation(&self, _: &Self::Translation) -> Self { self.clone() } #[inline] fn append_rotation(&self, r: &Self::Rotation) -> Self { r * self } #[inline] fn prepend_rotation(&self, r: &Self::Rotation) -> Self { self * r } #[inline] fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { self.clone() } #[inline] fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { self.clone() } } impl Similarity> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator, SB::Alloc: OwnedAllocator { type Scaling = Id; #[inline] fn translation(&self) -> Id { Id::new() } #[inline] fn rotation(&self) -> Self { self.clone() } #[inline] fn scaling(&self) -> Id { Id::new() } } macro_rules! marker_impl( ($($Trait: ident),*) => {$( impl $Trait> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator, SB::Alloc: OwnedAllocator { } )*} ); marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); impl Rotation> for UnitQuaternionBase where N: Real, SA: OwnedStorage, SB: OwnedStorage, SA::Alloc: OwnedAllocator + Allocator, SB::Alloc: OwnedAllocator { #[inline] fn powf(&self, n: N) -> Option { Some(self.powf(n)) } #[inline] fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Option { Self::rotation_between(a, b) } #[inline] fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, s: N) -> Option { Self::scaled_rotation_between(a, b, s) } }