|
Unit Conversion and Dimensional Analysis Library 3.6.1
A compile-time, header-only C++23 dimensional-analysis library
|
Store dimensioned quantities in Eigen vectors and matrices, with the dimensions checked at compile time.
units and Eigen compose without either library depending on the other. Include <units/eigen.h> (it is also pulled in automatically by <units.h>) and, if <Eigen/Core> is on your include path, units teaches Eigen how to use a unit as a matrix scalar. If Eigen is not present, the header is a no-op — units has no dependency on Eigen, exactly as its optional JSON support has no dependency on a JSON library. There is nothing to enable and no build flag to set; the support activates from the presence of the Eigen headers alone.
Once a unit is a valid scalar, the operations whose result keeps the same dimension work on Eigen vectors and matrices with no special syntax:
| Operation | Example | Result |
|---|---|---|
| Construction / storage | Eigen::Matrix<meters<double>, 3, 1> v; | a vector of meters |
| Element access | v(0), v.x() | a meters<double> |
| Addition / subtraction | a + b, a - b | a vector of meters |
| Scale by a plain scalar | v * 2.0, 2.0 * v, v / 2.0 | a vector of meters |
| Reductions that keep the dimension | v.sum() | a meters<double> |
| Block / segment views | v.head<2>() | a vector of meters |
| Map over unit storage | Eigen::Map<Vector3m>(ptr) | a view of meters |
| Cast the underlying type | vi.cast<meters<double>>() | meters<int> → meters<double> |
A dot product of two lengths is an area; a norm takes a square root; a cross product of two lengths is an area vector. Eigen's built-in dot(), norm(), and cross() assume that the product of two scalars is the same scalar type, which is not true for dimensioned quantities — so units provides free helper functions that return the dimensionally-correct type:
| Helper | Meaning | Result dimension |
|---|---|---|
| unit_dot(a, b) | dot product Σ aᵢ·bᵢ | product of the operands' units (meters · meters → square_meters) |
| unit_squared_norm(v) | unit_dot(v, v) | the squared unit |
| unit_norm(v) | Euclidean magnitude √(Σ vᵢ²) | the vector's own unit |
| unit_normalized(v) | direction (unit vector) | dimensionless (a plain-scalar vector) |
| unit_cross(a, b) | 3D cross product | product of the operands' units |
| unit_transform(M, v) | dimensionless matrix M times unit vector v | the vector's own unit |
The common aerospace / simulation case is a dimensionless rotation (or direction-cosine) matrix applied to a dimensioned position, velocity, or acceleration. unit_transform applies a plain-scalar matrix to a vector of units and returns a vector of the same unit:
The cross product carries the product dimension — a moment arm (meters) crossed with a force (newtons) is a torque-dimensioned (newton_meters) vector, for example:
The header specializes two Eigen traits for any type satisfying the units::UnitType concept: Eigen::NumTraits (so Eigen knows the scalar's numeric properties, forwarded from the underlying arithmetic type) and Eigen::ScalarBinaryOpTraits for the product and quotient with a plain scalar (so scaling a unit by a scalar yields the same unit). Because a named unit such as meters<double> is a class derived from units::unit, the specializations are written against the concept, not a structural unit<...> pattern. The dimension-changing operations cannot be expressed through Eigen's scalar-preserving assumption, which is why they are free helper functions rather than trait specializations. No part of units is modified to support Eigen; the whole adapter lives in units/eigen.h, guarded by __has_include(<Eigen/Core>).