raw proof

Quaternion from two vectors

Robert Eisele

Given two vectors \(\mathbf{u}, \mathbf{v}\in\mathbb{R}^3\) enclosed by the angle \(\theta\), we want to find the quaternion \(\mathbf{\hat{Q}}\) to rotate from \(\mathbf{u}\) to \(\mathbf{v}\).

θw = u × v u v

The text-book solution for this problem is creating an orthogonal rotation axis \(\mathbf{w}\) to both vectors using the cross product and calculating the rotation angle between the vectors using the dot product. The axis-angle form then allows us to create the desired quaternion. However, this naive solution is very slow when implemented straight ahead due to a lot of square roots and divisions and lacks numerical stability.


From the definition of the vector dot-product follows that

\[\mathbf{a}\cdot\mathbf{b} = |\mathbf{a}| |\mathbf{b}| \cos\theta\]

The length of the vector cross-product is given by

\[|\mathbf{a}\times\mathbf{b}| = |\mathbf{a}| |\mathbf{b}| |\sin\theta|\]

Unit Quaternions can be created using axis-angle form

\[\mathbf{\hat{Q}} = \left(\cos\frac{\theta}{2}, \mathbf{\hat{v}}\sin\frac{\theta}{2}\right)\]

From Lagrange Identity we can conclude that

\[|\mathbf{a}\times\mathbf{b}|^2 = |\mathbf{a}|^2|\mathbf{b}|^2 - (\mathbf{a}\cdot\mathbf{b})^2\]

From trigonometry we know the half-angle formulas

\[\sin\frac{\theta}{2} = \sqrt{\frac{1-\cos\theta}{2}}\]

\[\cos\frac{\theta}{2} = \sqrt{\frac{1+\cos\theta}{2}}\]

\[\sin\theta = 2\sin\frac{\theta}{2}\cos\frac{\theta}{2}\]


\[\begin{array}{rl} \mathbf{\hat{Q}} &= \left(\cos\frac{\theta}{2}, \mathbf{\hat{w}}\sin\frac{\theta}{2}\right)\\ &= \left(\sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}, \frac{\mathbf{u}\times\mathbf{v}}{|\mathbf{u}\times\mathbf{v}|}\sqrt{\frac{1-\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}\right)\\ &= \left(\sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}, \frac{\mathbf{u}\times\mathbf{v}}{|\mathbf{u}| |\mathbf{v}| |\sin\theta|}\sqrt{\frac{1-\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}\right)\\ &= \left(\sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}, \frac{\mathbf{u}\times\mathbf{v}}{|\mathbf{u}| |\mathbf{v}| \left|2\sin\frac{\theta}{2}\cos\frac{\theta}{2}\right|}\sqrt{\frac{1-\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}\right)\\ &= \left(\sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}, \frac{\mathbf{u}\times\mathbf{v}}{|\mathbf{u}| |\mathbf{v}| 2 \sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}} }\right)\\ \end{array}\]

This is a quite good finding, we don’t need trig functions at all and have a lot of repetitive elements to compute only once. However, for numerical stability, we should normalize the quaternion at the end, which brings in another square root though.

When we normalize the quaternion at the end in any case, we can scale it arbitrarily until then. When we first scale it by \(2 \sqrt{\frac{1+\mathbf{\hat{u}}\cdot\mathbf{\hat{v}}}{2}}\) and after that by \(|\mathbf{u}| |\mathbf{v}|\), we find that

\[\begin{array}{rl} \mathbf{Q} &= \left(1+\frac{\mathbf{{u}}\cdot\mathbf{{v}}}{|\mathbf{u}| |\mathbf{v}|}, \frac{\mathbf{u}\times\mathbf{v}}{|\mathbf{u}| |\mathbf{v}| }\right)\\ &= \left(|\mathbf{u}| |\mathbf{v}|+ \mathbf{{u}}\cdot\mathbf{{v}}, \mathbf{u}\times\mathbf{v}\right)\\ \end{array}\]

This is pretty nice! We could use this result already and would have a much faster solution than the naive implementation. But when we look at \(|\mathbf{u}| |\mathbf{v}|\), we can use the Lagrange Identity to come up with \(|\mathbf{u}|^2 |\mathbf{v}|^2 = |\mathbf{u}\times\mathbf{v}|^2 + (\mathbf{u}\cdot\mathbf{v})^2\), which gives the final form:

\[\begin{array}{rl} \mathbf{Q} &= \left(\sqrt{|\mathbf{u}\times\mathbf{v}|^2 + (\mathbf{u}\cdot\mathbf{v})^2}+ \mathbf{{u}}\cdot\mathbf{{v}}, \mathbf{u}\times\mathbf{v}\right)\\ &= \left(\mathbf{{u}}\cdot\mathbf{{v}}+\sqrt{\mathbf{w}\cdot \mathbf{w} + (\mathbf{u}\cdot\mathbf{v})^2}, \mathbf{w}\right)\\ \end{array}\]

Implementing the algorithm is then pretty straightforward:

function fromVectors(u, v) {

  d = dot(u, v)
  w = cross(u, v)

  return Quaternion(d + sqrt(d * d + dot(w, w)), w).normalize()

The unit vector case

For the case that \(\mathbf{u}\) and \(\mathbf{v}\) are already normalized unit vectors, the solution becomes much prettier:

\[\begin{array}{rl} \mathbf{Q} &= \left(1+ \mathbf{\hat{u}}\cdot\mathbf{\hat{v}}, \mathbf{\hat{u}}\times\mathbf{\hat{v}}\right)\\ \end{array}\]

Implementing the algorithm is also pretty straightforward:

function fromUnitVectors(u, v) {
  return Quaternion(1 + dot(u, v), cross(u, v)).normalize()

The case of Anti-Parallel vectors

If the vectors \(\mathbf{u}\) and \(\mathbf{v}\) are pointing in the exact opposite direction, their dot product \(\mathbf{u}\cdot\mathbf{v}\) is \(-1\). In this case we have infinitely many axes of rotation and thus can take any vector that is orthogonal to \(\mathbf{u}\). We could choose for example \(\mathbf{w} = (1, 0, 0)^T\times\mathbf{u}\), \((0, 1, 0)^T\times\mathbf{u}\), ... and rotate by \(\theta:= \pi\) in the axis-angle form:

\[\mathbf{\hat{Q}} = \left(\cos\frac{\pi}{2}, \mathbf{\hat{w}}\sin\frac{\pi}{2}\right) = \left(0, \mathbf{\hat{w}}\right) \]