diff --git a/src/transform.rs b/src/transform.rs
index de3d33a..48e966e 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -17,13 +17,12 @@ use std::fmt;
 
 use approx::ApproxEq;
 use matrix::*;
-use num::{BaseNum, BaseFloat, zero, one};
-use point::{Point, Point3};
-use quaternion::*;
+use num::*;
+use point::*;
 use ray::Ray;
-use rotation::{Rotation, Rotation3};
+use rotation::*;
 use std::marker::PhantomFn;
-use vector::{Vector, Vector3};
+use vector::*;
 
 /// A trait representing an [affine
 /// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
@@ -89,7 +88,7 @@ impl<
     S: BaseFloat,
     V: Vector<S>,
     P: Point<S, V>,
-    R: Rotation<S, V, P>
+    R: Rotation<S, V, P>,
 > Transform<S, V, P> for Decomposed<S, V, R> {
     #[inline]
     fn identity() -> Decomposed<S, V, R> {
@@ -146,11 +145,23 @@ impl<
     }
 }
 
+pub trait Transform2<S>: Transform<S, Vector2<S>, Point2<S>> + ToMatrix3<S> {}
 pub trait Transform3<S>: Transform<S, Vector3<S>, Point3<S>> + ToMatrix4<S> {}
 
 impl<
     S: BaseFloat + 'static,
-    R: Rotation3<S>
+    R: Rotation2<S>,
+> ToMatrix3<S> for Decomposed<S, Vector2<S>, R> {
+    fn to_matrix3(&self) -> Matrix3<S> {
+        let mut m = self.rot.to_matrix2().mul_s(self.scale.clone()).to_matrix3();
+        m.z = self.disp.extend(one());
+        m
+    }
+}
+
+impl<
+    S: BaseFloat + 'static,
+    R: Rotation3<S>,
 > ToMatrix4<S> for Decomposed<S, Vector3<S>, R> {
     fn to_matrix4(&self) -> Matrix4<S> {
         let mut m = self.rot.to_matrix3().mul_s(self.scale.clone()).to_matrix4();
@@ -161,12 +172,17 @@ impl<
 
 impl<
     S: BaseFloat + 'static,
-    R: Rotation3<S>
+    R: Rotation2<S>,
+> Transform2<S> for Decomposed<S, Vector2<S>, R> {}
+
+impl<
+    S: BaseFloat + 'static,
+    R: Rotation3<S>,
 > Transform3<S> for Decomposed<S, Vector3<S>, R> {}
 
 impl<
     S: BaseFloat,
-    R: fmt::Debug + Rotation3<S>
+    R: fmt::Debug + Rotation3<S>,
 > fmt::Debug for Decomposed<S, Vector3<S>, R> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "(scale({:?}), rot({:?}), disp{:?})",
@@ -216,72 +232,54 @@ impl<S: BaseNum> ToMatrix4<S> for AffineMatrix3<S> {
     #[inline] fn to_matrix4(&self) -> Matrix4<S> { self.mat.clone() }
 }
 
-impl<S: BaseFloat> Transform3<S> for AffineMatrix3<S> where S: 'static {}
+impl<S: BaseFloat + 'static> Transform3<S> for AffineMatrix3<S> {}
 
 /// A trait that allows extracting components (rotation, translation, scale)
-/// from an arbitrary transformation/
-pub trait ToComponents<S, V: Vector<S>, P: Point<S, V>> {
-    /// Associated rotation type
-    type Rotation;
-    /// Extract translation component
-    fn to_translation(&self) -> V;
-    /// Extract rotation component
-    fn to_rotation(&self) -> Self::Rotation;
-    /// Extract scale component
-    fn to_scale(&self) -> V;
+/// from an arbitrary transformations
+pub trait ToComponents<S, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>>: PhantomFn<(S, P)> {
+    /// Extract the (scale, rotation, translation) triple
+    fn decompose(&self) -> (V, R, V);
 }
 
-pub trait ToComponents3<S>: ToComponents<S, Vector3<S>, Point3<S>>
-    where Self::Rotation: ToMatrix3<S> {}
+pub trait ToComponents2<S, R: Rotation2<S>>:
+    ToComponents<S, Vector2<S>, Point2<S>, R> {}
+pub trait ToComponents3<S, R: Rotation3<S>>:
+    ToComponents<S, Vector3<S>, Point3<S>, R> {}
+
+pub trait CompositeTransform<S, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>>:
+    Transform<S, V, P> + ToComponents<S, V, P, R> {}
+pub trait CompositeTransform2<S, R: Rotation2<S>>:
+    Transform2<S> + ToComponents2<S, R> {}
+pub trait CompositeTransform3<S, R: Rotation3<S>>:
+    Transform3<S> + ToComponents3<S, R> {}
 
 impl<
     S: BaseFloat,
     V: Vector<S> + Clone,
     P: Point<S, V>,
     R: Rotation<S, V, P> + Clone,
-> ToComponents<S, V, P> for Decomposed<S, V, R> {
-    type Rotation = R;
-    
-    fn to_translation(&self) -> V {
-        self.disp.clone()
-    }
-
-    fn to_rotation(&self) -> R {
-        self.rot.clone()
-    }
-
-    fn to_scale(&self) -> V {
-        Vector::from_value(self.scale)
+> ToComponents<S, V, P, R> for Decomposed<S, V, R> {
+    fn decompose(&self) -> (V, R, V) {
+        (Vector::from_value(self.scale), self.rot.clone(), self.disp.clone())
     }
 }
 
 impl<
     S: BaseFloat,
-    R: Rotation<S, Vector3<S>, Point3<S>> + Clone + ToMatrix3<S>,
-> ToComponents3<S> for Decomposed<S, Vector3<S>, R> {}
+    R: Rotation2<S> + Clone,
+> ToComponents2<S, R> for Decomposed<S, Vector2<S>, R> {}
+
+impl<
+    S: BaseFloat,
+    R: Rotation3<S> + Clone,
+> ToComponents3<S, R> for Decomposed<S, Vector3<S>, R> {}
 
 impl<
     S: BaseFloat + 'static,
-> ToComponents<S, Vector3<S>, Point3<S>> for AffineMatrix3<S> {
-    type Rotation = Quaternion<S>;
-
-    fn to_translation(&self) -> Vector3<S> {
-        Vector3::new(self.mat.w.x, self.mat.w.y, self.mat.w.z)
-    }
-
-    fn to_rotation(&self) -> Quaternion<S> {
-        Matrix3::new(
-            self.mat.x.x, self.mat.x.y, self.mat.x.z,
-            self.mat.y.x, self.mat.y.y, self.mat.y.z,
-            self.mat.z.x, self.mat.z.y, self.mat.z.z,
-        ).to_quaternion()
-    }
-
-    fn to_scale(&self) -> Vector3<S> {
-        Vector3::new(self.mat.x.x, self.mat.y.y, self.mat.z.z)
-    }
-}
+    R: Rotation2<S> + Clone,
+> CompositeTransform2<S, R> for Decomposed<S, Vector2<S>, R> {}
 
 impl<
     S: BaseFloat + 'static,
-> ToComponents3<S> for AffineMatrix3<S> {}
+    R: Rotation3<S> + Clone,
+> CompositeTransform3<S, R> for Decomposed<S, Vector3<S>, R> {}
diff --git a/tests/transform.rs b/tests/transform.rs
index 3ec7b1a..64683e2 100644
--- a/tests/transform.rs
+++ b/tests/transform.rs
@@ -20,11 +20,11 @@ use cgmath::*;
 
 #[test]
 fn test_invert() {
-	let v = Vector3::new(1.0f64, 2.0f64, 3.0f64);
+	let v = Vector3::new(1.0f64, 2.0, 3.0);
 	let t = Decomposed {
         scale: 1.5f64,
         rot: Quaternion::new(0.5f64,0.5,0.5,0.5),
-        disp: Vector3::new(6.0f64,-7.0f64,8.0)
+        disp: Vector3::new(6.0f64,-7.0,8.0)
     };
 	let ti = t.invert().expect("Expected successful inversion");
 	let vt = t.transform_vector( &v );
@@ -33,12 +33,12 @@ fn test_invert() {
 
 #[test]
 fn test_look_at() {
-	let eye = Point3::new(0.0f64, 0.0f64, -5.0f64);
-	let center = Point3::new(0.0f64, 0.0f64, 0.0f64);
-	let up = Vector3::new(1.0f64, 0.0f64, 0.0f64);
+	let eye = Point3::new(0.0f64, 0.0, -5.0);
+	let center = Point3::new(0.0f64, 0.0, 0.0);
+	let up = Vector3::new(1.0f64, 0.0, 0.0);
 	let t: Decomposed<f64,Vector3<f64>,Quaternion<f64>> = Transform::look_at(&eye, &center, &up);
-	let point = Point3::new(1.0f64, 0.0f64, 0.0f64);
-	let view_point = Point3::new(0.0f64, 1.0f64, 5.0f64);
+	let point = Point3::new(1.0f64, 0.0, 0.0);
+	let view_point = Point3::new(0.0f64, 1.0, 5.0);
 	assert!( t.transform_point(&point).approx_eq(&view_point) );
 }
 
@@ -47,9 +47,10 @@ fn test_components() {
 	let t = Decomposed {
         scale: 1.5f64,
         rot: Quaternion::new(0.5f64,0.5,0.5,0.5),
-        disp: Vector3::new(6.0f64,-7.0f64,8.0)
+        disp: Vector3::new(6.0f64,-7.0,8.0)
     };
-    assert_eq!(t.to_translation(), t.disp);
-    assert_eq!(t.to_rotation(), t.rot);
-    assert_eq!(t.to_scale(), Vector::from_value(t.scale));
+    let (scale, rot, disp) = t.decompose();
+    assert_eq!(scale, Vector::from_value(t.scale));
+    assert_eq!(rot, t.rot);
+    assert_eq!(disp, t.disp);
 }