#include <morph/Quaternion.h>
Header file: morph/Quaternion.h. Test and example code: tests/testQuaternion
A class for doing quaternion operations. Initially developed for use in morph::Visual
to compute rotations of the scene.
Defined as:
namespace morph {
template <typename Flt>
class Quaternion
where Flt
hints that the template arg is a floating point type. The Hamiltonian convention is adopted for the order of the member elements: Flt w, x, y, z;
. These are the only member data attributes.
Create a Quaternion:
morph::Quaternion<float> q; // By default w=1, and x, y, z = 0;
morph::Quaternion<float> q(1, 0, 0, 0); // Explicit setting of elements
A newly created Quaternion will be an identity Quaternion (1,0,0,0) unless explicity set otherwise.
Copy a Quaternion:
morph::Quaternion<float> q1;
morph::Quaternion<float> q2 = q1; // Assignment works as expected
You can use equality and inequality operators on a Quaternion: q1 == q2
and q1 != q2
.
Stream a Quaternion:
morph::Quaternion<float> q1(1, 0, 0, 0);
std::cout << q1 << std::endl;
Output: Quaternion[wxyz]=(1,0,0,0)
Renormalize to magnitude 1 or check if it’s a unit quaternion:
q1.renormalize();
q1.checkunit();
Setting the value of the Quaternion. This function sets a rotation (specified in radians) about the given three dimensional axis:
void initFromAxisAngle (const vec<Flt>& axis, const Flt& angle);
The Quaternion can be reset to the identity with reset()
.
Manipulating rotations. The most useful feature of Quaternions, and the reason for their popularity in computer programs is the fact that the rotations can be combined by multiplication.
morph::Quaternion<float> q1;
morph::Quaternion<float> q2;
using mc = morph::mathconst<float>;
q1.initFromAxisAngle (morph::vec<float>({1,0,0}), mc::pi_over_3);
q2.initFromAxisAngle (morph::vec<float>({0,1,0}), mc::pi_over_4);
morph::Quaternion<float> q3 = q1 * q2;
To multiply one Quaternion by another, it’s important to specify the multiplication order.
q1.postmultiply (q2); // Places result of q1 * q2 into q1.
q1.premultiply (q2); // Places result of q2 * q1 into q1.
Quaternion division is also possible: q3 = q1/q2;
as is division by a scalar.
The rotational inversion, or ‘reverse rotation’ is obtained with invert
:
q.invert(); // Obtains the opposite rotation to the one specified by q
For the algebraic inverse or reciprocal, q-1, use inverse
. This finds the reciprocal, q-1 which has the property that q-1 * q = the identity Quaternion (1,0,0,0).
q.inverse(); // q^-1
The conjugate is also obtainable with q.conjugate();
and the magnitude of the Quaternion with q.magnitude();
.
Rotate the Quaternion with these methods:
void rotate (const vec<Flt, 3>& axis, const Flt angle);
void rotate (const std::array<Flt, 3>& axis, const Flt angle);
void rotate (const Flt axis_x, const Flt axis_y, const Flt axis_z, const Flt angle)
Each method rotates the Quaternion by an angle in radians about a 3D axis specified by the axis array (or by the individual components of the axis).
You can obtain the equivalent rotation matrix in column-major format (OpenGL friendly) from the Quaternion with
std::array<Flt, 16> rotationMatrix() const; // Returns the rotation matrix
void rotationMatrix (std::array<Flt, 16>& mat) const // sets the values in the passed-in matrix
If you know that your Quaternion can be assumed to be a unit Quaternion, you can use
std::array<Flt, 16> unitRotationMatrix() const;
void unitRotationMatrix (std::array<Flt, 16>& mat) const;
These involve slightly less computation.