Great Circle Algorithms

OpenLayers is a wonderful JavaScript framework for map making, but its functions assume a FlatLand view of the Earth. This is fine for simply displaying maps, but if you're trying to interact with your map by measuring distances or angles over large areas you're not likely to get accurate results.

The Earth is essentially a sphere, and so it's more appropriate to measure distances and angles using spherical trigonometry. First, note that the shortest distance between two points on a sphere is the route traced out by a plane passing through the center of the sphere and the two points where it intersects the sphere's surface. The arc described by the intersection of any plane that passes through the center of a sphere and the surface of the sphere is known as a great circle. All the meridians (lines of longitude) are great circles as is the Equator. For detailed discussion of great circles and their application see the  Great Circle page at WikiPedia.

The OpenLayers.Geometry.Point class can easily be extended to provide great circle functionality for calculating distances and angles between points as well as computing waypoints along a great circle route (i.e. finding the coordinates of a point that is a specified distance and bearing from an origin point.) The mathematics for the following functions comes from Ed Williams' excellent  Aviation Formulary site.

If you want to download some working JavaScript code that implements these algorithms in OpenLayers it's available at  Point.js. This is used in an  OpenLayers demonstration of animating a line.

Great Circle Distance

In this discussion (and in the actual functions), we assume that coordinates are Latitude and Longitude as signed decimal degrees with negative longitude in the western hemisphere and negative latitude in the southern hemisphere. Coordinates are also converted to radians to do the calculations as this simplifies the spherical trigonometry a great deal.

Constants:
Radius of the Earth in miles
EARTH_RADIUS = 3958.75

Ratio of a circle's circumference to its diameter
PI = 3.1415926535897932384626433832795

Factor to convert decimal degrees to radians
DEG2RAD =  0.01745329252

Factor to convert decimal degrees to radians
RAD2DEG = 57.29577951308

Great Circle Distance:
Inputs are 2 coordinates x1,y1 and x2,y2

  Convert to radians
  x1 = x1 * DEG2RAD
  y1 = y1 * DEG2RAD
  x2 = x2 * DEG2RAD
  y2 = y2 * DEG2RAD
  
  a = sin(( y2-y1 ) / 2.0 )^2
  b = sin(( x2-x1 ) / 2.0 )^2
  c = sqrt( a + cos( y2 ) * cos( y1 ) * b )

  distance = 2 * asin( c ) * EARTH_RADIUS

Great Circle Bearing

This algorithm calculates the angle that point 2 bears to point 1 along a great circle route. Note that as you move along that route from point 1 to point 2 the bearing is always changing.

Inputs are 2 coordinates x1,y1 and x2,y2

  Convert to radians
  x1 = x1 * DEG2RAD
  y1 = y1 * DEG2RAD
  x2 = x2 * DEG2RAD
  y2 = y2 * DEG2RAD
  
  a = cos(y2) * sin(x2 - x1)
  b = cos(y1) * sin(y2) - sin(y1) * cos(y2) * cos(x2 - x1)
  adjust = 0
    
  if((a == 0) && (b == 0)) {
      bearing = 0
  } else if( b == 0) {
      if( a < 0)  
          bearing = 3 * PI / 2
      else
          bearing = PI / 2
  } else if( b < 0) 
      adjust = PI
  else {
      if( a < 0) 
          adjust = 2 * PI
      else
          adjust = 0
  }
  bearing = (atan(a/b) + adjust) * RAD2DEG

Great Circle Waypoints

This algorithm returns a point that is a specified distance and bearing from the input point. Inputs are 2 coordinates x1,y1, bearing (an angle) and distance (units match EARTH_RADIUS). It returns coordinates x2, y2.

  Convert to radians
  x1 = x1 * DEG2RAD
  y1 = y1 * DEG2RAD
  bearing = bearing * DEG2RAD

  // Convert arc distance to radians
  c = distance / EARTH_RADIUS

  y2 = asin( sin(y1) * cos(c) + cos(y1) * sin(c) * cos(bearing)) * RAD2DEG


  a = sin(c) * sin(bearing)
  b = cos(y1) * cos(c) - sin(y1) * sin(c) * cos(bearing)

  if( b == 0 ) 
      x2 = x1
  else
      x2 = x1 + atan(a/b) * RAD2DEG

  return x2,y2