Add .axis_angle to UnitComplex and UnitQuaternion + .rotation_between_axis to UnitComplex.
This commit is contained in:
parent
e7c0e95d3f
commit
1ac8bbd3d1
|
@ -7,3 +7,4 @@ target/
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
*.orig
|
*.orig
|
||||||
*.swo
|
*.swo
|
||||||
|
site/
|
|
@ -4,6 +4,14 @@ documented here.
|
||||||
|
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [0.15.0] - WIP
|
||||||
|
### Modified
|
||||||
|
### Added
|
||||||
|
* Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex`
|
||||||
|
to compute the rotation matrix between two 2D **unit** vectors.
|
||||||
|
* Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the
|
||||||
|
unit rotation axis and the rotation angle simultaneously.
|
||||||
|
|
||||||
## [0.14.0]
|
## [0.14.0]
|
||||||
### Modified
|
### Modified
|
||||||
* Allow the `Isometry * Unit<Vector>` multiplication.
|
* Allow the `Isometry * Unit<Vector>` multiplication.
|
||||||
|
|
|
@ -462,8 +462,7 @@ where
|
||||||
let (nrows3, ncols3) = b.shape();
|
let (nrows3, ncols3) = b.shape();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ncols2,
|
ncols2, nrows3,
|
||||||
nrows3,
|
|
||||||
"gemm: dimensions mismatch for multiplication."
|
"gemm: dimensions mismatch for multiplication."
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -564,8 +563,7 @@ where
|
||||||
let (nrows3, ncols3) = b.shape();
|
let (nrows3, ncols3) = b.shape();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nrows2,
|
nrows2, nrows3,
|
||||||
nrows3,
|
|
||||||
"gemm: dimensions mismatch for multiplication."
|
"gemm: dimensions mismatch for multiplication."
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -491,6 +491,18 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The rotation axis and angle in ]0, pi] of this unit quaternion.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the angle is zero.
|
||||||
|
#[inline]
|
||||||
|
pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> {
|
||||||
|
if let Some(axis) = self.axis() {
|
||||||
|
Some((axis, self.angle()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the exponential of a quaternion.
|
/// Compute the exponential of a quaternion.
|
||||||
///
|
///
|
||||||
/// Note that this function yields a `Quaternion<N>` because it looses the unit property.
|
/// Note that this function yields a `Quaternion<N>` because it looses the unit property.
|
||||||
|
|
|
@ -34,6 +34,22 @@ impl<N: Real> UnitComplex<N> {
|
||||||
Vector1::new(self.angle())
|
Vector1::new(self.angle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The rotation axis and angle in ]0, pi] of this complex number.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the angle is zero.
|
||||||
|
#[inline]
|
||||||
|
pub fn axis_angle(&self) -> Option<(Unit<Vector1<N>>, N)> {
|
||||||
|
let ang = self.angle();
|
||||||
|
|
||||||
|
if ang.is_zero() {
|
||||||
|
None
|
||||||
|
} else if ang.is_sign_negative() {
|
||||||
|
Some((Unit::new_unchecked(Vector1::x()), -ang))
|
||||||
|
} else {
|
||||||
|
Some((Unit::new_unchecked(-Vector1::<N>::x()), ang))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The underlying complex number.
|
/// The underlying complex number.
|
||||||
///
|
///
|
||||||
/// Same as `self.as_ref()`.
|
/// Same as `self.as_ref()`.
|
||||||
|
|
|
@ -6,7 +6,7 @@ use num_complex::Complex;
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
use core::{DefaultAllocator, Vector};
|
use core::{DefaultAllocator, Unit, Vector};
|
||||||
use core::dimension::{U1, U2};
|
use core::dimension::{U1, U2};
|
||||||
use core::storage::Storage;
|
use core::storage::Storage;
|
||||||
use core::allocator::Allocator;
|
use core::allocator::Allocator;
|
||||||
|
@ -99,15 +99,48 @@ impl<N: Real> UnitComplex<N> {
|
||||||
SB: Storage<N, U2, U1>,
|
SB: Storage<N, U2, U1>,
|
||||||
SC: Storage<N, U2, U1>,
|
SC: Storage<N, U2, U1>,
|
||||||
{
|
{
|
||||||
if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) {
|
// FIXME: code duplication with Rotation.
|
||||||
let sang = na.perp(&nb);
|
if let (Some(na), Some(nb)) = (
|
||||||
let cang = na.dot(&nb);
|
Unit::try_new(a.clone_owned(), N::zero()),
|
||||||
|
Unit::try_new(b.clone_owned(), N::zero()),
|
||||||
Self::from_angle(sang.atan2(cang) * s)
|
) {
|
||||||
|
Self::scaled_rotation_between_axis(&na, &nb, s)
|
||||||
} else {
|
} else {
|
||||||
Self::identity()
|
Self::identity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The unit complex 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, U2, SB>>,
|
||||||
|
b: &Unit<Vector<N, U2, SC>>,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
SB: Storage<N, U2>,
|
||||||
|
SC: Storage<N, U2>,
|
||||||
|
{
|
||||||
|
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, U2, SB>>,
|
||||||
|
nb: &Unit<Vector<N, U2, SC>>,
|
||||||
|
s: N,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
SB: Storage<N, U2>,
|
||||||
|
SC: Storage<N, U2>,
|
||||||
|
{
|
||||||
|
let sang = na.perp(&nb);
|
||||||
|
let cang = na.dot(&nb);
|
||||||
|
|
||||||
|
Self::from_angle(sang.atan2(cang) * s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real> One for UnitComplex<N> {
|
impl<N: Real> One for UnitComplex<N> {
|
||||||
|
|
Loading…
Reference in New Issue