use crate::general::{
ClosedDiv, ClosedMul, ClosedNeg, ComplexField, Id, MultiplicativeGroup, MultiplicativeMonoid,
RealField, SubsetOf, TwoSidedInverse,
};
use crate::linear::{EuclideanSpace, NormedSpace};
pub trait Transformation<E: EuclideanSpace>: MultiplicativeMonoid {
fn transform_point(&self, pt: &E) -> E;
fn transform_vector(&self, v: &E::Coordinates) -> E::Coordinates;
}
pub trait ProjectiveTransformation<E: EuclideanSpace>:
MultiplicativeGroup + Transformation<E>
{
fn inverse_transform_point(&self, pt: &E) -> E;
fn inverse_transform_vector(&self, v: &E::Coordinates) -> E::Coordinates;
}
pub trait AffineTransformation<E: EuclideanSpace>: ProjectiveTransformation<E> {
type Rotation: Rotation<E>;
type NonUniformScaling: AffineTransformation<E>;
type Translation: Translation<E>;
fn decompose(
&self,
) -> (
Self::Translation,
Self::Rotation,
Self::NonUniformScaling,
Self::Rotation,
);
fn append_translation(&self, t: &Self::Translation) -> Self;
fn prepend_translation(&self, t: &Self::Translation) -> Self;
fn append_rotation(&self, r: &Self::Rotation) -> Self;
fn prepend_rotation(&self, r: &Self::Rotation) -> Self;
fn append_scaling(&self, s: &Self::NonUniformScaling) -> Self;
fn prepend_scaling(&self, s: &Self::NonUniformScaling) -> Self;
#[inline]
fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &E) -> Option<Self> {
if let Some(t) = Self::Translation::from_vector(p.coordinates()) {
let it = t.two_sided_inverse();
Some(
self.append_translation(&it)
.append_rotation(&r)
.append_translation(&t),
)
} else {
None
}
}
}
pub trait Similarity<E: EuclideanSpace>:
AffineTransformation<E, NonUniformScaling = <Self as Similarity<E>>::Scaling>
{
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::Coordinates) -> E::Coordinates {
self.rotation().transform_vector(pt)
}
#[inline]
fn scale_vector(&self, pt: &E::Coordinates) -> E::Coordinates {
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::Coordinates) -> E::Coordinates {
self.rotation().inverse_transform_vector(pt)
}
#[inline]
fn inverse_scale_vector(&self, pt: &E::Coordinates) -> E::Coordinates {
self.scaling().inverse_transform_vector(pt)
}
}
pub trait Isometry<E: EuclideanSpace>: Similarity<E, Scaling = Id> {}
pub trait DirectIsometry<E: EuclideanSpace>: Isometry<E> {}
pub trait OrthogonalTransformation<E: EuclideanSpace>: Isometry<E, Translation = Id> {}
pub trait Scaling<E: EuclideanSpace>:
AffineTransformation<E, NonUniformScaling = Self, Translation = Id, Rotation = Id>
+ SubsetOf<E::RealField>
{
#[inline]
fn to_real(&self) -> E::RealField {
self.to_superset()
}
#[inline]
fn from_real(r: E::RealField) -> Option<Self> {
Self::from_superset(&r)
}
#[inline]
fn powf(&self, n: E::RealField) -> Option<Self> {
Self::from_superset(&self.to_superset().powf(n))
}
#[inline]
fn scale_between(a: &E::Coordinates, b: &E::Coordinates) -> Option<Self> {
Self::from_superset(&(b.norm() / a.norm()))
}
}
pub trait Translation<E: EuclideanSpace>:
DirectIsometry<E, Translation = Self, Rotation = Id>
{
fn to_vector(&self) -> E::Coordinates;
fn from_vector(v: E::Coordinates) -> Option<Self>;
#[inline]
fn powf(&self, n: E::RealField) -> 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, Rotation = Self> + DirectIsometry<E, Rotation = Self>
{
fn powf(&self, n: E::RealField) -> Option<Self>;
fn rotation_between(a: &E::Coordinates, b: &E::Coordinates) -> Option<Self>;
#[inline]
fn scaled_rotation_between(
a: &E::Coordinates,
b: &E::Coordinates,
s: E::RealField,
) -> Option<Self>;
}
impl<R, E> Transformation<E> for R
where
R: RealField,
E: EuclideanSpace<RealField = R>,
E::Coordinates: ClosedMul<R> + ClosedDiv<R> + ClosedNeg,
{
#[inline]
fn transform_point(&self, pt: &E) -> E {
pt.scale_by(*self)
}
#[inline]
fn transform_vector(&self, v: &E::Coordinates) -> E::Coordinates {
v.clone() * *self
}
}
impl<R, E> ProjectiveTransformation<E> for R
where
R: RealField,
E: EuclideanSpace<RealField = R>,
E::Coordinates: ClosedMul<R> + ClosedDiv<R> + ClosedNeg,
{
#[inline]
fn inverse_transform_point(&self, pt: &E) -> E {
assert!(*self != R::zero());
pt.scale_by(R::one() / *self)
}
#[inline]
fn inverse_transform_vector(&self, v: &E::Coordinates) -> E::Coordinates {
assert!(*self != R::zero());
v.clone() * (R::one() / *self)
}
}
impl<R, E> AffineTransformation<E> for R
where
R: RealField,
E: EuclideanSpace<RealField = R>,
E::Coordinates: ClosedMul<R> + ClosedDiv<R> + ClosedNeg,
{
type Rotation = Id;
type NonUniformScaling = R;
type Translation = Id;
#[inline]
fn decompose(&self) -> (Id, Id, R, Id) {
(Id::new(), Id::new(), *self, Id::new())
}
#[inline]
fn append_translation(&self, _: &Self::Translation) -> Self {
*self
}
#[inline]
fn prepend_translation(&self, _: &Self::Translation) -> Self {
*self
}
#[inline]
fn append_rotation(&self, _: &Self::Rotation) -> Self {
*self
}
#[inline]
fn prepend_rotation(&self, _: &Self::Rotation) -> Self {
*self
}
#[inline]
fn append_scaling(&self, s: &Self::NonUniformScaling) -> Self {
*s * *self
}
#[inline]
fn prepend_scaling(&self, s: &Self::NonUniformScaling) -> Self {
*self * *s
}
}
impl<R, E> Scaling<E> for R
where
R: RealField + SubsetOf<R>,
E: EuclideanSpace<RealField = R>,
E::Coordinates: ClosedMul<R> + ClosedDiv<R> + ClosedNeg,
{
#[inline]
fn to_real(&self) -> E::RealField {
*self
}
#[inline]
fn from_real(r: E::RealField) -> Option<Self> {
Some(r)
}
#[inline]
fn powf(&self, n: E::RealField) -> Option<Self> {
Some(n.powf(n))
}
#[inline]
fn scale_between(a: &E::Coordinates, b: &E::Coordinates) -> Option<Self> {
Some(b.norm() / a.norm())
}
}
impl<R, E> Similarity<E> for R
where
R: RealField + SubsetOf<R>,
E: EuclideanSpace<RealField = R>,
E::Coordinates: ClosedMul<R> + ClosedDiv<R> + ClosedNeg,
{
type Scaling = R;
fn translation(&self) -> Self::Translation {
Id::new()
}
fn rotation(&self) -> Self::Rotation {
Id::new()
}
fn scaling(&self) -> Self::Scaling {
*self
}
}