Introduction
Wherever you see a CGAffineTransform or a CATransform3D, Apple supplies a matrix illustrating the transformation. For those who understand matrixes this is great, but for the rest of us it's a WTF moment.The aim here is to walk through the interpretation of these matrixes by adding small but significant pieces to the puzzle for those who collapse on the floor when faced with these illustrations. This post deals with CGAffineTransforms but I will examine CATransform3D matrixes in a later post.
Explaining the matrix
Let's look first at this translation matrix from Wikipedia:Taking the first row of the matrix it can be read as:
x' = 1 * x + 0 * y + txWe arrive at this by treating the first numeral as a number by which x is multiplied and the second numeral in the row as the number by which y is multiplied, while tx is whatever number is passed as the translation. And added together together they equal x' or in other words the new (translated) x position.
The second row can be similarly read:
y' = 0 * x + 1 * y + tyAs before the first column relates to x coordinate, the second column to the y coordinate and the third column to the translation.
The third row can be read as:
1 = 0 * x + 0 * y + 1 * 1Where 1 is the multiplier, as defined by the system of homogenous coordinates explained here:
the Cartesian point (1,2) can be represented in homogeneous coordinates as (1,2,1) or (2,4,2). The original Cartesian coordinates are recovered by dividing the first two positions by the third. Thus unlike Cartesian coordinates, a single point can be represented by infinitely many homogeneous coordinates
CGAffineTransforms
In Apple's documentation you'll notice that the following matrix is provided for the CGAffineTransformMakeTranslation() function:
What has happened is that Apple has created a matrix to be read downwards instead of across. So the first column provides us with x' like so
x' = 1 * x + 0 * y + txThe second column:
y' = 0 * x + 1 * y + ty
And the third:
1 = 0 * x + 0 * y + 1 * 1The reason we are told that we can ignore the third column by Apple is because as explained above it is the multiplier and since all coordinates are multiplied by 1 there's nothing to be done here.
A rotation matrix is similarly read downwards adding each element to arrive at the rotation of each x and y point within the element being rotated:
To explain the shifted x position of each pixel being translated is:
x' = cos(angle) * x − sin(angle) * yWhere the angle is in radians (not degrees), while the y position is:
y' = sin(angle) * x + cos(angle) * yAnd finally the column that can be ignored is equal to:
1 = 0 * x + 0 * y + 1 * 1To complete the trio, scaling can be illustrated in the following way:
So the new x position becomes:
x' = Sx * x + 0 * y + 0And the new y position is
y' = x * 0 + Sy * y + 0By now it should be clear that the final column can be ignored, but here it is anyway:
1 = 0 * x + 0 * y + 1 * 1
Great article, thank you. It inspired my implementation in Swift:
ReplyDeletehttps://github.com/paulz/PerspectiveTransform
This helps to calculate CATransform3D
This looks great, thanks for leaving a comment.
Delete