Open juliohm opened 7 months ago
Discussing with other people on Zulip, we can better document this theorem:
Sorry for the late response!
I was planning to answer with some visualizations after resolving #279, but that may take time a bit. Intrinsic operations can be obtained by changing the rotation order or axes and signs of rotation angles.
julia> import Rotations
julia> import ReferenceFrameRotations
julia> ReferenceFrameRotations.angle_to_dcm(ReferenceFrameRotations.EulerAngles(1.2, 0.3, -0.8, :XYZ))
DCM{Float64}:
0.665589 -0.0680412 -0.74321
0.685316 0.450043 0.57254
0.29552 -0.890411 0.346174
julia> Rotations.RotZYX(0.8,-0.3,-1.2)
3×3 RotZYX{Float64} with indices SOneTo(3)×SOneTo(3)(0.8, -0.3, -1.2):
0.665589 -0.0680412 -0.74321
0.685316 0.450043 0.57254
0.29552 -0.890411 0.346174
julia> ReferenceFrameRotations.angle_to_dcm(ReferenceFrameRotations.EulerAngles(1.2, 0.3, -0.8, :ZYZ))
DCM{Float64}:
0.909785 0.360416 -0.205891
-0.401028 0.891199 -0.211993
0.107084 0.275436 0.955336
julia> Rotations.RotZYZ(0.8,-0.3,-1.2)
3×3 RotZYZ{Float64} with indices SOneTo(3)×SOneTo(3)(0.8, -0.3, -1.2):
0.909785 0.360416 -0.205891
-0.401028 0.891199 -0.211993
0.107084 0.275436 0.955336
Even inside Rotations.jl we can do that conversion with something like:
RotXYZ(a1, a2, a3) # extrinsic with a3 around Z, followed by a2 around Y, followed by a1 around X
RotZYX(a1, a2, a3) # intrinsic with a1 around Z, followed by a2 around Y, followed by a3 around X
We don't need to flip the signs if we read from left-to-right (intrinsic) versus right-to-left (extrinsic)
So maybe the docs could emphasize this "reading" convention. If users seek "intrinsic" rotations they can read the struct names and angles from left-to-right.
A dedicated paragraph explaining this reading convention and how angles are applied in order can really help end users.
If I am not mistaken, the following sentence in the readme covers this now?
This may be interpreted as an "extrinsic" rotation about the Z, Y, and X axes or as an "intrinsic" rotation about the X, Y, and Z axes. Similarly, RotZYX(z, y, x) may be interpreted as an "extrinsic" rotation about the X, Y, and Z axes or an "intrinsic" rotation about the Z, Y, and X axes.
I am not sure if this issue is asking for more words on the topic, or if it should be closed in light of the above quote.
I have to admit, I am quite fond of how Scipy allows users to specify the representation as a string, e.g. "xyz" for extrinsic x, y, z, for "XYZ" for intrinsic z, then y, then x. It frees the user from first having to understand the equivalency between the repsentations.
Discussing with other people on Zulip, we can better document this theorem:
I actually ended up "proving" this myself recently for my master's thesis. It is not that mathematical in language and structure, making it somewhat more accasable, and I am pretty sure it holds up. The relevant page can be found here That might provide some inspiration on how to quickly prove the equivalency without invoking the heavy machinery of mathematical proofs xD
What about a section like the following? It is rather verbose, but also extremely explicit and hopefully understandable. It also helps showing how a single rotation matrix has both an intrinsic and extrinsic interpretation, which I think the tables below do even better than the wikipedia article on euler angles.
In the tables below, note that
Constructor | Factorized Rotation Matrix | Extrinsic Interpretation | Intrinsic Interpretation |
---|---|---|---|
RotXYZ(a, b, c) |
$R_x(a) R_y(b) R_z(c)$ | 1. Rotate $c$ radians about $z$ 2. Rotate $b$ radians about $y$ 3. Rotate $a$ radians about $x$ |
1. Rotate $a$ radians about $x$ 2. Rotate $b$ radians about $y'$ 3. Rotate $c$ radians about $z''$ |
RotXZY(a, b, c) |
$R_x(a) R_z(b) R_y(c)$ | 1. Rotate $c$ radians about $y$ 2. Rotate $b$ radians about $z$ 3. Rotate $a$ radians about $x$ |
1. Rotate $a$ radians about $x$ 2. Rotate $b$ radians about $z'$ 3. Rotate $c$ radians about $y''$ |
RotYXZ(a, b, c) |
$R_y(a) R_x(b) R_z(c)$ | 1. Rotate $c$ radians about $z$ 2. Rotate $b$ radians about $x$ 3. Rotate $a$ radians about $y$ |
1. Rotate $a$ radians about $y$ 2. Rotate $b$ radians about $x'$ 3. Rotate $c$ radians about $z''$ |
RotYZX(a, b, c) |
$R_y(a) R_z(b) R_x(c)$ | 1. Rotate $c$ radians about $x$ 2. Rotate $b$ radians about $z$ 3. Rotate $a$ radians about $y$ |
1. Rotate $a$ radians about $y$ 2. Rotate $b$ radians about $z'$ 3. Rotate $c$ radians about $x''$ |
RotZXY(a, b, c) |
$R_z(a) R_x(b) R_y(c)$ | 1. Rotate $c$ radians about $y$ 2. Rotate $b$ radians about $x$ 3. Rotate $a$ radians about $z$ |
1. Rotate $a$ radians about $z$ 2. Rotate $b$ radians about $x'$ 3. Rotate $c$ radians about $y''$ |
RotZYX(a, b, c) |
$R_z(a) R_y(b) R_x(c)$ | 1. Rotate $c$ radians about $x$ 2. Rotate $b$ radians about $y$ 3. Rotate $a$ radians about $z$ |
1. Rotate $a$ radians about $z$ 2. Rotate $b$ radians about $y'$ 3. Rotate $c$ radians about $x''$ |
Constructor | Factorized Rotation Matrix | Extrinsic Interpretation | Intrinsic Interpretation |
---|---|---|---|
RotZXZ(a, b, c) |
$R_z(a) R_x(b) R_z(c)$ | 1. Rotate $c$ radians about $z$ 2. Rotate $b$ radians about $x$ 3. Rotate $a$ radians about $z$ |
1. Rotate $a$ radians about $z$ 2. Rotate $b$ radians about $x'$ 3. Rotate $c$ radians about $z''$ |
RotZYZ(a, b, c) |
$R_z(a) R_y(b) R_z(c)$ | 1. Rotate $c$ radians about $z$ 2. Rotate $b$ radians about $y$ 3. Rotate $a$ radians about $z$ |
1. Rotate $a$ radians about $z$ 2. Rotate $b$ radians about $y'$ 3. Rotate $c$ radians about $z''$ |
RotXYX(a, b, c) |
$R_x(a) R_y(b) R_x(c)$ | 1. Rotate $c$ radians about $x$ 2. Rotate $b$ radians about $y$ 3. Rotate $a$ radians about $x$ |
1. Rotate $a$ radians about $x$ 2. Rotate $b$ radians about $y'$ 3. Rotate $c$ radians about $x''$ |
RotXZX(a, b, c) |
$R_x(a) R_z(b) R_x(c)$ | 1. Rotate $c$ radians about $x$ 2. Rotate $b$ radians about $z$ 3. Rotate $a$ radians about $x$ |
1. Rotate $a$ radians about $x$ 2. Rotate $b$ radians about $z'$ 3. Rotate $c$ radians about $x''$ |
RotYXY(a, b, c) |
$R_y(a) R_x(b) R_y(c)$ | 1. Rotate $c$ radians about $y$ 2. Rotate $b$ radians about $x$ 3. Rotate $a$ radians about $y$ |
1. Rotate $a$ radians about $y$ 2. Rotate $b$ radians about $x'$ 3. Rotate $c$ radians about $y''$ |
RotYZY(a, b, c) |
$R_y(a) R_z(b) R_y(c)$ | 1. Rotate $c$ radians about $y$ 2. Rotate $b$ radians about $z$ 3. Rotate $a$ radians about $y$ |
1. Rotate $a$ radians about $y$ 2. Rotate $b$ radians about $z'$ 3. Rotate $c$ radians about $y''$ |
We recently noticed that rotations such as
RotXYZ
are extrinsic, meaning that they rotate with respect to the original xyz axis. Is it possible to rotate around z, then rotate around the new y' and finally around the new x''? The so called intrinsic rotations?https://en.wikipedia.org/wiki/Euler_angles#Chained_rotations_equivalence
We migrated from ReferenceFrameRotations.jl to Rotations.jl and noticed that some of our rotation conventions were compromised.
cc: @hyrodium