Pieter Jongsma
Pieter Jongsma

Reputation: 3373

Get just the rotation from a CGAffineTransform

Is it possible to get just the angle of rotation from a CGAffineTransform that also has translation and scaling values? If yes, how?

Thanks in advance!

Upvotes: 6

Views: 5413

Answers (5)

Joseph Lord
Joseph Lord

Reputation: 6504

atan2(rotationTransform.b, rotationTransform.d)

The acos(b) solution suggested by someone is only valid in the range +/-0.5pi. This solution seems robust under combinations of rotation, translation and scaling although almost certainly not shear. My earlier answer (atan2(rotationTransform.b, rotationTransform.a) was not robust to scaling.

This duplicate was the basis for my original answer.

Upvotes: 6

andrewchan2022
andrewchan2022

Reputation: 5300

asin and acos is not correct when there is scale.

the correct formula is:

CGFloat radians = atan2f(self.view.transform.b, self.view.transform.a); 
CGFloat degrees = radians * (180 / M_PI); 

or:

CGFloat angle = [(NSNumber *)[view valueForKeyPath:@"layer.transform.rotation.z"] floatValue];

Upvotes: 0

Felixyz
Felixyz

Reputation: 19143

I have in the past used the XAffineTransform class from the GeoTools toolkit to extract the rotation from an affine matrix. It works even when scaling and shearing has been applied.

It's a Java library, but you should be able to easily convert it to (Objective-)C. You can look at the source for XAffineTransform here. (The method is called getRotation.) And you can read the API here.

This is the heart of the method:

final double scaleX = getScaleX0(tr);
final double scaleY = getScaleY0(tr) * flip;
return Math.atan2(tr.getShearY()/scaleY - tr.getShearX()/scaleX,
                  tr.getScaleY()/scaleY + tr.getScaleX()/scaleX);

You'd need to also implement the getScale/getShear methods. Not hard at all. (For the most part you can just copy the Java code as is.)

Upvotes: 0

zaph
zaph

Reputation: 112857

Take the asin() or acos() of the affine member b or c.

struct CGAffineTransform {
   CGFloat a;
   CGFloat b;
   CGFloat c;
   CGFloat d;
   CGFloat tx;
   CGFloat ty;
};

Upvotes: 5

Dave DeLong
Dave DeLong

Reputation: 243156

You can try using the acos() and asin() functions to reverse what CGAffineTransformMakeRotation does. However, since you've got the Scale transform matrix multiplied in there, it might be a bit difficult to do that.

Upvotes: 0

Related Questions