pub fn to_euler_angles<T>(
rt: RotationType,
rs: RotationSequence,
q: Quaternion<T>,
) -> Vector3<T>where
T: Float + FloatConst,Expand description
Converts a Versor into a Euler Angles.
This function requires two parameters to fully define the rotation:
RotationType: Specifies whether the rotation is Intrinsic or Extrinsic.RotationSequence: Defines the three-axis sequence (e.g., XYZ, ZYX, XZX, …).
The output angles array contains the three angles, corresponding to the sequence:
angles[0] -> angles[1] -> angles[2].
Each angle is returned in the range: (-PI, PI].
§Singularity (Gimbal Lock)
§RotationType::Intrinsic
For Proper Euler Angles (ZXZ, XYX, YZY, ZYZ, XZX, YXY), the singularity is reached when the sine of the second rotation angle is 0 (angle = 0, ±π, …), and for Tait-Bryan angles (XYZ, YZX, ZXY, XZY, ZYX, YXZ), the singularity is reached when the cosine of the second rotation angle is 0 (angle = ±π/2).
§RotationType::Extrinsic
As in the case of Intrinsic rotation, for Proper Euler Angles, the singularity occurs when the sine of the second rotation angle is 0 (angle = 0, ±π, …), and for Tait-Bryan angles, the singularity occurs when the cosine of the second rotation angle is 0 (angle = ±π/2).
§Resolution at Singularity
- For Intrinsic rotation, the third angle (
angles[2]) is set to 0 [rad]. - For Extrinsic rotation, the first angle (
angles[0]) is set to 0 [rad].
§Examples
Depending on the rotation angle of each axis, it may not be possible to recover the same rotation angle as the original. However, they represent the same rotation in 3D space.
use quaternion_core::{RotationType::*, RotationSequence::XYZ};
let angles = [PI/6.0, PI/4.0, PI/3.0];
// ---- Intrinsic (X-Y-Z) ---- //
let q_in = from_euler_angles(Intrinsic, XYZ, angles);
let e_in = to_euler_angles(Intrinsic, XYZ, q_in);
assert!( (angles[0] - e_in[0]).abs() < 1e-12 );
assert!( (angles[1] - e_in[1]).abs() < 1e-12 );
assert!( (angles[2] - e_in[2]).abs() < 1e-12 );
// ---- Extrinsic (X-Y-Z) ---- //
let q_ex = from_euler_angles(Extrinsic, XYZ, angles);
let e_ex = to_euler_angles(Extrinsic, XYZ, q_ex);
assert!( (angles[0] - e_ex[0]).abs() < 1e-12 );
assert!( (angles[1] - e_ex[1]).abs() < 1e-12 );
assert!( (angles[2] - e_ex[2]).abs() < 1e-12 );