I can never remember the difference between left and right multiplying transform matrices, so I’m writing all this down mostly for myself.
Let be an array of 2D vectors of shape
:
Let be a
degrees counterclockwise rotation
matrix:
Expressed with a right multiply, the rotated would be
Note the shapes: is
and
is
, so we end up
with
. In numpy for a 30 degree counterclockwise
rotation:
v = np.array([[0.8, 0], [0.9, 0.1], [1, 0.2]])
def make_rotation_matrix(K_rad):
return np.array([[np.cos(K_rad), -np.sin(K_rad)],
[np.sin(K_rad), np.cos(K_rad)]])
vprime = (make_rotation_matrix(np.deg2rad(30)) @ v.T).T
which, visualized as vectors from the origin, produces the expected result:
Expressed with a left multiply, the rotated would be
Note the shapes: is
and
is
, so we end up
with
. In
numpy:
vprime = v @ make_rotation_matrix(np.deg2rad(30)).T
which again visualized as vectors from the origin produces the same result:
Imagine instead of a simple rotation by , we also wanted to transform the points
that included a translation
. We
could represent this as two separate operations, a rotation and a
translation, or we could represent it as a single homogeneous transform
:
where is the same rotation matrix as before,
and
is the column version of the
translation vector (i.e.
). To do this, we augment
the
vectors with a third column of ones,
i.e.
making it an matrix. The
homogeneous transform
is a
matrix, so we
can left multiply it with
to get the transformed
:
In numpy
def make_transform_matrix(K_rad, translation):
return np.array([[np.cos(K_rad), -np.sin(K_rad), translation[0]],
[np.sin(K_rad), np.cos(K_rad), translation[1]],
[0, 0, 1]])
def make_homogeneous(v):
return np.hstack((v, np.ones((v.shape[0], 1))))
vprime_h = v_h @ make_transform_matrix(rotation, translation).T
which, visualized as vectors from the origin, produces the expected result: