Measure Ellipsoidal Routes with geod and invgeod
Work out the distance and bearings between two latitude and longitude pairs with geod, then run it backwards to find a destination. You will use the installed PROJ 9.4.0 command, feed it from standard input and change no files, so it takes about 10 minutes to try.
The route
Jump straight to the step you need, or tick off Done means at the end.
Two results to look for:
- Inverse calculation: two azimuths and a distance.
- Direct calculation: the destination latitude, longitude and back azimuth.
1. Check the command and choose an ellipsoid
geod performs direct calculations. invgeod is the inverse-mode alias this installation supplies. The command works on an ellipsoid, and the distance unit is normally the unit of that ellipsoid's major axis, which is metres for the usual definitions. The installed package is proj-bin 9.4.0-1build2.
$ geod --version
Rel. 9.4.0, March 1st, 2024
$ command -v invgeod
/usr/bin/invgeod
The man page examples use +ellps=clrk66, a historical Clarke 1866 ellipsoid. That makes their results reproducible, but it is no recommendation for new work. Pick the ellipsoid that belongs to your data and write that choice down. List the names available on this host before you guess one:
$ geod -le | head -5
MERIT a=6378137.0 rf=298.257 MERIT 1983
SGS85 a=6378136.0 rf=298.257 Soviet Geodetic System 85
GRS80 a=6378137.0 rf=298.257222101 GRS 1980(IUGG, 1980)
IAU76 a=6378140.0 rf=298.257 IAU 1976
airy a=6377563.396 rf=299.3249646 Airy 1830
Warning
Do not silently swap ellipsoids when you compare results. A plausible-looking number can still be wrong for the reference surface your coordinates need.
2. Solve the inverse problem
The inverse problem takes the latitude and longitude of the initial point, then those of the terminal point. The -I option switches geod to inverse mode. Input can be decimal degrees or degrees, minutes and seconds. This example follows the installed man page: Boston to Portland, in US statute miles.
$ printf "42d15'N 71d07'W 45d31'N 123d41'W\n" | \
geod +ellps=clrk66 -I +units=us-mi
-66d31'50.141" 75d39'13.083" 2587.504
The fields are the forward azimuth from the initial point, the back azimuth from the terminal point, and the distance. The negative first azimuth is a signed DMS value. If your consumer expects azimuths from 0 to 360 degrees, add -p:
$ printf "42d15'N 71d07'W 45d31'N 123d41'W\n" | \
geod +ellps=clrk66 -I -p +units=us-mi
293d28'9.859" 75d39'13.083" 2587.504
Checkpoint
The distance is 2587.504 US statute miles for this exact ellipsoid, unit and input. If yours differs, check the point order, hemisphere letters and +units before you go hunting for a precision problem.
3. Run the result as a direct calculation
The direct problem takes an initial latitude and longitude, a forward azimuth and a distance. Feed the first inverse output back in as the azimuth and distance, with the same ellipsoid and units:
$ printf "42d15'N 71d07'W -66d31'50.141\" 2587.504\n" | \
geod +ellps=clrk66 +units=us-mi
45d31'0.003"N 123d40'59.985"W 75d39'13.094"
The output is the destination latitude, destination longitude and back azimuth. It lands close to the original Portland coordinate but not character for character, because the distance was rounded to three decimal places. More input precision gives a more precise destination.
Tip
In scripts, prefer a stable numeric format to parsing the default DMS text. The -f option controls geographic coordinate formatting and -F controls the distance format. Test the exact format your downstream program accepts first, because these are printf-style strings, not arbitrary labels.
4. Set units and precision
Run geod -lu to see the unit names this installation accepts. The default is metres, so the +units=us-mi setting in the examples matters: leave it out and the distance field changes unit, not just its display.
$ geod -lu | head -10
mm 0.001 millimetre
cm 0.01 centimetre
m 1 metre
ft 0.3048 foot
us-ft 0.304800609601219 US survey foot
fath 1.8288 fathom
kmi 1852 nautical mile
us-ch 20.1168402336805 US survey chain
us-mi 1609.34721869444 US survey mile
km 1000 kilometre
Geographic output defaults to DMS, and distance defaults to three decimal places. Two switches adjust the coordinates:
-w: changes the significant fractional seconds shown.-W: does the same with constant-width fields and leading zeroes.
Both affect presentation only. They cannot improve coordinates that were already rounded before you supplied them.
5. Read files or standard input
With no input file, geod reads standard input. You can name a file instead, and several files are processed from left to right. A lone - names standard input explicitly. That makes a saved input handy for a repeatable check:
$ printf "51d30'N 0d08'W 48d51'N 2d21'E\n" > /tmp/geod-route.txt
$ geod +ellps=WGS84 -I +units=km /tmp/geod-route.txt
147d59'57.761" -30d5'34" 343.982
That creates a temporary input file and nothing else. Remove it when you have finished, or keep it if the coordinates are deliberately non-sensitive test data:
$ rm -- /tmp/geod-route.txt
Warning
Do not put confidential coordinates in shell history, shared temporary files or copied transcripts. The calculations need no elevated privileges, so there is no sudo step.
6. Generate points along a geodesic
geod can also emit intermediate points. Give it the initial point with +lat_1 and +lon_1, then either a terminal point with +lat_2 and +lon_2, or a distance and azimuth with +S and +A. Use +n_S for a number of intermediate points or +del_S for a distance increment.
$ geod +ellps=WGS84 +lat_1=51.5 +lon_1=-0.133333 \
+lat_2=48.85 +lon_2=2.35 +n_S=3
51d30'N 0d7'59.999"W
50d37'21.947"N 0d43'31.058"E
49d44'21.469"N 1d33'8.803"E
48d51'N 2d21'E
Here +n_S=3 gives the two endpoints plus two points between them: four lines in total. Check this specialised mode with a small, known input before you build a data pipeline on it. If all you need is one route measurement, stop after the direct or inverse calculation.
7. Diagnose the common errors
- Odd distance or non-zero result. Usually the input order, hemisphere, ellipsoid or unit is wrong. Re-run with one line of known test data.
- Latitude outside -90 to 90 degrees. That is invalid. Check whether longitude and latitude got swapped.
- No
invgeodon another machine. Usegeod -I, the documented fallback. - A format change breaks a parser. Go back to default DMS output and change one option at a time. Display precision is not calculation precision.
- Reading it as a road route. A geodesic distance is not a road route, a travel time or a local survey result. It follows the selected ellipsoid, not a transport network or every local datum correction.
Apart from the temporary file, these commands are read-only, so there is no configuration change to undo. If you created that file, the recovery is the explicit rm -- /tmp/geod-route.txt command above.
Done means
- Version confirmed: you checked the installed PROJ version and the available ellipsoids.
- Modes distinguished: inverse input takes two points, and direct input takes one point, an azimuth and a distance.
- Choices deliberate: you picked the ellipsoid and distance unit yourself.
- Result verified: you compared one result with the expected output before scripting it.
- Fallback known:
invgeodcan be replaced bygeod -I. - System untouched: no elevated privileges, no changed system state.