From CATransform3D to CGAffineTransform
core-animation, core-graphics
Solution
It's possible convert a `CATransform3D` to a `CGAffineTransform`, but you will lose some capabilities. I found it useful to convert the aggregate transform of a layer and its ancestors into a `CGAffineTransform` so I could render it with Core Graphics. The constraints are:
- Your input will be treated as flat in the XY plane
- Your output will be treated as flat in the XY plane too
- Perspective / foreshortening from `.m34` will be neutralized
If that sounds OK for your purposes:
// m13, m23, m33, m43 are not important since the destination is a flat XY plane.
// m31, m32 are not important since they would multiply with z = 0.
// m34 is zeroed here, so that neutralizes foreshortening. We can't avoid that.
// m44 is implicitly 1 as CGAffineTransform's m33.
CATransform3D fullTransform = <your 3D transform>
CGAffineTransform affine = CGAffineTransformMake(fullTransform.m11, fullTransform.m12, fullTransform.m21, fullTransform.m22, fullTransform.m41, fullTransform.m42);
You will want to do all your work in 3D transforms first, say by concatenating from your superlayers, and then finally convert the aggregate `CATransform3D` to a `CGAffineTransform`. Given that layers are flat to begin with and render onto a flat target, I found this very suitable since my 3D rotations became 2D shears. I also found it acceptable to sacrifice foreshortening. There's no way around that because affine transforms have to preserve parallel lines.
To render a 3D-transformed layer using Core Graphics, for instance, you might concatenate the transforms (respecting anchor points!), then convert to affine, and finally:
CGContextSaveGState(context);
CGContextConcatCTM(context, affine);
[layer renderInContext:context];
CGContextRestoreGState(context);
Problem
I'm using the following function to apply a pulse effect to a view ``` - (void)pulse { CATransform3D trasform = CATransform3DScale(self.layer.transform, 1.15, 1.15, 1); trasform = CATransform3DRotate(trasform, angle, 0, 0, 0); CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; animation.toValue = [NSValue valueWithCATransform3D:trasform]; animation.autoreverses = YES; animation.duration = 0.3; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.repeatCount = 2; [self.layer addAnimation:animation forKey:@"pulseAnimation"]; } ``` I would like to obtain the same result using the CGAffineTransform self.transform instead of the CATransform3D self.layer.transform. Is this possible?