Loading editor...

Quaternions

3. Quaternions

Here's another way to think of a rotation in 3D space: rotating a vector about another vector (or direction). Quaternions have an algebra that allows this view of rotation.

Quaternions are seen as a generalization of complex numbers. A quaternion is a 4-tuple where .


3.1 A little bit of algebra with quaternions

The product of two quaternions and is:

Now if , then which is equal to the square of the norm of the vector .


One can create two quaternions from a 3D unit vector and an angle like so:

Note that

If is a unit vector, then is also a unit vector for any .

Thus, is the inverse of and we can write it as .


3.2 Rotating a vector using quaternions

Let's say we want to rotate a vector around an axis represented by a unit vector . Let's denote the output vector as . Then:

Here we took the liberty to represent a quaternion as a vector . One can verify the above equation by multiplying the quaternions on the right hand side.

Let's see how it looks like for 2D rotations.


3.3 Visualizing quaternion rotations

3.3.1 Rotations in 2D

Since quaternions describe rotations in 3D, once can think of a rotation of by in a 2D plane as rotation of about the z-axis by the same angle.

  • Say we want to rotate
  • Turn it into a .

It is essentially this operation:

  • after the multiplication

  • after the multiplication

The reverse mapping simply drops the first (zero) component of :

  • is equal to .
    • Try the angle to see how this entire setup evolves.
  • The first and last values of the quaternion products and are zero.
    • Indeed once can verify this in the and the .

3.3.2 Rotations in 3D

Unlike the 2D case, in general all four numbers in the product are non-zero. So it is not possible to visualize it.

  • : You can see all four values are non-zero

However the product always has the first value equal to 0, which allows one to interpret it as a 3D vector:

  • : the .

One can visualize 3D rotations by rotating a cube.

  • is the cube we want to rotate about by an angle deg, currently set to .
  • degrees deg to to see how the cube rotates.

  • One can also from x-axis to y-axis and see its effect on the orientation of the cube.
  • it to z-axis.

3.4 Matrix representation of a quaternion

A quaternion can be represented as a matrix:

where and .

class Quaternion:
    def __init__(self, w:float, x:float, y:float, z:float):
        self.w = w
        self.x = x
        self.y = y
        self.z = z

    def norm(self):
        return np.sqrt(self.w**2 + self.x**2 + self.y**2 + self.z**2)

    def unit(self):
        n = self.norm()
        return Quaternion(self.w/n, self.x/n, self.y/n, self.z/n)

    def conjugate(self):
        return Quaternion(self.w, -self.x, -self.y, -self.z)

    def __mul__(self, other):
        w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z
        x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y
        y = self.w*other.y - self.x*other.z + self.y*other.w + self.z*other.x
        z = self.w*other.z + self.x*other.y - self.y*other.x + self.z*other.w
        return Quaternion(w, x, y, z)

    def to_matrix(self):
        u = self.unit()
        w,x,y,z = u.w, u.x, u.y, u.z
        xx, yy, zz = x*x, y*y, z*z
        xy, xz, yz = x*y, x*z, y*z
        wx, wy, wz = w*x, w*y, w*z
        m = [[1 - 2*(yy + zz), 2*(xy - wz), 2*(xz + wy)],
             [2*(xy + wz), 1 - 2*(xx + zz), 2*(yz - wx)],
             [2*(xz - wy), 2*(yz + wx), 1 - 2*(xx + yy)]]
        return np.array(m)

Here is how one would use it to rotate a vector:

def rotate_vector(
    axis_x:float, axis_y:float, axis_z:float,
    angle:float,
    vector_x:float, vector_y:float, vector_z:float
):
    cos_angle, sin_angle = np.cos(angle/2), np.sin(angle/2)
    # make the axis a unit vector
    axis_norm = np.sqrt(axis_x**2 + axis_y**2 + axis_z**2)
    axis_x, axis_y, axis_z = axis_x/axis_norm, axis_y/axis_norm, axis_z/axis_norm
    q = Quaternion(cos_angle, sin_angle*axis_x, sin_angle*axis_y, sin_angle*axis_z)
    v = Quaternion(0, vector_x, vector_y, vector_z)
    y = q * v * q.conjugate()
    return y.x, y.y, y.z

← 3D rotation matrices · Rotations as reflections →