Given a CATransform3D transform, I want to extract the scale, translation and rotation as separate transforms. From some digging, I was able to accomplish this for CGAffineTransform in Swift, like so:
extension CGAffineTransform {
var scaleDelta:CGAffineTransform {
let xScale = sqrt(a * a + c * c)
let yScale = sqrt(b * b + d * d)
return CGAffineTransform(scaleX: xScale, y: yScale)
}
var rotationDelta:CGAffineTransform {
let rotation = CGFloat(atan2f(Float(b), Float(a)))
return CGAffineTransform(rotationAngle: rotation)
}
var translationDelta:CGAffineTransform {
return CGAffineTransform(translationX: tx, y: ty)
}
}
How would one do something similar for CATransform3D using math? (I am looking for a solution that doesn't use keypaths.)
(implementation or math-only answers at your discretion)
If you're starting from a proper affine matrix that can be decomposed correctly (if not unambiguously) into a sequence of scale, rotate, translate, this method will perform the decomposition into a tuple of vectors representing the translation, rotation (Euler angles), and scale components:
To show that this routine correctly extracts the various components, construct a transform and ensure that it decomposes as expected:
This produces:
Note that this decomposition assumes an Euler multiplication order of XYZ, which is only one of several possible orderings.
Caveat: There are certainly values for which this method is not numerically stable. I haven't tested it extensively enough to know where these pitfalls lie, so caveat emptor.