use general::{ClosedMul, ClosedDiv, ClosedNeg, Real, MultiplicativeGroup, SubsetOf, Id};
use linear::{NormedSpace, EuclideanSpace};
pub trait Transformation<E: EuclideanSpace>: MultiplicativeGroup {
fn transform_point(&self, pt: &E) -> E;
fn transform_vector(&self, v: &E::Vector) -> E::Vector;
fn inverse_transform_point(&self, pt: &E) -> E;
fn inverse_transform_vector(&self, v: &E::Vector) -> E::Vector;
}
pub trait AffineTransformation<E: EuclideanSpace>: Transformation<E> {
type PreRotation: Rotation<E>;
type NonUniformScaling: AffineTransformation<E>;
type PostRotation: Rotation<E>;
type Translation: Translation<E>;
fn decompose(&self) -> (Self::Translation, Self::PostRotation,
Self::NonUniformScaling, Self::PreRotation);
}
pub trait Similarity<E: EuclideanSpace>: AffineTransformation<E,
PreRotation = Id,
NonUniformScaling = <Self as Similarity<E>>::Scaling,
PostRotation = <Self as Similarity<E>>::Rotation> {
type Rotation: Rotation<E>;
type Scaling: Scaling<E>;
fn translation(&self) -> Self::Translation;
fn rotation(&self) -> Self::Rotation;
fn scaling(&self) -> Self::Scaling;
#[inline]
fn translate_point(&self, pt: &E) -> E {
self.translation().transform_point(pt)
}
#[inline]
fn rotate_point(&self, pt: &E) -> E {
self.rotation().transform_point(pt)
}
#[inline]
fn scale_point(&self, pt: &E) -> E {
self.scaling().transform_point(pt)
}
#[inline]
fn rotate_vector(&self, pt: &E::Vector) -> E::Vector {
self.rotation().transform_vector(pt)
}
#[inline]
fn scale_vector(&self, pt: &E::Vector) -> E::Vector {
self.scaling().transform_vector(pt)
}
#[inline]
fn inverse_translate_point(&self, pt: &E) -> E {
self.translation().inverse_transform_point(pt)
}
#[inline]
fn inverse_rotate_point(&self, pt: &E) -> E {
self.rotation().inverse_transform_point(pt)
}
#[inline]
fn inverse_scale_point(&self, pt: &E) -> E {
self.scaling().inverse_transform_point(pt)
}
#[inline]
fn inverse_rotate_vector(&self, pt: &E::Vector) -> E::Vector {
self.rotation().inverse_transform_vector(pt)
}
#[inline]
fn inverse_scale_vector(&self, pt: &E::Vector) -> E::Vector {
self.scaling().inverse_transform_vector(pt)
}
}
pub trait Isometry<E: EuclideanSpace>: Similarity<E> {
}
pub trait DirectIsometry<E: EuclideanSpace>: Isometry<E> {
}
pub trait OrthogonalTransformation<E: EuclideanSpace>: Isometry<E> {
}
pub trait Scaling<E: EuclideanSpace>: AffineTransformation<E> + SubsetOf<E::Real> {
#[inline]
fn to_real(&self) -> E::Real {
self.to_superset()
}
#[inline]
fn from_real(r: E::Real) -> Option<Self> {
Self::from_superset(&r)
}
#[inline]
fn powf(&self, n: E::Real) -> Option<Self> {
Self::from_superset(&self.to_superset().powf(n))
}
#[inline]
fn scale_between(a: &E::Vector, b: &E::Vector) -> Option<Self> {
Self::from_superset(&(b.norm() / a.norm()))
}
}
pub trait Translation<E: EuclideanSpace>: DirectIsometry<E> {
fn to_vector(&self) -> E::Vector;
fn from_vector(v: &E::Vector) -> Option<Self>;
#[inline]
fn powf(&self, n: E::Real) -> Option<Self> {
Self::from_vector(&(self.to_vector() * n))
}
#[inline]
fn translation_between(a: &E, b: &E) -> Option<Self> {
Self::from_vector(&(b.clone() - a.clone()))
}
}
pub trait Rotation<E: EuclideanSpace>: OrthogonalTransformation<E> + DirectIsometry<E> {
fn powf(&self, n: E::Real) -> Option<Self>;
fn rotation_between(a: &E::Vector, b: &E::Vector) -> Option<Self>;
}
impl<R, E> Transformation<E> for R
where R: Real,
E: EuclideanSpace<Real = R>,
E::Vector: ClosedMul<R> + ClosedDiv<R> + ClosedNeg {
fn transform_point(&self, pt: &E) -> E {
pt.scale_by(*self)
}
fn transform_vector(&self, v: &E::Vector) -> E::Vector {
v.clone() * *self
}
fn inverse_transform_point(&self, pt: &E) -> E {
assert!(*self != R::zero());
pt.scale_by(R::one() / *self)
}
fn inverse_transform_vector(&self, v: &E::Vector) -> E::Vector {
assert!(*self != R::zero());
v.clone() * (R::one() / *self)
}
}
impl<R, E> AffineTransformation<E> for R
where R: Real,
E: EuclideanSpace<Real = R>,
E::Vector: ClosedMul<R> + ClosedDiv<R> + ClosedNeg {
type PreRotation = Id;
type NonUniformScaling = R;
type PostRotation = Id;
type Translation = Id;
#[inline]
fn decompose(&self) -> (Id, Id, R, Id) {
(Id::new(), Id::new(), *self, Id::new())
}
}
impl<R, E> Scaling<E> for R
where R: Real + SubsetOf<R>,
E: EuclideanSpace<Real = R>,
E::Vector: ClosedMul<R> + ClosedDiv<R> + ClosedNeg {
#[inline]
fn to_real(&self) -> E::Real {
*self
}
#[inline]
fn from_real(r: E::Real) -> Option<Self> {
Some(r)
}
#[inline]
fn powf(&self, n: E::Real) -> Option<Self> {
Some(n.powf(n))
}
#[inline]
fn scale_between(a: &E::Vector, b: &E::Vector) -> Option<Self> {
Some((b.norm() / a.norm()))
}
}
impl<R, E> Similarity<E> for R
where R: Real + SubsetOf<R>,
E: EuclideanSpace<Real = R>,
E::Vector: ClosedMul<R> + ClosedDiv<R> + ClosedNeg {
type Rotation = Id;
type Scaling = R;
fn translation(&self) -> Self::Translation {
Id::new()
}
fn rotation(&self) -> Self::Rotation {
Id::new()
}
fn scaling(&self) -> Self::Scaling {
*self
}
}