Add rotation_between_axis/scaled_rotation_between_axis.
This commit is contained in:
parent
dc41b55e5a
commit
52598de44c
|
@ -12,6 +12,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
`::from_element(...)`.
|
`::from_element(...)`.
|
||||||
* The `.iamin()` methods that returns the index of the vector entry with
|
* The `.iamin()` methods that returns the index of the vector entry with
|
||||||
smallest absolute value.
|
smallest absolute value.
|
||||||
|
* `UnitQuaternion::scaled_rotation_between_axis` and
|
||||||
|
`UnitQuaternion::rotation_between_axis` that take Unit vectors instead of
|
||||||
|
Vector as arguments.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -207,25 +207,63 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
where SB: Storage<N, U3>,
|
where SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3> {
|
SC: Storage<N, U3> {
|
||||||
// FIXME: code duplication with Rotation.
|
// FIXME: code duplication with Rotation.
|
||||||
if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) {
|
if let (Some(na), Some(nb)) = (Unit::try_new(a.clone_owned(), N::zero()),
|
||||||
|
Unit::try_new(b.clone_owned(), N::zero())) {
|
||||||
|
Self::scaled_rotation_between_axis(&na, &nb, s)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Self::identity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The unit quaternion needed to make `a` and `b` be collinear and point toward the same
|
||||||
|
/// direction.
|
||||||
|
#[inline]
|
||||||
|
pub fn rotation_between_axis<SB, SC>(a: &Unit<Vector<N, U3, SB>>, b: &Unit<Vector<N, U3, SC>>) -> Option<Self>
|
||||||
|
where SB: Storage<N, U3>,
|
||||||
|
SC: Storage<N, U3> {
|
||||||
|
Self::scaled_rotation_between_axis(a, b, N::one())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same
|
||||||
|
/// direction, raised to the power `s`.
|
||||||
|
#[inline]
|
||||||
|
pub fn scaled_rotation_between_axis<SB, SC>(na: &Unit<Vector<N, U3, SB>>,
|
||||||
|
nb: &Unit<Vector<N, U3, SC>>,
|
||||||
|
s: N)
|
||||||
|
-> Option<Self>
|
||||||
|
where SB: Storage<N, U3>,
|
||||||
|
SC: Storage<N, U3> {
|
||||||
|
|
||||||
|
// FIXME: code duplication with Rotation.
|
||||||
let c = na.cross(&nb);
|
let c = na.cross(&nb);
|
||||||
|
|
||||||
if let Some(axis) = Unit::try_new(c, N::default_epsilon()) {
|
if let Some(axis) = Unit::try_new(c, N::default_epsilon()) {
|
||||||
return Some(Self::from_axis_angle(&axis, na.dot(&nb).acos() * s))
|
let cos = na.dot(&nb);
|
||||||
}
|
|
||||||
|
|
||||||
// Zero or PI.
|
// The cosinus may be out of [-1, 1] because of innacuracies.
|
||||||
if na.dot(&nb) < N::zero() {
|
if cos <= -N::one() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
else if cos >= N::one() {
|
||||||
|
return Some(Self::identity())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Some(Self::from_axis_angle(&axis, cos.acos() * s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if na.dot(&nb) < N::zero() {
|
||||||
// PI
|
// PI
|
||||||
//
|
//
|
||||||
// The rotation axis is undefined but the angle not zero. This is not a
|
// The rotation axis is undefined but the angle not zero. This is not a
|
||||||
// simple rotation.
|
// simple rotation.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
// Zero
|
||||||
Some(Self::identity())
|
Some(Self::identity())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Creates an unit quaternion that corresponds to the local frame of an observer standing at the
|
/// Creates an unit quaternion that corresponds to the local frame of an observer standing at the
|
||||||
|
|
Loading…
Reference in New Issue