The problem

Two staples of maps, games with minimaps, and robotics: which direction is the target (compass bearing), and how far is it over the curved Earth (great-circle distance).

Bearings from atan2

A compass bearing \(\beta\) is measured clockwise from north, in \([0°, 360)\). With \(x\) = east offset and \(y\) = north offset (note the swapped argument order versus the usual math convention):

$$ \beta = \operatorname{atan2}(x,\; y), \qquad \beta_{deg} = (\beta \cdot \tfrac{180}{\pi} + 360) \bmod 360 $$

Check: due east \((1, 0)\) → \(\operatorname{atan2}(1, 0) = 90°\) ✓. Due south \((0, −1)\) → 180° ✓.

import math

def bearing(lat1, lon1, lat2, lon2):
    """Initial bearing from point 1 to point 2, degrees [0, 360)."""
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dlon = math.radians(lon2 - lon1)
    x = math.sin(dlon) * math.cos(p2)
    y = math.cos(p1) * math.sin(p2) - math.sin(p1) * math.cos(p2) * math.cos(dlon)
    return (math.degrees(math.atan2(x, y)) + 360) % 360

print(f"{bearing(40.7128, -74.0060, 51.5074, -0.1278):.1f}°")  # NYC → London ≈ 51.2°

Distances with haversine

For two points with latitudes \(\varphi\) and longitude difference \(\Delta\lambda\) (all in radians), with Earth radius \(R = 6371\) km:

$$ a = \sin^2\!\left(\tfrac{\Delta\varphi}{2}\right) + \cos\varphi_1\cos\varphi_2\sin^2\!\left(\tfrac{\Delta\lambda}{2}\right), \qquad d = 2R\,\operatorname{atan2}\!\left(\sqrt{a},\; \sqrt{1-a}\right) $$

The atan2 form (instead of arcsin) keeps full precision for tiny distances — the same quadrant-safe habit from Inverse Trig Functions.

function haversine(lat1, lon1, lat2, lon2, R = 6371) {
  const toRad = (d) => d * Math.PI / 180;
  const p1 = toRad(lat1), p2 = toRad(lat2);
  const dp = toRad(lat2 - lat1), dl = toRad(lon2 - lon1);
  const a = Math.sin(dp / 2) ** 2 + Math.cos(p1) * Math.cos(p2) * Math.sin(dl / 2) ** 2;
  return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
console.log(haversine(40.7128, -74.0060, 51.5074, -0.1278).toFixed(0) + ' km'); // 5570 km

Try it

  1. Bearing sanity: compute bearings due north, east, south, west from anywhere. Then NYC → Tokyo (35.6762, 139.6503) — why is it ~333° (northwest over the Arctic) instead of east?
  2. Nearby precision: distance between two points 100 m apart. Compare the atan2 version against an arcsin version — do they agree to the millimeter?
  3. Minimap project: combine this unit — plot waypoints on a canvas radar using bearing (angle) + distance (radius), with the player at the center. That is Unit Circle + Turret Aiming fused together.

You have finished the course — every unit from foundations to here. Rebuild something from Unit 1 with your new eyes: it will feel easy now.