Transformations

Mathematical Conventions

Generic Transformations

Transformations are denoted in general as functions T_{ab}. In this case, T_{ab} is the frame-forward transformation from frame a to frame b, also shown in Fig. 1.

../_images/transforms.png

Fig.1: Transformations between different frames.

The concatenation of multiple transformations is denoted as

T_{ad} = T_{ab} \circ T_{bc} \circ T_{cd} \, .

Since we use frame-forward transformations, T_{ad} expressed as multiplication of homogeneous transformation matrices (HMs) yields

\boldsymbol{T}_{ad} = \boldsymbol{T}_{ab} \, \boldsymbol{T}_{bc} \, \boldsymbol{T}_{cd} \, .

This also implies that a point \boldsymbol{p}_{d} in frame d is transformed to frame a using

\boldsymbol{p}_{a}\ = T_{ad}(\boldsymbol{p}_{d}) = T_{ab}(T_{bc}(T_{cd}(\boldsymbol{p}_{d}))) \, ,

or expressed as HMs using

\boldsymbol{p}_{a}\ = \boldsymbol{T}_{ad} \, \boldsymbol{p}_{d} = \boldsymbol{T}_{ab} \, \boldsymbol{T}_{bc} \, \boldsymbol{T}_{cd} \, \boldsymbol{p}_{d} \, .

The inverse of a transformation is denoted as

T_{ab}^{-1} = T_{ba} \, .

Motions and Poses

The TransformContainer makes it possible to store transformations as either motions or poses and to convert between both representations. Fig. 2 gives an overview over the relation between motions and poses.

../_images/motions_poses.png

Fig. 2: Motions and poses.

The pose of a frame a at step t is denoted as P_{a,t}, the motion between two poses at step t is denoted V_{a,t}. Thus, the motion between two poses is calculated as

V_{a,t} = P_{a,t}^{-1} \circ P_{a,t+1} \, .

Vice versa, the next pose, given the previous pose and the motion, is calculated as

P_{a,t+1} = P_{a,t} \circ V_{a,t} \, .

When converting a full dataset from motions to poses, the initial pose P_{a,1} must be provided. The identity transformation is a trivial choice for this.

In case of two rigidly coupled frames a and b as in Fig. 2, e.g., sensors mounted on a vehicle, the respective motions and poses can be converted into each other using the rigid frame transformation T:

V_{b,t} &= T^{-1} \circ V_{a,t} \circ T \\
P_{b,t} &= T^{-1} \circ P_{a,t} \circ T

Representations

A transformation representation is necessary for using and applying the previously described generic transformations. The following table lists all implemented transformation representations. Some representations do not directly support operations like concatenation or inversion. However, they are implicitly converted by this library to other representations for this. We refer to the respective documentation of each class for more detailed information.

Representation

Class

Axis-Angle Rotation and Translation Vector

motion3d::AxisAngleTransform

DualQuaternion

motion3d::DualQuaternionTransform

Euler Angles and Translation Vector

motion3d::EulerTransform

Homogenous Matrix

motion3d::MatrixTransform

Quaternion and Translation Vector

motion3d::QuaternionTransform

Implementation

Representations

For each representation, a separate class is implemented. Furthermore, in order to enable representation-independent processing, all these classes inherit from motion3d::TransformInterface. This makes it possible to store, access, modify and combine transformations without taking care of the underlying representation. The asType() methods of each class can be used to convert between the different representations.

For maximizing performance, it is still necessary to convert transformations to a fixed representation, since the usage of motion3d::TransformInterface involves vtable access. We recommend to use either motion3d::DualQuaternionTransform or motion3d::MatrixTransform for this, since they provide direct implementations for all possible operations instead of converting to a different representation first.

Single Transformations

Transformations are created using either the respective constructors or the motion3d::TransformInterface::Factory() method. The default constructor automatically initializes an identity transformation.

By default, transformations are marked as safe. This means that at each operation, the transformation is automatically checked for validity. The unsafe parameter of the constructors can be used to disable this. However, this can lead to errors since most operations only work properly on valid transformations. A safe and valid transformation can be obtained using the normalized() methods.

The following table gives an overview of possible operations on single transformations.

Operation

Equation

Implementation(s)

Apply T_b after T_a

T_a \circ T_b

a.applyPost(b) a * b

Apply T_b before T_a

T_b \circ T_a

a.applyPre(b)

Invert T_a

T_a^{-1}

a.inverse()

Apply T_b^{-1} after T_a

T_a \circ T_b^{-1}

a.applyPost(b.inverse()) a / b

Translation norm of T_a

a.translationNorm()

Rotation norm of T_a

a.rotationNorm()

Scale translation of T_a by x

a.scaleTranslation(x)

Normalize T_a and ensure that it is valid

a.normalized(x)

Transformation Container

In addition to the previously described operations on single transformations, motion3d::TransformContainer also provides container specific functions.

Description

Implementation

Apply T_a before and T_b after all transformations

container.apply(a, b)

Change the coordinate frame using the rigid frame transformation T_a

container.changeFrame(a)

Get container as poses with the identity pose as initial pose

container.asPoses()

Get container as poses with the T_a as initial pose

container.asPoses(a)

Get container as motions

container.asMotions()

More methods, e.g., involving stamped data, can be found in the motion3d::TransformContainer documentation.

Inplace Operations

All previously described method do not alter the original objects. For performing operations directly on the object, some methods have an inplace variant, marked by a trailing underscore, e.g., normalized_() instead of normalized().