use num::Zero;
use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Module,
Multiplicative, RealField, TwoSidedInverse,
};
use alga::linear::{
AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace,
ProjectiveTransformation, Similarity, Transformation, VectorSpace,
};
use crate::base::Vector3;
use crate::geometry::{
DualQuaternion, Point3, Quaternion, Translation3, UnitDualQuaternion, UnitQuaternion,
};
impl<T: RealField + simba::scalar::RealField> Identity<Multiplicative> for DualQuaternion<T> {
#[inline]
fn identity() -> Self {
Self::identity()
}
}
impl<T: RealField + simba::scalar::RealField> Identity<Additive> for DualQuaternion<T> {
#[inline]
fn identity() -> Self {
Self::zero()
}
}
impl<T: RealField + simba::scalar::RealField> AbstractMagma<Multiplicative> for DualQuaternion<T> {
#[inline]
fn operate(&self, rhs: &Self) -> Self {
self * rhs
}
}
impl<T: RealField + simba::scalar::RealField> AbstractMagma<Additive> for DualQuaternion<T> {
#[inline]
fn operate(&self, rhs: &Self) -> Self {
self + rhs
}
}
impl<T: RealField + simba::scalar::RealField> TwoSidedInverse<Additive> for DualQuaternion<T> {
#[inline]
fn two_sided_inverse(&self) -> Self {
-self
}
}
macro_rules! impl_structures(
($DualQuaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<T: RealField + simba::scalar::RealField> $marker<$operator> for $DualQuaternion<T> { }
)*}
);
impl_structures!(
DualQuaternion;
AbstractSemigroup<Multiplicative>,
AbstractMonoid<Multiplicative>,
AbstractSemigroup<Additive>,
AbstractQuasigroup<Additive>,
AbstractMonoid<Additive>,
AbstractLoop<Additive>,
AbstractGroup<Additive>,
AbstractGroupAbelian<Additive>
);
impl<T: RealField + simba::scalar::RealField> AbstractModule for DualQuaternion<T> {
type AbstractRing = T;
#[inline]
fn multiply_by(&self, n: T) -> Self {
self * n
}
}
impl<T: RealField + simba::scalar::RealField> Module for DualQuaternion<T> {
type Ring = T;
}
impl<T: RealField + simba::scalar::RealField> VectorSpace for DualQuaternion<T> {
type Field = T;
}
impl<T: RealField + simba::scalar::RealField> FiniteDimVectorSpace for DualQuaternion<T> {
#[inline]
fn dimension() -> usize {
8
}
#[inline]
fn canonical_basis_element(i: usize) -> Self {
if i < 4 {
DualQuaternion::from_real_and_dual(
Quaternion::canonical_basis_element(i),
Quaternion::zero(),
)
} else {
DualQuaternion::from_real_and_dual(
Quaternion::zero(),
Quaternion::canonical_basis_element(i - 4),
)
}
}
#[inline]
fn dot(&self, other: &Self) -> T {
self.real.dot(&other.real) + self.dual.dot(&other.dual)
}
#[inline]
unsafe fn component_unchecked(&self, i: usize) -> &T {
self.as_ref().get_unchecked(i)
}
#[inline]
unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut T {
self.as_mut().get_unchecked_mut(i)
}
}
impl<T: RealField + simba::scalar::RealField> NormedSpace for DualQuaternion<T> {
type RealField = T;
type ComplexField = T;
#[inline]
fn norm_squared(&self) -> T {
self.real.norm_squared()
}
#[inline]
fn norm(&self) -> T {
self.real.norm()
}
#[inline]
fn normalize(&self) -> Self {
self.normalize()
}
#[inline]
fn normalize_mut(&mut self) -> T {
self.normalize_mut()
}
#[inline]
fn try_normalize(&self, min_norm: T) -> Option<Self> {
let real_norm = self.real.norm();
if real_norm > min_norm {
Some(Self::from_real_and_dual(
self.real / real_norm,
self.dual / real_norm,
))
} else {
None
}
}
#[inline]
fn try_normalize_mut(&mut self, min_norm: T) -> Option<T> {
let real_norm = self.real.norm();
if real_norm > min_norm {
self.real /= real_norm;
self.dual /= real_norm;
Some(real_norm)
} else {
None
}
}
}
impl<T: RealField + simba::scalar::RealField> Identity<Multiplicative> for UnitDualQuaternion<T> {
#[inline]
fn identity() -> Self {
Self::identity()
}
}
impl<T: RealField + simba::scalar::RealField> AbstractMagma<Multiplicative>
for UnitDualQuaternion<T>
{
#[inline]
fn operate(&self, rhs: &Self) -> Self {
self * rhs
}
}
impl<T: RealField + simba::scalar::RealField> TwoSidedInverse<Multiplicative>
for UnitDualQuaternion<T>
{
#[inline]
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}
impl_structures!(
UnitDualQuaternion;
AbstractSemigroup<Multiplicative>,
AbstractQuasigroup<Multiplicative>,
AbstractMonoid<Multiplicative>,
AbstractLoop<Multiplicative>,
AbstractGroup<Multiplicative>
);
impl<T: RealField + simba::scalar::RealField> Transformation<Point3<T>> for UnitDualQuaternion<T> {
#[inline]
fn transform_point(&self, pt: &Point3<T>) -> Point3<T> {
self.transform_point(pt)
}
#[inline]
fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self.transform_vector(v)
}
}
impl<T: RealField + simba::scalar::RealField> ProjectiveTransformation<Point3<T>>
for UnitDualQuaternion<T>
{
#[inline]
fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> {
self.inverse_transform_point(pt)
}
#[inline]
fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self.inverse_transform_vector(v)
}
}
impl<T: RealField + simba::scalar::RealField> AffineTransformation<Point3<T>>
for UnitDualQuaternion<T>
{
type Rotation = UnitQuaternion<T>;
type NonUniformScaling = Id;
type Translation = Translation3<T>;
#[inline]
fn decompose(&self) -> (Self::Translation, Self::Rotation, Id, Self::Rotation) {
(
self.translation(),
self.rotation(),
Id::new(),
UnitQuaternion::identity(),
)
}
#[inline]
fn append_translation(&self, translation: &Self::Translation) -> Self {
self * Self::from_parts(*translation, UnitQuaternion::identity())
}
#[inline]
fn prepend_translation(&self, translation: &Self::Translation) -> Self {
Self::from_parts(*translation, UnitQuaternion::identity()) * self
}
#[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
}
#[inline]
fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self {
*self
}
}
impl<T: RealField + simba::scalar::RealField> Similarity<Point3<T>> for UnitDualQuaternion<T> {
type Scaling = Id;
#[inline]
fn translation(&self) -> Translation3<T> {
self.translation()
}
#[inline]
fn rotation(&self) -> UnitQuaternion<T> {
self.rotation()
}
#[inline]
fn scaling(&self) -> Id {
Id::new()
}
}
macro_rules! marker_impl(
($($Trait: ident),*) => {$(
impl<T: RealField + simba::scalar::RealField> $Trait<Point3<T>> for UnitDualQuaternion<T> { }
)*}
);
marker_impl!(Isometry, DirectIsometry);