diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 10b973b4..fc82e061 100644 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -980,7 +980,7 @@ impl UnitQuaternion { #[inline] #[deprecated(note = "This is renamed to use `.euler_angles()`.")] 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. @@ -1000,7 +1000,7 @@ impl UnitQuaternion { /// ``` #[inline] 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. diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index e747cb59..65f206ef 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -196,6 +196,14 @@ impl UnitQuaternion { /// Creates a new unit quaternion from a quaternion. /// /// The input quaternion will be normalized. + #[inline] + pub fn from_quaternion(q: Quaternion) -> 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 /// ``` @@ -209,14 +217,6 @@ impl UnitQuaternion { /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// ``` #[inline] - pub fn from_quaternion(q: Quaternion) -> 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 { let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos(); let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos(); @@ -435,7 +435,7 @@ impl UnitQuaternion { /// Creates an unit quaternion that corresponds to the local frame of an observer standing at the /// 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 /// * dir - The look direction. It does not need to be normalized. diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index e4e97ac4..62227c1a 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -22,6 +22,18 @@ use geometry::{Rotation2, Rotation3, UnitComplex}; */ impl Rotation2 { /// 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 { let (sia, coa) = angle.sin_cos(); Self::from_matrix_unchecked(MatrixN::::new(coa, -sia, sia, coa)) @@ -29,7 +41,9 @@ impl Rotation2 { /// 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] pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::new(axisangle[0]) @@ -38,6 +52,18 @@ impl Rotation2 { /// 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()`. + /// + /// # 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] pub fn rotation_between(a: &Vector, b: &Vector) -> Self where @@ -49,6 +75,19 @@ impl Rotation2 { /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// 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] pub fn scaled_rotation_between( a: &Vector, @@ -65,12 +104,28 @@ impl Rotation2 { impl Rotation2 { /// The rotation angle. + /// + /// # Example + /// ``` + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::new(1.78); + /// assert_eq!(rot.angle(), 1.78); + /// ``` #[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. + /// + /// # 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] pub fn angle_to(&self, other: &Rotation2) -> N { self.rotation_to(other).angle() @@ -79,6 +134,19 @@ impl Rotation2 { /// The rotation matrix needed to make `self` and `other` coincide. /// /// 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] pub fn rotation_to(&self, other: &Rotation2) -> Rotation2 { other * self.inverse() @@ -86,12 +154,23 @@ impl Rotation2 { /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// 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] pub fn powf(&self, n: N) -> Rotation2 { Self::new(self.angle() * n) } /// 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] pub fn scaled_axis(&self) -> VectorN { Vector1::new(self.angle()) @@ -129,6 +208,25 @@ impl Rotation3 { /// # Arguments /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount 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::::zeros()), Rotation3::identity()); + /// ``` pub fn new>(axisangle: Vector) -> Self { let axisangle = axisangle.into_owned(); let (axis, angle) = Unit::new_and_get(axisangle); @@ -136,11 +234,54 @@ impl Rotation3 { } /// 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::::zeros()), Rotation3::identity()); + /// ``` pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::new(axisangle) } /// 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::::zeros()), Rotation3::identity()); + /// ``` pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self where SB: Storage { if angle.is_zero() { @@ -172,6 +313,18 @@ impl Rotation3 { /// Creates a new rotation from Euler angles. /// /// 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 { let (sr, cr) = roll.sin_cos(); let (sp, cp) = pitch.sin_cos(); @@ -192,8 +345,28 @@ impl Rotation3 { /// 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) { + 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 // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 if self[(2, 0)].abs() != N::one() { @@ -215,13 +388,25 @@ impl Rotation3 { /// 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. + /// It maps the `z` axis to the direction `dir`. /// /// # 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. + /// collinear 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] pub fn new_observer_frame(dir: &Vector, up: &Vector) -> Self where @@ -239,13 +424,27 @@ impl Rotation3 { /// 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 /// graphics community. /// /// # Arguments /// * dir - The direction toward which the camera looks. /// * 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] pub fn look_at_rh(dir: &Vector, up: &Vector) -> Self where @@ -257,13 +456,27 @@ impl Rotation3 { /// 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 /// graphics community. /// /// # Arguments /// * dir - The direction toward which the camera looks. /// * 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] pub fn look_at_lh(dir: &Vector, up: &Vector) -> Self where @@ -276,6 +489,18 @@ impl Rotation3 { /// 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()`. + /// + /// # 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] pub fn rotation_between(a: &Vector, b: &Vector) -> Option where @@ -287,6 +512,19 @@ impl Rotation3 { /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// 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] pub fn scaled_rotation_between( a: &Vector, @@ -318,7 +556,17 @@ impl Rotation3 { 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] pub fn angle(&self) -> N { ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) @@ -327,6 +575,21 @@ impl Rotation3 { } /// 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] pub fn axis(&self) -> Option>> { let axis = VectorN::::new( @@ -339,6 +602,16 @@ impl Rotation3 { } /// 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] pub fn scaled_axis(&self) -> Vector3 { if let Some(axis) = self.axis() { @@ -348,7 +621,46 @@ impl Rotation3 { } } + /// 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>, N)> { + if let Some(axis) = self.axis() { + Some((axis, self.angle())) + } else { + None + } + } + /// 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] pub fn angle_to(&self, other: &Rotation3) -> N { self.rotation_to(other).angle() @@ -357,6 +669,17 @@ impl Rotation3 { /// The rotation matrix needed to make `self` and `other` coincide. /// /// 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] pub fn rotation_to(&self, other: &Rotation3) -> Rotation3 { other * self.inverse() @@ -364,6 +687,19 @@ impl Rotation3 { /// 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`. + /// + /// # 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] pub fn powf(&self, n: N) -> Rotation3 { if let Some(axis) = self.axis() {