// 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 structure::*; use approx::ApproxEq; use matrix::{Matrix2, Matrix3, Matrix4}; use num::{BaseFloat, BaseNum}; use point::{Point2, Point3}; use rotation::*; use vector::{Vector2, Vector3}; /// 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::Diff) -> Self; /// Transform a vector using this transform. fn transform_vector(&self, vec: P::Diff) -> P::Diff; /// Transform a point using this transform. fn transform_point(&self, point: P) -> P; /// 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 inverse_transform(&self) -> Option; /// Combine this transform with another, in-place. #[inline] fn concat_self(&mut self, other: &Self) { *self = Self::concat(self, other); } } /// A generic transformation consisting of a rotation, /// displacement vector and scale amount. #[derive(Copy, Clone, Debug, 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!

::Diff: VectorSpace, { #[inline] fn one() -> Decomposed { Decomposed { scale: P::Scalar::one(), rot: R::one(), disp: P::Diff::zero(), } } #[inline] fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed { let rot = R::look_at(center - eye, up); let disp = rot.rotate_vector(P::origin() - eye); Decomposed { scale: P::Scalar::one(), rot: rot, disp: disp, } } #[inline] fn transform_vector(&self, vec: P::Diff) -> P::Diff { 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.disp + other.disp, } } fn inverse_transform(&self) -> Option> { if self.scale.approx_eq(&P::Scalar::zero()) { None } else { let s = P::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> {}