An image should be scaled and transformed.
Depending on how the transform matrix is composed, I get different results:
// A) This produces the desired result, scales the image and translates the image independently from each other
let transform = CGAffineTransform(translationX: translation.x, y: translation.y).scaledBy(x: scale.width, y: scale.height)
// B) This also produces the desired result
let scaleTransform = CGAffineTransform(scaleX: scale.width, y: scale.height)
let translateTransform = CGAffineTransform(translationX: translation.x, y: translation.y)
let transform = scaleTransform.concatenating(translateTransform)
// C) This does not produce the desired result, it also scales the translation, so a 10x scale results in a 10x translation
let transform = CGAffineTransform(scaleX: scale.width, y: scale.height).translatedBy(x: translation.x, y: translation.y)
// Transform image
image = image.transformed(by: transform)
If .concatenating
means multiplying and .scaledBy
or .translatedBy
means adding the two matrices, why does A and C not produce the same results given that matrix order should not matter when adding them together?
It is a coincidence that the multiplication and the addition of a scaling matrix and a translation matrix have the same result.
In the general case, scaledBy
and translatedBy
don't mean adding, they are shorthand for concatenating two transforms, which is a matrix multiplication. Matrix multiplication is only commutative for diagonal matrices (matrices that only have non-zero values in the diagonal line), so S * T
generally isn't the same as T * S
.
Look up $(xcrun --show-sdk-path)/System/Library/Frameworks/CoreGraphics.framework/Headers/CGAffineTransform.h
for what each function does:
CGAffineTransformTranslate
: t' = [ 1 0 0 1 tx ty ] * tCGAffineTransformScale
: t' = [ sx 0 0 sy 0 0 ] * tCGAffineTransformRotate
: t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * tCGAffineTransformConcat
: t' = t1 * t2This means that when you use CGAffineTransformConcat
, t1
must be the transformation that you're applying and t2
must be the matrix that you're transforming. In other words, scale.translatedBy
is equivalent to concat(translation, scale)
, not concat(scale, translation)
. When using concatenate
as a method, this makes the operation look backwards because of its mathematical definition.