Saturday, April 16, 2011

Calculating the average of two angles (two bearings actually)

I recently needed to find the average of two angles.  I was programmatically creating a irregular polygon. I wanted to draw a small square at the points of the polygon, and I wanted the squares to be rotated to the average of the two lines that met at that point.

The issue is that if you have two bearings, one at 20° and one at 350°, or one at 15° and one at 315°. If you just average the two numbers, you get 185°, but the more appropriate number is 5°.  This is called by some a “Wraparound issue” and if you search the web you will see lots of ways to solve this problem. Unfortunately they mostly try to solve it using a mathematical equation.  Now for people that have read this blog for awhile know that I am not allergic to math, but if we can solve this problem simply with an algorithm, we should … that’s what computers are for, right?

So, here is my algorithm and the thought behind it.


(Assumptions: 0 >= bearings < 360)

First if you look at the difference between the two bearings, you will see that there are two possibilities, the actual difference is greater than 180° or less than 180°.  Since we are only concerned about “fixing” the issue when the difference is greater than 180°, that is the first thing we will check.

We will call the smaller value bearing bearingA and the larger value bearing bearingB.

Since we know that bearingB has a larger value and that the difference is greater than 180, so bearingB > 180.

So, if we subtract 360  –  bearingB, then just add bearingA + bearingB and divide the total in half, we are 90% there.

One last check. If the result is less than 0, we need to add 360 back in.





So, example #1
20° & 350°
350 – 20 > 180
350 – 360 = –10
(–10 + 20) / 2 = 5
5 ≥ 0
= 5 °

So, example #2

15° & 315°
315 – 15 > 180
315 – 360 = –45
(-45 + 15) / 2 = –30
–30 < 0–30 + 360 = 354°



And here is the code:



Code Snippet
  1. private static double GetAverageBearing(double bearingA, double bearingB)
  2.         {
  3.             if (bearingA > bearingB)
  4.             {

  5.                 var temp = bearingA;
  6.                 bearingA = bearingB;

  7.                 bearingB = temp;
  8.             }
  9.  
  10.             if (bearingB - bearingA > 180) bearingB -= 360;
  11.  
  12.             var finalBearing = (bearingB + bearingA)/2;
  13.  
  14.             if (finalBearing < 0) finalBearing += 360;
  15.             
  16.             return finalBearing;
  17.         }

1 comment:

Anonymous said...

Thanks! I believe there is a typo above in the example: 354 degrees should be 345 degrees.
I used this example to translate a VB equivalent. Here it is if anyone else is interested:

Public Function AverageBearing(ByVal BearingA As Double, ByVal BearingB As Double) As Double
Dim TempBearing As Double
Dim FinalBearing As Double
If BearingA > BearingB Then
TempBearing = BearingA
BearingA = BearingB
BearingB = TempBearing
End If
If (BearingB - BearingA) > 180 Then BearingB = BearingB - 360
FinalBearing = (BearingB + BearingA) / 2
If FinalBearing < 0 Then FinalBearing = FinalBearing + 360
AverageBearing = FinalBearing
End Function