views:

198

answers:

5

There are two views:

viewA and viewB. Both are rotated.

The coordinate system for rotation is weird: It goes from 0 to 179,999999 or -179,99999 degrees. So essentially 179,99999 and -179,99999 are very close together!

I want to calculate how much degrees or radians are between these rotations.

For example:

viewA is rotated at 20 degrees

viewB is rotated at 30 degrees

I could just do: rotationB - rotationA = 10.

But the problem with this formula:

viewA is rotated at 179 degrees viewB is rotated at -179 degrees

that would go wrong: rotationB - rotationA = -179 - 179 = -358

358 is plain wrong, because they are very close together in reality. So one thing I could do maybe is to check if the absolute result value is bigger than 180, and if so, calculate it the other way around to get the short true delta. But I feel this is plain wrong and bad, because of possible floating point errors and unprecision. So if two views are rotated essentially equally at 179,99999999999 degrees I might get a weird 180 or a 0 if I am lucky.

Maybe there's a genius-style math formular with PI, sine or other useful stuff to get around this problem?

A: 

Take the difference, add 360, and mod by 360.

Ignacio Vazquez-Abrams
mod by 180, not by 360...
Charles Bretana
@Charles: Even if the angles are, say, 160 and -30?
Ignacio Vazquez-Abrams
well, no, but your rule needs to handle any possible angles, no ?? With 50 and -30, for example, you don't need to add anything...
Charles Bretana
@Charles: And the mod of 360 undoes the adding 360 where it makes sense.
Ignacio Vazquez-Abrams
@Ignatio, well, I was wrong, moding by anything will not always work... see my edited answer...
Charles Bretana
+2  A: 

EDIT: Original answer (with Mod) was wrong. would have given 180 - right answer in certain circumstances (angles 30 and -20 for example would give answer of 130, not correct answer of 50):

Two correct answers for all scenarios:

If A1 and A2 are two angles (between -179.99999 and 179.99999, and Abs means take the Absolute Value, The angular distance between them, is expressed by:

Angle between = 180 - Abs(Abs(A1 - A2) - 180)

Or, using C-style ternary operator:

Angle between = A1 < 180 + A2? A1 - A2: 360 + A1 - A2
Charles Bretana
what's the Mod doing?
openfrog
My shortcut abbreviation for Modulus... i.e. divide and return only the remainder...
Charles Bretana
I'd suggest modifying your answer and removing your original incorrect portion. We have answer history, so we can look at it later. It only serves to distract now.
Simucal
@Simucal, Thanks, didn't know that... thought that leaving the original wrong answer there would alleviate confusion looking at comments...
Charles Bretana
@Charles Bretana, I understand what you are saying. However, when I look at your "Answer", I don't care about its history. I only care that it is the canonical, most perfect form, of the answer to the question. When people come to look at this question and answer months from now, it makes sense to have a clean and concise answer.
Simucal
@openfrog `Abs()` is just as fast as `Min()`, so in reality this is slightly slower than my answer
BlueRaja - Danny Pflughoeft
A: 

Let's try this again:
There are two angles between A and B. One of them is

θ1 = A - B

The other is

θ2 = 360 - θ1

So just take the minimum of those two.

BlueRaja - Danny Pflughoeft
Note that if you allow angles outside of the range -180 < A < 180, you will need to use `θ = (A-B) mod 360` instead
BlueRaja - Danny Pflughoeft
A: 

Judging from the recent questions you've asked, you might want to read up on the unit circle. This is a fundamental concept in trigonometry, and it is how angles are calculated when doing rotations using CGAffineTransforms or CATransform3Ds.

Basically, the unit circle goes from 0 to 360 degrees, or 0 to 2 * pi (M_PI is the constant used on the iPhone) radians. Any angle greater than 360 degrees is the same as that angle minus a multiple of 360 degrees. For example, 740 degrees is the same as 380 degrees, which is the same as 20 degrees, when it comes to the ending position of something rotated by that much.

Likewise, negative degrees are the same as if you'd added a multiple of 360 degrees to them. -20 degrees is the same as 340 degrees.

There's no magic behind any of these calculations, you just have to pay attention to when something crosses the 0 / 360 degree point on the circle. In the case you describe, you can add 360 to any negative values to express them in positive angles. When subtracting angles, if the ending angle is less than the starting angle, you may also need to add 360 to the result to account for crossing the zero point on the unit circle.

Brad Larson
A: 

In addition to Brad Larson's excellent answer I would add that you can do:

CGFloat adjustAngle(angle) { return fmod(angle + 180.0, 360.0); }
...
CGFloat difference = fmod(adjustAngle(angle1) - adjustAngle(angle2), 360.0);
Colin Barrett