A tiny python module for Quaternions
Author: Reza Ahmadzadeh - 2019
There are two options:
pip install tinyquaternionin case you have more than one version of python on your computer, install it using python3
python3 -m pip install tinyquaterniongit clone https://github.com/rezaahmadzadeh/tinyquaternion.gitFor separate projects you need to copy the tinyQuaternion.py file into your source folder and import the module as follows:
from tinyQuaternion import QuaternionThe only dependency is numpy, so import it as follows:
import numpy as npIn this package, there are two methods to define a quaternion:
- using a 4D array representing the elements of a quaternion
q=[w,x,y,z]. Define the array using numpy'sndarray.
q = Quaternion(q=np.array([0., 0., 1., 0.]))
>>> q
Quaternion(0.0, 0.0, 1.0, 0.0)- using an axis-angle representation. Use
nfor denoting the axis of rotation andafor denoting the angle of rotation in radians.
q = Quaternion(a=np.pi/3, n=np.array([0.,0.,1.]))
q
Quaternion(0.8660254037844387, 0.0, 0.0, 0.49999999999999994)Each quaternion is a vector q=[w,x,y,z] with four elements w, x, y, z. Each element of the quaternion can be retrieved as follows:
q.w
q.x
q.y
q.zExample:
>>> q.w
0.8660254037844387
>>> q.x
0.0
>>> q.y
0.0
>>> q.z
0.49999999999999994
>>> To retrieve the scalar part of the quaternion, w use the scalar method as follows:
q.scalarand to retrieve the vector part of the quaternion, [x,y,z] use the vector method as follows:
q.vectorExample:
>>> q.scalar
0.8660254037844387
>>> q.vector
array([0. , 0. , 0.5])
>>> Get the norm or magnitude of the quaternion as follows:
q.magnitudeExample
>>> q.magnitude
1.0To see if the quaternion is normalized you can use the is_unit() method. This will return True if the magnitude of the quaternion is equal to 1 and False otherwise.
q.is_unit()Example:
>>> q.is_unit()
TrueTo normalize the quaternion use the normalized method.
q.normalizedExample:
>>> q.normalized
Quaternion(0.8660254037844387, 0.0, 0.0, 0.49999999999999994)To retrieve the conjugate of a quaternion q=[w,x,y,z] as q*=[w,-x,-y,-z] use the conjugate method as follows:
q.conjugateExample:
>>> q.conjugate
Quaternion(0.8660254037844387, -0.0, -0.0, -0.49999999999999994)To retrieve the inverse of a quaternion use the inverse method as follows:
q.inverseExample:
>>> q.inverse
Quaternion(0.8660254037844387, -0.0, -0.0, -0.49999999999999994)To extract the axis-angle form of a quaternion use this method as follows:
q.axisangle()Example:
>>> q.axisangle()
(array([0., 0., 1.]), 1.0471975511965974)keep in mind that this is not equal to the original quaternion that we defined above. The main reason is that we have performed some operations on the original quaternion.
# addition
q1.add(q2)
# subtraction
q1.sub(q2)
# multiplication
q1.mul(q2)
# division
q1.div(q2)Example:
>>> q1 = Quaternion(np.array([1.,0.,0.,0.]))
>>> q2 = Quaternion(np.array([0.,0.,0.,1.]))
>>> q1.add(q2)
Quaternion(1.0, 0.0, 0.0, 1.0)
>>> q1.sub(q2)
Quaternion(1.0, 0.0, 0.0, -1.0)
>>> q1.mul(q2)
Quaternion(0.0, 0.0, 0.0, 1.0)
>>> q1.div(q2)
Quaternion(0.0, 0.0, 0.0, -1.0)Note that these operations do not perfrom normalization implicitly.
To get logarithm of a quaternion perform
q.logExample:
>>> q=Quaternion(np.array([0.,1.,0.,0.]))
>>> q
Quaternion(0.0, 1.0, 0.0, 0.0)
>>> q.log
Quaternion(0.0, 1.5707963267948966, 0.0, 0.0)To get exponential of a quaternion perform
q.expExample:
>>> q=Quaternion(np.array([0.,1.,0.,0.]))
>>> q
Quaternion(0.0, 1.0, 0.0, 0.0)
>>> q.exp
Quaternion(0.5403023058681398, 0.8414709848078965, 0.0, 0.0)q.rotatePoint(p)Example:
The point should be define using a 3D numpy array as follows:
>>> q = Quaternion(a=np.pi/3, n=np.array([0.,0.,1.]))
>>> p = np.array([1.,2.,-1.])
>>> q.rotatePoint(p)
array([-1.23205081, 1.8660254 , -1. ])The code can be found in the test folder. First import all the required packages:
import numpy as np
from tinyQuaternion import Quaternion
from plotCube import plot_cubeTo perform this test, we first plot a cube using the function plotCube.py provided in the test folder.
# plot the initial cube
p1 = np.array([0.,0.,0.])
p2 = np.array([0.,.1,0.])
p3 = np.array([2.,0.,0.])
p4 = np.array([0.,0.,.1])
cube1 = [
(p1[0],p1[1],p1[2]), (p2[0],p2[1],p2[2]), (p3[0],p3[1],p3[2]), (p4[0],p4[1],p4[2])
]
plot_cube(cube1)This will result in the following cube:
Now, we define a known quaternion. Assume, we want to rotate about Y-axis by 90 degrees. The quaternion will look like this:
# define a known quaternion
q = Quaternion(a=np.pi/2, n=np.array([0., 1., 0.]))By using the a and n keywords, we tell the function that we are representing the quaternion by defining the angle and axis of rotation.
Now, we rotate each point using the quaternion through the method rotatePoint as follows:
# rotate the cube
p1r = q.rotatePoint(p1)
p2r = q.rotatePoint(p2)
p3r = q.rotatePoint(p3)
p4r = q.rotatePoint(p4)and plot the rotated cube
cube2 = [
(p1r[0],p1r[1],p1r[2]), (p2r[0],p2r[1],p2r[2]), (p3r[0],p3r[1],p3r[2]), (p4r[0],p4r[1],p4r[2])
]
plot_cube(cube2)Now let's perform two rotations using quaternions. We consider a new rotation and then combine it with the previous rotation. Our previous rotation was about Y-axis by 90 degrees. For this one we want to have a rotation about X-axis by 90 degrees. The quaternion will look like this:
q2 = Quaternion(a=np.pi/2, n=np.array([1.,0.,0.])) # rotate about x by 90Now, we should combine the two quaternions. The rule is that "First rotation should go last", so we can write
q = q2.mul(q) This quaternion has the effect of a rotation about Y-axis, followed by a rotation about X-axis.
Now perform the rotation:
p1r = q.rotatePoint(p1)
p2r = q.rotatePoint(p2)
p3r = q.rotatePoint(p3)
p4r = q.rotatePoint(p4)and plot the rotated cube:
cube3 = [
(p1r[0],p1r[1],p1r[2]), (p2r[0],p2r[1],p2r[2]), (p3r[0],p3r[1],p3r[2]), (p4r[0],p4r[1],p4r[2])
]
plot_cube(cube3)

