1

I would like to calculate the distance between two degree values. I know that I could use this if the points just where on one axis:

var dist = Math.abs( x1 - x2 );

...but the problem with degrees is, that they can either be negative or positive, also they could be somewhere above 360. My goal is to calculate the distance, no matter if the rotation is negative or higher then 360°

EDIT

To make it clearer what I want: For example, I could could have the values -90deg and 270deg. This should result in a result of 0 for the distance. If the first element's rotation would change to either -100deg of -80deg, the distance should change to 10.

rassoh
  • 421
  • 1
  • 3
  • 18

4 Answers4

3

If you want this to work for any angle (including angles like 750 deg) and in a language where you have a remainder operator that's signed (like Java or JavaScript), then you need to do more work. If you're in a language with an unsigned operator, then the answer by Rory Daulton is good. (That is, in summary, use rot1%360 below where I call modulo(rot1,360) and similarly for rot2.)

First you need to make each negative angle into an equivalent positive angle. There's no single operator that will do this since, for example, -10 % 360 = -10 in these languages. You can get this with a function like this (assuming y is positive):

function modulo(x,y) {
    var xPrime = x;
    while(xPrime<0) {
        xPrime += y; // ASSUMES y > 0
    }
    return xPrime % y;
}

Then you can do more or less as suggested by others, but using this custom function instead of the % operator.

var distance = Math.abs(modulo(rot1,360) - modulo(rot2,360))
distance = Math.min(distance, 360-distance)
Brick
  • 3,475
  • 7
  • 21
  • 43
  • Thank you @Brick, this works perfectly! Just change the `x` in the while-loop to xPrime, so that it doesn't kill the browser :) Thank you! – rassoh Mar 03 '17 at 01:59
  • 1
    Great. I made the correction that you noted. Also, you might get better efficiency by taking the `%` first and then correcting the sign, like `z = x % y` followed by `if (z < 0) {z += y;}`. That would eliminate the loop, but I didn't check it in all cases. – Brick Mar 03 '17 at 02:13
1

Python code that seems to work in all cases is

dist = abs(x1 % 360 - x2 % 360)
dist = min(dist, 360 - dist)

That last line is needed to handle a case like x1=10; x2=350. The other answers would give 340 but the proper answer is 20.

Rory Daulton
  • 19,351
  • 5
  • 34
  • 45
  • This will fail in JavaScript when the operands are negative, I think. That `%` is signed, whereas this (and other answers) appear to assume that it is unsigned. Original version of the question specified JS. – Brick Mar 03 '17 at 01:31
  • @Brick: The `%` operator is unsigned in Python. As I look at the edit history of the problem I see no version where JavaScript is specified, either in the text or in a tag. – Rory Daulton Mar 03 '17 at 01:38
  • It's implied by the syntax and also the answer posted by the OP that he wants JS. Your answer is correct in Python, I believe, but not generally correct across languages for the reason that I mentioned. – Brick Mar 03 '17 at 01:40
1

Old topic but, the accepted answer is not really acceptable for a problem I had myself because of the while loop, and sadly that is the best I could find on a google search. However I found a better and faster solution if you might as well have to deal with very high negative rotation values.

This line of code takes a rotation value (r) and maps it to a range of 0-360.

r = (r<0) ? (r+(Math.ceil(-r/360)*360)) : (r%360);

Further explanation: The accepted answer adds 360 every loop to the negative rotation value until it is positive, whereas my solution calculates how often it needs to add 360 and does that in one go.

-1

So, I worked it out, following this answer:

function modulo(value, mod) {
    return value - Math.floor( value/mod ) * value;
}
var dist = rotation1 - rotation2;
dist = Math.abs( modulo( (dist + 180), 360 ) - 180 );

EDIT

Actually, this answer works as well. Ported to JavaScript it would be:

var dist = Math.abs(rotation1 % 360 - rotation2 % 360);
dist = Math.min(dist, 360 - dist);

I like it, because it doesn't need the special modulo function.

Community
  • 1
  • 1
rassoh
  • 421
  • 1
  • 3
  • 18
  • Try the second answer with negative angles. I believe it will fail. Try your original answer with angles like 750 deg and 10 deg. I believe it will fail. – Brick Mar 03 '17 at 01:35
  • @Brick, you are right. Actually, the first solution also seems to fail with negative values.... – rassoh Mar 03 '17 at 01:41
  • 1
    Hang on, I'm writing a full answer. – Brick Mar 03 '17 at 01:42