a map from position to position, as an object
A spatial transform relates two coordinate frames of one physical object - the distortion between an EBSD map and an image of the same area, the drift accumulated during a scan, the projection of a tilted specimen. Unlike a bare function handle it composes, inverts, displays, and can be saved and applied to a second data set.
Direction is fixed once and everything follows from it:
T maps a position in frame A to the same physical point's position in
frame B. T2 * T1 composes in matrix order - T1 is applied first.
Filling an output grid always uses inv(T), never T: for each target
pixel, ask where it came from.Transforms are 2D - they act on x and y and leave z alone.
Subclasses of one base may be collected in one array, so a chain of differently modelled hops is [T1 T2 T3] rather than a cell array.
AN ARRAY IS A CHAIN, not a collection of N transforms: [T1 T2 T3] means apply T1, then T2, then T3, and it is the composite T1 + T2 + T3 written out. So its inverse is [inv(T3) inv(T2) inv(T1)] - inverting REVERSES, as spatialTransformComposite/inv already does with its stages. This is the one place the class departs from the MTEX reading where an array is N entities and every method is elementwise. See docs/adr/0007.
None of that is implemented yet. Every method here takes one transform, and an array is only a container: MATLAB dispatches a method on a heterogeneous array only if it is sealed, and only mtimes, plus and display are, so inv(T), isid(T) and char(T) all fail on a sequence. Until they are sealed, fold the chain with * - inv(T(3)*T(2)*T(1)) - or go hop by hop with arrayfun(@inv,T,'UniformOutput',false), which does not reverse.
There are two ways to put two transforms together, and they are not the same operation:
T1 + T2 builds a MODEL. It reads left to right, T1 applied first, and
it keeps both as stages. Only a literal spatialTransformId is
dropped, since that is the class that MEANS nothing separates
the two frames.
T2 * T1 COMPOSES. It reads in matrix order, T1 applied first, and it
simplifies where it can - two affines make a third, and an
operand that reports isid disappears.Use + to declare a distortion that is about to be fitted, * for transforms that already are. An unfitted prototype has zero coefficients and so reports isid, which is why the two differ where it matters: shift * drift is a bare drift with the shift silently gone, while shift + drift is the two stage model it looks like.
Note that + is not the pointwise + of vector3d or S2Fun. It chains the maps, it does not add the displacements - though for displacements small against the scale they vary on the two agree to first order, which is why the notation reads the way it does.
Syntax
posB = eval(T,posA)
posB = T * posA % the same
T = T1 + T2 % chain as stages, T1 applied first
T = T2 * T1 % compose, T1 applied first
Tinv = inv(T)
tf = isid(T)Input
| T | spatialTransform |
| posA | vector3d |
Output
| posB | vector3d |
| Tinv | spatialTransform |
Derived Classes
| spatialTransformId | the identity |
| spatialTransformShift | 2D affine, as a homogeneous matrix |
| spatialTransformHandle | wraps a function handle |
| spatialTransformComposite | an ordered list of stages |