diff --git a/src/structs/quaternion.rs b/src/structs/quaternion.rs index d785321a..aa127402 100644 --- a/src/structs/quaternion.rs +++ b/src/structs/quaternion.rs @@ -568,6 +568,49 @@ impl Arbitrary for UnitQuaternion { } } +impl Quaternion { + /// Compute the exponential of a quaternion. + pub fn exp(&self) -> Self { + let v = *self.vector(); + let nn = v.norm_squared(); + + if nn.is_zero() { + ::one() + } else { + let n = nn.sqrt(); + let nv = v / n * n.sin(); + Quaternion::new(n.cos(), nv.x, nv.y, nv.z) + } + } + + /// Compute the natural logarithm (a.k.a ln()) of a quaternion. + /// + /// Becareful, this function yields a `Quaternion`, losing the unit property. + pub fn log(&self) -> Self { + (Quaternion { w: 0., .. *self }).normalize() * self.w.acos() + } + + /// Raise the quaternion to a given floating power. + pub fn powf(&self, n: f32) -> Self { + (self.log() * n).exp() + } +} + +impl Zero for Quaternion where T: Zero { + fn zero() -> Self { + Quaternion::new(::zero(), ::zero(), ::zero(), ::zero()) + } + + fn is_zero(&self) -> bool { + self.w.is_zero() && self.i.is_zero() && self.j.is_zero() && self.k.is_zero() + } +} + +impl One for Quaternion where T: Copy + One + Zero + Sub + Add { + fn one() -> Self { + Quaternion::new(T::one(), T::zero(), T::zero(), T::zero()) + } +} pord_impl!(Quaternion, w, i, j, k); vec_axis_impl!(Quaternion, w, i, j, k); @@ -586,7 +629,6 @@ scalar_sub_impl!(Quaternion, w, i, j, k); scalar_mul_impl!(Quaternion, w, i, j, k); scalar_div_impl!(Quaternion, w, i, j, k); neg_impl!(Quaternion, w, i, j, k); -zero_one_impl!(Quaternion, w, i, j, k); approx_eq_impl!(Quaternion, w, i, j, k); from_iterator_impl!(Quaternion, iterator, iterator, iterator, iterator); bounded_impl!(Quaternion, w, i, j, k); diff --git a/tests/quat.rs b/tests/quat.rs index 251fabfc..1b0185eb 100644 --- a/tests/quat.rs +++ b/tests/quat.rs @@ -1,7 +1,7 @@ extern crate nalgebra as na; extern crate rand; -use na::{Point3, Vector3, Rotation3, UnitQuaternion, Rotation}; +use na::{Point3, Quaternion, Vector3, Rotation3, UnitQuaternion, Rotation, one}; use rand::random; #[test] @@ -90,3 +90,21 @@ fn test_quaternion_angle_between() { assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle)) } + +#[test] +fn test_quaternion_exp_zero_is_one() { + let q = Quaternion::new(0., 0., 0., 0.); + assert!(na::approx_eq(&q.exp(), &one())) +} + +#[test] +fn test_quaternion_neutral() { + for _ in 0 .. 10000 { + let q1: Quaternion = random(); + let qi: Quaternion = one(); + let q2 = q1 * qi; + let q3 = qi * q1; + + assert!(na::approx_eq(&q1, &q2) && na::approx_eq(&q2, &q3)) + } +}