Add doc-tests to rotation_specialization.

This commit is contained in:
sebcrozet 2018-11-04 08:47:17 +01:00 committed by Sébastien Crozet
parent 80fc057ead
commit 536923f9fc
3 changed files with 355 additions and 19 deletions

View File

@ -980,7 +980,7 @@ impl<N: Real> UnitQuaternion<N> {
#[inline] #[inline]
#[deprecated(note = "This is renamed to use `.euler_angles()`.")] #[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (N, N, N) { pub fn to_euler_angles(&self) -> (N, N, N) {
self.to_rotation_matrix().to_euler_angles() self.euler_angles()
} }
/// Retrieves the euler angles corresponding to this unit quaternion. /// Retrieves the euler angles corresponding to this unit quaternion.
@ -1000,7 +1000,7 @@ impl<N: Real> UnitQuaternion<N> {
/// ``` /// ```
#[inline] #[inline]
pub fn euler_angles(&self) -> (N, N, N) { pub fn euler_angles(&self) -> (N, N, N) {
self.to_rotation_matrix().to_euler_angles() self.to_rotation_matrix().euler_angles()
} }
/// Converts this unit quaternion into its equivalent homogeneous transformation matrix. /// Converts this unit quaternion into its equivalent homogeneous transformation matrix.

View File

@ -196,6 +196,14 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new unit quaternion from a quaternion. /// Creates a new unit quaternion from a quaternion.
/// ///
/// The input quaternion will be normalized. /// The input quaternion will be normalized.
#[inline]
pub fn from_quaternion(q: Quaternion<N>) -> Self {
Self::new_normalize(q)
}
/// Creates a new unit quaternion from Euler angles.
///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw.
/// ///
/// # Example /// # Example
/// ``` /// ```
@ -209,14 +217,6 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn from_quaternion(q: Quaternion<N>) -> Self {
Self::new_normalize(q)
}
/// Creates a new unit quaternion from Euler angles.
///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw.
#[inline]
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos(); let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos();
let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos(); let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos();
@ -435,7 +435,7 @@ impl<N: Real> UnitQuaternion<N> {
/// 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
/// origin and looking toward `dir`. /// origin and looking toward `dir`.
/// ///
/// It maps the `z` axis to the view direction `dir`. /// It maps the `z` axis to the direction `dir`.
/// ///
/// # Arguments /// # Arguments
/// * dir - The look direction. It does not need to be normalized. /// * dir - The look direction. It does not need to be normalized.

View File

@ -22,6 +22,18 @@ use geometry::{Rotation2, Rotation3, UnitComplex};
*/ */
impl<N: Real> Rotation2<N> { impl<N: Real> Rotation2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian. /// Builds a 2 dimensional rotation matrix from an angle in radian.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation2, Vector2, Point2};
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
///
/// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
/// ```
pub fn new(angle: N) -> Self { pub fn new(angle: N) -> Self {
let (sia, coa) = angle.sin_cos(); let (sia, coa) = angle.sin_cos();
Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa)) Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa))
@ -29,7 +41,9 @@ impl<N: Real> Rotation2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
/// ///
/// Equivalent to `Self::new(axisangle[0])`. ///
/// This is generally used in the context of generic programming. Using
/// the `::new(angle)` method instead is more common.
#[inline] #[inline]
pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
Self::new(axisangle[0]) Self::new(axisangle[0])
@ -38,6 +52,18 @@ impl<N: Real> Rotation2<N> {
/// The rotation matrix required to align `a` and `b` but with its angle. /// The rotation matrix required to align `a` and `b` but with its angle.
/// ///
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
/// let rot = Rotation2::rotation_between(&a, &b);
/// assert_relative_eq!(rot * a, b);
/// assert_relative_eq!(rot.inverse() * b, a);
/// ```
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
where where
@ -49,6 +75,19 @@ impl<N: Real> Rotation2<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
/// let rot2 = Rotation2::scaled_rotation_between(&a, &b, 0.2);
/// let rot5 = Rotation2::scaled_rotation_between(&a, &b, 0.5);
/// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>( pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U2, SB>, a: &Vector<N, U2, SB>,
@ -65,12 +104,28 @@ impl<N: Real> Rotation2<N> {
impl<N: Real> Rotation2<N> { impl<N: Real> Rotation2<N> {
/// The rotation angle. /// The rotation angle.
///
/// # Example
/// ```
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(1.78);
/// assert_eq!(rot.angle(), 1.78);
/// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)]) self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)])
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation2<N>) -> N { pub fn angle_to(&self, other: &Rotation2<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
@ -79,6 +134,19 @@ impl<N: Real> Rotation2<N> {
/// The rotation matrix needed to make `self` and `other` coincide. /// The rotation matrix needed to make `self` and `other` coincide.
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
/// let rot_to = rot1.rotation_to(&rot2);
///
/// assert_relative_eq!(rot_to * rot1, rot2);
/// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
/// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> { pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> {
other * self.inverse() other * self.inverse()
@ -86,12 +154,23 @@ impl<N: Real> Rotation2<N> {
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle
/// of `self` multiplied by `n`. /// of `self` multiplied by `n`.
///
/// # Example
/// ```
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(0.78);
/// let pow = rot.powf(2.0);
/// assert_eq!(pow.angle(), 1.56);
/// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation2<N> { pub fn powf(&self, n: N) -> Rotation2<N> {
Self::new(self.angle() * n) Self::new(self.angle() * n)
} }
/// The rotation angle returned as a 1-dimensional vector. /// The rotation angle returned as a 1-dimensional vector.
///
/// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common.
#[inline] #[inline]
pub fn scaled_axis(&self) -> VectorN<N, U1> { pub fn scaled_axis(&self) -> VectorN<N, U1> {
Vector1::new(self.angle()) Vector1::new(self.angle())
@ -129,6 +208,25 @@ impl<N: Real> Rotation3<N> {
/// # Arguments /// # Arguments
/// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
/// in radian. Its direction is the axis of rotation. /// in radian. Its direction is the axis of rotation.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::new(axisangle);
///
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::new(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self { pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
let axisangle = axisangle.into_owned(); let axisangle = axisangle.into_owned();
let (axis, angle) = Unit::new_and_get(axisangle); let (axis, angle) = Unit::new_and_get(axisangle);
@ -136,11 +234,54 @@ impl<N: Real> Rotation3<N> {
} }
/// Builds a 3D rotation matrix from an axis scaled by the rotation angle. /// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
///
/// This is the same as `Self::new(axisangle)`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::new(axisangle);
///
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
Self::new(axisangle) Self::new(axisangle)
} }
/// Builds a 3D rotation matrix from an axis and a rotation angle. /// Builds a 3D rotation matrix from an axis and a rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axis = Vector3::y_axis();
/// let angle = f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::from_axis_angle(&axis, angle);
///
/// assert_eq!(rot.axis().unwrap(), axis);
/// assert_eq!(rot.angle(), angle);
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
if angle.is_zero() { if angle.is_zero() {
@ -172,6 +313,18 @@ impl<N: Real> Rotation3<N> {
/// Creates a new rotation from Euler angles. /// Creates a new rotation from Euler angles.
/// ///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw. /// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
let (sr, cr) = roll.sin_cos(); let (sr, cr) = roll.sin_cos();
let (sp, cp) = pitch.sin_cos(); let (sp, cp) = pitch.sin_cos();
@ -192,8 +345,28 @@ impl<N: Real> Rotation3<N> {
/// Creates Euler angles from a rotation. /// Creates Euler angles from a rotation.
/// ///
/// The angles are produced in the form (roll, yaw, pitch). /// The angles are produced in the form (roll, pitch, yaw).
#[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (N, N, N) { pub fn to_euler_angles(&self) -> (N, N, N) {
self.euler_angles()
}
/// Euler angles corresponding to this rotation from a rotation.
///
/// The angles are produced in the form (roll, pitch, yaw).
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
pub fn euler_angles(&self) -> (N, N, N) {
// Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh // 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 // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
if self[(2, 0)].abs() != N::one() { if self[(2, 0)].abs() != N::one() {
@ -215,13 +388,25 @@ impl<N: Real> Rotation3<N> {
/// Creates a rotation that corresponds to the local frame of an observer standing at the /// Creates a rotation that corresponds to the local frame of an observer standing at the
/// origin and looking toward `dir`. /// origin and looking toward `dir`.
/// ///
/// It maps the view direction `dir` to the positive `z` axis. /// It maps the `z` axis to the direction `dir`.
/// ///
/// # Arguments /// # Arguments
/// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with. /// * 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 /// * up - The vertical direction. The only requirement of this parameter is to not be
/// collinear /// collinear to `dir`. Non-collinearity is not checked.
/// to `dir`. Non-collinearity is not checked. ///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::new_observer_frame(&dir, &up);
/// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
/// ```
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
@ -239,13 +424,27 @@ impl<N: Real> Rotation3<N> {
/// Builds a right-handed look-at view matrix without translation. /// Builds a right-handed look-at view matrix without translation.
/// ///
/// It maps the view direction `dir` to the **negative** `z` axis.
/// This conforms to the common notion of right handed look-at matrix from the computer /// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * dir - The direction toward which the camera looks. /// * dir - The direction toward which the camera looks.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `dir`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::look_at_rh(&dir, &up);
/// assert_relative_eq!(rot * dir.normalize(), -Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
@ -257,13 +456,27 @@ impl<N: Real> Rotation3<N> {
/// Builds a left-handed look-at view matrix without translation. /// Builds a left-handed look-at view matrix without translation.
/// ///
/// It maps the view direction `dir` to the **positive** `z` axis.
/// This conforms to the common notion of left handed look-at matrix from the computer /// This conforms to the common notion of left handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * dir - The direction toward which the camera looks. /// * dir - The direction toward which the camera looks.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `dir`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::look_at_lh(&dir, &up);
/// assert_relative_eq!(rot * dir.normalize(), Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
@ -276,6 +489,18 @@ impl<N: Real> Rotation3<N> {
/// The rotation matrix required to align `a` and `b` but with its angle. /// The rotation matrix required to align `a` and `b` but with its angle.
/// ///
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let rot = Rotation3::rotation_between(&a, &b).unwrap();
/// assert_relative_eq!(rot * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot.inverse() * b, a, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self> pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
where where
@ -287,6 +512,19 @@ impl<N: Real> Rotation3<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let rot2 = Rotation3::scaled_rotation_between(&a, &b, 0.2).unwrap();
/// let rot5 = Rotation3::scaled_rotation_between(&a, &b, 0.5).unwrap();
/// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>( pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U3, SB>, a: &Vector<N, U3, SB>,
@ -318,7 +556,17 @@ impl<N: Real> Rotation3<N> {
Some(Self::identity()) Some(Self::identity())
} }
/// The rotation angle. /// The rotation angle in [0; pi].
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Rotation3, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = Rotation3::from_axis_angle(&axis, 1.78);
/// assert_relative_eq!(rot.angle(), 1.78);
/// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one())
@ -327,6 +575,21 @@ impl<N: Real> Rotation3<N> {
} }
/// The rotation axis. Returns `None` if the rotation angle is zero or PI. /// The rotation axis. Returns `None` if the rotation angle is zero or PI.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// assert_relative_eq!(rot.axis().unwrap(), axis);
///
/// // Case with a zero angle.
/// let rot = Rotation3::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis().is_none());
/// ```
#[inline] #[inline]
pub fn axis(&self) -> Option<Unit<Vector3<N>>> { pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let axis = VectorN::<N, U3>::new( let axis = VectorN::<N, U3>::new(
@ -339,6 +602,16 @@ impl<N: Real> Rotation3<N> {
} }
/// The rotation axis multiplied by the rotation angle. /// The rotation axis multiplied by the rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = Rotation3::new(axisangle);
/// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_axis(&self) -> Vector3<N> { pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
@ -348,7 +621,46 @@ impl<N: Real> Rotation3<N> {
} }
} }
/// The rotation axis and angle in ]0, pi] of this unit quaternion.
///
/// Returns `None` if the angle is zero.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// let axis_angle = rot.axis_angle().unwrap();
/// assert_relative_eq!(axis_angle.0, axis);
/// assert_relative_eq!(axis_angle.1, angle);
///
/// // Case with a zero angle.
/// let rot = Rotation3::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis_angle().is_none());
/// ```
#[inline]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> {
if let Some(axis) = self.axis() {
Some((axis, self.angle()))
} else {
None
}
}
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation3<N>) -> N { pub fn angle_to(&self, other: &Rotation3<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
@ -357,6 +669,17 @@ impl<N: Real> Rotation3<N> {
/// The rotation matrix needed to make `self` and `other` coincide. /// The rotation matrix needed to make `self` and `other` coincide.
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
/// let rot_to = rot1.rotation_to(&rot2);
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> { pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> {
other * self.inverse() other * self.inverse()
@ -364,6 +687,19 @@ impl<N: Real> Rotation3<N> {
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the same /// 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`. /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// let pow = rot.powf(2.0);
/// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6);
/// assert_eq!(pow.angle(), 2.4);
/// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation3<N> { pub fn powf(&self, n: N) -> Rotation3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {