tags:

views:

693

answers:

5

atan2(y,x) has that discontinuity at 180° where it switches to -180°..0° going clockwise.

How do I map the range of values to 0°..360°?

here is my code:

CGSize deltaPoint = CGSizeMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
float swipeBearing = atan2f(deltaPoint.height, deltaPoint.width);

I'm calculating the direction of a swiping touch event given the startPoint and endPoint, both XY point structs. The code is for the iPhone but any language that supports atan2f() will do.

Thanks for your help guys, with both the general solution and code.

Update: I made erikkallen's answer into a function with nice long variable names so I'll comprehend it 6 months from now. Maybe it will help some other iPhone noob.

float PointPairToBearingDegrees(CGPoint startingPoint, CGPoint endingPoint)
 {
 CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
  float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
  float bearingDegrees = bearingRadians * (180.0 / M_PI); // convert to degrees
  bearingDegrees = (bearingDegrees > 0.0 ? bearingDegrees : (360.0 + bearingDegrees)); // correct discontinuity
  return bearingDegrees;
 }
+5  A: 

Just add 360° if the answer from atan2 is less than 0°.

Dave Hinton
+2  A: 
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

Edit: Oops, wrong sign.

erikkallen
That's wrong, the sign of x should be positive.
starblue
+3  A: 

Or if you don't like branching, just negate the two parameters and add 180° to the answer.

aib
+1  A: 

@erikkallen is close but not quite right.

theta_rad = atan2(y,x);
theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);

This should work in C++: (depending on how fmod is implemented, it may be faster or slower than the conditional expression)

theta_deg = fmod(atan2(y,x)/M_PI*180,360);

Alternatively you could do this:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;

since (x,y) and (-x,-y) differ in angles by 180 degrees.

Jason S
note: just realized my 3rd eqn is what @aib said.
Jason S
A: 

@Jason S: your "fmod" variant will not work on a standards-compliant implementation. The C standard is explicit and clear (7.12.10.1, "the fmod functions"):

if y is nonzero, the result has the same sign as x

thus,

fmod(atan2(y,x)/M_PI*180,360)

is actually just a verbose rewriting of:

atan2(y,x)/M_PI*180

Your third suggestion, however, is spot on.

Stephen Canon