Rotation matrices: turn vectors, track frames, and check the order

Build rotation matrices that preserve length and handedness. Compare fixed-axis rotations in 3D, distinguish rotating a vector from changing its coordinates, and undo a rotation with its transpose.

By 12 min read

What you will learn

  • Calculate a two-dimensional rotation and identify the images of the basis vectors.
  • Compose rotations about fixed three-dimensional axes in the intended order.
  • Distinguish active vector rotation from changing the frame used for its coordinates.
  • Check orthogonality and determinant, then undo a rotation using its transpose.

Before you start

Two 90° rotations can send the same starting vector in different directions. Rotate (1, 0, 0) about a fixed x axis, then a fixed z axis: the result is (0, 1, 0). Reverse the order and the result is (0, 0, 1).

Rotation matrices let you calculate those turns and check what they preserve. The essential decisions come first: which object moves, which frame describes it, and which rotation acts first.

State what rotates and which axes stay fixed

This lesson uses column vectors and a right-handed orthonormal frame. Its axes are perpendicular unit directions, with eₓ × eᵧ = e_z. The coordinate-frames lesson explains why a coordinate tuple needs an associated frame.

In an active rotation, the geometric vector changes. Its old and new coordinates use the same fixed frame:

v′ = Rv

All rotations in the experiment act about fixed axes through the origin. A positive turn follows the right-hand rule: point your right thumb along the positive axis and curl your fingers in the direction of rotation. Around +z, this turns +x toward +y; around +x, it turns +y toward +z.

A change of frame, sometimes called a passive rotation, keeps the geometric vector fixed and changes the basis used to describe it. We will calculate that separately. Modern Robotics distinguishes orientation, coordinate changes, and active rotation as three uses of a rotation matrix.

Build the two-dimensional rotation

For a counterclockwise angle θ in a plane with x right and y up:

R(θ) = [cos θ, −sin θ; sin θ, cos θ]

The semicolon separates the rows. The first column is the image of eₓ = (1, 0): after the turn, it lies at (cos θ, sin θ). The second column is the image of eᵧ = (0, 1), which remains perpendicular and becomes (−sin θ, cos θ).

Multiplication gives x′ = x cos θ − y sin θ and y′ = x sin θ + y cos θ. At 90°, cosine is zero and sine is one, so (x, y) becomes (−y, x).

For input (2, 1), the output is (−1, 2). Both lengths are √5. At 30°, the unit input (1, 0) becomes (√3/2, 1/2), also unit length.

The interface uses degrees. Programming languages usually expect radians in their sine and cosine functions, so convert with radians = degrees × π/180. Mixing these units changes the rotation you compute.

Check length and handedness separately

A real three-dimensional rotation matrix satisfies two conditions:

RᵀR = I
det(R) = +1

The first condition says the columns form an orthonormal basis. It ensures that dot products survive the transformation: (Rv) · (Rw) = vᵀRᵀRw = v · w. Lengths and angles between nonzero vectors therefore stay the same.

The determinant condition preserves orientation. Together, these conditions define SO(3), the special orthogonal group in three dimensions. Modern Robotics gives this definition and its basic properties.

Check both conditions. The reflection F = [−1, 0, 0; 0, 1, 0; 0, 0, 1] preserves lengths and satisfies FᵀF = I, but det(F) = −1. The scale matrix S = [2, 0, 0; 0, 1/2, 0; 0, 0, 1] has determinant +1, yet stretches one direction and shrinks another.

A rotation also fixes the origin because R0 = 0. Turning points about a different pivot requires shifting to that pivot and back. Homogeneous transformations combine the needed translations with rotations.

Rotate about a fixed x or z axis

In three dimensions, a rotation about x leaves the x coordinate unchanged and rotates the y-z coordinates. A rotation about z leaves z unchanged and rotates x-y:

Rₓ(α) =
[1, 0, 0;
0, cos α, −sin α;
0, sin α, cos α]

R_z(β) =
[cos β, −sin β, 0;
sin β, cos β, 0;
0, 0, 1]

These signs follow the right-handed convention stated above. At +90°, Rₓ sends eᵧ to e_z and e_z to −eᵧ. R_z sends eₓ to eᵧ and eᵧ to −eₓ.

The axis itself stays fixed. Rotating eₓ about x does nothing to that vector, even though the same matrix changes most other vectors. A single unchanged input does not make the transformation an identity.

Rotation entries are dimensionless. If a displacement uses metres on all three axes, its rotated coordinates remain in metres and retain the same Euclidean length.

Apply the rightmost matrix first

To rotate first about fixed x by α and then about fixed z by β:

v′ = R_z(β)Rₓ(α)v

The matrix multiplication lesson develops this rightmost-first rule. It follows directly from nesting the operations: R_z(Rₓv).

With both angles +90°, track the basis vector eₓ through each step:

OrderInputAfter first turnFinal output
X then Z(1, 0, 0)(1, 0, 0)(0, 1, 0)
Z then X(1, 0, 0)(0, 1, 0)(0, 0, 1)

The complete products differ too:

R_zRₓ = [0, 0, 1; 1, 0, 0; 0, 1, 0]
RₓR_z = [0, −1, 0; 0, 0, −1; 1, 0, 0]

Three-dimensional rotations generally do not commute. Some pairs do: two rotations about the same fixed axis commute, and these x and z rotations commute when both are 180°. Two planar rotations about the same origin also commute because their angles simply add.

The fixed-axis assumption matters. Turning about an axis attached to an already rotated object is a different operation. MIT's rigid-body kinematics materials develop composition from rotations about coordinate axes.

Euler angles describe orientation with three ordered turns. That lesson adds a y rotation and shows how different angle triples can describe the same complete matrix at gimbal lock.

Compare both orders in two projections

The experiment begins with the quarter-turn example. The solid marker shows the selected order; the open square shows the reverse order. The open circle marks the input.

Interactive experiment

Compare two fixed-axis rotation orders

Actively rotate a vector about the fixed x and z axes. Both projections use the same scale; full coordinates retain the missing dimension.

90°
90°

Positive X rotation turns +y toward +z. Positive Z rotation turns +x toward +y. The second rotation uses a fixed world axis, and all displayed coordinates use that same right-handed frame.

Rx
1.0000.0000.000
0.0000.000-1.000
0.0001.0000.000
Rz
0.000-1.0000.000
1.0000.0000.000
0.0000.0001.000
R = Rz Rx
0.0000.0001.000
1.0000.0000.000
0.0001.0000.000
  • Open circle: input
  • Filled dot: selected order
  • Open square: reverse order

XY projection

XY projectionThis view shows x and y, dropping z. The selected output has z = 0.000; the reverse-order output has z = 1.000. A projection at the origin can still represent a nonzero three-dimensional vector.-1-1011xy
This view shows x and y, dropping z. The selected output has z = 0.000; the reverse-order output has z = 1.000. A projection at the origin can still represent a nonzero three-dimensional vector.

XZ projection

XZ projectionThis view shows x and z, dropping y. The selected output has y = 1.000; the reverse-order output has y = 0.000. A projection at the origin can still represent a nonzero three-dimensional vector.-1-1011xz
This view shows x and z, dropping y. The selected output has y = 1.000; the reverse-order output has y = 0.000. A projection at the origin can still represent a nonzero three-dimensional vector.
Input vector
(1.000, 0.000, 0.000)
After first rotation
(1.000, 0.000, 0.000)
Selected order output
(0.000, 1.000, 0.000)
Reverse order output
(0.000, 0.000, 1.000)
Output separation
1.414
Products commute
No
Input length
1.000
Output length
1.000
Determinant
1.000
Recovered input
(1.000, 0.000, 0.000)
Product difference
2.449
Orthogonality residual
0.00e+0

The two complete matrix products differ, and this input reaches different outputs when the order changes.

Recovered input is Rᵀ times the selected output. Product difference is the Frobenius norm of Rz Rx − Rx Rz; Products commute reports Yes when it is at most 10⁻¹². Orthogonality residual is ‖RᵀR − I‖F. The bounded controls build rotations directly; coordinates show three decimals, while calculations retain full precision.

Both projections use the same axis scale. The xy view drops z, and the xz view drops y. In the default xy view, the reverse-order output projects to the origin because its full coordinates are (0, 0, 1).

That vector still has length one. Read the full coordinate and length values before interpreting a short projected segment as a physical shortening.

Choose Diagonal (1, 1, −1)/√3 without changing the angles. Both orders produce (−1, 1, 1)/√3, yet Products commute still says No. The two matrices agree on this particular vector and disagree elsewhere.

Set either angle to zero to make one rotation the identity. Now the full products agree. Try 30° about x and 60° about z with Y unit vector: X then Z gives (−0.750, 0.433, 0.500), showing that the same rules work between quarter-turns.

The controls cover −180° through 180° in 15° steps. Calculations keep their precision while coordinates display three decimals. The orthogonality residual measures the entrywise discrepancy in RᵀR − I; small roundoff near zero does not indicate an intended stretch.

Express the same vector in another frame

Let W be a world frame and B a frame whose axes have turned +90° about world z. Define R_WB by placing B's axes, expressed in W coordinates, in its columns. For this example, R_WB is the same numeric array as R_z(90°).

Frame subscripts identify the coordinate conversion:

vW = RWBvB
vB = RWBᵀvW

Take a fixed geometric vector with world coordinates v_W = (1, 0, 0). Its coordinates in B are (0, −1, 0). The vector has not moved; B's negative y axis points along world +x.

An active +90° world-z rotation instead changes that vector to a new vector with world coordinates (0, 1, 0). Labeling the input and output frames separates these calculations, even though the same rotation array appears in both.

For free vectors such as displacements, this conversion uses orientation alone. For point coordinates, origins must coincide to use only R. Different origins require translation, as the homogeneous-transformations lesson explains.

Undo the rotation with its transpose

Because RᵀR = I, a rotation satisfies R⁻¹ = Rᵀ. In two dimensions, transposing R(θ) gives R(−θ). The same rule reverses an elementary rotation about a fixed three-dimensional axis.

Undo a sequence in reverse order. If R = R_z(β)Rₓ(α), then:

R⁻¹ = Rᵀ = Rₓ(−α)R_z(−β)

The rightmost factor first undoes the z turn. The remaining factor undoes x. The experiment's Recovered input applies this inverse to the selected output.

This shortcut depends on orthogonality. The transpose and inverse lesson explains why transposing a general matrix does not reverse its action.

A proper rotation also preserves the cross-product relationship: (Ra) × (Rb) = R(a × b). For the basis vectors, the rotated x and y directions still produce the rotated z direction. The cross-product lesson connects that orientation to the right-hand rule.

Reproduce the calculation in Python

This example uses only Python's standard library. The functions construct active fixed-axis rotations with the same signs as the lesson. show rounds the printed coordinates and removes a displayed negative zero; it leaves the calculations unchanged.

from math import cos, sin, radians, sqrt


def rx(degrees):
    c, s = cos(radians(degrees)), sin(radians(degrees))
    return [[1, 0, 0], [0, c, -s], [0, s, c]]


def rz(degrees):
    c, s = cos(radians(degrees)), sin(radians(degrees))
    return [[c, -s, 0], [s, c, 0], [0, 0, 1]]


def multiply(a, b):
    return [[sum(x * y for x, y in zip(row, column))
             for column in zip(*b)] for row in a]


def apply(a, v):
    return tuple(sum(x * y for x, y in zip(row, v)) for row in a)


def show(v):
    values = (0.0 if abs(x) < 0.0005 else x for x in v)
    return "(" + ", ".join(f"{x:.3f}" for x in values) + ")"


v = (1, 0, 0)
r = multiply(rz(90), rx(90))
reverse = multiply(rx(90), rz(90))
output = apply(r, v)
recovered = apply(list(zip(*r)), output)
print("X then Z:", show(output))
print("Z then X:", show(apply(reverse, v)))
print("Recovered input:", show(recovered))
print(f"Output length: {sqrt(sum(x * x for x in output)):.3f}")

oblique = multiply(rz(60), rx(30))
print("30 then 60 on e_y:", show(apply(oblique, (0, 1, 0))))

Expected output:

X then Z: (0.000, 1.000, 0.000)
Z then X: (0.000, 0.000, 1.000)
Recovered input: (1.000, 0.000, 0.000)
Output length: 1.000
30 then 60 on e_y: (-0.750, 0.433, 0.500)

For real applications, keep the frame convention and angle units beside the data. When importing a measured matrix, check orthogonality and determinant with a tolerance suited to its numerical precision and measurement process.

Try it yourself

Exercise 1. A vector has world coordinates (2, 1, 0). Find its new world coordinates after an active +90° rotation about world z. Then find the original vector's coordinates in a frame B whose axes are rotated +90° about world z.

Show solution 1

The active rotation gives R_z(90°)(2, 1, 0) = (−1, 2, 0). This is a new geometric vector described in the world frame.

For the unchanged vector, use R_WBᵀ = R_z(−90°). Its B coordinates are (1, −2, 0). Both coordinate triples preserve the original length √5, but the operations answer different questions.

Exercise 2. Start with eᵧ = (0, 1, 0) and use +90° rotations about fixed x and z. Calculate the output in each order. Which inverse sequence recovers eᵧ from the X-then-Z output?

Show solution 2

X then Z gives (0, 1, 0) → (0, 0, 1) → (0, 0, 1). Z then X gives (0, 1, 0) → (−1, 0, 0) → (−1, 0, 0).

Undo X then Z by applying R_z(−90°) first, then Rₓ(−90°). The first inverse leaves (0, 0, 1) unchanged; the second returns (0, 1, 0). The combined inverse matrix is Rₓ(−90°)R_z(−90°).

To describe an entire sensor pose, continue with homogeneous transformations. They keep rotation and translation in one composition while making the frame conversion explicit.

For other rotation representations, axis-angle and Rodrigues' formula build R from one unit axis and one angle. Unit quaternions express the same rotation with four constrained components and a multiplication rule for composition.

Sources and further study