3D rotations: intrinsic, extrinsic and Euler
2. 3D rotation matrices
Rotations in 3D space are more complex than in 2D space. In 2D space, we can describe a rotation with just one angle. In 3D space, there are many ways to describe a rotation but they can roughly be categorized into two types -
rotations around the axes (Davenport rotations, Euler angles)
axis-angle representation (Euler-Rodrigues formula, quaternions)
Let's start with rotations around fixed coordinate axes since they are simplest to define and other rotations can be defined as a composition of these simpler rotations.
2.1 Rotations are NOT commutative
Using the same logic used in 2D rotations above, the rotation matrices for rotations about the x-, y- and z-axes by an angle \( \theta \) are:
Around x-axis: \( R_x(θ) = \)\(
\begin{bmatrix}
1 & 0 & 0 \\ 0 & cos(\theta) & -sin(\theta) \\ 0 & sin(\theta) & cos(\theta)
\end{bmatrix}
\)
Around y-axis: \( R_y(θ) = \)\(
\begin{bmatrix}
cos(\theta) & 0 & -sin(\theta) \\ 0 & 1 & 0 \\ sin(\theta) & 0 & cos(\theta)
\end{bmatrix}
\)
Around z-axis: \( R_z(θ) = \)\(
\begin{bmatrix}
cos(\theta) & -sin(\theta) & 0 \\ sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1
\end{bmatrix}
\)
Just using these matrices, it is easy to show that rotations are not commutative. In other words, given two rotations \( R_1 \) and \( R_2 \), \( R_1R_2 \neq R_2R_1 \). This is because the order of rotations matters. This is a fundamental property of rotations which was not evident in 2D rotations.
2.1 Intrinsic and extrinsic rotations
In 3D space, we can rotate a vector about the x-axis, y-axis or z-axis. These axes are fixed and such rotations are called extrinsic rotations. Now imagine that a rotation also rotates the axes. Then the second rotation is with respect to the next axes. A good example is to imagine the x-, y- and z-axes attached to an aircraft. These axes are initially aligned with the fixed axes. When the aircraft rotates, the axes attached to the aircraft also rotate. The next rotation can be described with respect to the new axes. These rotations are called intrinsic rotations. We need a way to map the intrinsic rotations to extrinsic rotations and vice versa.
These two kinds of rotations are just a special case of change of basis. An intrinsic rotation is a change of basis followed by a rotation. Using our knowledge of change of basis , we can map an intrinsic rotation to an extrinsic rotation. First, let's see how the same set of rotations is described using intrinsic and extrinsic rotations.
We rotate a vector \( v = \)\(
\begin{bmatrix}
cos(\pi/6) \\ sin(\pi/6)
\end{bmatrix}
\) in two different ways:
2.1.1 Extrinsic rotations
The vector is rotated by 30° about the z-axis and then by 180° about the x-axis. These rotations can be described by matrices \( R_z(\pi/6) \) and \( R_x(\pi) \) respectively. The final rotation matrix is \( R_x(\pi)R_z(\pi/6) \).
A 30° rotation about z-axis followed by a 180° rotation about x-axis
Click the buttons to animate the rotations
This composition of rotations and the final rotated vector can be described like so:
\( R_x(\pi)R_z(\pi/6) = \)\(
\begin{bmatrix}
1 & 0 & 0 \\ 0 & cos(\pi) & -sin(\pi) \\ 0 & sin(\pi) & cos(\pi)
\end{bmatrix}
\)\(
\begin{bmatrix}
cos(\pi/6) & -sin(\pi/6) & 0 \\ sin(\pi/6) & cos(\pi/6) & 0 \\ 0 & 0 & 1
\end{bmatrix}
\)\( = \)\(
\begin{bmatrix}
cos(\pi/6) & -sin(\pi/6) & 0 \\ -sin(\pi/6) & -cos(\pi/6) & 0 \\ 0 & 0 & -1
\end{bmatrix}
\)
\( v_{rotated} = R_x(\pi)R_z(\pi/6)v = \)\(
\begin{bmatrix}
sin(\pi/6) \\ -cos(\pi/6) \\ 0
\end{bmatrix}
\)
from scipy.spatial.transform import Rotation
# lower case axis names imply extrinsic rotations
# r = rotation about z-axis by 30 degrees followed by rotation about x-axis by 180 degrees
r = Rotation.from_euler('zx', [30,180], degrees=True)
print(r.as_matrix())
'''
Output
- note that cos(30) ≈ 0.866 and sin(30) = 0.5
- the matrix is the same as what we just calculated above
'''
[[ 8.66025404e-01 -5.00000000e-01 0.00000000e+00]
[-5.00000000e-01 -8.66025404e-01 -1.22464680e-16]
[ 6.12323400e-17 1.06057524e-16 -1.00000000e+00]]
2.1.2 Intrinsic rotations
In this case, the first rotation about z-axis also rotates the entire xy-plane alongwith the vector. The second rotation is about the new x-axis.
A 30° rotation about z-axis followed by a 180° rotation about intrinsic x-axis
Click the buttons to animate the rotations
Now here is a key insight: after the first rotation, the rotated vector still has the same coordinates in the new basis. In other words, the vector is still \(
\begin{bmatrix}
cos(\pi/6) \\ sin(\pi/6) \\ 0
\end{bmatrix}
\) in the basis defined by the rotation matrix \(
\begin{bmatrix}
cos(\pi/6) & -sin(\pi/6) & 0 \\ sin(\pi/6) & cos(\pi/6) & 0 \\ 0 & 0 & 1
\end{bmatrix}
\). The second rotation \( R_x(\pi) \) is just a rotation about the x-axis in the new basis. The coordinates of the vector in the new basis are \( R_x(\pi)v \). To get the coordinates of the vector in the original basis, we simply multiply the rotated vector by the basis matrix \( R_z(\pi/6) \). Thus, the final rotation matrix is \( R_z(\pi/6)R_x(\pi) \).
Indeed you can verify that:
\( R_z(\pi/6)R_x(\pi) = \)\(
\begin{bmatrix}
cos(\pi/6) & -sin(\pi/6) & 0 \\ sin(\pi/6) & cos(\pi/6) & 0 \\ 0 & 0 & 1
\end{bmatrix}
\)\(
\begin{bmatrix}
1 & 0 & 0 \\ 0 & cos(\pi) & -sin(\pi) \\ 0 & sin(\pi) & cos(\pi)
\end{bmatrix}
\)\( = \)\(
\begin{bmatrix}
cos(\pi/6) & sin(\pi/6) & 0 \\ sin(\pi/6) & -cos(\pi/6) & 0 \\ 0 & 0 & -1
\end{bmatrix}
\)
\( v_{rotated} = R_z(\pi/6)R_x(\pi)v = \)\(
\begin{bmatrix}
1 \\ 0 \\ 0
\end{bmatrix}
\)
Final note: the matrix \( R_z(\pi/6)R_x(\pi) \) can also be interpreted as a composition of two rotations around the fixed axes: a 180 degree rotation about the x-axis followed by a 30 degree rotation about the z-axis.
from scipy.spatial.transform import Rotation
# upper case axis names imply intrinsic rotations
# r = _intrinsic_ rotation about z-axis by 30 degrees followed by rotation about x-axis by 180 degrees
r = Rotation.from_euler('ZX', [30,180], degrees=True)
print(r.as_matrix())
'''
Output
- note that cos(30) ≈ 0.866 and sin(30) = 0.5
- the matrix is the same as what we just calculated above
'''
[[ 8.66025404e-01 5.00000000e-01 6.12323400e-17]
[ 5.00000000e-01 -8.66025404e-01 -1.06057524e-16]
[ 0.00000000e+00 1.22464680e-16 -1.00000000e+00]]
2.2 Euler angles
Euler angles are an extension of the idea of intrinsic rotations - they involve three rotations about the (intrinsic) axes by three angles \( \phi, \theta, \psi \). The three axes of rotations have the format axis 1 → (rotated) axis 2 → (twice rotated) axis 1 where each axis is one of the x-, y- or z-axes. There are 6 such combinations - \( x-y'-x'', y-x'-y'', z-x'-z'', x-z'-x'', y-z'-y'', z-y'-z'' \). Each rotation not only rotates the vector but also the remaining two axes. The single and double ticks denote that these axes are intrinsic axes.
Now consider the rotation \( z-x'-z'' \) by angles \( \phi, \theta, \psi \). The corresponding rotation matrices are \( R_z(\phi), R_x(\theta), R_z(\psi) \). Using the same logic as above, we can consider the first rotation as a change of basis. The second and third rotations can also be considered change of bases. Note that after each change of basis, the vector coordinates in the new basis remain the same. Thus the coordinates of the (thrice rotated) vector in the original basis is \( R_z(\phi)R_x(\theta)R_z(\psi)v \).
from scipy.spatial.transform import Rotation
# upper case axis names imply intrinsic rotations
# r = three 90 degree intrinsic rotations about x, z and x axes respectively
r = Rotation.from_euler('XZX', [90,90,90], degrees=True)
print(r.as_matrix())
'''
Output
'''
[[ 2.22044605e-16 -1.89526925e-16 1.00000000e+00]
[ 1.89526925e-16 -1.00000000e+00 -1.89526925e-16]
[ 1.00000000e+00 1.89526925e-16 -2.22044605e-16]]
2.2.1 Intrinsic to extrinsic rotations and vice versa
Note that the composition of rotations \( R_z(\phi)R_x(\theta)R_z(\psi)v \) can be interpreted in two different ways. The first way is to consider the rotations as intrinsic rotations, which we have already covered. The second way is to consider the rotations as extrinsic rotations. In that interpretation, all rotations occur around the fixed x-, y- and z-axes. The first rotation is about the z-axis by an angle \( \psi \), the second rotation is about the new x-axis by an angle \( \theta \) and the third rotation is about the new z-axis by an angle \( \phi \).
Thus, an intrinsic rotation around the axes \( x,y',z'' \) by angles \( \alpha, \beta, \gamma \) is equivalent to an extrinsic rotation around the axes \( z,y,x \) by angles \( \gamma, \beta, \alpha \).