Bearings
Great circle on a sphere, proposed · checked against GeographicLib's GeodSolve
Preview
The test data isn't published yet; the work is in issue #3. The case count, the expiry date and everything under Test data are made up to show how the finished page will look.
Planned · 4 cases
What it is
A bearing is only meaningful with its north. A map has three: true north along the meridian, grid north along the map’s grid lines, and magnetic north where the compass points. Converting between them means adding or subtracting the angles between them, and the sign of each angle is where code goes wrong.
- Grid convergence is true to grid. It’s zero on a UTM zone’s centre line and grows toward the zone’s edges and the poles.
- Declination is true to magnetic. It comes from the magnetic model.
- The G-M angle is grid to magnetic: declination minus convergence. Military maps print it in the margin.
Operations
| Operation | Gives |
|---|---|
inverse |
The distance and initial bearing between two pointsIn: fromLatitudeInDegrees, fromLongitudeInDegrees, toLatitudeInDegrees, toLongitudeInDegreesOut: distanceInMeters, bearingInDegrees |
destination |
The point at a distance and bearing from anotherIn: fromLatitudeInDegrees, fromLongitudeInDegrees, distanceInMeters, bearingInDegreesOut: toLatitudeInDegrees, toLongitudeInDegrees |
backAzimuth |
The reverse of a bearingIn: bearingInDegreesOut: backAzimuthInDegrees |
turn |
The shortest turn from one bearing to anotherIn: fromBearingInDegrees, toBearingInDegreesOut: turnInDegrees, direction |
convertNorth |
A bearing converted between true, magnetic and grid northIn: bearingInDegrees, fromNorth, toNorth, magneticDeclinationInDegrees, convergenceInDegreesOut: convertedBearingInDegrees |
formatBearing |
A bearing written in degrees or milsIn: bearingInDegrees, angleUnitOut: bearingText |
compassPoint |
The compass point nearest a bearingIn: bearingInDegrees, pointCount, styleOut: compassPointText |
Fields
| Field | Meaning |
|---|---|
fromLatitudeInDegrees | The start, −90 to 90 |
fromLongitudeInDegrees | The start, −180 to 180 |
toLatitudeInDegrees | The end, −90 to 90 |
toLongitudeInDegrees | The end, −180 to 180 |
distanceInMeters | Along the great circle |
bearingInDegrees | 0 to 360, clockwise from north |
backAzimuthInDegrees | The bearing plus 180°, in 0 to 360 |
fromBearingInDegrees | The heading now |
toBearingInDegrees | The heading wanted |
turnInDegrees | 0 to 180 |
direction | left or right |
fromNorth | true, magnetic or grid |
toNorth | true, magnetic or grid |
magneticDeclinationInDegrees | True to magnetic, east positive, from the magnetic model |
convergenceInDegrees | True to grid, east positive, from UTM |
convertedBearingInDegrees | 0 to 360 |
angleUnit | degrees, natoMils (6400), warsawPactMils (6000) or swedishMils (6300) |
bearingText | 000° to 359°, or four-digit mils |
pointCount | 4, 8, 16 or 32 |
style | abbreviation or words |
compassPointText | Like NNE, NbE or north by east |
Edge cases
| Case | What's right |
|---|---|
| 359.6° | bearingText is 000°, never 360°. The same for mils. |
| A turn across north | 350° to 10° is 20° right, not 340° left |
| Every sign of declination and convergence | Each combination has a convertNorth case |
For agents
Measure on a sphere of radius 6,371,008.8 m, not the ellipsoid, so distances match Turf and the map; this is proposed in issue #3. Normalize every bearing into [0°, 360°) after rounding, not before, so 359.6° writes as 000°. In convertNorth, take magneticDeclinationInDegrees and convergenceInDegrees east positive, with true = magnetic + declination and grid = true − convergence. Pass every case in vectors.json; text must match exactly.
Test data
In vectors.json, published 2026-01-01. Earth model: Sphere, radius 6,371,008.8 m (proposed). How to read it: Test data format.
| Field | Tolerance |
|---|---|
distanceInMeters | ± 0.001 |
bearingInDegrees | ± 0.000001 |
toLatitudeInDegrees | ± 0.0000001 |
toLongitudeInDegrees | ± 0.0000001 |
backAzimuthInDegrees | ± 0.000001 |
turnInDegrees | ± 0.000001 |
convertedBearingInDegrees | ± 0.000001 |
Every other field is compared exactly.
| Case | Input | Expected |
|---|---|---|
placeholder-1inverse · reference |
fromLatitudeInDegrees 11.11fromLongitudeInDegrees 22.22toLatitudeInDegrees 33.33toLongitudeInDegrees 44.44 |
distanceInMeters 1234567.891bearingInDegrees 12.345678 |
placeholder-2formatBearing · edge, hand |
bearingInDegrees 359.6angleUnit "degrees" |
bearingText "000°" |
placeholder-3turn · edge, hand |
fromBearingInDegrees 350toBearingInDegrees 10 |
turnInDegrees 20direction "right" |
placeholder-4compassPoint · hand |
bearingInDegrees 11.25pointCount 32style "words" |
compassPointText "north by east" |
Implementations
| Repo | Status |
|---|---|
| gshaw/algorithms-swiftSwift | Incomplete |
Each is a public repo that runs this page's test data with mise run test. See how implementations work.
Source
| Reference program | GeodSolve, GeographicLib 2.7Charles Karney · MIT |
| Definitions | Mils and compass points, written from their definitionsCC0 |