Join the official 2020 Python Developers Survey

A Tiny Python Package for Quaternions

# tinyQuaternion

A tiny python module for Quaternions

## 1. Installation

Clone the repository. For separate projects you need to copy the `tinyQuaternion.py` file into your source folder and import the module as follows:

```from tinyQuaternion import Quaternion
```

The only dependency is `numpy`, so import it as follows:

```import numpy as np
```

## 2. Documentation

### 2.1 Define Quaternions

In this package, there are two methods to define a quaternion:

1. using a 4D array representing the elements of a quaternion `q=[w,x,y,z]`. Define the array using numpy's `ndarray`.
```q = Quaternion(q=np.array([0., 0., 1., 0.]))

>>> q
Quaternion(0.0, 0.0, 1.0, 0.0)
```
1. using an axis-angle representation. Use `n` for denoting the axis of rotation and `a` for 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)
```

### 2.2. Quaternion elements

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.z
```

Example:

```>>> q.w
0.8660254037844387
>>> q.x
0.0
>>> q.y
0.0
>>> q.z
0.49999999999999994
>>>
```

### 2.3. Scalar and Vector parts

To retrieve the scalar part of the quaternion, `w` use the `scalar` method as follows:

```q.scalar
```

and to retrieve the vector part of the quaternion, `[x,y,z]` use the `vector` method as follows:

```q.vector
```

Example:

```>>> q.scalar
0.8660254037844387
>>> q.vector
array([0. , 0. , 0.5])
>>>
```

### 2.4. Magnitude

Get the norm or magnitude of the quaternion as follows:

```q.magnitude
```

Example

```>>> q.magnitude
1.0
```

### 2.5. Check if the quaternion is normalized

To 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()
True
```

### 2.6. Normalize

To normalize the quaternion use the `normalized` method.

```q.normalized
```

Example:

```>>> q.normalized
Quaternion(0.8660254037844387, 0.0, 0.0, 0.49999999999999994)
```

### 2.7. Conjugate

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.conjugate
```

Example:

```>>> q.conjugate
Quaternion(0.8660254037844387, -0.0, -0.0, -0.49999999999999994)
```

### 2.8. Inverse

To retrieve the inverse of a quaternion use the `inverse` method as follows:

```q.inverse
```

Example:

```>>> q.inverse
Quaternion(0.8660254037844387, -0.0, -0.0, -0.49999999999999994)
```

### 2.9. Extract Axis-Angle from Quaternion

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.

### 2.10. Main operations

```# addition

# 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.]))
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.

### 2.11. Quaternion Log

To get logarithm of a quaternion perform

```q.log
```

Example:

```>>> 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)
```

### 2.12. Quaternion Exp

To get exponential of a quaternion perform

```q.exp
```

Example:

```>>> 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)
```

### 2.13. Rotate point in 3D space using Quaternion (axis-angle)

```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.        ])
```

## 3.1. Rotation Using Quaternions

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_cube
```

To 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,p1,p1), (p2,p2,p2), (p3,p3,p3), (p4,p4,p4)
]
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,p1r,p1r), (p2r,p2r,p2r), (p3r,p3r,p3r), (p4r,p4r,p4r)
]
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 90
```

Now, 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,p1r,p1r), (p2r,p2r,p2r), (p3r,p3r,p3r), (p4r,p4r,p4r)
]
plot_cube(cube3)
``` ## Project details

This version 0.0.1