Angle difference between two bearings: Difference between revisions
(Added Sidef) |
Catskill549 (talk | contribs) |
||
Line 23: | Line 23: | ||
*60175.77306795546 and 42213.07192354373 |
*60175.77306795546 and 42213.07192354373 |
||
=={{header|AWK}}== |
|||
<lang AWK> |
|||
# syntax: GAWK -f ANGLE_DIFFERENCE_BETWEEN_TWO_BEARINGS.AWK |
|||
BEGIN { |
|||
fmt = "%11s %11s %11s\n" |
|||
while (++i <= 11) { u = u "-" } |
|||
printf(fmt,"B1","B2","DIFFERENCE") |
|||
printf(fmt,u,u,u) |
|||
main(20,45) |
|||
main(-45,45) |
|||
main(-85,90) |
|||
main(-95,90) |
|||
main(-45,125) |
|||
main(-45,145) |
|||
main(29.4803,-88.6381) |
|||
main(-78.3251,-159.036) |
|||
main(-70099.74233810938,29840.67437876723) |
|||
main(-165313.6666297357,33693.9894517456) |
|||
main(1174.8380510598456,-154146.66490124757) |
|||
main(60175.77306795546,42213.07192354373) |
|||
exit(0) |
|||
} |
|||
function main(b1,b2) { |
|||
printf("%11.2f %11.2f %11.2f\n",b1,b2,angle_difference(b1,b2)) |
|||
} |
|||
function angle_difference(b1,b2, r) { |
|||
r = (b2 - b1) % 360 |
|||
if (r < -180) { |
|||
r += 360 |
|||
} |
|||
if (r >= 180) { |
|||
r -= 360 |
|||
} |
|||
return(r) |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
B1 B2 DIFFERENCE |
|||
----------- ----------- ----------- |
|||
20.00 45.00 25.00 |
|||
-45.00 45.00 90.00 |
|||
-85.00 90.00 175.00 |
|||
-95.00 90.00 -175.00 |
|||
-45.00 125.00 170.00 |
|||
-45.00 145.00 -170.00 |
|||
29.48 -88.64 -118.12 |
|||
-78.33 -159.04 -80.71 |
|||
-70099.74 29840.67 -139.58 |
|||
-165313.67 33693.99 -72.34 |
|||
1174.84 -154146.66 -161.50 |
|||
60175.77 42213.07 37.30 |
|||
</pre> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
<lang cpp>#include <cmath> |
<lang cpp>#include <cmath> |
Revision as of 04:25, 13 February 2017
Finding the angle between two bearings is often confusing.[1]
- Task
We need to find the angle which is the result of the subtraction b2-b1, where b1 and b2 are both bearings. Input bearings are expressed by numbers in the range -180 to +180 degrees. The result must also be expressed in the range +180 to -180 degrees. Compute the angle for the following pairs:
- 20 degrees (b1) and 45 degrees (b2)
- -45 and 45
- -85 and 90
- -95 and 90
- -45 and 125
- -45 and 145
- 29.4803 and -88.6381
- -78.3251 and -159.036
Optional extra: allow the input bearings to be any (finite) value. Test cases:
- -70099.74233810938 and 29840.67437876723
- -165313.6666297357 and 33693.9894517456
- 1174.8380510598456 and -154146.66490124757
- 60175.77306795546 and 42213.07192354373
AWK
<lang AWK>
- syntax: GAWK -f ANGLE_DIFFERENCE_BETWEEN_TWO_BEARINGS.AWK
BEGIN {
fmt = "%11s %11s %11s\n" while (++i <= 11) { u = u "-" } printf(fmt,"B1","B2","DIFFERENCE") printf(fmt,u,u,u) main(20,45) main(-45,45) main(-85,90) main(-95,90) main(-45,125) main(-45,145) main(29.4803,-88.6381) main(-78.3251,-159.036) main(-70099.74233810938,29840.67437876723) main(-165313.6666297357,33693.9894517456) main(1174.8380510598456,-154146.66490124757) main(60175.77306795546,42213.07192354373) exit(0)
} function main(b1,b2) {
printf("%11.2f %11.2f %11.2f\n",b1,b2,angle_difference(b1,b2))
} function angle_difference(b1,b2, r) {
r = (b2 - b1) % 360 if (r < -180) { r += 360 } if (r >= 180) { r -= 360 } return(r)
} </lang>
- Output:
B1 B2 DIFFERENCE ----------- ----------- ----------- 20.00 45.00 25.00 -45.00 45.00 90.00 -85.00 90.00 175.00 -95.00 90.00 -175.00 -45.00 125.00 170.00 -45.00 145.00 -170.00 29.48 -88.64 -118.12 -78.33 -159.04 -80.71 -70099.74 29840.67 -139.58 -165313.67 33693.99 -72.34 1174.84 -154146.66 -161.50 60175.77 42213.07 37.30
C++
<lang cpp>#include <cmath>
- include <iostream>
using namespace std;
double getDifference(double b1, double b2) { double r = fmod(b2 - b1, 360.0); if (r < -180.0) r += 360.0; if (r >= 180.0) r -= 360.0; return r; }
int main() { cout << "Input in -180 to +180 range" << endl; cout << getDifference(20.0, 45.0) << endl; cout << getDifference(-45.0, 45.0) << endl; cout << getDifference(-85.0, 90.0) << endl; cout << getDifference(-95.0, 90.0) << endl; cout << getDifference(-45.0, 125.0) << endl; cout << getDifference(-45.0, 145.0) << endl; cout << getDifference(-45.0, 125.0) << endl; cout << getDifference(-45.0, 145.0) << endl; cout << getDifference(29.4803, -88.6381) << endl; cout << getDifference(-78.3251, -159.036) << endl;
cout << "Input in wider range" << endl; cout << getDifference(-70099.74233810938, 29840.67437876723) << endl; cout << getDifference(-165313.6666297357, 33693.9894517456) << endl; cout << getDifference(1174.8380510598456, -154146.66490124757) << endl; cout << getDifference(60175.77306795546, 42213.07192354373) << endl;
return 0; }</lang>
- Output:
Input in -180 to +180 range 25 90 175 -175 170 -170 170 -170 -118.118 -80.7109 Input in wider range -139.583 -72.3439 -161.503 37.2989
Haskell
<lang Haskell>import Text.Printf
type Radians = Float
type Degrees = Float
angleBetweenDegrees :: Degrees -> Degrees -> Degrees angleBetweenDegrees a b = degrees $ relBearing (radians a) (radians b)
relBearing :: Radians -> Radians -> Radians relBearing a b -- sign * dot-product
= sign * acos ((ax * bx) + (ay * by)) where (ax, ay) = (sin a, cos a) (bx, by) = (sin b, cos b) sign -- cross-product > 0 ? = if ((ay * bx) - (by * ax)) > 0 then 1 else (-1)
degrees :: Radians -> Degrees degrees = (/ pi) . (180 *)
radians :: Degrees -> Radians radians = (/ 180) . (pi *)
main :: IO () main =
mapM_ putStrLn $ displayRow <$> [ (20.0, 45.0) , (-45.0, 45.0) , (-85.0, 90.0) , (-95.0, 90.0) , (-45.0, 125.0) , (-45.0, 145.0) ] where displayRow (x, y) = printf "%6.2f° + %6.2f° -> %7.2f°" x y $ angleBetweenDegrees x y</lang>
- Output:
20.00° + 45.00° -> 25.00° -45.00° + 45.00° -> 90.00° -85.00° + 90.00° -> 175.00° -95.00° + 90.00° -> -175.00° -45.00° + 125.00° -> 170.00° -45.00° + 145.00° -> -170.00°
J
<lang j>relativeBearing=: -&360^:(180&<)@(360 | 720 + -~)/</lang> <lang j>tests=: _99&".;._2 noun define 20 45 -45 45 -85 90 -95 90 -45 125 -45 145 29.4803 -88.6381 -78.3251 -159.036 -70099.74233810938 29840.67437876723 -165313.6666297357 33693.9894517456 1174.8380510598456 -154146.66490124757 60175.77306795546 42213.07192354373 )
tests ,. relativeBearing"1 tests 20 45 25 _45 45 90 _85 90 175 _95 90 _175 _45 125 170 _45 145 _170 29.4803 _88.6381 _118.118
_78.3251 _159.036 _80.7109 _70099.7 29840.7 _139.583
_165314 33694 _72.3439 1174.84 _154147 _161.503 60175.8 42213.1 37.2989</lang>
Java
<lang java>public class AngleDifference {
public static double getDifference(double b1, double b2) { double r = (b2 - b1) % 360.0; if (r < -180.0) r += 360.0; if (r >= 180.0) r -= 360.0; return r; }
public static void main(String[] args) { System.out.println("Input in -180 to +180 range"); System.out.println(getDifference(20.0, 45.0)); System.out.println(getDifference(-45.0, 45.0)); System.out.println(getDifference(-85.0, 90.0)); System.out.println(getDifference(-95.0, 90.0)); System.out.println(getDifference(-45.0, 125.0)); System.out.println(getDifference(-45.0, 145.0)); System.out.println(getDifference(-45.0, 125.0)); System.out.println(getDifference(-45.0, 145.0)); System.out.println(getDifference(29.4803, -88.6381)); System.out.println(getDifference(-78.3251, -159.036));
System.out.println("Input in wider range"); System.out.println(getDifference(-70099.74233810938, 29840.67437876723)); System.out.println(getDifference(-165313.6666297357, 33693.9894517456)); System.out.println(getDifference(1174.8380510598456, -154146.66490124757)); System.out.println(getDifference(60175.77306795546, 42213.07192354373)); } }</lang>
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.1184 -80.7109 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
JavaScript
ES5
This approach should be reliable but it is also very inefficient.
<lang javascript>function relativeBearing(b1Rad, b2Rad) { b1y = Math.cos(b1Rad); b1x = Math.sin(b1Rad); b2y = Math.cos(b2Rad); b2x = Math.sin(b2Rad); crossp = b1y * b2x - b2y * b1x; dotp = b1x * b2x + b1y * b2y; if(crossp > 0.) return Math.acos(dotp); return -Math.acos(dotp); }
function test() { var deg2rad = 3.14159265/180.0; var rad2deg = 180.0/3.14159265; return "Input in -180 to +180 range\n" +relativeBearing(20.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n" +relativeBearing(-45.0*deg2rad, 45.0*deg2rad)*rad2deg+"\n" +relativeBearing(-85.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n" +relativeBearing(-95.0*deg2rad, 90.0*deg2rad)*rad2deg+"\n" +relativeBearing(-45.0*deg2rad, 125.0*deg2rad)*rad2deg+"\n" +relativeBearing(-45.0*deg2rad, 145.0*deg2rad)*rad2deg+"\n"
+relativeBearing(29.4803*deg2rad, -88.6381*deg2rad)*rad2deg+"\n" +relativeBearing(-78.3251*deg2rad, -159.036*deg2rad)*rad2deg+"\n"
+ "Input in wider range\n" +relativeBearing(-70099.74233810938*deg2rad, 29840.67437876723*deg2rad)*rad2deg+"\n" +relativeBearing(-165313.6666297357*deg2rad, 33693.9894517456*deg2rad)*rad2deg+"\n" +relativeBearing(1174.8380510598456*deg2rad, -154146.66490124757*deg2rad)*rad2deg+"\n" +relativeBearing(60175.77306795546*deg2rad, 42213.07192354373*deg2rad)*rad2deg+"\n";
}</lang>
- Output:
Input in -180 to +180 range 25.000000000000004 90 174.99999999999997 -175.00000041135993 170.00000000000003 -170.00000041135996 -118.1184 -80.71089999999998 Input in wider range -139.5833974814558 -72.34414600076728 -161.50277501127033 37.2988761562732
ES6
<lang JavaScript>(() => {
const [Pi, sin, cos, acos] = ['PI', 'sin', 'cos', 'acos'] .map(k => Math[k]), degRad = x => Pi * x / 180.0, radDeg = x => 180.0 * x / Pi;
// relBearing :: Radians -> Radians -> Radians const relBearing = (ar, br) => { const [ax, ay] = [sin(ar), cos(ar)], [bx, by] = [sin(br), cos(br)],
// Cross-product > 0 ? sign = ((ay * bx) - (by * ax)) > 0 ? +1 : -1;
// Sign * dot-product return sign * acos((ax * bx) + (ay * by)); }
// TEST
// justifyRight :: Int -> Char -> Text -> Text const justifyRight = (n, cFiller, strText) => n > strText.length ? ( (cFiller.repeat(n) + strText) .slice(-n) ) : strText;
// showMap :: Degrees -> Degrees -> String const showMap = (da, db) => justifyRight(6, ' ', `${da}° +`) + justifyRight(11, ' ',` ${db}° -> `) + justifyRight(7, ' ', `${(radDeg(relBearing(degRad(da), degRad(db)))) .toPrecision(4)}°`);
return [ [20, 45], [-45, 45], [-85, 90], [-95, 90], [-45, 125], [-45, 145] ].map(xy => showMap(...xy)) .join('\n');
})();</lang>
- Output:
20° + 45° -> 25.00° -45° + 45° -> 90.00° -85° + 90° -> 175.0° -95° + 90° -> -175.0° -45° + 125° -> 170.0° -45° + 145° -> -170.0°
Perl 6
<lang perl6>sub infix:<∠> (Real $b1, Real $b2) {
(my $b = ($b2 - $b1 + 720) % 360) > 180 ?? $b - 360 !! $b;
}
- TESTING
for 20, 45,
-45, 45, -85, 90, -95, 90, -45, 125, -45, 145, 29.4803, -88.6381, -78.3251, -159.036, -70099.74233810938, 29840.67437876723, -165313.6666297357, 33693.9894517456, 1174.8380510598456, -154146.66490124757, 60175.77306795546, 42213.07192354373
-> $b1, $b2 { say "$b1 ∠ $b2 = ", $b1 ∠ $b2 }</lang>
- Output:
20 ∠ 45 = 25 -45 ∠ 45 = 90 -85 ∠ 90 = 175 -95 ∠ 90 = -175 -45 ∠ 125 = 170 -45 ∠ 145 = -170 29.4803 ∠ -88.6381 = -118.1184 -78.3251 ∠ -159.036 = -80.7109 -70099.74233810938 ∠ 29840.67437876723 = -139.58328312339 -165313.6666297357 ∠ 33693.9894517456 = -72.3439185187 1174.8380510598456 ∠ -154146.66490124757 = -161.5029523074156 60175.77306795546 ∠ 42213.07192354373 = 37.29885558827
Python
<lang python>from __future__ import print_function
def getDifference(b1, b2): r = (b2 - b1) % 360.0 # Python modulus has same sign as divisor, which is positive here, # so no need to consider negative case if r >= 180.0: r -= 360.0 return r
if __name__ == "__main__": print ("Input in -180 to +180 range") print (getDifference(20.0, 45.0)) print (getDifference(-45.0, 45.0)) print (getDifference(-85.0, 90.0)) print (getDifference(-95.0, 90.0)) print (getDifference(-45.0, 125.0)) print (getDifference(-45.0, 145.0)) print (getDifference(-45.0, 125.0)) print (getDifference(-45.0, 145.0)) print (getDifference(29.4803, -88.6381)) print (getDifference(-78.3251, -159.036))
print ("Input in wider range") print (getDifference(-70099.74233810938, 29840.67437876723)) print (getDifference(-165313.6666297357, 33693.9894517456)) print (getDifference(1174.8380510598456, -154146.66490124757)) print (getDifference(60175.77306795546, 42213.07192354373))</lang>
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.11840000000001 -80.71089999999998 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
Ruby
<lang ruby>def getDifference(b1, b2) r = (b2 - b1) % 360.0 # Ruby modulus has same sign as divisor, which is positive here, # so no need to consider negative case if r >= 180.0 r -= 360.0 end return r end
if __FILE__ == $PROGRAM_NAME puts "Input in -180 to +180 range" puts getDifference(20.0, 45.0) puts getDifference(-45.0, 45.0) puts getDifference(-85.0, 90.0) puts getDifference(-95.0, 90.0) puts getDifference(-45.0, 125.0) puts getDifference(-45.0, 145.0) puts getDifference(-45.0, 125.0) puts getDifference(-45.0, 145.0) puts getDifference(29.4803, -88.6381) puts getDifference(-78.3251, -159.036)
puts "Input in wider range" puts getDifference(-70099.74233810938, 29840.67437876723) puts getDifference(-165313.6666297357, 33693.9894517456) puts getDifference(1174.8380510598456, -154146.66490124757) puts getDifference(60175.77306795546, 42213.07192354373) end</lang>
- Output:
Input in -180 to +180 range 25.0 90.0 175.0 -175.0 170.0 -170.0 170.0 -170.0 -118.11840000000001 -80.71089999999998 Input in wider range -139.58328312338563 -72.34391851868713 -161.50295230740448 37.29885558826936
Racket
see my comments in discussion regards bearing-heading or vice versa
<lang racket>#lang racket (define (% a b) (- a (* b (truncate (/ a b)))))
(define (bearing- bearing heading)
(- (% (+ (% (- bearing heading) 360) 540) 360) 180))
(module+ main
(bearing- 20 45) (bearing- -45 45) (bearing- -85 90) (bearing- -95 90) (bearing- -45 125) (bearing- -45 145) (bearing- 29.4803 -88.6381) (bearing- -78.3251 -159.036)
(bearing- -70099.74233810938 29840.67437876723) (bearing- -165313.6666297357 33693.9894517456) (bearing- 1174.8380510598456 -154146.66490124757) (bearing- 60175.77306795546 42213.07192354373))
(module+ test
(require rackunit)
(check-equal? (% 7.5 10) 7.5) (check-equal? (% 17.5 10) 7.5) (check-equal? (% -7.5 10) -7.5) (check-equal? (% -17.5 10) -7.5))</lang>
- Output:
-25 -90 -175 175 -170 170 118.11839999999995 80.71090000000004 139.58328312338563 72.34391851868713 161.50295230740448 -37.29885558826936
REXX
A little extra coding was added for a better visual presentation; the angles were centered, the answers were aligned. <lang rexx>/*REXX pgm calculates the difference between 2 angles (degrees), normalizes the result. */ numeric digits 25 /*use enough decimal diigits for angles*/ call show 20, 45 /*display the angular difference (deg).*/ call show -45, 45 /* " " " " " */ call show -85, 90 /* " " " " " */ call show -95, 90 /* " " " " " */ call show -45, 125 /* " " " " " */ call show 45, 145 /* " " " " " */ call show 29.4803, -88.6361 /* " " " " " */ call show -78.3251, -159.036 /* " " " " " */ call show -70099.74233810938, 29840.67437876723 /* " " " " " */ call show -165313.6666297357, 33693.9894517456 /* " " " " " */ call show 1174.8380510598456,-154146.66490124757 /* " " " " " */ call show 60175.773067955546, 42213.07192354373 /* " " " " " */ exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ show: parse arg a,b; d=digits(); $='º' /*obtain the 2 angles (are in degrees).*/
x=format( ( ( ((b-a) // 360) + 540) // 360) - 180, 4, d-4) /*compute and format. */ if pos(., x)\==0 then x=strip( strip(x, 'T', 0), "T", .) /*strip trailing chaff.*/ say center(a || $, d) '─' center(b || $, d) "───►" x || $ return /* [↑] display the angular difference.*/</lang>
output
20º ─ 45º ───► 25º -45º ─ 45º ───► 90º -85º ─ 90º ───► 175º -95º ─ 90º ───► -175º -45º ─ 125º ───► 170º 45º ─ 145º ───► 100º 29.4803º ─ -88.6361º ───► -118.1164º -78.3251º ─ -159.036º ───► -80.7109º -70099.74233810938º ─ 29840.67437876723º ───► -139.58328312339º -165313.6666297357º ─ 33693.9894517456º ───► -72.3439185187º 1174.8380510598456º ─ -154146.66490124757º ───► -161.5029523074156º 60175.773067955546º ─ 42213.07192354373º ───► 37.298855588184º
Sidef
<lang ruby>func bearingAngleDiff(b1, b2) {
(var b = ((b2 - b1 + 720) % 360)) > 180 ? (b - 360) : b
}
printf("%25s %25s %25s\n", "B1", "B2", "Difference") printf("%25s %25s %25s\n", "-"*20, "-"*20, "-"*20)
for b1,b2 in ([
20, 45 -45, 45 -85, 90 -95, 90 -45, 125 -45, 145 29.4803, -88.6381 -78.3251, -159.036 -70099.74233810938, 29840.67437876723 -165313.6666297357, 33693.9894517456 1174.8380510598456, -154146.66490124757 60175.77306795546, 42213.07192354373 ].slices(2)
) {
printf("%25s %25s %25s\n", b1, b2, bearingAngleDiff(b1, b2))
}</lang>
- Output:
B1 B2 Difference -------------------- -------------------- -------------------- 20 45 25 -45 45 90 -85 90 175 -95 90 -175 -45 125 170 -45 145 -170 29.4803 -88.6381 -118.1184 -78.3251 -159.036 -80.7109 -70099.74233810938 29840.67437876723 -139.58328312339 -165313.6666297357 33693.9894517456 -72.3439185187 1174.8380510598456 -154146.66490124757 -161.5029523074156 60175.77306795546 42213.07192354373 37.29885558827
zkl
<lang zkl>fcn bearingAngleDiff(b1,b2){ // -->Float, b1,b2 can be int or float
( (b:=(0.0 + b2 - b1 + 720)%360) > 180 ) and b - 360 or b;
}</lang> <lang zkl>T( 20,45, -45,45, -85,90, -95,90, -45,125, -45,145 ) .pump(Console.println,Void.Read,
fcn(b1,b2){ "%.1f\UB0; + %.1f\UB0; = %.1f\UB0;" .fmt(b1,b2,bearingAngleDiff(b1,b2)) });</lang>
- Output:
20.0° + 45.0° = 25.0° -45.0° + 45.0° = 90.0° -85.0° + 90.0° = 175.0° -95.0° + 90.0° = -175.0° -45.0° + 125.0° = 170.0° -45.0° + 145.0° = -170.0°