// 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)] #[cfg_attr(feature = "rustc-serialize", derive(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 * 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> {} impl ApproxEq for Decomposed where S: ApproxEq, S::Scalar: ApproxEq, R: ApproxEq { type Epsilon = E; fn approx_eq_eps(&self, other: &Self, epsilon: &Self::Epsilon) -> bool { self.scale.approx_eq_eps(&other.scale, epsilon) && self.rot.approx_eq_eps(&other.rot, epsilon) && self.disp.approx_eq_eps(&other.disp, epsilon) } } #[cfg(feature = "eders")] #[doc(hidden)] mod eders_ser { use structure::VectorSpace; use super::Decomposed; use serde::{self, Serialize}; impl Serialize for Decomposed where V: Serialize, V::Scalar: Serialize, R: Serialize { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { serializer.serialize_struct("Decomposed", DecomposedVisitor { value: self, state: 0, }) } } struct DecomposedVisitor<'a, V: 'a + VectorSpace, R: 'a> { value: &'a Decomposed, state: u8, } impl<'a, V: 'a + VectorSpace, R> serde::ser::MapVisitor for DecomposedVisitor<'a, V, R> where V: Serialize, V::Scalar: Serialize, R: Serialize { fn visit(&mut self, serializer: &mut S) -> Result, S::Error> where S: serde::Serializer { match self.state { 0 => { self.state += 1; Ok(Some(try!(serializer.serialize_struct_elt("scale", &self.value.scale)))) }, 1 => { self.state += 1; Ok(Some(try!(serializer.serialize_struct_elt("rot", &self.value.rot)))) }, 2 => { self.state += 1; Ok(Some(try!(serializer.serialize_struct_elt("disp", &self.value.disp)))) }, _ => { Ok(None) }, } } } } #[cfg(feature = "eders")] #[doc(hidden)] mod eders_de { use structure::VectorSpace; use super::Decomposed; use serde::{self, Deserialize}; use std::marker::PhantomData; enum DecomposedField { Scale, Rot, Disp, } impl Deserialize for DecomposedField { fn deserialize(deserializer: &mut D) -> Result where D: serde::Deserializer { struct DecomposedFieldVisitor; impl serde::de::Visitor for DecomposedFieldVisitor { type Value = DecomposedField; fn visit_str(&mut self, value: &str) -> Result where E: serde::de::Error { match value { "scale" => Ok(DecomposedField::Scale), "rot" => Ok(DecomposedField::Rot), "disp" => Ok(DecomposedField::Disp), _ => Err(serde::de::Error::custom("expected scale, rot or disp")), } } } deserializer.deserialize(DecomposedFieldVisitor) } } impl Deserialize for Decomposed where S: Deserialize, S::Scalar: Deserialize, R: Deserialize { fn deserialize(deserializer: &mut D) -> Result, D::Error> where D: serde::de::Deserializer { const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"]; deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData)) } } struct DecomposedVisitor(PhantomData<(S, R)>); impl serde::de::Visitor for DecomposedVisitor where S: Deserialize, S::Scalar: Deserialize, R: Deserialize { type Value = Decomposed; fn visit_map(&mut self, mut visitor: V) -> Result, V::Error> where V: serde::de::MapVisitor { let mut scale = None; let mut rot = None; let mut disp = None; loop { match try!(visitor.visit_key()) { Some(DecomposedField::Scale) => { scale = Some(try!(visitor.visit_value())); }, Some(DecomposedField::Rot) => { rot = Some(try!(visitor.visit_value())); }, Some(DecomposedField::Disp) => { disp = Some(try!(visitor.visit_value())); }, _ => { break; }, } } let scale = match scale { Some(scale) => scale, None => try!(visitor.missing_field("scale")), }; let rot = match rot { Some(rot) => rot, None => try!(visitor.missing_field("rot")), }; let disp = match disp { Some(disp) => disp, None => try!(visitor.missing_field("disp")), }; try!(visitor.end()); Ok(Decomposed { scale: scale, rot: rot, disp: disp }) } } }