Date: 2026-06-14 Purpose: Comprehensive guide to BELFEM's quaternion math helper Module: src/math/quaternion
Quaternion<T> is a small, header-only value type for 3D rotations. It is used to compose rotations, interpolate orientations (slerp), rotate vectors, and convert to/from 3x3 rotation matrices. It is a plain value type: four inline components, trivially copyable, no heap allocation, safe to memcpy / MPI-transfer (cl_Quaternion.hpp:34-39, cl_Quaternion.hpp:87-89).
The module is header-only; its CMakeLists.txt declares no library target (src/math/quaternion/CMakeLists.txt:1).
These three choices are the classic silent-bug sources. BELFEM's are:
| Aspect | BELFEM choice | Evidence |
|---|---|---|
| Component storage | Scalar-first q = (w, x, y, z) | mData[4] with accessors a()=w, b()=x, c()=y, d()=z (cl_Quaternion.hpp:34-39, :110-148) |
| Multiplication | Hamilton (not JPL) | product carries +v1 x v2 cross term (cl_Quaternion.hpp:226-243); tests pin i*j=k, j*k=i, k*i=j (tests/math/test_Quaternion.cpp:374-413) |
| Vector rotation | Active: v' = q v q* | rotate() embeds v as (0,v) and computes q*v*conj(q) (cl_Quaternion.hpp:286-304) |
The source does not use the words active/passive or alibi/alias; "active" here is the behavioral fact – rotating the vector in a fixed frame – confirmed by the tests pinning +90 deg about +z: (1,0,0) -> (0,1,0), matching R*v.
Not implemented: Euler-angle conversion and quaternion-to-axis-angle extraction. Axis-angle is only an input (the (axis, angle) constructor). A separate DIN-9300 Euler helper exists outside this module (src/math/tools/fn_rotation_matrix.hpp).
| Operation | Signature | Notes |
|---|---|---|
| Default | Quaternion() | all zeros |
| Components | Quaternion(a,b,c,d) | (w,x,y,z) |
| Pure quaternion | Quaternion(const Vector<T>&) | length-3 vector -> (0,v) |
| Rotation | Quaternion(const Vector<T>& axis, T angle) | axis normalized internally; angle in radians |
| Identity | static Quaternion identity() | (1,0,0,0) |
| Accessors | a() b() c() d(), data(), begin()/end() | a is the scalar |
| Norm | T norm() | Euclidean 4-norm |
| Conjugate | Quaternion conj() | negates vector part |
| Inverse | Quaternion inv() | conj()/|q|^2; errors on zero | | Normalize | Quaternion& normalize() | in place; errors on zero | | Rotate vector | Vector<T> rotate(const Vector<T>&) | requires unit quaternion |
| Expression | Meaning |
|---|---|
| q1 * q2 | Hamilton product (also *=) |
| q + q2, q - q2, s*q, q*s, q/s | componentwise / scalar |
| q1 == q2, q1 != q2 | componentwise within BELFEM_EPSILON (does not treat q and -q as equal) |
| dot(q1,q2), cross(q1,q2) | 4-vector dot; vector-part cross as pure quaternion |
| slerp(q1,q2,t) | shortest-arc spherical interpolation |
| quaternion_to_rotation_matrix(q, R) | R is a pre-allocated 3x3 (fn_quaternion_to_rotation_matrix.hpp) |
| quaternion_from_rotation_matrix(R) -> q | Shepperd's method (fn_quaternion_from_rotation_matrix.hpp) |
| quaternion_rotate_vector(q, in, out) | allocation-free v + 2w(uxv) + 2 ux(uxv), equals q v q* (fn_quaternion_rotate_vector.hpp) |
rotate() (the member) constructs intermediate quaternions; prefer quaternion_rotate_vector() on critical paths.
| File | Contents |
|---|---|
| cl_Quaternion.hpp | Quaternion<T> class, operators, dot, cross, slerp |
| fn_quaternion_to_rotation_matrix.hpp | unit quaternion -> 3x3 matrix |
| fn_quaternion_from_rotation_matrix.hpp | 3x3 matrix -> unit quaternion (Shepperd) |
| fn_quaternion_rotate_vector.hpp | allocation-free active vector rotation |