Merge pull request #400 from andystanton/fix_between_vectors_for_opposite_vectors
Fix between_vectors for opposite vectors
This commit is contained in:
commit
613d2b7f23
2 changed files with 76 additions and 3 deletions
|
@ -624,9 +624,28 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
|
|||
|
||||
#[inline]
|
||||
fn between_vectors(a: Vector3<S>, b: Vector3<S>) -> Quaternion<S> {
|
||||
//http://stackoverflow.com/questions/1171849/
|
||||
//finding-quaternion-representing-the-rotation-from-one-vector-to-another
|
||||
Quaternion::from_sv(S::one() + a.dot(b), a.cross(b)).normalize()
|
||||
// http://stackoverflow.com/a/11741520/2074937 see 'Half-Way Quaternion Solution'
|
||||
|
||||
let k_cos_theta = a.dot(b);
|
||||
|
||||
// same direction
|
||||
if ulps_eq!(k_cos_theta, S::one()) {
|
||||
return Quaternion::one();
|
||||
}
|
||||
|
||||
let k = (a.magnitude2() * b.magnitude2()).sqrt();
|
||||
|
||||
// opposite direction
|
||||
if ulps_eq!(k_cos_theta / k, -S::one()) {
|
||||
let mut orthogonal = a.cross(Vector3::unit_x());
|
||||
if ulps_eq!(orthogonal.magnitude2(), S::zero()) {
|
||||
orthogonal = a.cross(Vector3::unit_y());
|
||||
}
|
||||
return Quaternion::from_sv(S::zero(), orthogonal.normalize());
|
||||
}
|
||||
|
||||
// any other direction
|
||||
Quaternion::from_sv(k + k_cos_theta, a.cross(b)).normalize()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -258,3 +258,57 @@ mod rotate_from_axis_angle {
|
|||
assert_ulps_eq!(vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), rot * vec);
|
||||
}
|
||||
}
|
||||
|
||||
mod rotate_between_vectors {
|
||||
use cgmath::*;
|
||||
|
||||
#[test]
|
||||
fn test_around_z_0() {
|
||||
let expected = Quaternion::new(1.0, 0.0, 0.0, 0.0);
|
||||
|
||||
let a = vec3(12.0, 0.0, 0.0);
|
||||
let b = vec3(1.0, 0.0, 0.0);
|
||||
|
||||
assert_ulps_eq!(Quaternion::between_vectors(a, b), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_around_z_90_cw() {
|
||||
let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, 0.5_f32.sqrt());
|
||||
|
||||
let a = vec3(8.0, 0.0, 0.0);
|
||||
let b = vec3(0.0, 9.0, 0.0);
|
||||
|
||||
assert_ulps_eq!(Quaternion::between_vectors(a, b), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_around_z_90_ccw() {
|
||||
let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, -0.5_f32.sqrt());
|
||||
|
||||
let a = vec3(-26.0, 0.0, 0.0);
|
||||
let b = vec3(0.0, 10.0, 0.0);
|
||||
|
||||
assert_ulps_eq!(Quaternion::between_vectors(a, b), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_around_z_180_cw() {
|
||||
let expected = Quaternion::new(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
let a = vec3(10.0, 0.0, 0.0);
|
||||
let b = vec3(-5.0, 0.0, 0.0);
|
||||
|
||||
assert_ulps_eq!(Quaternion::between_vectors(a, b), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_around_z_180_ccw() {
|
||||
let expected = Quaternion::new(0.0, 0.0, 0.0, -1.0);
|
||||
|
||||
let a = vec3(-3.0, 0.0, 0.0);
|
||||
let b = vec3(40.0, 0.0, 0.0);
|
||||
|
||||
assert_ulps_eq!(Quaternion::between_vectors(a, b), expected);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue