I'm looking for a formula to find the shortest distance in degrees between two degree marks on a circle: for instance, 30 degrees and 170 degrees (140 degrees).
The two degree marks can be virtually any real number, and isn't necessarily between 0 and 360 (can be negative, or much greater than 360, for instance -528.2 and 740 (which is 171.8 degrees)). However, the distance should always be <= 180 degrees and >= 0 degrees.
It sounds simple enough. But, I've been trying to find a good solution for this and I've tried a lot of different code but nothing I've found so far works in all the cases I've tried. I'm working in c++. Does anyone have any ideas?
So, the distance between the circle and the point will be the difference of the distance of the point from the origin and the radius of the circle. Using the Distance Formula , the shortest distance between the point and the circle is |√(x1)2+(y1)2−r | .
The area that a chord cuts off is called a segment. The area inside a circle and bounded by two radii is a sector. The length between two points around the circumference of a circle is an arc.
Solution As discussed earlier, the shortest distance between a line and a circle will be the perpendicular distance of the line from the centre of the circle, minus the radius. The radius of the circle is 1.
A straight line is the shortest distance between two points.
I had been looking for a microcontroller solution like this for gearbox seeking for an animatronic puppet and I didn't have the grunt to calculate trig properly.
@ruakh's answer was a good basis but I founded that the sign was incorrectly flipped in certain conditions.
Here's the solution that worked for me. This solution works for degree marks in a circle but changing MAX_VALUE
allows this to work for an arbitrary max range that's useful when measuring gear encoder pulses.
Tested on Arduino.
#define MAX_VALUE 360
float shortestSignedDistanceBetweenCircularValues(float origin, float target){
float signedDiff = 0.0;
float raw_diff = origin > target ? origin - target : target - origin;
float mod_diff = fmod(raw_diff, MAX_VALUE); //equates rollover values. E.g 0 == 360 degrees in circle
if(mod_diff > (MAX_VALUE/2) ){
//There is a shorter path in opposite direction
signedDiff = (MAX_VALUE - mod_diff);
if(target>origin) signedDiff = signedDiff * -1;
} else {
signedDiff = mod_diff;
if(origin>target) signedDiff = signedDiff * -1;
}
return signedDiff;
}
Step 1: Get the "raw" difference. For example, given -528.2
and 740.0
, this is 1268.2
.
raw_diff = first > second ? first - second : second - first
raw_diff = std::fabs(first - second)
Step 2: Subtract a multiple of 360.0
to get a value between 0.0
(inclusive) and 360.0
(exclusive).
mod_diff = std::fmod(raw_diff, 360.0)
Step 3: If this value is greater than 180.0
, subtract it from 360.0
.
dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff
dist = 180.0 - std::fabs(mod_diff - 180.0)
It's probably most readable as a series of statements:
double raw_diff = first > second ? first - second : second - first;
double mod_diff = std::fmod(raw_diff, 360.0);
double dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff;
But if desired, it's not hard to put it all into a single expression:
180.0 - std::fabs(std::fmod(std::fabs(first - second), 360.0) - 180.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With