// 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.rot.rotate_vector(other.disp * self.scale) + self.disp, } } fn inverse_transform(&self) -> Option> { if ulps_eq!(self.scale, &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; #[inline] fn default_epsilon() -> E { E::default_epsilon() } #[inline] fn default_max_relative() -> E { E::default_max_relative() } #[inline] fn default_max_ulps() -> u32 { E::default_max_ulps() } #[inline] fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool { S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative) && R::relative_eq(&self.rot, &other.rot, epsilon, max_relative) && S::relative_eq(&self.disp, &other.disp, epsilon, max_relative) } #[inline] fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool { S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps) && R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps) && S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps) } } #[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 { let mut state = try!(serializer.serialize_struct("Decomposed", 3)); try!(serializer.serialize_struct_elt(&mut state, "scale", &self.scale)); try!(serializer.serialize_struct_elt(&mut state, "rot", &self.rot)); try!(serializer.serialize_struct_elt(&mut state, "disp", &self.disp)); serializer.serialize_struct_end(state) } } } #[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 }) } } }