This experiment explores the results of either (1) finding the cross product of
two transformation matrices before multiplying the result to a vector
((M_{1}×M_{2})×v), or
(2) applying a transformation to the vector, then applying another
transformation to the changed vector
(M_{1}×(M_{2}×v)).
The goal is to develop techniques to either manipulate a vector in its
local coordinates or manipulate a vector in global coordinates.

The vector is [1,0,0] in each case.
Rotations are always π/2 around the *z*-axis, scales are always by
2× in *x*, and translations are always +3 in *y*.

Name | First Operation | Second Operation | Concatenated Matrices | Applied to Vector |

TT | Translation | Translation | (T×T)×v= | T×(T×v)= |

TR | Translation | Rotation | (T×R)×v= | T×(R×v)= |

TS | Translation | Scale | (T×S)×v= | T×(S×v)= |

ST | Scale | Translation | (S×T)×v= | S×(T×v)= |

SR | Scale | Rotation | (S×R)×v= | S×(R×v)= |

SS | Scale | Scale | (S×S)×v= | S×(S×v)= |

RT | Rotation | Translation | (R×T)×v= | R×(T×v)= |

RR | Rotation | Rotation | (R×R)×v= | R×(R×v)= |

RS | Rotation | Scale | (R×S)×v= | R×(S×v)= |

Let's look at RT. You rotate [1,0,0] by π/2 around *z* to get [0,1,0].
Translate +3 in *y* and you end up with [-3,1,0]. Why -3? Because the
transform occured in the object's local coordinates, where the object's *y*
has rotated to the global *x* axis.

Not the result I had expected. (M_{1}×M_{2})×v
appears to work in object coordinates as expected, but the results are always
the same. Knowing that matrix multiplication is not commutative, let's try
reversing the order of some operations and see what happens.

This time we reverse the order of transformation matrices.

Name | First Operation | Second Operation | Concatenated Matrices | Applied to Vector |

TR | Translation | Rotation | (R×T)×v= | R×(T×v)= |

TS | Translation | Scale | (S×T)×v= | S×(T×v)= |

ST | Scale | Translation | (T×S)×v= | T×(S×v)= |

SR | Scale | Rotation | (R×S)×v= | R×(S×v)= |

RT | Rotation | Translation | (T×R)×v= | T×(R×v)= |

RS | Rotation | Scale | (S×R)×v= | S×(R×v)= |

Let's take a look at RT again. We rotated [1,0,0] by π/2 around *z* to get
[0,1,0]. We translate by +3 in *y* as before, but this time we end up with
[0,4,0]. The translation occurred in global coordinates.

A closer look shows that TR in this table is identical to RT in the above table.
The real difference is how one *thinks* about the effect these operations
have. By multiplying a transform to the left or right of another transform we
can influence its behavior in global or local coordinates.

`java.awt.geom.AffineTransform`
has an interesting discussion on this subject. The class provides methods to
`concatenate`
and
`preConcatenate`
a transformation matrix. The JavaDoc explains that these methods are to be used
to manipulate a transformation in local (or "user space") or global coordinates
("absolute pixel space"). The results of this experiment support this approach.
Multiplying a transform on the right updates the transform in its
local coordinates, and multiplying a transform on the left ("pre") updates the
transform in global coordinates.

House
explains that matrix multiplication is *associative* and x'=R(H(Sx))=(RHS)x.
Thus,
(M_{1}×M_{2})×v=M_{1}×(M_{2}×v)
and
(M_{2}×M_{1})×v=M_{2}×(M_{1}×v).