1
votes

I'm pretty confused by radians at the best of times, so I tend to work in degrees when I'm rotating UIViews. So far I've been using the following formula to convert degrees to radians:

#define radians(x) (M_PI * x / 180.0)

So far so good. The problem comes when I have a UIView on the screen which the user is rotating through 360 degrees and more, and I want to display on the screen how many degrees the image has been rotated. I have this and it works fine up to 180 degrees:

float rot = [recognizer rotation];
[self.steeringWheel setTransform:CGAffineTransformRotate([self.steeringWheel transform], (rot))]; // turn wheel

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

self.degreesBox.text = [NSString stringWithFormat:@"%1.0f", degrees]; // show degrees of rotation on screen

After 180 degrees, my read out changes to -179, -178 etc all the way back to zero. Instead, I want it to continue counting on up to 359 (and then back to zero, 1, 2, etc if possible).

I could use a formula that adds 2 to 179, 3 to 178 etc to get the right amount, but this would not work when I then go and turn the wheel in the opposite direction (a -1 degree turn would read out as 359, when really I want it to read out as either 1 or -1).

I hope this makes sense. Basically, I want to read how much the wheel has turned in each direction from the start point. What I'm getting at the moment is a reading of how many degrees back to the start point via the shortest route.

2

2 Answers

1
votes

Try this code:

CGFloat radians = atan2f(steeringWheel.transform.b, steeringWheel.transform.a); 
if (radians < 0.0) radians += 2 * M_PI;
CGFloat degrees = radians * (180 / M_PI);

EDIT:

After rereading your question i saw where your problem really is. atan2 will always return results in range (−π, π].

And it looks you want the stearing wheel to be able to rotate a full circle to the left and a full cricle to the right. You can solve this by comparing new angle to the old angle so you'd know if user is rotating the wheel in CW or CCW.

You can also set a flag when user rotates the wheel left (CCW) from starting (idle) position to manage sign accordingly.

0
votes

Swift 3:
Animation with nested closure is better than animation delay block.

UIView.animate(withDuration: 0.5, animations: { 
     button.transform = CGAffineTransform(rotationAngle: (CGFloat(Double.pi)) 
}) { (isAnimationComplete) in

           // Nested Block
            UIView.animate(withDuration: 0.5) { 
               button.transform = CGAffineTransform(rotationAngle: (CGFloat(Double.pi * 2))
           }    
     }

Animation with delay and options:

// Rotation from 0 to 360 degree    
UIView.animate(withDuration:0.5, animations: { () -> Void in
      button.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
})

// Rotation from 180 to 360 degree
UIView.animate(withDuration: 0.5, delay: 0.45, options: .curveEaseIn, animations: { () -> Void in
       button.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi * 2))
}, completion: nil)