diff --git a/src/transform.rs b/src/transform.rs index f995cc7..5397c03 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -37,6 +37,11 @@ pub trait Transform: Sized { /// Transform a vector using this transform. fn transform_vector(&self, vec: P::Diff) -> P::Diff; + /// Inverse transform a vector using this transform + fn inverse_transform_vector(&self, vec: P::Diff) -> Option { + self.inverse_transform().and_then(|inverse| Some(inverse.transform_vector(vec))) + } + /// Transform a point using this transform. fn transform_point(&self, point: P) -> P; @@ -93,6 +98,15 @@ impl> Transform

for Decomposed self.rot.rotate_vector(vec * self.scale) } + #[inline] + fn inverse_transform_vector(&self, vec: P::Diff) -> Option { + if ulps_eq!(self.scale, &P::Scalar::zero()) { + None + } else { + Some(self.rot.invert().rotate_vector(vec / self.scale)) + } + } + #[inline] fn transform_point(&self, point: P) -> P { self.rot.rotate_point(point * self.scale) + self.disp diff --git a/tests/transform.rs b/tests/transform.rs index b1362a3..3cd2753 100644 --- a/tests/transform.rs +++ b/tests/transform.rs @@ -35,6 +35,18 @@ fn test_invert() { assert_ulps_eq!(&v, &ti.transform_vector(vt)); } +#[test] +fn test_inverse_vector() { + 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.0, 8.0), + }; + let vt = t.inverse_transform_vector(v).expect("Expected successful inversion"); + assert_ulps_eq!(v, t.transform_vector(vt)); +} + #[test] fn test_look_at() { let eye = Point3::new(0.0f64, 0.0, -5.0);