Explaining the CGAffineTransform Matrix (Swift, Xcode, iOS)


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 + tx
We 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 +  ty
As 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 * 1
Where 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 + tx
The second column:
y' = 0 * x + 1 * y +  ty
And the third:
1 = 0 * x + 0 * y + 1 * 1
The 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) * y
Where the angle is in radians (not degrees), while the y position is:
y' = sin(angle) * x + cos(angle) * y
And finally the column that can be ignored is equal to:
1 = 0 * x + 0 * y + 1 * 1
To complete the trio, scaling can be illustrated in the following way:


So the new x position becomes:
x' = Sx * x + 0 * y + 0
 And the new y position is
 y' = x * 0 + Sy * y + 0
By now it should be clear that the final column can be ignored, but here it is anyway:
1 = 0 * x + 0 * y + 1 * 1 

Endorse on Coderwall

Comments

  1. Great article, thank you. It inspired my implementation in Swift:

    https://github.com/paulz/PerspectiveTransform

    This helps to calculate CATransform3D

    ReplyDelete
    Replies
    1. This looks great, thanks for leaving a comment.

      Delete

Post a Comment