use num::Zero; use alga::general::{ AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module, Multiplicative, Real, }; use alga::linear::{ AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace, OrthogonalTransformation, ProjectiveTransformation, Rotation, Similarity, Transformation, VectorSpace, }; use crate::base::{Vector3, Vector4}; use crate::geometry::{Point3, Quaternion, UnitQuaternion}; impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::identity() } } impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::zero() } } impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self + rhs } } impl TwoSidedInverse for Quaternion { #[inline] fn two_sided_inverse(&self) -> Self { -self } } macro_rules! impl_structures( ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( impl $marker<$operator> for $Quaternion { } )*} ); impl_structures!( Quaternion; AbstractSemigroup, AbstractMonoid, AbstractSemigroup, AbstractQuasigroup, AbstractMonoid, AbstractLoop, AbstractGroup, AbstractGroupAbelian ); /* * * Vector space. * */ impl AbstractModule for Quaternion { type AbstractRing = N; #[inline] fn multiply_by(&self, n: N) -> Self { self * n } } impl Module for Quaternion { type Ring = N; } impl VectorSpace for Quaternion { type Field = N; } impl FiniteDimVectorSpace for Quaternion { #[inline] fn dimension() -> usize { 4 } #[inline] fn canonical_basis_element(i: usize) -> Self { Self::from(Vector4::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 Quaternion { type Real = N; type ComplexField = N; #[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(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(v)) } else { None } } #[inline] fn try_normalize_mut(&mut self, min_norm: N) -> Option { self.coords.try_normalize_mut(min_norm) } } /* * * Implementations for UnitQuaternion. * */ impl Identity for UnitQuaternion { #[inline] fn identity() -> Self { Self::identity() } } impl AbstractMagma for UnitQuaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } impl TwoSidedInverse for UnitQuaternion { #[inline] fn two_sided_inverse(&self) -> Self { self.inverse() } #[inline] fn two_sided_inverse_mut(&mut self) { self.inverse_mut() } } impl_structures!( UnitQuaternion; AbstractSemigroup, AbstractQuasigroup, AbstractMonoid, AbstractLoop, AbstractGroup ); impl Transformation> for UnitQuaternion { #[inline] fn transform_point(&self, pt: &Point3) -> Point3 { self * pt } #[inline] fn transform_vector(&self, v: &Vector3) -> Vector3 { self * v } } impl ProjectiveTransformation> for UnitQuaternion { #[inline] fn inverse_transform_point(&self, pt: &Point3) -> Point3 { // 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: &Vector3) -> Vector3 { self.inverse() * v } } impl AffineTransformation> for UnitQuaternion { 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 UnitQuaternion { 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 UnitQuaternion { } )*} ); marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); impl Rotation> for UnitQuaternion { #[inline] fn powf(&self, n: N) -> Option { Some(self.powf(n)) } #[inline] fn rotation_between(a: &Vector3, b: &Vector3) -> Option { Self::rotation_between(a, b) } #[inline] fn scaled_rotation_between(a: &Vector3, b: &Vector3, s: N) -> Option { Self::scaled_rotation_between(a, b, s) } }