Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CGAffineTransform: How to calculate multiply CGAffineTransform?

I need transform view from origin(250, 250) to origin(352, 315), and width/height change from (100.0, 100.0) to (68, 68). I know I can combine several CGAffineTransform function together, such as scale, rotate, translate. But i don't know how to count the order of those transformations, and the exact parameter of them. I have try several time, but can't move the view to correct position.

Anyone can help?

like image 395
Cindy Avatar asked Feb 16 '16 10:02

Cindy


People also ask

How CGAffineTransform works?

The CGAffineTransform type provides functions for creating, concatenating, and applying affine transformations. Affine transforms are represented by a 3 by 3 matrix: Because the third column is always (0,0,1) , the CGAffineTransform data structure contains values for only the first two columns.

When would you use CGAffineTransform?

We can also use CGAffineTransform to rotate views, using its rotationAngle initializer. This accepts one parameter, which is the amount in radians you want to rotate. There are three catches to using this function: You need to provide the value in radians specified as a CGFloat .

How do you change view in IOS Swift?

To change a UIView's position, a translate matrix is applied to the transform matrix. This will change the values tx and ty values of the transform matrix. This function creates an affine transform matrix translating the current transform with the provided values.


1 Answers

A little understanding about what is happening behind the scenes is always nice in these matrix transformations.

Apple docs has a great documentation about transforms, so let's use it.


A translation matrix looks like :

|  1   0   0  |
|  0   1   0  |
|  tx  ty  1  |

where (tx, ty) is your translation vector.


A scaling matrix looks like :

|  sx  0   0  |
|  0   sy  0  |
|  0   0   1  |

where sxand sy are the scale factor in the X and Y axis.


You want to concatenate these matrix using CGAffineTransformConcat, but as according to its doc :

Note that matrix operations are not commutative—the order in which you concatenate matrices is important. That is, the result of multiplying matrix t1 by matrix t2 does not necessarily equal the result of multiplying matrix t2 by matrix t1.

You have to translate your view before scaling it, otherwise your translation vector will be scaled according to sx and sy coefficients.

Let's show it easily :

let scaleMatrix = CGAffineTransformMakeScale(0.68, 0.68)
let translateMatrix = CGAffineTransformMakeTranslation(102, 65)

let translateThenScaleMatrix = CGAffineTransformConcat(scaleMatrix, translateMatrix)
NSLog("translateThenScaleMatrix : \(translateThenScaleMatrix)")
// outputs : CGAffineTransform(a: 0.68, b: 0.0, c: 0.0, d: 0.68, tx: 102.0, ty: 65.0)
// the translation is the same

let scaleThenTranslateMatrix = CGAffineTransformConcat(translateMatrix, scaleMatrix)
NSLog("scaleThenTranslateMatrix : \(scaleThenTranslateMatrix)")
// outputs : CGAffineTransform(a: 0.68, b: 0.0, c: 0.0, d: 0.68, tx: 69.36, ty: 44.2)
// the translation has been scaled too

And let's prove it mathematically. Please note that when you perform an operation A then an operation B, the related matrix is computed by doing matB*matA, the first operation is on the right. Since multiplication is not commutative for matrix, it's important.

// Translate then  scaling :
|  sx  0   0  |   |  1   0   0  |   |    sx   0    0 |
|  0   sy  0  | . |  0   1   0  | = |    0    sy   0 |
|  0   0   1  |   |  tx  ty  1  |   |    tx   ty   1 |
// The resulting matrix has the same value for translation

// Scaling then translation :
|  1   0   0  |   |  sx  0   0  |   |    sx     0      0 |
|  0   1   0  | . |  0   sy  0  | = |    0      sy     0 |
|  tx  ty  1  |   |  0   0   1  |   |  sx.tx   sy.ty   1 |
// The translation values are affected by scaling coefficient
like image 126
Michaël Azevedo Avatar answered Sep 21 '22 10:09

Michaël Azevedo