Book contents
Contents
raw Math
RAW Book Geometry Rotations

Introduction to Rotations with Complex Numbers and Quaternions

Robert Eisele

Almost every text that introduces quaternions arrives sooner or later at the sandwich product

\[\mathbf{r}' = \mathbf{q}\,\mathbf{r}\,\overline{\mathbf{q}}\]

and then explains how to use it. The more interesting questions are usually left out: why a rotation should be expressed as a product on both sides of the vector, why the quaternion stores half of the physical rotation angle, and why \(\mathbf{q}\) and \(-\mathbf{q}\) describe exactly the same orientation. None of these are notational accidents. Each of them follows from the geometry of rotations, and each of them already has a visible shadow in the two-dimensional case.

This chapter therefore starts where the structure is still small enough to see: a rotation in the plane, derived from the definition of what a rotation is. From there the plane rotation is rewritten as multiplication by a complex number, rotations are decomposed into reflections, the reflection picture is carried into three dimensions, and the quaternion rotor appears as the only thing it could reasonably be. The algebra of \(\mathbb{H}\) itself is developed separately in the chapter on quaternions; here it is used as a tool for rotation, and only the parts that are needed are restated.

What Makes a Map a Rotation

A rotation is not defined by "turning something". It is defined by what it preserves. A linear map \(\mathbf{R}:\mathbb{R}^n\to\mathbb{R}^n\) is a proper rotation exactly when

\[\mathbf{R}^T\mathbf{R}=\mathbf{I},\qquad \det\mathbf{R}=+1.\]

The first condition is orthogonality, and it is precisely the statement that dot products survive the map:

\[(\mathbf{R}\mathbf{a})\cdot(\mathbf{R}\mathbf{b}) =\mathbf{a}^T\mathbf{R}^T\mathbf{R}\,\mathbf{b} =\mathbf{a}\cdot\mathbf{b}.\]

Since lengths and angles are both expressible through dot products, an orthogonal map leaves every length and every angle unchanged. That is not yet enough. A mirror also preserves lengths and angles, and orthogonality alone admits mirrors: from \(\mathbf{R}^T\mathbf{R}=\mathbf{I}\) we only get

\[\det(\mathbf{R}^T\mathbf{R})=(\det\mathbf{R})^2=1 \quad\Longrightarrow\quad \det\mathbf{R}=\pm 1.\]

The second condition, \(\det\mathbf{R}=+1\), removes the reflections and keeps only the maps that also preserve orientation, i.e. that turn a right-handed frame into a right-handed frame. The set of these maps is closed under composition and inversion, so it forms a group, the special orthogonal group \(SO(n)\).

Two consequences are worth stating explicitly, because they are used constantly later. First, the inverse of a rotation is its transpose:

\[\mathbf{R}^{-1}=\mathbf{R}^T.\]

Second, the columns of \(\mathbf{R}\) are orthonormal, since \(\mathbf{R}^T\mathbf{R}=\mathbf{I}\) states exactly that every column has unit length and every pair of distinct columns is orthogonal.

Conventions Used Throughout

Rotation formulas differ between texts almost exclusively because of unstated conventions, so they are fixed here once:

The word "clockwise" carries no information unless the viewing direction and the active or passive reading are given as well. The reverse rotation, on the other hand, is unambiguous:

\[\mathbf{R}(-\theta)=\mathbf{R}(\theta)^{-1}=\mathbf{R}(\theta)^T.\]

Rotations Do Not Commute

Translations behave like vectors: they add, and the order in which they are applied is irrelevant. Rotations in three dimensions do not have that property. Two quarter-turns applied to \(\mathbf{e}_z\) in the two possible orders give two different results:

\[ \mathbf{R}_y\!\left(\frac{\pi}{2}\right)\mathbf{R}_x\!\left(\frac{\pi}{2}\right)\mathbf{e}_z=-\mathbf{e}_y, \qquad \mathbf{R}_x\!\left(\frac{\pi}{2}\right)\mathbf{R}_y\!\left(\frac{\pi}{2}\right)\mathbf{e}_z=\mathbf{e}_x. \]

Both sequences use the same two rotations and differ only in their order, and the two outcomes are a quarter-turn apart.

The same two quarter-turns applied to \(\mathbf{e}_z\) in the two possible orders. Rotating first about \(x\) and then about \(y\) sends \(\mathbf{e}_z\) to \(-\mathbf{e}_y\); the reverse order sends it to \(\mathbf{e}_x\). Noncommutativity is a property of three-dimensional rotation itself, not of a particular way of writing it down.

This matters for everything that follows. Any algebra that faithfully represents three-dimensional rotations must itself be noncommutative, which immediately rules out the complex numbers and any other commutative extension of \(\mathbb{R}\). In the plane, by contrast, rotations do commute, and that is exactly why the plane admits such a compact description.

Rotation in the Plane

Start with a point in polar coordinates,

\[x=\rho\cos\beta,\qquad y=\rho\sin\beta.\]

A rotation by \(\alpha\) about the origin leaves the radius \(\rho\) untouched, since it preserves length, and adds \(\alpha\) to the polar angle. That is the entire content of a plane rotation, and everything else is trigonometry. Using the angle-addition identities

\[\begin{array}{rl} \cos(\beta+\alpha)&=\cos\beta\cos\alpha-\sin\beta\sin\alpha,\\ \sin(\beta+\alpha)&=\sin\beta\cos\alpha+\cos\beta\sin\alpha, \end{array}\]

the new coordinates become

\[\begin{array}{rl} x'&=\rho\cos(\beta+\alpha)=\underbrace{\rho\cos\beta}_{x}\cos\alpha-\underbrace{\rho\sin\beta}_{y}\sin\alpha,\\ y'&=\rho\sin(\beta+\alpha)=\underbrace{\rho\sin\beta}_{y}\cos\alpha+\underbrace{\rho\cos\beta}_{x}\sin\alpha. \end{array}\]

The radius has cancelled out of both expressions, which is what makes the map linear. In matrix form,

\[\boxed{ \begin{pmatrix}x'\\y'\end{pmatrix} = \begin{pmatrix} \cos\alpha&-\sin\alpha\\ \sin\alpha&\cos\alpha \end{pmatrix} \begin{pmatrix}x\\y\end{pmatrix} =:\mathbf{R}(\alpha)\begin{pmatrix}x\\y\end{pmatrix}.}\]

A rotation by \(\alpha\) moves the point along the circle of radius \(\rho\), from polar angle \(\beta\) to \(\beta+\alpha\). The radius is fixed by orthogonality, so the whole map is determined by the angle addition.

Both defining properties are easy to confirm. The columns are orthonormal because \(\cos^2\alpha+\sin^2\alpha=1\) and \(-\cos\alpha\sin\alpha+\sin\alpha\cos\alpha=0\), and

\[\det\mathbf{R}(\alpha)=\cos^2\alpha+\sin^2\alpha=1.\]

The Columns Are the Images of the Basis

There is a second derivation, and it explains why the trigonometric entries appear as columns rather than rows. A linear map is completely determined by what it does to a basis, and the \(j\)-th column of a matrix is by construction the image of the \(j\)-th basis vector. For a rotation by \(\alpha\) the two basis vectors move to

\[\mathbf{R}(\alpha)\mathbf{e}_1=\begin{pmatrix}\cos\alpha\\\sin\alpha\end{pmatrix}, \qquad \mathbf{R}(\alpha)\mathbf{e}_2=\begin{pmatrix}-\sin\alpha\\\cos\alpha\end{pmatrix},\]

which can be read off the unit circle without any computation: \(\mathbf{e}_1\) lands at polar angle \(\alpha\), and \(\mathbf{e}_2\), starting a quarter-turn ahead, lands at \(\alpha+\frac{\pi}{2}\). Writing those two vectors side by side reproduces the matrix exactly.

The images of \(\mathbf{e}_1\) and \(\mathbf{e}_2\) under a rotation by \(\alpha\) are the two columns of \(\mathbf{R}(\alpha)\). The second column is the first one turned a further quarter-turn, which is why the sine changes sign.

Composition Is Angle Addition

Multiplying two plane rotations gives, after expanding the product and applying the same angle-addition identities again,

\[\mathbf{R}(\alpha_2)\mathbf{R}(\alpha_1)=\mathbf{R}(\alpha_1+\alpha_2)=\mathbf{R}(\alpha_1)\mathbf{R}(\alpha_2).\]

So \(SO(2)\) is not just a group, it is a commutative one, isomorphic to the additive group of angles modulo \(2\pi\). A single real parameter suffices, angles simply add, and there is no order to worry about. Every convenience of the two-dimensional case comes from this one fact, and every complication in three dimensions comes from its absence.

The Quarter-Turn Generator

The quarter-turn is special. Setting \(\alpha=\frac{\pi}{2}\) gives

\[\mathbf{J}:=\mathbf{R}\!\left(\frac{\pi}{2}\right)=\begin{pmatrix}0&-1\\1&0\end{pmatrix}, \qquad \mathbf{J}\begin{pmatrix}x\\y\end{pmatrix}=\begin{pmatrix}-y\\x\end{pmatrix},\]

which is exactly the perp operator. Applying it twice turns by a half-turn, so

\[\mathbf{J}^2=-\mathbf{I}.\]

That single identity is the whole reason complex numbers are about to show up. The general rotation matrix splits along \(\mathbf{I}\) and \(\mathbf{J}\),

\[\mathbf{R}(\alpha)=\cos\alpha\,\mathbf{I}+\sin\alpha\,\mathbf{J},\]

and because \(\mathbf{J}^2=-\mathbf{I}\), the matrix exponential of \(\alpha\mathbf{J}\) collapses in exactly the way the real exponential of an imaginary argument does:

\[\exp(\alpha\mathbf{J}) =\sum_{n=0}^{\infty}\frac{(\alpha\mathbf{J})^n}{n!} =\underbrace{\left(1-\frac{\alpha^2}{2!}+\frac{\alpha^4}{4!}-\cdots\right)}_{\cos\alpha}\mathbf{I} +\underbrace{\left(\alpha-\frac{\alpha^3}{3!}+\frac{\alpha^5}{5!}-\cdots\right)}_{\sin\alpha}\mathbf{J} =\mathbf{R}(\alpha).\]

The even powers of \(\mathbf{J}\) alternate between \(\mathbf{I}\) and \(-\mathbf{I}\), the odd powers between \(\mathbf{J}\) and \(-\mathbf{J}\), which is what sorts the Taylor series into a cosine part and a sine part. A rotation is thus generated by a single skew-symmetric matrix, and the angle is nothing but how far the generator is exponentiated.

Complex Numbers as Rotors in the Plane

Since \(\{\mathbf{I},\mathbf{J}\}\) behaves algebraically like \(\{1,\mathbf{i}\}\), the plane can be treated as \(\mathbb{C}\) instead of \(\mathbb{R}^2\). Identify

\[(x,y)\;\longleftrightarrow\;z=x+\mathbf{i}y,\]

and write both the point and the rotation in polar form, \(z=\rho e^{\mathbf{i}\beta}\). Multiplying by a unit complex number then does the same bookkeeping as before, but in one step:

\[z'=e^{\mathbf{i}\alpha}z=e^{\mathbf{i}\alpha}\rho e^{\mathbf{i}\beta}=\rho e^{\mathbf{i}(\beta+\alpha)}.\]

Moduli multiply and arguments add, so multiplication by \(e^{\mathbf{i}\alpha}\) preserves the length and adds \(\alpha\) to the angle. That is the definition of a plane rotation, reached without touching a trigonometric identity. Expanding the same product in Cartesian form,

\[(\cos\alpha+\mathbf{i}\sin\alpha)(x+\mathbf{i}y) =(x\cos\alpha-y\sin\alpha)+\mathbf{i}(x\sin\alpha+y\cos\alpha),\]

returns the two rows of \(\mathbf{R}(\alpha)\) as the real and imaginary parts. The matrix and the complex number carry identical information; under the correspondence

\[x+\mathbf{i}y\;\longmapsto\;x\mathbf{I}+y\mathbf{J}=\begin{pmatrix}x&-y\\y&x\end{pmatrix}\]

the field \(\mathbb{C}\) is isomorphic to that two-dimensional matrix algebra, \(\mathbf{i}\) corresponds to \(\mathbf{J}\), and \(\mathbf{i}^2=-1\) corresponds to \(\mathbf{J}^2=-\mathbf{I}\).

Multiplication in the complex plane acts as a rotation combined with a scaling. Multiplying by \(\mathbf{i}\) is a quarter-turn, multiplying by the unit number \(e^{\mathbf{i}\alpha}\) is a rotation by \(\alpha\). The rotor itself lives on the unit circle.

A unit complex number used this way is called a rotor. The rotors form the unit circle \(U(1)=\{z\in\mathbb{C}:|z|=1\}\), and

\[e^{\mathbf{i}\alpha_2}\left(e^{\mathbf{i}\alpha_1}z\right)=e^{\mathbf{i}(\alpha_1+\alpha_2)}z\]

shows that composing rotations is multiplying rotors. Powers give repeated rotation, \(z\mapsto e^{\mathbf{i}n\alpha}z\), and fractional powers interpolate between orientations. The correspondence \(U(1)\cong SO(2)\) is one-to-one: distinct unit complex numbers give distinct plane rotations, and every plane rotation comes from exactly one of them. In three dimensions this last property is the one that fails.

Why One Factor Is Enough Here

It is worth noticing what the plane case does not need. A vector and a rotor are both elements of \(\mathbb{C}\), so multiplying a vector by a rotor produces something that is again a vector; the multiplication never leaves the space it acts on. A two-sided product would also be pointless, because \(\mathbb{C}\) is commutative:

\[\mathbf{q}z\overline{\mathbf{q}}=z\,\mathbf{q}\overline{\mathbf{q}}=|\mathbf{q}|^2z,\]

which for a unit rotor is just \(z\) again. Conjugation by a complex number does nothing at all. Both observations reverse in three dimensions: a one-sided product will leave the space of vectors, and conjugation will no longer be trivial. That reversal is the whole reason for the sandwich.

Reflections and the Origin of the Half Angle

Before leaving the plane, one more decomposition is needed, and it is the key to everything that follows. A rotation can be built out of two reflections.

In complex notation, reflection across the line through the origin at angle \(\theta\) is

\[\sigma_\theta(z)=e^{2\mathbf{i}\theta}\overline{z},\]

which is verified directly: a point \(z=\rho e^{\mathbf{i}\beta}\) is mapped to \(\rho e^{\mathbf{i}(2\theta-\beta)}\), and \(2\theta-\beta\) is precisely the polar angle mirrored about \(\theta\). Note that the map is anti-linear, since it conjugates \(z\); a reflection cannot be a plain multiplication. Composing two of them, however, the conjugations cancel:

\[\sigma_{\theta_2}\!\left(\sigma_{\theta_1}(z)\right) =e^{2\mathbf{i}\theta_2}\overline{e^{2\mathbf{i}\theta_1}\overline{z}} =e^{2\mathbf{i}\theta_2}e^{-2\mathbf{i}\theta_1}z =e^{2\mathbf{i}(\theta_2-\theta_1)}z.\]

Two reflections give a rotation, and its angle is twice the angle between the two mirror lines. The result depends only on the difference \(\theta_2-\theta_1\), so the pair of mirrors can be rotated freely as long as the angle between them is kept: infinitely many pairs of reflections produce the same rotation.

Reflecting \(\mathbf{v}\) first in the mirror line \(m_1\) and then in \(m_2\) rotates it by \(2\psi\), where \(\psi\) is the angle between the two lines. Each reflection reverses orientation, so their composition preserves it, and only the relative angle of the mirrors survives.

Reading the result the other way round is what makes it useful. To rotate by \(\alpha\), pick two mirrors that are \(\frac{\alpha}{2}\) apart. The object that describes the rotation, the rotor

\[\mathbf{q}=e^{\mathbf{i}\alpha/2},\qquad z'=\mathbf{q}^2z=\mathbf{q}z\mathbf{q},\]

naturally carries half the rotation angle, because it comes from one mirror pair separated by half that angle. The two factors of \(\mathbf{q}\) can be pushed onto the same side only because \(\mathbb{C}\) is commutative. When the same construction is repeated in three dimensions, they cannot be moved, and the half angle stays visible in the formula.

That two reflections always suffice in the plane, and that \(2k\) reflections suffice in general for a rotation in \(\mathbb{R}^n\), is the content of the Cartan–Dieudonné theorem: every orthogonal map is a product of at most \(n\) reflections, and the proper ones use an even number of them.

What Breaks in Three Dimensions

A plane rotation needs one number. A three-dimensional rotation needs three, which is easiest to count on the matrix: nine entries, minus the six independent constraints in \(\mathbf{R}^T\mathbf{R}=\mathbf{I}\), leaves three degrees of freedom. Three parameters, but which three?

Every Rotation Has an Axis

The three parameters can be organised around a fixed direction, and the reason is a short determinant argument. Let \(\mathbf{R}\in SO(3)\). Then

\[\begin{array}{rl} \det(\mathbf{R}-\mathbf{I}) &=\det(\mathbf{R}^T)\det(\mathbf{R}-\mathbf{I})\\ &=\det(\mathbf{R}^T\mathbf{R}-\mathbf{R}^T)\\ &=\det(\mathbf{I}-\mathbf{R}^T)\\ &=\det\!\left((\mathbf{I}-\mathbf{R})^T\right)\\ &=\det(\mathbf{I}-\mathbf{R})\\ &=(-1)^3\det(\mathbf{R}-\mathbf{I})=-\det(\mathbf{R}-\mathbf{I}), \end{array}\]

where \(\det\mathbf{R}^T=\det\mathbf{R}=1\) was used in the first line. A number equal to its own negative is zero, so \(\det(\mathbf{R}-\mathbf{I})=0\), which means \(\mathbf{R}\) has the eigenvalue \(1\). Any corresponding eigenvector \(\hat{\mathbf{n}}\) satisfies \(\mathbf{R}\hat{\mathbf{n}}=\hat{\mathbf{n}}\) and is left completely untouched by the rotation.

This is Euler's rotation theorem: every rotation in three dimensions is a rotation by some angle \(\varphi\) about some fixed axis \(\hat{\mathbf{n}}\). The odd dimension is essential; the argument uses \((-1)^3=-1\) and fails in the plane, where a rotation has no fixed direction at all. Axis and angle account for the three degrees of freedom: two for the direction of \(\hat{\mathbf{n}}\), one for \(\varphi\).

Why Not Simply Extend the Complex Numbers

The natural next move is to look for a three-dimensional analogue of \(\mathbb{C}\): numbers \(a+b\mathbf{i}+c\mathbf{j}\) that multiply, divide, and rotate space the way complex numbers rotate the plane. Hamilton spent years on precisely this, and it cannot be done. By Frobenius's theorem, the only finite-dimensional associative division algebras over \(\mathbb{R}\) are \(\mathbb{R}\), \(\mathbb{C}\) and the quaternions \(\mathbb{H}\), of dimensions one, two and four. There is no three-dimensional one, so the search was doomed from the start.

The obstruction is visible without the theorem. Suppose \(\mathbf{i}\) and \(\mathbf{j}\) are two independent imaginary units. Their product \(\mathbf{i}\mathbf{j}\) has to be something, and it cannot be a real combination of \(1,\mathbf{i},\mathbf{j}\) without immediately producing contradictions. Hamilton's resolution was to accept it as a new, fourth basis element, \(\mathbf{k}:=\mathbf{i}\mathbf{j}\), and to give up commutativity. Given the previous section, giving up commutativity is not a regrettable side effect but a requirement: three-dimensional rotations do not commute, so no commutative algebra can represent them faithfully.

The dimension count that results is worth keeping in mind. Rotations in three dimensions have three degrees of freedom, and the unit quaternions, constrained by \(|\mathbf{q}|=1\) inside a four-dimensional space, have three as well. Four coordinates plus one constraint is a redundant description of a three-parameter family, and that redundancy is exactly what buys the absence of coordinate singularities discussed at the end of this chapter.

Rotation About an Arbitrary Axis

Before introducing any new algebra, the geometry can be settled directly. Euler's theorem gives an axis \(\hat{\mathbf{n}}\) with \(|\hat{\mathbf{n}}|=1\) and an angle \(\varphi\). Split an arbitrary vector \(\mathbf{r}\) into the part along the axis and the part perpendicular to it,

\[\mathbf{r}_{\parallel}=(\hat{\mathbf{n}}\cdot\mathbf{r})\,\hat{\mathbf{n}}, \qquad \mathbf{r}_{\perp}=\mathbf{r}-(\hat{\mathbf{n}}\cdot\mathbf{r})\,\hat{\mathbf{n}}.\]

The axial part is fixed by the rotation. Everything that happens, happens in the plane perpendicular to \(\hat{\mathbf{n}}\), and in that plane the earlier two-dimensional result applies verbatim, provided a second axis is available. The cross product supplies it: \(\hat{\mathbf{n}}\times\mathbf{r}\) is perpendicular to both \(\hat{\mathbf{n}}\) and \(\mathbf{r}\), it lies in the rotation plane, and

\[|\hat{\mathbf{n}}\times\mathbf{r}|=|\mathbf{r}|\sin\angle(\hat{\mathbf{n}},\mathbf{r})=|\mathbf{r}_{\perp}|,\]

so \(\{\mathbf{r}_{\perp},\hat{\mathbf{n}}\times\mathbf{r}\}\) is an orthogonal pair of equal length spanning that plane, with \(\hat{\mathbf{n}}\times\mathbf{r}\) exactly a quarter-turn ahead of \(\mathbf{r}_{\perp}\). It plays the role \(\mathbf{J}\mathbf{r}\) played in the plane.

Rotation about \(\hat{\mathbf{n}}\) splits \(\mathbf{r}\) into a fixed axial part \(\mathbf{r}_{\parallel}\) and a perpendicular part \(\mathbf{r}_{\perp}\) that travels on a circle. The tip of \(\mathbf{r}\) therefore moves on a circle in the plane orthogonal to the axis, at constant distance from it.

Within the rotation plane, the perpendicular component turns by \(\varphi\) in the frame just constructed:

\[\mathbf{r}_{\perp}'=\mathbf{r}_{\perp}\cos\varphi+(\hat{\mathbf{n}}\times\mathbf{r})\sin\varphi.\]

The same rotation seen inside the plane perpendicular to the axis. In the orthogonal frame \(\{\mathbf{r}_{\perp},\hat{\mathbf{n}}\times\mathbf{r}\}\), both of length \(|\mathbf{r}_{\perp}|\), the rotated component has coordinates \((\cos\varphi,\sin\varphi)\), exactly as in the two-dimensional case.

Adding back the untouched axial part and substituting \(\mathbf{r}_{\perp}=\mathbf{r}-(\hat{\mathbf{n}}\cdot\mathbf{r})\hat{\mathbf{n}}\) gives Rodrigues' rotation formula:

\[\begin{array}{rl} \mathbf{r}'&=\mathbf{r}_{\parallel}+\mathbf{r}_{\perp}'\\ &=(\hat{\mathbf{n}}\cdot\mathbf{r})\hat{\mathbf{n}} +\left(\mathbf{r}-(\hat{\mathbf{n}}\cdot\mathbf{r})\hat{\mathbf{n}}\right)\cos\varphi +(\hat{\mathbf{n}}\times\mathbf{r})\sin\varphi\\ \end{array}\]

and after collecting terms,

\[\boxed{\;\mathbf{r}'=\mathbf{r}\cos\varphi+(\hat{\mathbf{n}}\times\mathbf{r})\sin\varphi +(\hat{\mathbf{n}}\cdot\mathbf{r})\hat{\mathbf{n}}\,(1-\cos\varphi).\;}\]

Two sanity checks: for \(\mathbf{r}=\hat{\mathbf{n}}\) the cross product vanishes and the dot product is one, giving \(\mathbf{r}'=\hat{\mathbf{n}}\cos\varphi+\hat{\mathbf{n}}(1-\cos\varphi)=\hat{\mathbf{n}}\), so the axis is fixed; and for \(\varphi=0\) the formula collapses to \(\mathbf{r}'=\mathbf{r}\).

In matrix form, writing the cross product with \(\hat{\mathbf{n}}=(n_x,n_y,n_z)^T\) as the skew-symmetric matrix

\[[\hat{\mathbf{n}}]_\times:=\begin{pmatrix} 0&-n_z&n_y\\ n_z&0&-n_x\\ -n_y&n_x&0 \end{pmatrix}, \qquad [\hat{\mathbf{n}}]_\times\mathbf{r}=\hat{\mathbf{n}}\times\mathbf{r},\]

Rodrigues' formula becomes

\[\mathbf{R}(\hat{\mathbf{n}},\varphi) =\mathbf{I}+\sin\varphi\,[\hat{\mathbf{n}}]_\times+(1-\cos\varphi)\,[\hat{\mathbf{n}}]_\times^2 =\exp\!\left(\varphi[\hat{\mathbf{n}}]_\times\right),\]

the three-dimensional counterpart of \(\mathbf{R}(\alpha)=\exp(\alpha\mathbf{J})\). The identity \([\hat{\mathbf{n}}]_\times^3=-[\hat{\mathbf{n}}]_\times\), which is the three-dimensional echo of \(\mathbf{J}^2=-\mathbf{I}\), is what makes the exponential series collapse into sines and cosines again.

The rotation problem is, at this point, solved. Rodrigues' formula is correct, complete, and needs nothing beyond vector algebra. What it is not is composable: given two axis–angle pairs, there is no pleasant way to compute the axis and angle of their composition, and interpolating between two orientations expressed this way is awkward. That is the gap quaternions fill. Everything derived from here on must reproduce the boxed formula above, which serves as the reference.

Quaternions as Rotors

The quaternions extend \(\mathbb{C}\) by two further imaginary units, subject to Hamilton's rules

\[\mathbf{i}^2=\mathbf{j}^2=\mathbf{k}^2=\mathbf{ijk}=-1,\]

from which the pairwise products \(\mathbf{ij}=-\mathbf{ji}=\mathbf{k}\), \(\mathbf{jk}=-\mathbf{kj}=\mathbf{i}\) and \(\mathbf{ki}=-\mathbf{ik}=\mathbf{j}\) follow. A quaternion is written either by components or, more usefully here, as a scalar-vector pair:

\[\mathbf{q}=w+x\mathbf{i}+y\mathbf{j}+z\mathbf{k}=(w,\mathbf{v}),\qquad \mathbf{v}=(x,y,z)^T\in\mathbb{R}^3.\]

Only four facts about \(\mathbb{H}\) are needed below. The product, expressed in the pair notation, is

\[\mathbf{q}_1\mathbf{q}_2=\left(w_1w_2-\mathbf{v}_1\cdot\mathbf{v}_2,\; w_1\mathbf{v}_2+w_2\mathbf{v}_1+\mathbf{v}_1\times\mathbf{v}_2\right),\]

the conjugate flips the vector part, \(\overline{\mathbf{q}}=(w,-\mathbf{v})\), the norm is multiplicative and satisfies \(|\mathbf{q}|^2=\mathbf{q}\overline{\mathbf{q}}=w^2+|\mathbf{v}|^2\), and consequently a unit quaternion has \(\mathbf{q}^{-1}=\overline{\mathbf{q}}\). The cross product inside the product formula is where noncommutativity enters, and reversing the factors flips only that term.

A quaternion with zero scalar part is called pure, and pure quaternions are identified with vectors in \(\mathbb{R}^3\) throughout, writing \(\mathbf{v}\) for \((0,\mathbf{v})\). For two pure quaternions the product formula reduces to

\[\mathbf{v}_1\mathbf{v}_2=(-\mathbf{v}_1\cdot\mathbf{v}_2,\;\mathbf{v}_1\times\mathbf{v}_2),\]

so a single quaternion multiplication carries both the dot product and the cross product of two vectors. In particular, a unit pure quaternion satisfies

\[\hat{\mathbf{v}}^2=(-\hat{\mathbf{v}}\cdot\hat{\mathbf{v}},\;\hat{\mathbf{v}}\times\hat{\mathbf{v}})=(-1,\mathbf{0})=-1,\]

which means every unit vector in \(\mathbb{R}^3\) behaves like an imaginary unit. Each of them spans, together with the reals, a copy of \(\mathbb{C}\) inside \(\mathbb{H}\), and rotation about that particular axis will happen inside that copy.

Why a One-Sided Product Cannot Work

The obvious attempt is to imitate the plane and rotate by left multiplication, \(\mathbf{v}\mapsto\mathbf{q}\mathbf{v}\). It fails immediately. For a unit \(\mathbf{q}=(w,\mathbf{u})\) and a pure \(\mathbf{v}\),

\[\mathbf{q}\mathbf{v}=(-\mathbf{u}\cdot\mathbf{v},\;w\mathbf{v}+\mathbf{u}\times\mathbf{v}),\]

whose scalar part \(-\mathbf{u}\cdot\mathbf{v}\) is generally nonzero. The result is not a pure quaternion, so it is not a vector at all; the product has left the three-dimensional subspace it was supposed to act on. This is the structural difference from the plane, where vectors and rotors inhabited the same space. Here the vectors form a three-dimensional subspace of a four-dimensional algebra, and any operation used for rotation must map that subspace to itself.

Reflection Is a Quaternion Sandwich

The reflection route taken in the plane resolves this. Let \(\hat{\mathbf{m}}\) be a unit vector, regarded as a pure quaternion, and consider the two-sided product \(\hat{\mathbf{m}}\mathbf{v}\hat{\mathbf{m}}\). Expanding with the pure product formula,

\[\hat{\mathbf{m}}\mathbf{v}=(-\hat{\mathbf{m}}\cdot\mathbf{v},\;\hat{\mathbf{m}}\times\mathbf{v}),\]

and multiplying by \(\hat{\mathbf{m}}\) from the right gives, for the scalar part,

\[-(\hat{\mathbf{m}}\times\mathbf{v})\cdot\hat{\mathbf{m}}=0,\]

since \(\hat{\mathbf{m}}\times\mathbf{v}\) is perpendicular to \(\hat{\mathbf{m}}\). The result is pure, which is already the property that one-sided multiplication lacked. For the vector part,

\[\begin{array}{rl} \left[\hat{\mathbf{m}}\mathbf{v}\hat{\mathbf{m}}\right]_{\mathrm{vec}} &=-(\hat{\mathbf{m}}\cdot\mathbf{v})\hat{\mathbf{m}}+(\hat{\mathbf{m}}\times\mathbf{v})\times\hat{\mathbf{m}}\\ &=-(\hat{\mathbf{m}}\cdot\mathbf{v})\hat{\mathbf{m}} +\mathbf{v}(\hat{\mathbf{m}}\cdot\hat{\mathbf{m}})-\hat{\mathbf{m}}(\mathbf{v}\cdot\hat{\mathbf{m}})\\ &=\mathbf{v}-2(\hat{\mathbf{m}}\cdot\mathbf{v})\hat{\mathbf{m}}, \end{array}\]

using \((\mathbf{a}\times\mathbf{b})\times\mathbf{c}=\mathbf{b}(\mathbf{a}\cdot\mathbf{c})-\mathbf{a}(\mathbf{b}\cdot\mathbf{c})\) and \(|\hat{\mathbf{m}}|=1\). Therefore

\[\hat{\mathbf{m}}\mathbf{v}\hat{\mathbf{m}}=\mathbf{v}-2(\hat{\mathbf{m}}\cdot\mathbf{v})\hat{\mathbf{m}},\]

which is exactly the reflection of \(\mathbf{v}\) in the plane through the origin with normal \(\hat{\mathbf{m}}\): the component along the normal is negated, everything in the plane is kept. Reflections in \(\mathbb{H}\) are two-sided products, and unlike the complex case they are honestly linear, with no conjugation of the argument.

Two Reflections Give the Rotor

Now compose two of them. Reflect first in the plane with normal \(\hat{\mathbf{m}}_1\), then in the plane with normal \(\hat{\mathbf{m}}_2\):

\[\mathbf{v}\;\longmapsto\; \hat{\mathbf{m}}_2\left(\hat{\mathbf{m}}_1\mathbf{v}\hat{\mathbf{m}}_1\right)\hat{\mathbf{m}}_2 =\left(\hat{\mathbf{m}}_2\hat{\mathbf{m}}_1\right)\mathbf{v}\left(\hat{\mathbf{m}}_1\hat{\mathbf{m}}_2\right),\]

which used only associativity. Setting \(\mathbf{q}:=\hat{\mathbf{m}}_2\hat{\mathbf{m}}_1\), the right-hand factor is the product of the same two mirrors in reverse order, and

\[\overline{\mathbf{q}}=\overline{\hat{\mathbf{m}}_2\hat{\mathbf{m}}_1} =\overline{\hat{\mathbf{m}}_1}\,\overline{\hat{\mathbf{m}}_2} =(-\hat{\mathbf{m}}_1)(-\hat{\mathbf{m}}_2) =\hat{\mathbf{m}}_1\hat{\mathbf{m}}_2,\]

because conjugation reverses products and negates pure quaternions. So the composition of two reflections is precisely

\[\mathbf{v}'=\mathbf{q}\,\mathbf{v}\,\overline{\mathbf{q}}.\]

The sandwich is not a definition adopted for convenience; it is what two reflections do. The conjugate on the right is the reversed mirror order, and it cannot be moved to the left because \(\mathbb{H}\) does not commute. In the plane, the corresponding factors could be pushed together into \(\mathbf{q}^2\), which is the only reason the two-sided structure was invisible there.

Both mirror planes contain the rotation axis, so both normals are perpendicular to \(\hat{\mathbf{n}}\). Let \(\psi\) be the angle from \(\hat{\mathbf{m}}_1\) to \(\hat{\mathbf{m}}_2\), measured about \(\hat{\mathbf{n}}\), so that \(\hat{\mathbf{m}}_1\times\hat{\mathbf{m}}_2=\hat{\mathbf{n}}\sin\psi\). Then

\[\mathbf{q}=\hat{\mathbf{m}}_2\hat{\mathbf{m}}_1 =(-\hat{\mathbf{m}}_2\cdot\hat{\mathbf{m}}_1,\;\hat{\mathbf{m}}_2\times\hat{\mathbf{m}}_1) =(-\cos\psi,\;-\hat{\mathbf{n}}\sin\psi) =-\left(\cos\psi,\;\hat{\mathbf{n}}\sin\psi\right).\]

The overall minus sign is harmless here, because \(\mathbf{q}\) appears twice in the sandwich and \((-\mathbf{q})\mathbf{v}\overline{(-\mathbf{q})}=\mathbf{q}\mathbf{v}\overline{\mathbf{q}}\). It is, however, the first appearance of a fact that will be made precise shortly: the rotor is determined by the rotation only up to sign. Dropping it, the rotor built from a mirror pair at angle \(\psi\) is

\[\mathbf{q}=\left(\cos\psi,\;\hat{\mathbf{n}}\sin\psi\right)=\exp\left(\hat{\mathbf{n}}\psi\right),\]

the last equality being the quaternion exponential of a pure quaternion, which behaves exactly like \(e^{\mathbf{i}\psi}\) because \(\hat{\mathbf{n}}^2=-1\). Since two reflections at angle \(\psi\) produce a rotation by \(2\psi\), the rotor holds half the rotation angle:

\[\boxed{\;\hat{\mathbf{q}}=\left(\cos\frac{\varphi}{2},\;\hat{\mathbf{n}}\sin\frac{\varphi}{2}\right), \qquad \mathbf{r}'=\hat{\mathbf{q}}\,\mathbf{r}\,\overline{\hat{\mathbf{q}}}.\;}\]

The half angle is therefore not a normalisation trick. It is the angle between the two mirrors whose composition is the rotation, and it appeared in the plane for the same reason.

Direct Verification Against Rodrigues

The reflection argument explains the structure; a direct expansion confirms the result. Write \(c=\cos\frac{\varphi}{2}\), \(s=\sin\frac{\varphi}{2}\) and \(\hat{\mathbf{q}}=(c,s\hat{\mathbf{n}})\) with \(|\hat{\mathbf{n}}|=1\), and let \(\mathbf{v}\) be pure. The first product is

\[\hat{\mathbf{q}}\mathbf{v}=(-s\,\hat{\mathbf{n}}\cdot\mathbf{v},\;c\mathbf{v}+s\,\hat{\mathbf{n}}\times\mathbf{v}),\]

and multiplying by \(\overline{\hat{\mathbf{q}}}=(c,-s\hat{\mathbf{n}})\) gives for the scalar part

\[-cs(\hat{\mathbf{n}}\cdot\mathbf{v}) +s\left(c\,\mathbf{v}\cdot\hat{\mathbf{n}}+s(\hat{\mathbf{n}}\times\mathbf{v})\cdot\hat{\mathbf{n}}\right)=0,\]

so the result is again pure, as it must be. The vector part evaluates to

\[\begin{array}{rl} \left[\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}}\right]_{\mathrm{vec}} &=s^2(\hat{\mathbf{n}}\cdot\mathbf{v})\hat{\mathbf{n}}+c^2\mathbf{v}+cs(\hat{\mathbf{n}}\times\mathbf{v}) -cs(\mathbf{v}\times\hat{\mathbf{n}})-s^2(\hat{\mathbf{n}}\times\mathbf{v})\times\hat{\mathbf{n}}\\ &=s^2(\hat{\mathbf{n}}\cdot\mathbf{v})\hat{\mathbf{n}}+c^2\mathbf{v}+2cs(\hat{\mathbf{n}}\times\mathbf{v}) -s^2\left(\mathbf{v}-(\hat{\mathbf{n}}\cdot\mathbf{v})\hat{\mathbf{n}}\right)\\ &=(c^2-s^2)\,\mathbf{v}+2s^2(\hat{\mathbf{n}}\cdot\mathbf{v})\hat{\mathbf{n}}+2cs\,(\hat{\mathbf{n}}\times\mathbf{v}), \end{array}\]

where \(\mathbf{v}\times\hat{\mathbf{n}}=-(\hat{\mathbf{n}}\times\mathbf{v})\) and the same triple-product identity as before were used. Now the half-angle identities

\[c^2-s^2=\cos\varphi,\qquad 2s^2=1-\cos\varphi,\qquad 2cs=\sin\varphi\]

turn this into

\[\mathbf{v}'=\mathbf{v}\cos\varphi+(\hat{\mathbf{n}}\times\mathbf{v})\sin\varphi +(\hat{\mathbf{n}}\cdot\mathbf{v})\hat{\mathbf{n}}(1-\cos\varphi),\]

which is Rodrigues' formula, unchanged. The sandwich product with a half-angle rotor and the geometric derivation describe the same map, and the doubling of the angle is now visible in three independent ways: as the two mirror planes, as the half-angle identities above, and as the two occurrences of \(\hat{\mathbf{q}}\) in the product.

Why the Sandwich Is a Rotation at All

It is instructive to see that the map \(\Phi(\mathbf{v})=\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}}\) must be a rotation, without computing anything. Four observations suffice:

Hence \(\Phi\in SO(3)\). The axis is found just as quickly: for \(\mathbf{v}=\hat{\mathbf{n}}\), the cross product vanishes and \(\hat{\mathbf{n}}\) commutes with \(\hat{\mathbf{q}}=(c,s\hat{\mathbf{n}})\), so

\[\hat{\mathbf{q}}\hat{\mathbf{n}}\overline{\hat{\mathbf{q}}} =\hat{\mathbf{n}}\hat{\mathbf{q}}\overline{\hat{\mathbf{q}}}=\hat{\mathbf{n}},\]

confirming that the vector part of the rotor is the rotation axis. The angle then follows from the trace, or from applying the map to any vector perpendicular to the axis.

The Plane as a Special Case

Taking \(\hat{\mathbf{n}}=\mathbf{e}_z\) closes the loop. The rotor is \(\hat{\mathbf{q}}=(\cos\frac{\varphi}{2},0,0,\sin\frac{\varphi}{2})\), and it lives in the copy of \(\mathbb{C}\) spanned by \(1\) and \(\mathbf{k}\). Applying Rodrigues' formula to a vector \(\mathbf{r}=(x,y,0)^T\) in the \(xy\)-plane gives \(\hat{\mathbf{n}}\cdot\mathbf{r}=0\) and \(\hat{\mathbf{n}}\times\mathbf{r}=(-y,x,0)^T\), hence

\[\mathbf{r}'=\begin{pmatrix}x\cos\varphi-y\sin\varphi\\x\sin\varphi+y\cos\varphi\\0\end{pmatrix},\]

the plane rotation matrix from the beginning of the chapter. The complex rotor \(e^{\mathbf{i}\alpha}\) is the quaternion rotor restricted to a single fixed axis, with its two half-angle factors collapsed into one.

The Double Cover

Unit quaternions form the unit sphere \(S^3=\{\mathbf{q}\in\mathbb{H}:|\mathbf{q}|=1\}\) in four dimensions, and the sandwich map sends every point of \(S^3\) to a rotation. The correspondence is not one-to-one. Since \(\mathbf{q}\) occurs twice,

\[(-\hat{\mathbf{q}})\,\mathbf{v}\,\overline{(-\hat{\mathbf{q}})} =(-1)(-1)\,\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}} =\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}},\]

so \(\hat{\mathbf{q}}\) and \(-\hat{\mathbf{q}}\) produce exactly the same rotation. Read through the axis–angle parameterisation, the two describe a rotation by \(\varphi\) about \(\hat{\mathbf{n}}\) and a rotation by \(2\pi-\varphi\) about \(-\hat{\mathbf{n}}\), which are indeed the same motion:

\[-\left(\cos\frac{\varphi}{2},\hat{\mathbf{n}}\sin\frac{\varphi}{2}\right) =\left(\cos\frac{2\pi-\varphi}{2},(-\hat{\mathbf{n}})\sin\frac{2\pi-\varphi}{2}\right).\]

A two-dimensional slice through \(S^3\) containing the real axis and one axis direction. Antipodal points \(\hat{\mathbf{q}}\) and \(-\hat{\mathbf{q}}\) describe the same rotation, so a full turn of the rotor, \(\psi:0\to2\pi\), traverses every rotation twice while the physical angle \(\varphi=2\psi\) runs from \(0\) to \(4\pi\).

The map \(S^3\to SO(3)\) is thus two-to-one; it is a double cover. The half angle is what makes it so: as the rotor travels once around a great circle, the physical rotation angle passes through \(4\pi\), i.e. two full turns. In particular \(\hat{\mathbf{q}}=1\) and \(\hat{\mathbf{q}}=-1\) both represent the identity rotation, even though they are antipodal on \(S^3\).

This is not a defect of the representation but a fact about \(SO(3)\), which is not simply connected: a path of rotations that returns to its start after one full turn cannot be contracted to a point, while one that turns twice can. The familiar demonstrations, rotating a plate on the palm of a hand or untwisting a belt through two full turns, are precisely this property.

Three practical consequences follow:

Composing and Inverting Rotations

The reason for introducing quaternions was composability, so this is where the payoff is. Rotate first by \(\hat{\mathbf{q}}_1\), then by \(\hat{\mathbf{q}}_2\):

\[\begin{array}{rl} \mathbf{r}''&=\hat{\mathbf{q}}_2\left(\hat{\mathbf{q}}_1\mathbf{r}\,\overline{\hat{\mathbf{q}}_1}\right)\overline{\hat{\mathbf{q}}_2}\\ &=\left(\hat{\mathbf{q}}_2\hat{\mathbf{q}}_1\right)\mathbf{r} \left(\overline{\hat{\mathbf{q}}_1}\,\overline{\hat{\mathbf{q}}_2}\right)\\ &=\left(\hat{\mathbf{q}}_2\hat{\mathbf{q}}_1\right)\mathbf{r} \,\overline{\left(\hat{\mathbf{q}}_2\hat{\mathbf{q}}_1\right)}, \end{array}\]

using associativity and \(\overline{\mathbf{ab}}=\overline{\mathbf{b}}\,\overline{\mathbf{a}}\). Composition of rotations is multiplication of rotors, in the same right-to-left order as matrices:

\[\hat{\mathbf{q}}_{2\circ1}=\hat{\mathbf{q}}_2\hat{\mathbf{q}}_1.\]

Since the norm is multiplicative, the product of two unit quaternions is again a unit quaternion, so the composition stays in the representation without any repair step. The inverse rotation is the conjugate,

\[\overline{\hat{\mathbf{q}}}\left(\hat{\mathbf{q}}\mathbf{r}\overline{\hat{\mathbf{q}}}\right)\hat{\mathbf{q}}=\mathbf{r},\]

which negates the axis and thus reverses the angle, at the cost of three sign flips.

The comparison with matrices is straightforward. A quaternion product costs \(16\) multiplications and \(12\) additions; a \(3\times3\) matrix product costs \(27\) and \(18\). A quaternion needs four numbers instead of nine. More importantly, repeated composition degrades differently: accumulated floating-point error pushes a quaternion off the unit sphere, and dividing by its norm restores it exactly, while a drifting rotation matrix has to be re-orthonormalised, which is considerably more work.

Quaternions and Rotation Matrices

Rendering pipelines, solvers and sensor code all expect matrices at some point, so both directions of the conversion are needed. Applying the expansion from above to the three basis vectors gives the columns of the matrix directly. With \(\hat{\mathbf{q}}=(w,x,y,z)\) and \(w^2+x^2+y^2+z^2=1\),

\[\boxed{\;\mathbf{R}(\hat{\mathbf{q}})=\begin{pmatrix} 1-2(y^2+z^2)&2(xy-wz)&2(xz+wy)\\ 2(xy+wz)&1-2(x^2+z^2)&2(yz-wx)\\ 2(xz-wy)&2(yz+wx)&1-2(x^2+y^2) \end{pmatrix}.\;}\]

As a check on the first column, take \(\mathbf{v}=\mathbf{e}_x\) in the expansion \(\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}}=(w^2-|\mathbf{u}|^2)\mathbf{v}+2(\mathbf{u}\cdot\mathbf{v})\mathbf{u}+2w(\mathbf{u}\times\mathbf{v})\) with \(\mathbf{u}=(x,y,z)^T\). Then \(\mathbf{u}\cdot\mathbf{v}=x\) and \(\mathbf{u}\times\mathbf{v}=(0,z,-y)^T\), so the image is

\[\begin{pmatrix}w^2-x^2-y^2-z^2+2x^2\\2xy+2wz\\2xz-2wy\end{pmatrix} =\begin{pmatrix}1-2(y^2+z^2)\\2(xy+wz)\\2(xz-wy)\end{pmatrix},\]

where the unit-norm condition was used in the first entry. Note that every entry is quadratic in the components, which is the algebraic form of the double cover: replacing \(\hat{\mathbf{q}}\) by \(-\hat{\mathbf{q}}\) leaves all quadratic terms unchanged.

Recovering a Quaternion from a Matrix

The reverse direction starts from the trace. Summing the diagonal of \(\mathbf{R}(\hat{\mathbf{q}})\),

\[\operatorname{tr}\mathbf{R}=3-4(x^2+y^2+z^2)=3-4(1-w^2)=4w^2-1,\]

so \(w=\frac{1}{2}\sqrt{1+\operatorname{tr}\mathbf{R}}\) up to the unavoidable sign. The off-diagonal differences then give the vector part, since the symmetric parts cancel:

\[R_{32}-R_{23}=4wx,\qquad R_{13}-R_{31}=4wy,\qquad R_{21}-R_{12}=4wz.\]

Dividing by \(4w\) finishes the job, but only if \(w\) is not small. For a rotation close to a half-turn, \(\operatorname{tr}\mathbf{R}\to-1\) and \(w\to 0\), and the division loses all precision. The standard remedy is to solve for the largest component instead. The four candidate expressions

\[\begin{array}{rl} 4w^2&=1+R_{11}+R_{22}+R_{33},\\ 4x^2&=1+R_{11}-R_{22}-R_{33},\\ 4y^2&=1-R_{11}+R_{22}-R_{33},\\ 4z^2&=1-R_{11}-R_{22}+R_{33} \end{array}\]

always contain at least one that is \(\ge 1\), since they sum to \(4\). Taking the square root of the largest one and obtaining the remaining three components from the appropriate sums and differences of off-diagonal entries keeps the divisor safely away from zero. This branch-selecting algorithm is due to Shepperd, and any robust implementation uses it rather than the trace formula alone.

Efficient Rotation of a Vector

Evaluating \(\hat{\mathbf{q}}\mathbf{v}\overline{\hat{\mathbf{q}}}\) as two quaternion products wastes work: the scalar part of the result is known in advance to be zero, and half of the intermediate terms cancel. Starting again from

\[\mathbf{v}'=(w^2-|\mathbf{u}|^2)\mathbf{v}+2(\mathbf{u}\cdot\mathbf{v})\mathbf{u}+2w(\mathbf{u}\times\mathbf{v}),\]

the dot product can be eliminated with the triple-product identity \(\mathbf{u}\times(\mathbf{u}\times\mathbf{v})=(\mathbf{u}\cdot\mathbf{v})\mathbf{u}-|\mathbf{u}|^2\mathbf{v}\). Substituting and using \(w^2+|\mathbf{u}|^2=1\) collapses everything into

\[\boxed{\;\mathbf{t}=2\,\mathbf{u}\times\mathbf{v}, \qquad \mathbf{v}'=\mathbf{v}+w\,\mathbf{t}+\mathbf{u}\times\mathbf{t}.\;}\]

Two cross products, one scaling and two vector additions: about \(18\) multiplications and \(12\) additions, against \(28\) multiplications and \(20\) additions for the naive double product. This is the form used in practice, and it is what Quaternion.js implements in rotateVector. A longer discussion of the algebraic reduction is in the article on vector rotation using quaternions.

const q = Quaternion.fromAxisAngle([0, 0, 1], Math.PI / 2);

q.rotateVector([1, 0, 0]);          // [0, 1, 0]
q.mul(q).rotateVector([1, 0, 0]);   // [-1, 0, 0]
q.conjugate().rotateVector([1, 0, 0]); // [0, -1, 0]

The cost comparison with matrices depends on how many vectors are involved. A single matrix–vector product needs \(9\) multiplications and \(6\) additions, which is cheaper than the sandwich, but building the matrix from a quaternion already costs about a dozen operations. Rotating one or two vectors is faster directly from the quaternion; rotating a mesh is faster after converting once to a matrix. Storing, composing and interpolating orientations is where the quaternion is unambiguously better.

Interpolating Orientations

Interpolation is the operation that makes the unit-sphere picture pay off. Linear interpolation of the components,

\[\mathbf{q}(t)=(1-t)\hat{\mathbf{q}}_0+t\hat{\mathbf{q}}_1,\]

leaves the unit sphere: it follows the chord instead of the sphere, so the result has to be renormalised, and even then the rotation rate is not constant. The correct path is the great-circle arc, which is what the exponential and logarithm provide. For a unit quaternion, \(\log\hat{\mathbf{q}}=\hat{\mathbf{n}}\psi\) is pure, and

\[\hat{\mathbf{q}}^{\,t}=\exp\left(t\log\hat{\mathbf{q}}\right)=\left(\cos t\psi,\;\hat{\mathbf{n}}\sin t\psi\right),\]

which simply scales the angle. Applying this to the relative rotation between the endpoints gives spherical linear interpolation:

\[\operatorname{slerp}(\hat{\mathbf{q}}_0,\hat{\mathbf{q}}_1;t) =\hat{\mathbf{q}}_0\left(\overline{\hat{\mathbf{q}}_0}\hat{\mathbf{q}}_1\right)^{t}.\]

Read from left to right, this undoes the start orientation, takes the \(t\)-th fraction of what remains, and applies it to the start again. Because \(\overline{\hat{\mathbf{q}}_0}\hat{\mathbf{q}}_1\) is a rotation about a fixed axis, the interpolated motion is a rotation about a fixed axis at constant angular speed, which is exactly the shortest path between the two orientations. Writing \(\cos\Omega=\hat{\mathbf{q}}_0\cdot\hat{\mathbf{q}}_1\) for the four-dimensional dot product, the same curve has the closed form

\[\operatorname{slerp}(\hat{\mathbf{q}}_0,\hat{\mathbf{q}}_1;t) =\frac{\sin\left((1-t)\Omega\right)}{\sin\Omega}\hat{\mathbf{q}}_0 +\frac{\sin\left(t\Omega\right)}{\sin\Omega}\hat{\mathbf{q}}_1,\]

which is the usual arc interpolation of two unit vectors and needs no quaternion multiplication at all.

Equally spaced parameter values \(t\) on the chord between \(\hat{\mathbf{q}}_0\) and \(\hat{\mathbf{q}}_1\), projected back onto the sphere, are not equally spaced in angle: the samples bunch up towards the middle. Spherical linear interpolation follows the arc itself and keeps the angular speed constant.

Two details decide whether an implementation is usable:

Normalised linear interpolation, nlerp, is the cheap alternative: interpolate the components, then divide by the norm. It stays on the sphere and follows the same path as slerp, but not at constant speed. For small steps, for instance between adjacent animation frames, the difference is invisible and the saving is real; for a slow camera sweep between two distant orientations it shows up as a visible speed-up in the middle.

Angular Velocity and Integration

A rotation that changes over time gives one more independent sighting of the factor \(\frac{1}{2}\). Let \(\hat{\mathbf{q}}(t)\) be a differentiable curve of unit quaternions. Differentiating \(\hat{\mathbf{q}}\overline{\hat{\mathbf{q}}}=1\) yields

\[\dot{\hat{\mathbf{q}}}\,\overline{\hat{\mathbf{q}}}+\hat{\mathbf{q}}\,\overline{\dot{\hat{\mathbf{q}}}}=0,\]

and since \(\hat{\mathbf{q}}\overline{\dot{\hat{\mathbf{q}}}}=\overline{\dot{\hat{\mathbf{q}}}\overline{\hat{\mathbf{q}}}}\), the quantity \(\dot{\hat{\mathbf{q}}}\overline{\hat{\mathbf{q}}}\) equals the negative of its own conjugate and is therefore pure. Call it \(\frac{1}{2}\boldsymbol{\omega}\), so that

\[\dot{\hat{\mathbf{q}}}=\tfrac{1}{2}\boldsymbol{\omega}\,\hat{\mathbf{q}}.\]

The factor is a definition at this stage; the following computation is what justifies it. For a body-fixed vector \(\mathbf{r}_0\), the rotated vector is \(\mathbf{r}=\hat{\mathbf{q}}\mathbf{r}_0\overline{\hat{\mathbf{q}}}\), and with \(\overline{\dot{\hat{\mathbf{q}}}}=-\frac{1}{2}\overline{\hat{\mathbf{q}}}\boldsymbol{\omega}\),

\[\dot{\mathbf{r}} =\dot{\hat{\mathbf{q}}}\mathbf{r}_0\overline{\hat{\mathbf{q}}}+\hat{\mathbf{q}}\mathbf{r}_0\overline{\dot{\hat{\mathbf{q}}}} =\tfrac{1}{2}\left(\boldsymbol{\omega}\mathbf{r}-\mathbf{r}\boldsymbol{\omega}\right).\]

For two pure quaternions the product formula gives \(\boldsymbol{\omega}\mathbf{r}-\mathbf{r}\boldsymbol{\omega}=(0,2\,\boldsymbol{\omega}\times\mathbf{r})\), the dot products cancelling and the cross products doubling, so

\[\dot{\mathbf{r}}=\boldsymbol{\omega}\times\mathbf{r},\]

the standard rigid-body relation, with \(\boldsymbol{\omega}\) the angular velocity in the fixed frame. The \(\frac{1}{2}\) in the quaternion equation is precisely what the two-sided product doubles away, the same half angle seen from the derivative side. Using the body-frame angular velocity instead puts it on the other side, \(\dot{\hat{\mathbf{q}}}=\frac{1}{2}\hat{\mathbf{q}}\boldsymbol{\omega}_{\text{body}}\).

For integration this is convenient. Over a step \(\Delta t\) with roughly constant \(\boldsymbol{\omega}\),

\[\hat{\mathbf{q}}(t+\Delta t)=\exp\left(\tfrac{1}{2}\Delta t\,\boldsymbol{\omega}\right)\hat{\mathbf{q}}(t), \qquad \exp\left(\tfrac{1}{2}\Delta t\,\boldsymbol{\omega}\right) =\left(\cos\frac{|\boldsymbol{\omega}|\Delta t}{2},\; \frac{\boldsymbol{\omega}}{|\boldsymbol{\omega}|}\sin\frac{|\boldsymbol{\omega}|\Delta t}{2}\right).\]

The exponential map lands on the unit sphere exactly, so this step preserves normalisation by construction, unlike a plain Euler step \(\hat{\mathbf{q}}+\Delta t\,\dot{\hat{\mathbf{q}}}\), which leaves the sphere and needs renormalising. This is how orientation is propagated in attitude filters and IMU integration. Body- and world-frame rates, angular acceleration, group-aware finite differences, and tangent-space Jacobians follow from the same quaternion derivative.

Euler Angles and Gimbal Lock

The competing representation stacks three rotations about coordinate axes. With the common \(z\)-\(y\)-\(x\) sequence,

\[\mathbf{R}=\mathbf{R}_z(\alpha)\mathbf{R}_y(\beta)\mathbf{R}_x(\gamma) =\begin{pmatrix} c_\alpha c_\beta&c_\alpha s_\beta s_\gamma-s_\alpha c_\gamma&c_\alpha s_\beta c_\gamma+s_\alpha s_\gamma\\ s_\alpha c_\beta&s_\alpha s_\beta s_\gamma+c_\alpha c_\gamma&s_\alpha s_\beta c_\gamma-c_\alpha s_\gamma\\ -s_\beta&c_\beta s_\gamma&c_\beta c_\gamma \end{pmatrix},\]

with \(c_\alpha=\cos\alpha\) and so on. Reading the angles back off the matrix is direct:

\[\beta=-\arcsin R_{31},\qquad \alpha=\operatorname{atan2}(R_{21},R_{11}),\qquad \gamma=\operatorname{atan2}(R_{32},R_{33}).\]

The failure is visible in these formulas. When \(\beta=\pm\frac{\pi}{2}\), \(\cos\beta=0\) and the four entries \(R_{11},R_{21},R_{32},R_{33}\) all vanish, leaving both \(\operatorname{atan2}\) calls undefined. Geometrically, the first and third rotation axes have become parallel, so they perform the same motion and only one combination of the two angles survives: \(\gamma-\alpha\) for \(\beta=+\frac{\pi}{2}\) and \(\gamma+\alpha\) for \(\beta=-\frac{\pi}{2}\). One degree of freedom has been lost from the parameterisation, not from the rotation. That is gimbal lock. Near the singularity it is worse than at it, since small changes in orientation force large changes in the angles, which is exactly what makes interpolation in Euler angles unusable there.

No choice of axis sequence removes the problem. Any three-parameter description of \(SO(3)\) must be singular somewhere, because \(SO(3)\) is a compact three-dimensional manifold and cannot be covered by a single nonsingular chart. Quaternions do not evade this by being cleverer, but by being redundant: four coordinates with one constraint, \(|\hat{\mathbf{q}}|=1\), instead of three free ones. The price is the two-to-one ambiguity of the double cover, which is far easier to handle than a coordinate singularity, since it amounts to a sign convention.

Common Pitfalls

Connections

The algebraic side of \(\mathbb{H}\), including its exponential, logarithm, powers and polar decomposition, is developed in the chapter on quaternions; the plane case that started this chapter is treated in full in complex numbers. The two vector operations hidden inside a single quaternion product are the dot product and the 3D cross product, and the quarter-turn that generates plane rotations is the 2D perp operator.

Constructing the rotor that carries one given direction into another is treated separately in quaternion from two vectors, and the reduced evaluation of the sandwich product in vector rotation using quaternions. Sampling orientations without bias, which is a question about the measure on \(S^3\) rather than about the algebra, is covered in uniform random rotations. An interactive application of everything above is trackball rotation using quaternions, and a worked engineering use is the inverse kinematics of a Stewart platform. The JavaScript implementation used in the code above is Quaternion.js, with Vector3.js for the vector algebra and Complex.js for the two-dimensional case. Symbolic derivations of the identities above can be reproduced with quaternion operations in SymPy.

References