// Copyright 2014 The CGMath Developers. For a full listing of the authors, // refer to the Cargo.toml file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::fmt; use rust_num::{Zero, One}; use approx::ApproxEq; use matrix::*; use num::*; use point::*; use rotation::*; use vector::*; /// A trait representing an [affine /// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that /// can be applied to points or vectors. An affine transformation is one which pub trait Transform: Sized { /// Create an identity transformation. That is, a transformation which /// does nothing. fn one() -> Self; /// Create a transformation that rotates a vector to look at `center` from /// `eye`, using `up` for orientation. fn look_at(eye: P, center: P, up: P::Vector) -> Self; /// Transform a vector using this transform. fn transform_vector(&self, vec: P::Vector) -> P::Vector; /// Transform a point using this transform. fn transform_point(&self, point: P) -> P; /// Transform a vector as a point using this transform. #[inline] fn transform_as_point(&self, vec: P::Vector) -> P::Vector { self.transform_point(P::from_vec(vec)).to_vec() } /// Combine this transform with another, yielding a new transformation /// which has the effects of both. fn concat(&self, other: &Self) -> Self; /// Create a transform that "un-does" this one. fn invert(&self) -> Option; /// Combine this transform with another, in-place. #[inline] fn concat_self(&mut self, other: &Self) { *self = Self::concat(self, other); } /// Invert this transform in-place, failing if the transformation is not /// invertible. #[inline] fn invert_self(&mut self) { *self = self.invert().unwrap() } } /// A generic transformation consisting of a rotation, /// displacement vector and scale amount. #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Decomposed { pub scale: V::Scalar, pub rot: R, pub disp: V, } impl> Transform

for Decomposed where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092

::Scalar: BaseFloat, // FIXME: Investigate why this is needed!

::Vector: Vector, { #[inline] fn one() -> Decomposed { Decomposed { scale:

::Scalar::one(), rot: R::one(), disp: P::Vector::zero(), } } #[inline] fn look_at(eye: P, center: P, up: P::Vector) -> Decomposed { let rot = R::look_at(center - eye, up); let disp = rot.rotate_vector(P::origin() - eye); Decomposed { scale:

::Scalar::one(), rot: rot, disp: disp, } } #[inline] fn transform_vector(&self, vec: P::Vector) -> P::Vector { self.rot.rotate_vector(vec * self.scale) } #[inline] fn transform_point(&self, point: P) -> P { self.rot.rotate_point(point * self.scale) + self.disp } fn concat(&self, other: &Decomposed) -> Decomposed { Decomposed { scale: self.scale * other.scale, rot: self.rot.concat(&other.rot), disp: self.transform_as_point(other.disp.clone()), } } fn invert(&self) -> Option> { if self.scale.approx_eq(&

::Scalar::zero()) { None } else { let s =

::Scalar::one() / self.scale; let r = self.rot.invert(); let d = r.rotate_vector(self.disp.clone()) * -s; Some(Decomposed { scale: s, rot: r, disp: d, }) } } } pub trait Transform2: Transform> + Into> {} pub trait Transform3: Transform> + Into> {} impl> From, R>> for Matrix3 { fn from(dec: Decomposed, R>) -> Matrix3 { let m: Matrix2<_> = dec.rot.into(); let mut m: Matrix3<_> = (&m * dec.scale).into(); m.z = dec.disp.extend(S::one()); m } } impl> From, R>> for Matrix4 { fn from(dec: Decomposed, R>) -> Matrix4 { let m: Matrix3<_> = dec.rot.into(); let mut m: Matrix4<_> = (&m * dec.scale).into(); m.w = dec.disp.extend(S::one()); m } } impl> Transform2 for Decomposed, R> {} impl> Transform3 for Decomposed, R> {} impl> fmt::Debug for Decomposed, R> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(scale({:?}), rot({:?}), disp{:?})", self.scale, self.rot, self.disp) } } /// A homogeneous transformation matrix. #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct AffineMatrix3 { pub mat: Matrix4, } impl Transform> for AffineMatrix3 { #[inline] fn one() -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::identity() } } #[inline] fn look_at(eye: Point3, center: Point3, up: Vector3) -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::look_at(eye, center, up) } } #[inline] fn transform_vector(&self, vec: Vector3) -> Vector3 { self.mat.mul_v(vec.extend(S::zero())).truncate() } #[inline] fn transform_point(&self, point: Point3) -> Point3 { Point3::from_homogeneous(self.mat.mul_v(point.to_homogeneous())) } #[inline] fn concat(&self, other: &AffineMatrix3) -> AffineMatrix3 { AffineMatrix3 { mat: self.mat.mul_m(&other.mat) } } #[inline] fn invert(&self) -> Option> { self.mat.invert().map(|m| AffineMatrix3{ mat: m }) } } impl From> for Matrix4 { #[inline] fn from(aff: AffineMatrix3) -> Matrix4 { aff.mat } } impl Transform3 for AffineMatrix3 {}