Project: Maps & Bearings
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):
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:
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
- 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?
- Nearby precision: distance between two points 100 m apart. Compare the
atan2version against anarcsinversion — do they agree to the millimeter? - 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.