How to define a bridge between two coordinate spaces
You have two coordinate spaces — typically with different coordsys_traits — and
you want mapCS() to be able to transform a coordinate from one into the other. The
piece you need to supply is a bridge: a type that satisfies
coordsys_bridge_traits.
A bridge is small. Most useful bridges are a couple of dozen lines. The work is mostly in choosing the conversion.
The recipe
-
Declare a
structthat inherits both fromcoordsys<traits_A>and fromcoordsys<traits_B>. -
Publish two type aliases:
coordsys_traits_Aandcoordsys_traits_B. -
Provide two static
convert()overloads, one in each direction. -
Add
static_assert(nin::coordsys_bridge_traits<my_bridge>)immediately after the struct, so any mistake is reported at the definition site instead of the first call tomapCS().
The concept requires
sizeof(Br) == sizeof(coordsys<traits_A>) + sizeof(coordsys<traits_B>), so the bridge
cannot have any data members of its own. The convert() overloads describe a pure
mapping of representation between the two spaces — they are typically
static constexpr noexcept and stateless. Any per-bridge state (calibration offsets,
mounting transforms) belongs in one of the inherited coordsys subobjects' backends.
Skeleton
struct my_bridge : public nin::coordsys<traits_A>,
public nin::coordsys<traits_B>
{
using coordsys_traits_A = traits_A;
using coordsys_traits_B = traits_B;
static constexpr
traits_B::quantity_type convert(traits_A::quantity_type const& q_inA) noexcept
{
return { /* … project q_inA into space B … */ };
}
static constexpr
traits_A::quantity_type convert(traits_B::quantity_type const& q_inB) noexcept
{
return { /* … project q_inB into space A … */ };
}
};
static_assert(nin::coordsys_bridge_traits<my_bridge>);
If the static_assert fires, work down the requirement list on
coordsys_bridge_traits: a missing alias, a missing
overload, the wrong return type, or an accidental data member breaking the size
constraint.
Using the bridge
A bridge instance occupies a position in the kinematic tree of both spaces, so it
is constructed and placed like any other coordinate system. Pass it to
mapCS() as an intermediate argument:
my_bridge bridge; // sits at WCS in both spaces
nin::coord_tf tf = nin::mapCS(cs_inA, bridge, cs_inB);
auto q_inB = tf(q_inA);
Bridges chain: mapCS(cs_inA, bridge_AB, bridge_BC, cs_inC) crosses two spaces in one
call. The traversal walks each subtree as usual and applies convert() at every
crossing.