2016-12-05 05:44:42 +08:00
|
|
|
|
#[cfg(feature = "arbitrary")]
|
|
|
|
|
use quickcheck::{Arbitrary, Gen};
|
2017-08-03 01:37:44 +08:00
|
|
|
|
#[cfg(feature = "arbitrary")]
|
2018-05-19 23:15:15 +08:00
|
|
|
|
use base::storage::Owned;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
use std::ops::Neg;
|
|
|
|
|
use num::Zero;
|
|
|
|
|
use rand::{Rand, Rng};
|
|
|
|
|
use alga::general::Real;
|
|
|
|
|
|
2018-05-19 23:15:15 +08:00
|
|
|
|
use base::{MatrixN, Unit, Vector, Vector1, Vector3, VectorN};
|
|
|
|
|
use base::dimension::{U1, U2, U3};
|
|
|
|
|
use base::storage::Storage;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
use geometry::{Rotation2, Rotation3, UnitComplex};
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*
|
2017-08-03 01:37:44 +08:00
|
|
|
|
* 2D Rotation matrix.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
*
|
|
|
|
|
*/
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real> Rotation2<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Builds a 2 dimensional rotation matrix from an angle in radian.
|
|
|
|
|
pub fn new(angle: N) -> Self {
|
|
|
|
|
let (sia, coa) = angle.sin_cos();
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
|
|
|
|
|
///
|
|
|
|
|
/// Equivalent to `Self::new(axisangle[0])`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Self::new(axisangle[0])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation matrix required to align `a` and `b` but with its angl.
|
|
|
|
|
///
|
|
|
|
|
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U2>,
|
|
|
|
|
SC: Storage<N, U2>,
|
|
|
|
|
{
|
2017-02-13 01:17:09 +08:00
|
|
|
|
::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix())
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same
|
|
|
|
|
/// direction, raised to the power `s`.
|
|
|
|
|
#[inline]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
pub fn scaled_rotation_between<SB, SC>(
|
|
|
|
|
a: &Vector<N, U2, SB>,
|
|
|
|
|
b: &Vector<N, U2, SC>,
|
|
|
|
|
s: N,
|
|
|
|
|
) -> Self
|
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U2>,
|
|
|
|
|
SC: Storage<N, U2>,
|
|
|
|
|
{
|
2017-02-13 01:17:09 +08:00
|
|
|
|
::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix())
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real> Rotation2<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// The rotation angle.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn angle(&self) -> N {
|
|
|
|
|
self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation angle needed to make `self` and `other` coincide.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn angle_to(&self, other: &Rotation2<N>) -> N {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.rotation_to(other).angle()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation matrix needed to make `self` and `other` coincide.
|
|
|
|
|
///
|
|
|
|
|
/// The result is such that: `self.rotation_to(other) * self == other`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
other * self.inverse()
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle
|
|
|
|
|
/// of `self` multiplied by `n`.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn powf(&self, n: N) -> Rotation2<N> {
|
|
|
|
|
Self::new(self.angle() * n)
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation angle returned as a 1-dimensional vector.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn scaled_axis(&self) -> VectorN<N, U1> {
|
2018-02-02 19:26:04 +08:00
|
|
|
|
Vector1::new(self.angle())
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real + Rand> Rand for Rotation2<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
fn rand<R: Rng>(rng: &mut R) -> Self {
|
|
|
|
|
Self::new(rng.gen())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
#[cfg(feature = "arbitrary")]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real + Arbitrary> Arbitrary for Rotation2<N>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
Owned<N, U2, U2>: Send,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
|
|
|
|
Self::new(N::arbitrary(g))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*
|
2017-08-03 01:37:44 +08:00
|
|
|
|
* 3D Rotation matrix.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
*
|
|
|
|
|
*/
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real> Rotation3<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Builds a 3 dimensional rotation matrix from an axis and an angle.
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
|
|
|
|
|
/// in radian. Its direction is the axis of rotation.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
|
|
|
|
|
let axisangle = axisangle.into_owned();
|
|
|
|
|
let (axis, angle) = Unit::new_and_get(axisangle);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Self::from_axis_angle(&axis, angle)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Self::new(axisangle)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a 3D rotation matrix from an axis and a rotation angle.
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
if angle.is_zero() {
|
|
|
|
|
Self::identity()
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
|
|
|
|
let ux = axis.as_ref()[0];
|
|
|
|
|
let uy = axis.as_ref()[1];
|
|
|
|
|
let uz = axis.as_ref()[2];
|
|
|
|
|
let sqx = ux * ux;
|
|
|
|
|
let sqy = uy * uy;
|
|
|
|
|
let sqz = uz * uz;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let (sin, cos) = angle.sin_cos();
|
2018-02-02 19:26:35 +08:00
|
|
|
|
let one_m_cos = N::one() - cos;
|
|
|
|
|
|
|
|
|
|
Self::from_matrix_unchecked(MatrixN::<N, U3>::new(
|
2018-02-02 19:26:37 +08:00
|
|
|
|
sqx + (N::one() - sqx) * cos,
|
|
|
|
|
ux * uy * one_m_cos - uz * sin,
|
|
|
|
|
ux * uz * one_m_cos + uy * sin,
|
|
|
|
|
ux * uy * one_m_cos + uz * sin,
|
|
|
|
|
sqy + (N::one() - sqy) * cos,
|
|
|
|
|
uy * uz * one_m_cos - ux * sin,
|
|
|
|
|
ux * uz * one_m_cos - uy * sin,
|
|
|
|
|
uy * uz * one_m_cos + ux * sin,
|
|
|
|
|
sqz + (N::one() - sqz) * cos,
|
2018-02-02 19:26:35 +08:00
|
|
|
|
))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Creates a new rotation from Euler angles.
|
|
|
|
|
///
|
|
|
|
|
/// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw.
|
|
|
|
|
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
|
|
|
|
|
let (sr, cr) = roll.sin_cos();
|
|
|
|
|
let (sp, cp) = pitch.sin_cos();
|
|
|
|
|
let (sy, cy) = yaw.sin_cos();
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
Self::from_matrix_unchecked(MatrixN::<N, U3>::new(
|
|
|
|
|
cy * cp,
|
|
|
|
|
cy * sp * sr - sy * cr,
|
|
|
|
|
cy * sp * cr + sy * sr,
|
|
|
|
|
sy * cp,
|
|
|
|
|
sy * sp * sr + cy * cr,
|
|
|
|
|
sy * sp * cr - cy * sr,
|
|
|
|
|
-sp,
|
|
|
|
|
cp * sr,
|
|
|
|
|
cp * cr,
|
|
|
|
|
))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-10 04:15:57 +08:00
|
|
|
|
/// Creates Euler angles from a rotation.
|
|
|
|
|
///
|
|
|
|
|
/// The angles are produced in the form (roll, yaw, pitch).
|
|
|
|
|
pub fn to_euler_angles(&self) -> (N, N, N) {
|
|
|
|
|
// Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh
|
|
|
|
|
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
|
|
|
|
|
if self[(2,0)].abs() != N::one() {
|
|
|
|
|
let yaw = -self[(2,0)].asin();
|
|
|
|
|
let roll = (self[(2,1)] / yaw.cos()).atan2(self[(2,2)] / yaw.cos());
|
|
|
|
|
let pitch = (self[(1,0)] / yaw.cos()).atan2(self[(0,0)] / yaw.cos());
|
|
|
|
|
(roll, yaw, pitch)
|
|
|
|
|
} else if self[(2,0)] == -N::one() {
|
|
|
|
|
(self[(0,1)].atan2(self[(0,2)]), N::frac_pi_2(), N::zero())
|
|
|
|
|
} else {
|
|
|
|
|
(-self[(0,1)].atan2(-self[(0,2)]), -N::frac_pi_2(), N::zero())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 05:44:42 +08:00
|
|
|
|
/// Creates a rotation that corresponds to the local frame of an observer standing at the
|
|
|
|
|
/// origin and looking toward `dir`.
|
|
|
|
|
///
|
|
|
|
|
/// It maps the view direction `dir` to the positive `z` axis.
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with.
|
|
|
|
|
/// * up - The vertical direction. The only requirement of this parameter is to not be
|
|
|
|
|
/// collinear
|
|
|
|
|
/// to `dir`. Non-collinearity is not checked.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
SC: Storage<N, U3>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
let zaxis = dir.normalize();
|
|
|
|
|
let xaxis = up.cross(&zaxis).normalize();
|
|
|
|
|
let yaxis = zaxis.cross(&xaxis).normalize();
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::from_matrix_unchecked(MatrixN::<N, U3>::new(
|
2018-02-02 19:26:35 +08:00
|
|
|
|
xaxis.x,
|
|
|
|
|
yaxis.x,
|
|
|
|
|
zaxis.x,
|
|
|
|
|
xaxis.y,
|
|
|
|
|
yaxis.y,
|
|
|
|
|
zaxis.y,
|
|
|
|
|
xaxis.z,
|
|
|
|
|
yaxis.z,
|
|
|
|
|
zaxis.z,
|
|
|
|
|
))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a right-handed look-at view matrix without translation.
|
|
|
|
|
///
|
|
|
|
|
/// This conforms to the common notion of right handed look-at matrix from the computer
|
|
|
|
|
/// graphics community.
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * eye - The eye position.
|
|
|
|
|
/// * target - The target position.
|
|
|
|
|
/// * up - A vector approximately aligned with required the vertical axis. The only
|
|
|
|
|
/// requirement of this parameter is to not be collinear to `target - eye`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
SC: Storage<N, U3>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Self::new_observer_frame(&dir.neg(), up).inverse()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builds a left-handed look-at view matrix without translation.
|
|
|
|
|
///
|
|
|
|
|
/// This conforms to the common notion of left handed look-at matrix from the computer
|
|
|
|
|
/// graphics community.
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * eye - The eye position.
|
|
|
|
|
/// * target - The target position.
|
|
|
|
|
/// * up - A vector approximately aligned with required the vertical axis. The only
|
|
|
|
|
/// requirement of this parameter is to not be collinear to `target - eye`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
SC: Storage<N, U3>,
|
|
|
|
|
{
|
|
|
|
|
Self::new_observer_frame(dir, up).inverse()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation matrix required to align `a` and `b` but with its angl.
|
|
|
|
|
///
|
|
|
|
|
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
SC: Storage<N, U3>,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
Self::scaled_rotation_between(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]
|
2018-02-02 19:26:35 +08:00
|
|
|
|
pub fn scaled_rotation_between<SB, SC>(
|
|
|
|
|
a: &Vector<N, U3, SB>,
|
|
|
|
|
b: &Vector<N, U3, SC>,
|
|
|
|
|
n: N,
|
|
|
|
|
) -> Option<Self>
|
|
|
|
|
where
|
|
|
|
|
SB: Storage<N, U3>,
|
|
|
|
|
SC: Storage<N, U3>,
|
|
|
|
|
{
|
2017-08-03 01:37:44 +08:00
|
|
|
|
// FIXME: code duplication with Rotation.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) {
|
|
|
|
|
let c = na.cross(&nb);
|
|
|
|
|
|
|
|
|
|
if let Some(axis) = Unit::try_new(c, N::default_epsilon()) {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
return Some(Self::from_axis_angle(&axis, na.dot(&nb).acos() * n));
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zero or PI.
|
|
|
|
|
if na.dot(&nb) < N::zero() {
|
|
|
|
|
// PI
|
|
|
|
|
//
|
|
|
|
|
// The rotation axis is undefined but the angle not zero. This is not a
|
|
|
|
|
// simple rotation.
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Some(Self::identity())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation angle.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn angle(&self) -> N {
|
2018-02-02 19:26:35 +08:00
|
|
|
|
((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one())
|
|
|
|
|
/ ::convert(2.0))
|
|
|
|
|
.acos()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation axis. Returns `None` if the rotation angle is zero or PI.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
|
|
|
|
|
let axis = VectorN::<N, U3>::new(
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.matrix()[(2, 1)] - self.matrix()[(1, 2)],
|
|
|
|
|
self.matrix()[(0, 2)] - self.matrix()[(2, 0)],
|
2018-02-02 19:26:35 +08:00
|
|
|
|
self.matrix()[(1, 0)] - self.matrix()[(0, 1)],
|
|
|
|
|
);
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
Unit::try_new(axis, N::default_epsilon())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation axis multiplied by the rotation angle.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn scaled_axis(&self) -> Vector3<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
if let Some(axis) = self.axis() {
|
|
|
|
|
axis.unwrap() * self.angle()
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Vector::zero()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation angle needed to make `self` and `other` coincide.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn angle_to(&self, other: &Rotation3<N>) -> N {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
self.rotation_to(other).angle()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation matrix needed to make `self` and `other` coincide.
|
|
|
|
|
///
|
|
|
|
|
/// The result is such that: `self.rotation_to(other) * self == other`.
|
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
other * self.inverse()
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-13 01:17:09 +08:00
|
|
|
|
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the same
|
|
|
|
|
/// axis as `self` and an angle equal to `self.angle()` multiplied by `n`.
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
pub fn powf(&self, n: N) -> Rotation3<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
if let Some(axis) = self.axis() {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::from_axis_angle(&axis, self.angle() * n)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else if self.matrix()[(0, 0)] < N::zero() {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
let minus_id = MatrixN::<N, U3>::from_diagonal_element(-N::one());
|
|
|
|
|
Self::from_matrix_unchecked(minus_id)
|
2018-02-02 19:26:35 +08:00
|
|
|
|
} else {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::identity()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real + Rand> Rand for Rotation3<N> {
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
fn rand<R: Rng>(rng: &mut R) -> Self {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::new(VectorN::rand(rng))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-02 19:26:35 +08:00
|
|
|
|
#[cfg(feature = "arbitrary")]
|
2017-08-03 01:37:44 +08:00
|
|
|
|
impl<N: Real + Arbitrary> Arbitrary for Rotation3<N>
|
2018-02-02 19:26:35 +08:00
|
|
|
|
where
|
|
|
|
|
Owned<N, U3, U3>: Send,
|
|
|
|
|
Owned<N, U3>: Send,
|
|
|
|
|
{
|
2016-12-05 05:44:42 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
2017-08-03 01:37:44 +08:00
|
|
|
|
Self::new(VectorN::arbitrary(g))
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|