This is a collection of functions allowing interconversion between four commonly used rotation representations:
- Quaternion
- Axis-angle
- Direction cosine matrix
- Euler angles
Axis-angle The axis must be a unit vector and the angle should be in [0,
Euler angles We consider six sequences of Euler angles with non-repeated axes: (1) XYZ, (2) XZY, (3) ZXY, (4) ZYX, (5) YZX, and (6) YXZ. For example, the sequence 'XYZ' (in the world frame) = [phi, theta, psi] signifies first rotation by phi about X, second rotation by theta about Y, and the third rotation by psi about Z axis of the world (i.e. fixed) frame.
Euler angle ranges
| Sequence | phi | theta | psi |
|---|---|---|---|
| XYZ, ZYX | [-pi, pi] | [-pi/2, pi/2] | [-pi, pi] |
| XZY, YZX | [-pi, pi] | [-pi, pi] | [-pi/2, pi/2] |
| ZXY, YXZ | [-pi/2, pi/2] | [-pi, pi] | [-pi, pi] |
Functions for converting from one euler sequence to another are also available.
The above convention the same as the sequence used in the Blender blenlib code.
In contrast, the 'XYZ' sequence is understood in the aerospace community as: First rotation about Z-axis, second rotation about Y-axis, and the third rotation about X-axis of the body frame.
The functions are available in C, Fortran, and python. The source files
are in c/src, fortran/src, and python/rotlib, respectively.
A makefile is available for the GCC compiler in c/build. The command make lib will create a static library librotlib.a put it in the c/lib
directory. A calling program can link appropriately to this library.
Tests are available in c/test. The command make test will build the tests
as an executable c/test/test_main.
Documentation is generated using Doxygen. The command
make doc will build the HTML documentation in docs/c_api.
The function aa_rand() requires a random number generator. In the code, the
library functions srand() and rand() have been used as the random number
generation is not crucial for the rest of the functions. If a better random
number generator is required, the files c/src/ran_num.c and c/src/ran_num.h
provide an interface to the random number generation routines of the Intel
Math Kernel Library
(MKL).
The implementation of aa_rand() may be modified (as well as the makefile) to
incorporate the routines from MKL.
A makefile is available for the gfortran compiler in fortran/build. The
command make lib will create a static library librotlib.a put it in the
fortran/lib directory. A calling program can link appropriately to this
library.
Tests are available in fortran/test. The command make test will build the tests
as an executable fortran/test/test_main.
Documentation is generated using
FORD. The command make doc will
build the HTML documentation in docs/fortran_api.
Fortran intrinsic functions are used for random number generation which are good enough for our purposes.
Dependency The code has been tested with python >= 3.11. The only
dependency is numpy (>=2.0.0).
The rotlib module can be installed directly from the GitHub repo. In a
virtual environment with python >= 3.11, run the command below. If numpy is
not found, pip will install it as well.
pip install "rotlib @ git+https://github.com/saridut/rotlib.git/#subdirectory=python"To use the functions, it is sufficient to import it as import rotlib in the
user code.
A makefile for Sphinx
autogenerated HTML documentaion is available in python/docs.
Tests are available in python/tests. The file python/pyproject.toml
contains directives for ruff,
pytest, and tox.
Autogenerated documentation for the functions are available here.
Convert a set of euler angles to unit quaternion and back.
import rotlib
import numpy as np
# Euler angle sequence
ea = np.array([0.2, 0.5, 1.0])
# Convert euler to unit quaternion. Assume the sequence is 'XYZ' in the world frame.
q = rotlib.euler_to_quat(ea, seq='XYZ', world=True)
#Convert the unit quaternion back to euler with the same sequence.
ea_ = rotlib.quat_to_euler(q, seq='XYZ', world=True)
#Check: ea and ea_ must be same within floating point precision
print(f"ea = {ea}\n q = {q}\n ea_ = {ea_}")The output is
ea = [0.2 0.5 1. ]
q = [ 0.8578941 -0.03313079 0.26240747 0.44052512]
ea_ = [0.2 0.5 1. ]Tha same example as above in C.
double q[4], ea[3], ea_[3];
ea[0] = 0.2; /* Rotation about X */
ea[1] = 0.5; /* Rotation about Y */
ea[2] = 1.0; /* Rotation about Z */
euler_to_quat(ea, ES_XYZ, true, q); /* enum ES_XYZ defined in rotation.h */
quat_to_euler(q, ES_XYZ, true, ea_);
/* using the function allclose() defined in `utils_math.h` to check closeness */
printf("ea == ea_? %d\n", allclose(3, ea, ea_, 1e-8, 1e-14) )Tha same example as above in fortran.
real(rp) q[4], ea[3], ea_[3]
! `rp` defined in constants_m. It is set to `iso_fortran_env:real64`.
ea = (0.2_rp, 0.5_rp, 1.0_rp)
call euler_to_quat(ea, 'XYZ', .true., q)
call quat_to_euler(q, 'XYZ', .true., ea_)
! using the function allclose() defined in `utils_math_m` to check closeness
write(*,'(a,1l)') "ea == ea_? ", allclose(ea, ea_, 1e-8_rp, 1e-14_rp)For further examples, check the files c/test/test_main.c, fortran/test/test_main.f90, and
python/tests/test_main.py.