Skip to content
Rotation Converter3D ORIENTATION / TECHNICAL REFERENCE
ROTATION CONVERTER / IMPLEMENTATION GUIDE

Quaternion ordering, units, gimbal lock & invalid matrices

A plausible-looking output is not sufficient evidence that an orientation is valid. Use these implementation-specific checks before sending values to a robot, flight model, animation pipeline, or another numerical library.

Component ordering is an interface contract

Interactive input, bulk input, MATLAB output, and attitude playback data use quaternion components [x, y, z, w]. The Eigen output formatter instead emits Eigen::Quaterniond q(w, x, y, z), and the Python formatter emits quaternion.Quaternion(w, x, y, z). The constructor arguments are scalar-first even though the output field’s generic heading lists x, y, z, w. Read the generated constructor, not just the heading.

A Python constructor expression is a formatting target, not a complete runnable program: import and install the matching quaternion library in your own environment. Bulk parsing does not execute constructors. Do not paste a scalar-first constructor into the bulk quaternion input and expect the parser to reorder it; submit a bare [x, y, z, w] array.

Normalize nonzero quaternions before input. For example [0, 0, 1, 1] has norm √2; use [0, 0, 1/√2, 1/√2] for a quarter-turn about Z. The converter does not automatically correct the nonunit input. q and −q are equivalent, but changing only one component’s sign generally is not.

Degrees and radians are separate input and output choices

Input angle units apply to Euler and axis-angle parameters. The UI converts Euler values to degrees before calling the Euler helper and converts axis-angle values to radians before calling the axis-angle helper. Internally trigonometric functions use radians. DCM entries and quaternion components have no angle unit.

The output unit selector is independent of the input selector. It changes the formatted Euler and axis-angle numbers, not the matrix or quaternion. A value of 90° equals π/2 radians. Always include a unit in data files and API contracts rather than relying on a remembered UI choice.

Eigen::AngleAxisd expects radians. The existing Eigen formatter follows the chosen output unit, including degrees when Degrees is selected. Choose Radians before using that constructor in C++, or explicitly convert the angle. This guide flags that existing behavior rather than changing the export convention.

Near gimbal lock: the orientation survives, the coordinates do not

For the six supported distinct-axis sequences, the singularity occurs when the middle angle is ±90°. Two rotation axes become aligned and the first and third angles are no longer independently recoverable. A matrix or unit quaternion still describes the orientation; the singularity belongs to the Euler parameterization.

The Euler solver uses a branch tolerance: when the magnitude of its middle-angle sine reaches 1 − 10⁻⁶, it selects a singular branch, fixes the first sequence angle to zero, and sets the middle angle to ±90°. This can happen before the input is exactly 90°. The near-lock worked example uses 89.95°: its matrix and quaternion retain that angle, but its Euler output reads 90°.

The output warns when the middle Euler angle is within 2° of a singularity. This is a diagnostic, not a rejection. Near the solver’s singular branch, reconstructing a matrix from the displayed Euler angles may not reproduce the original matrix to machine precision. Use the matrix or quaternion for precision-critical transfer and interpolation.

Equivalent Euler triples can arise from full turns, different branches, different sequences, and at exact gimbal lock a family of first/third-angle combinations. Compare the matrices produced under the same convention rather than comparing angle strings. For unit quaternions, |q₁ · q₂| close to 1 indicates the same orientation up to sign.

Determinant alone does not prove orthogonality

The historical “Orthogonality Score” field was actually the matrix determinant. It is now labeled Matrix Determinant, with a separate orthogonality residual. A determinant near +1 is necessary but not sufficient: a shear matrix can have determinant exactly 1 while its rows are not perpendicular.

Check both det(C) ≈ 1 and C Cᵀ ≈ I. The residual shown is the largest absolute entry of C Cᵀ − I; a warning appears above 10⁻⁴, a practical tolerance for rounded input. The existing determinant warning remains at |det(C) − 1| > 0.1. These thresholds are diagnostics, not certification or automatic repair.

For example [1 0.2 0; 0 1 0; 0 0 1] has determinant 1 but a residual of 0.2. A reflection has determinant −1 and is not a proper rotation. Non-finite matrix entries are rejected before being sent to the visualizer. Finite invalid matrices are not silently orthogonalized: results may still be shown with a warning and should not be trusted as a physical rotation.

Re-export source data with more precision, check frame conventions and quaternion norm, and look for scale or shear before converting again. The displayed quaternion is normalized after extraction, but that does not make a bad matrix valid. There is no implemented nearest-rotation repair button.