JuliaGeometry / Rotations.jl

Julia implementations for different rotation parameterizations
https://juliageometry.github.io/Rotations.jl
MIT License
176 stars 44 forks source link

Document intrinsic vs. extrinsic rotations #281

Open juliohm opened 7 months ago

juliohm commented 7 months ago

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

juliohm commented 7 months ago

Discussing with other people on Zulip, we can better document this theorem:

https://math.stackexchange.com/questions/1137745/proof-of-the-extrinsic-to-intrinsic-rotation-transform

hyrodium commented 7 months ago

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
juliohm commented 7 months ago

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)

juliohm commented 7 months ago

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.

KronosTheLate commented 3 months ago

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:

https://math.stackexchange.com/questions/1137745/proof-of-the-extrinsic-to-intrinsic-rotation-transform

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

KronosTheLate commented 3 months ago

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

Tait-Bryan convention:

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''$

"Proper" euler angles:

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''$