maxgrinev maxgrinev - 4 months ago 27
iOS Question

CGAffineTransformInvert does not reverse view transformation

I want to scale+translate a view and then animate this transformation back. But CGAffineTransformInvert returns a transformation that does something different (cannot understand the logic of it).

#import <UIKit/UIKit.h>
@interface TestView : UIView {
UIView *view;
CGAffineTransform transform;
}
@end


#import "TestView.h"
#import <QuartzCore/QuartzCore.h>
@implementation TestView
- (void)testAnimation:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
CGAffineTransform transformInverted = CGAffineTransformInvert(transform);
[UIView beginAnimations:@"test2" context:NULL];
[UIView setAnimationDuration:3.0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
view.transform = transformInverted;
[UIView commitAnimations];
}

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
view = [[UIView alloc] initWithFrame:CGRectMake(150, 150, 100, 100)];
view.backgroundColor = [UIColor greenColor];
[self addSubview:view];

CGAffineTransform transform1 = CGAffineTransformTranslate(view.transform, -150, -150);
transform = CGAffineTransformScale(transform1, (float)1/2, (float)1/2);

[UIView beginAnimations:@"test1" context:NULL];
[UIView setAnimationDuration:3.0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(testAnimation:finished:context:) ];

view.transform = transform;

[UIView commitAnimations];
}
return self;
}

Answer

CGAffineTransformInvert inverts the transform matrix, and returns a matrix that when multiplied by the original results in the CGAffineTransformIdentity.

If you want to invert the translation/scale, you should track them yourself.

PS. Matrices are very complex, they don't store the translation/scale/rotation values, they are composed of several values that when multiplied by the coordinates give you the translated/scaled/rotated values, so you can't expect to invert the matrix and get a matrix with the translation, scale and rotations inverted.

You can read more about them here.

EDIT TO ANSWER YOUR COMMENT:

When working with matrices, the order of operations matters a lot, if you rotate and then translate, the result will be different than if you translate and then rotate.

To reverse the operations applied to a matrix, you should apply the opposite operations in the reverse order, in this case, to reverse this:

CGAffineTransform transform1 = CGAffineTransformTranslate(view.transform, x1, x2);
CGAffineTransform transform2 = CGAffineTransformScale(transform1, r1, r2);
CGAffineTransform transform3 = CGAffineTransformRotate(transform2, a);

You'd need to do this:

CGAffineTransform reversed3 = CGAffineTransformRotate(transform3, -a);
CGAffineTransform reversed2 = CGAffineTransformScale(reversed3, 1/r1, 1/r2);
CGAffineTransform reversed1 = CGAffineTransformTranslate(reversed2, -x1, -x2);

[view setTransform:reversed1];

If you hadn't modified the view's transform before, you can just do:

[view setTransform:CGAffineTransformIdentity];

Which is zero rotation, zero translation, and a scale of 1.