2d rotation

A 2d rotation has only one parameter \(\theta\), when the basis vectors \(\unit{i} = [1, 0]\) and \(\unit{j} = [0, 1]\) are rotated by an angle \(\theta\)

\[ \mbold{p} = \cos{\theta} \unit{i} + \sin{\theta} \unit{j} \\ \mbold{q} = -\sin{\theta} \unit{i} + \cos{\theta} \unit{j} \]

Which builds the rotation matrix

\[ \mbold{R}(\theta) = \begin{bmatrix} \textbf{p} \\ \textbf{q} \end{bmatrix} = \begin{bmatrix} \cos{\theta} & \sin{\theta} \\ -\sin{\theta} & \cos{\theta} \end{bmatrix} \]

When a vector \(\mbold{v}\) is transformed by this matrix we know that the vector will be a linear combination of the basis which are \(\mbold{p}\) and \(\mbold{q}\)

\[ \begin{align*} \mbold{v'} = \mbold{vR}(\theta) &= v_x \mbold{p} + v_y \mbold{q} \\ &= v_x \begin{bmatrix}\cos{\theta} & \sin{\theta}\end{bmatrix} + v_y \begin{bmatrix}-\sin{\theta} & \cos{\theta}\end{bmatrix} \\ &= \begin{bmatrix} v_x \cos{\theta} - v_y \sin{\theta} \\ v_x \sin{\theta} + v_y \cos{\theta} \end{bmatrix}^T \end{align*} \]

Using a matrix to encode this operation

\[ \begin{align*} \mbold{v'} = \mbold{vR}(\theta) &= \begin{bmatrix}v_x & v_y\end{bmatrix} \begin{bmatrix} \cos{\theta} & \sin{\theta} \\ -\sin{\theta} & \cos{\theta} \end{bmatrix} \\ &= \begin{bmatrix} v_x \cos{\theta} - v_y \sin{\theta} \\ v_x \sin{\theta} + v_y \cos{\theta} \end{bmatrix}^T \end{align*} \]

See also complex numbers

3d rotation

About cardinal axes

\[ \mathbf{R_x}(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos{\alpha} & -\sin{\alpha} \\ 0 & \sin{\alpha} & \cos{\alpha} \end{bmatrix} \]

\[ \mathbf{R_y}(\beta) = \begin{bmatrix} \cos{\beta} & 0 & \sin{\beta} \\ 0 & 1 & 0 \\ -\sin{\beta} & 0 & \cos{\beta} \end{bmatrix} \]

\[ \mathbf{R_z}(\gamma) = \begin{bmatrix} \cos{\gamma} & -\sin{\gamma} & 0 \\ \sin{\gamma} & \cos{\gamma} & 0 \\ 0 & 0 & 1 \end{bmatrix} \]

See also

About an arbitrary axis

Given an axis \(\unit{n}\) and an amount of rotation around it \(\theta\) our goal is to find a rotation matrix that rotates about \(\unit{n}\) by th angle \(\theta\)

\[ \mathbf{v'} = \mathbf{R}(\unit{n}, \theta)\mathbf{v} \]

The basic idea is to solve this problem in a plane perpendicular to \(\unit{n}\) which becomes a 2d problem

Separate \(\mbold{v}\) in two vectors, a vector parallel to \(\unit{v}\) called \(\mbold{v_{\parallel}}\) and a vector perpendicular to \(\unit{v}\) called \(\mbold{v_{\perp}}\) such that \(\mbold{v_{\parallel}} + \mbold{v_{\perp}} = \mbold{v}\)

\[ \begin{align*} \mbold{v_{\parallel}} &= (\mbold{v} \cdot \unit{n}) \unit{n} \\ \mbold{v_{\perp}} &= \mbold{v} - \mbold{v_{\parallel}} \end{align*} \]

After the rotation it's obvious that the \(\mbold{v_{\parallel}}\) component will be the same and only the vector \(\mbold{v_{\perp}}\) will be rotated

A plane can be defined with two vectors that lie on it, since we have \(\mbold{v_{\perp}}\) and we also know the normal of the plane (which is \(\unit{n}\)) any vector perpendicular to both vectors will also lie in the plane, we can use the cross product to find this vector

\[ \mbold{w} = \unit{n} \times \mbold{v_{\perp}} \]

The length of \(\mbold{w}\) is

\[ \begin{align*} \left \| \mbold{w} \right \| &= \left \| \unit{n} \right \| \left \| \mbold{v_{\perp}}\right \| \sin{\deg{90}} \\ &= \left \| \mbold{v_{\perp}}\right \| \end{align*} \]

Which means that \(\mbold{w}\) has the same length as \(\mbold{v_{\perp}}\), note that even though they have the same length they don't neccesarily have unit length

\(\mbold{w}\) and \(\mbold{v_{\perp}}\) form now a 2d coordinate space where the \(x\)-axis is \(\mbold{v_{\perp}}\) and the \(y\)-axis is \(\mbold{v_{\perp}}\)

Let \(\mbold{v_{\perp}'}\) be a vector that is the result of rotating \(\mbold{v_{\perp}}\) by an angle \(\theta\), we can find the projection of it onto the \(x\)-axis and the \(y\)-axis as follows

\[ \begin{align*} \mbold{v_{\perp,x}'} &= (\magnitude{ \mbold{v_{\perp}} } \cos{\theta}) \unit{v_{\perp}} = \cos{\theta} \mbold{v_{\perp}}\\ \mbold{v_{\perp,y}'} &= (\magnitude{ \mbold{v_{\perp}} } \sin{\theta}) \unit{w} = \sin{\theta} \mbold{w} \end{align*} \]

  • Expressing \[\mbold{v_{\perp}'}\] as a linear combination of the basis

\[ \mbold{v_{\perp}'} = \cos{\theta} \mbold{v_{\perp}} + \sin{\theta} \mbold{w} \]

Reconstructing the solution from the observations above

\[ \begin{align*} \mbold{v_{\parallel}} &= (\mbold{v} \cdot \unit{n}) \unit{n} \\ \mbold{v_{\perp}} &= \mbold{v} - \mbold{v_{\parallel}} \\ &= \mbold{v} - (\mbold{v} \cdot \unit{n}) \unit{n} \\ \mbold{w} &= \unit{n} \times \mbold{v_{\perp}} \\ &= \unit{n} \times (\mbold{v} - \mbold{v_{\parallel}}) \\ &= \unit{n} \times \mbold{v} - \unit{n} \times \mbold{v_{\parallel}} \\ &= \unit{n} \times \mbold{v} \end{align*} \]

Finally

\[ \begin{align} \mbold{v'} &= \mbold{v_{\perp}'} + \mbold{v_{\parallel}'} \nonumber \\ &= \cos{\theta} \mbold{v_{\perp}} + \sin{\theta} \mbold{w} + (\mbold{v} \cdot \unit{n}) \unit{n} \nonumber \\ &= \cos{\theta} (\mbold{v - (\mbold{v} \cdot \unit{n}) \unit{n}}) + \sin{\theta} (\unit{n} \times \mbold{v}) + (\mbold{v} \cdot \unit{n}) \unit{n} \nonumber \\ &= \cos{\theta} \mbold{v} - \cost (\mathbf{v} \cdot \unit{n}) \unit{n} + \sin{\theta} (\unit{n} \times \mbold{v}) + (\mbold{v} \cdot \unit{n}) \unit{n} \nonumber \\ &= \cos{\theta} \mbold{v} + \sin{\theta} (\unit{n} \times \mbold{v}) + (1 - \cost)(\mathbf{v} \cdot \unit{n}) \unit{n} \label{3d-rotation} \end{align} \]

Now we can compute what the basis vectors are after the transformation above (by using each of the basis vectors as \(\mbold{v}\) on \eqref{3d-rotation}) to construct a rotation matrix

\[ \begin{align*} \mbold{p} &= \begin{bmatrix}1 \\ 0 \\ 0\end{bmatrix} \quad \quad \quad \quad \mbold{p'} = \begin{bmatrix} n_x^2(1 - \cost) + \cost \\ n_xn_y(1 - \cost) + n_z \sint \\ n_xn_z(1 - \cost) - n_z \sint \end{bmatrix}\\ \\ \mbold{q} &= \begin{bmatrix}0 \\ 1 \\ 0\end{bmatrix} \quad \quad \quad \quad \mbold{q'} = \begin{bmatrix} n_yn_x(1 - \cost) - n_z \sint \\ n_y^2(1 - \cost) + \cost \\ n_yn_z(1 - \cost) + n_x \sint \end{bmatrix}\\ \\ \mbold{r} &= \begin{bmatrix}0 \\ 0 \\ 1\end{bmatrix} \quad \quad \quad \quad \mbold{r'} = \begin{bmatrix} n_zn_x(1 - \cost) + n_y \sint \\ n_zn_y(1 - \cost) - n_x \sint \\ n_z^2(1 - \cost) + \cost \end{bmatrix}\\ \end{align*} \]

Constructing the matrix from these vectors

\[ \mathbf{R}(\unit{n}, \theta) = \begin{bmatrix} \mbold{p'} & \mbold{q'} & \mbold{r'} \end{bmatrix} \]

3d rotations using quaternions

See complex numbers and quaternions

A complex rotor is a unit norm complex number which rotates another complex number by the angle \(\theta\) and has the form

\[ e^{i\theta} = \cost + i \sint \]

Hamilton had hoped that a unit-norm quaternion \(q\) could be used to rotate a vector which is stored as a pure quaternion \(p\), the unit norm quaternion is given by

\[ \begin{align} q &= [s, \lambda \unit{n}] \quad s,\lambda \in \mathbb{R}, \unit{n} \in \mathbb{R}^3 \label{unit-norm-quaternion}\\ \left | \unit{n} \right | &= 1 \nonumber \\ s^2 + \lambda^2 &= 1 \nonumber \end{align} \]

\[ p = [0, \mbold{v}] \quad \mbold{v} \in \mathbb{R}^3 \]

Let's compute the product \(p' = qp\)

\[ \begin{align} p' &= qp \nonumber \\ &= [s, \lambda \unit{n}][0, \mathbf{v}] \nonumber \\ &= [-\lambda \unit{n} \cdot \mathbf{v}, s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}] \label{p-prime} \end{align} \]

Special case

What if \(\unit{n}\) is perpendicular to \(\mathbf{v}\)? Then the scalar quantity of \eqref{p-prime} is zero and we are left with the pure quaternion

\[ \begin{equation} \label{p-prime-perpendicular} p' = [0, s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}] \quad\quad \text{given that $\unit{n}$ is perpendicular to $\mathbf{n}$} \end{equation} \]

Let's analyze the vector part of \(\eqref{p-prime-perpendicular}\) (which is now a 3d entity because it's a pure quaternion), since \(\unit{n}\) is perpendicular to \(\mathbf{v}\) then the vector \(\unit{n} \times \mathbf{v}\) will have a norm equal to \(\magnitude{ \unit{n} \times \mathbf{v} } = \magnitude{ \unit{n} } \magnitude { \mathbf{v} } \sin{\deg{90}}\) and also since \(\unit{n}\) is a unit vector then \(\magnitude{\unit{n} \times \mathbf{v}} = \magnitude{\mathbf{v}}\) which means that we have two orthogonal vectors with the same length

To rotate the vector \(\mathbf{v}\) about \(\unit{n}\) let's transform \(\mathbf{v}\) to the 2d space whose basis vectors are \(\mathbf{v}\) and \(\unit{n} \times \mathbf{v}\) and perform the rotation there which is trivially \([\cost, \sint]\), therefore all we have to do in \eqref{p-prime-perpendicular} is make the scalar quantities multiplying each vector equal the projection of the rotated vector over the basis

\[ p' = [0, \cost \mathbf{v} + \sint \unit{n} \times \mathbf{v}] \]

Which makes the quaternion \(\mathbf{q}\) have the form

\[ \begin{align} q &= [\cost, \sint \unit{n}] \label{perp-rotor} \end{align} \]

And it acts as a rotor only when \(\unit{n}\) is perpendicular to \(\mathbf{v}\)

Important notes/facts about orthogonal quaternions

  • If \(q\) is a rotor about the unit vector \(\unit{n}\) by an angle \(\theta\) whose vector term is perpendicular to the pure quaternion \(p\)
    • \(qp\) and \(pq^{-1}\) rotate \(p\) by an angle \(\theta\) about \(\unit{n}\)
    • \(pq\) and \(q^{-1}p\) rotate \(p\) by an angle \(-\theta\) about \(\unit{n}\)
    • Each of these products leave \(p'\) unscaled (because \(q\) is a unit norm quaternion)

General case

Let's use \eqref{unit-norm-quaternion} as the starting point, note that this time its vector part it's not necessarily perpendicular to the pure quaternion \(p\), the product \(qp\) yields

\[ \begin{align*} qp &= [s, \lambda \unit{n}][0, \mathbf{v}] \\ &= [-\lambda \unit{n} \cdot \mathbf{v}, s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}] \end{align*} \]

Note that the term \(-\lambda \unit{n} \cdot \mathbf{v}\) does not vanish since for the general case \(\unit{n}\) and \(\mathbf{v}\) are no longer perpendicular, what's more important is that the product \(qp\) is no longer a pure quaternion, multiplying a vector by a non-orthogonal quaternion has converted some of the vector information into the quaternion's scalar component

What happens if we post-multiply \(qp\) by \(q^{-1}\), could it reverse the operation? (Note that since \(q\) is a norm quaternion \(q^{-1} = q^*\))

\[ qpq^{-1} = [-\lambda \unit{n} \cdot \mathbf{v}, s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}][s, -\lambda \unit{n}] \]

Let's first check if doing this multiplication makes the scalar component vanish

\[ \begin{align*} qpq^{-1} &= [-\lambda s \unit{n} \cdot \mathbf{v} - (s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}) \cdot (-\lambda \unit{n}), \ldots] \\ &= [-\lambda s \unit{n} \cdot \mathbf{v} + (s \mathbf{v}) \cdot (\lambda \unit{n}) + (\lambda \unit{n} \times \mathbf{v}) \cdot (\lambda \unit{n}), \ldots] \\ &= [-\lambda s \unit{n} \cdot \mathbf{v} + (s \mathbf{v}) \cdot (\lambda \unit{n}) + 0, \ldots] \quad \text {since $\unit{n}$ is perpendicular to $\unit{n} \times \mathbf{v}$ }\\ &= [-\lambda s \unit{n} \cdot \mathbf{v} + \lambda s \mathbf{v} \cdot \unit{n}), \ldots] \\ &= [0, \ldots] \end{align*} \]

Indeed it magically made the scalar component vanish! Now let's look at the vector component of \(qpq^{-1}\)

\[ \begin{align*} qpq^{-1} &= [0, s (s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}) + (-\lambda \unit{n} \cdot \mathbf{v})(-\lambda \unit{n}) + (s \mathbf{v} + \lambda \unit{n} \times \mathbf{v}) \times (-\lambda \unit{n})] \\ &= [0, s^2 \mathbf{v} + s \lambda (\unit{n} \times \mathbf{v}) + \lambda^2 (\unit{n} \cdot \mathbf{v})\unit{n} - s \lambda (\mathbf{v} \times \unit{n}) - \lambda^2 (\unit{n} \times \mathbf{v} \times \unit{n})] \end{align*} \]

Let's expand the cross product

\[ (\unit{n} \times \mathbf{v}) \times \unit{n} = (\unit{n} \cdot \unit{n}) \mathbf{v} - (\mathbf{v} \cdot \unit{n}) \unit{n} = \mathbf{v} - (\mathbf{v} \cdot \unit{n}) \unit{n} \]

Therefore

\[ \begin{align*} qpq^{-1} &= [0, s^2 \mathbf{v} + s \lambda (\unit{n} \times \mathbf{v}) + \lambda^2 (\unit{n} \cdot \mathbf{v})\unit{n} - s \lambda (\mathbf{v} \times \unit{n}) - \lambda^2 (\mathbf{v} - (\mathbf{v} \cdot \unit{n}) \unit{n})] \\ &= [0, s^2 \mathbf{v} + s \lambda (\unit{n} \times \mathbf{v}) + \lambda^2 (\unit{n} \cdot \mathbf{v})\unit{n} - s \lambda (\mathbf{v} \times \unit{n}) - \lambda^2 \mathbf{v} + \lambda^2 (\mathbf{v} \cdot \unit{n}) \unit{n})] \\ &= [0, s^2 \mathbf{v} + 2 s \lambda (\unit{n} \times \mathbf{v}) + \lambda^2 (\unit{n} \cdot \mathbf{v})\unit{n} - \lambda^2 \mathbf{v} + \lambda^2 (\mathbf{v} \cdot \unit{n}) \unit{n})] \\ &= [0, (s^2 - \lambda^2) \mathbf{v} + 2 s \lambda (\unit{n} \times \mathbf{v}) + 2 \lambda^2 (\mathbf{v} \cdot \unit{n}) \unit{n}] \\ \end{align*} \]

Let's make \(s = \cost\) and \(\lambda = \sint\) just like in \eqref{perp-rotor} (it worked as a rotor when it was orthogonal to \(p\), it might work with the general case too)

\[ qpq^{-1} = [0, (\cos^2{\theta} - \sin^2{\theta}) \mathbf{v} + 2 \cost \sint (\unit{n} \times \mathbf{v}) + 2 \sin^2{\theta} (\mathbf{v} \cdot \unit{n}) \unit{n}] \]

Which involves double-angle terms, replacing these terms with double angle-identities

\[ qpq^{-1} = [0, \cos{2\theta} \mathbf{v} + \sin{2\theta} (\unit{n} \times \mathbf{v}) + (1 - \cos{2\theta}) (\mathbf{v} \cdot \unit{n}) \unit{n}] \]

The product created a pure quaternion equal to \(\mathbf{v}\) rotated by an angle \(2\theta\), if we want to rotate \(\mathbf{v}\) by an angle \(\theta\) we must build a half angle \(\theta\) quaternion \(q\) (note above that \(q\) was equal to \eqref{perp-rotor})

\[ \begin{equation} \label{rotor} q = [\cos{\frac{1}{2}\theta}, \sin{\frac{1}{2}\theta}\unit{n}] \end{equation} \]

Using \eqref{rotor} the product is

\[ qpq^{-1} = [0, \cos{\theta} \mathbf{v} + \sin{\theta} (\unit{n} \times \mathbf{v}) + (1 - \cos{\theta}) (\mathbf{v} \cdot \unit{n}) \unit{n}] \]

Note that the vector part of \(qpq^{-1}\) is identical to \eqref{3d-rotation}

Quaternion difference and dot product

Let \(a\) and \(b'\) be two unit norm quaternions (rotors that have the same form as \eqref{rotor}), the quaternion to rotate from \(a\) to \(b\) is given by \(da = b\) and is known as quaternion difference, finding the value of \(d\) given that we know \(a\) and \(b\)

\[ \begin{align*} da &= b \\ d(aa^*) &= ba^* \quad \quad \text{since $a$ is a unit norm quaternion its inverse is equal to its conjugate} \\ d &= ba^* \end{align*} \]

Expanding the product

\[ \begin{align*} d &= [s_b, \mathbf{b}][s_a, -\mathbf{a}] \\ &= [s_bs_a + \mathbf{b} \cdot \mathbf{a}, -s_b\mathbf{a} + s_a\mathbf{b} - \mathbf{b} \times \mathbf{a}] \end{align*} \]

Note that the scalar part of this quaternion is equal to the inner product (a generalization of the dot product to abstract vector spaces) between two quaternions

\[ d = [\left \langle a, b \right \rangle, -s_b\mathbf{a} + s_a\mathbf{b} - \mathbf{b} \times \mathbf{a}] \]

Remembering that a rotor is given by \eqref{rotor} we can relate the inner product between rotor quaternions with the scalar quantity of \eqref{rotor} and interpret it geometrically just like the dot product between two vectors in 3d/2d space but this time noticing that the dot product gives the cosine of half the angle between the quaternions

\[ a \cdot b = \cos{\frac{\theta}{2}} \]

This means that the angle between \(a\) and \(b\) is equal to

\[ \theta = 2 \arccos{(a \cdot b)} \]

Or using the half angle formulas

\[ \begin{align*} \cos^2{\frac{\theta}{2}} &= \frac{1}{2}(1 + \cos{\theta}) \\ (a \cdot b)^2 &= \frac{1}{2}(1 + \cos{\theta}) \\ \cost &= 2 (a \cdot b)^2 - 1 \\ \theta &= \arccos(2(a \cdot b)^2 - 1) \end{align*} \]

The second formula works for all the cases as noted here (the first one doesn't work when \(a \cdot b < 0\))


References
  • Dunn, F. and Parberry, I. (2002). 3D math primer for graphics and game development. Plano, Tex.: Wordware Pub.
  • Vince, J. (2011). Quaternions for computer graphics. London: Springer.
  • Shoemake, K. (2016). Quaternions [online] Cs.ucr.edu. Available at: http://www.cs.ucr.edu/~vbz/resources/quatut.pdf [Accessed 7 Mar. 2016].