Spherical geodesy
The package contains a port for Dart language of spherical geodesy tools, originally written in JavaScript by Chris Veness. See the online form at the Movable Type Scripts web site and source code at GitHub.
These geodesy functions are based on calculations on a spherical earth model. Distance, bearing, destination and other functions are provided both for great circle paths and rhumb lines. All calculations use simple spherical trigonometric algorithms.
Actually the earth is slightly ellipsoidal, not spherical. However errors are typically up to 0.3% (see notes by Movable Type Scripts) when using a spherical model instead of an ellipsoidal.
🧐 Great circle vs rhumb line
According to Wikipedia, a great circle or orthodrome is the circular intersection of a sphere and a plane passing through the sphere’s center point. A rhumb line or loxodrome is an arc crossing all meridians of longitude at the same angle, that is, a path with constant bearing as measured relative to true north.
![](https://raw.githubusercontent.com/navibyte/geospatial_docs/v2023-08-12/assets/doc/geodesy/rhumb_line_vs_great_circle/197px_Rhumb_line_vs_great-circle_arc.png)
Differences between a rhumb line (blue) compared to a great-circle arc (red) as described by Wikipedia are visualized in the illustration (top: orthographic projection, bottom: Mercator projection) showing paths from Lisbon, Portugal to Havana, Cuba.
The rhumb line path is slightly longer than the path along the great circle. Rhumb lines are sometimes used in marine navigation as it’s easier to follow a constant compass bearing than adjusting bearings when following a great circle path.
🌐 Great circle paths
Examples using great circle paths (orthodromic) on a spherical earth model:
// sample geographic positions final greenwich = Geographic.parseDms(lat: '51°28′40″ N', lon: '0°00′05″ W'); final sydney = Geographic.parseDms(lat: '33.8688° S', lon: '151.2093° E');
// decimal degrees (DD) and degrees-minutes (DM) formats const dd = Dms(decimals: 0); const dm = Dms.narrowSpace(type: DmsType.degMin, decimals: 1);
// prints: 16988 km final distanceKm = greenwich.spherical.distanceTo(sydney) / 1000.0; print('${distanceKm.toStringAsFixed(0)} km');
// prints (bearing varies along the great circle path): 61° -> 139° final initialBearing = greenwich.spherical.initialBearingTo(sydney); final finalBearing = greenwich.spherical.finalBearingTo(sydney); print('${dd.bearing(initialBearing)} -> ${dd.bearing(finalBearing)}');
// prints: 51° 31.3′ N, 0° 07.5′ E final destPoint = greenwich.spherical.destinationPoint(distance: 10000, bearing: 61.0); print(destPoint.latLonDms(format: dm));
// prints: 28° 34.0′ N, 104° 41.6′ E final midPoint = greenwich.spherical.midPointTo(sydney); print(midPoint.latLonDms(format: dm));
// prints 10 intermediate points, like fraction 0.6: 16° 14.5′ N, 114° 29.3′ E for (var fr = 0.0; fr < 1.0; fr += 0.1) { final ip = greenwich.spherical.intermediatePointTo(sydney, fraction: fr); print('${fr.toStringAsFixed(1)}: ${ip.latLonDms(format: dm)}'); }
// prints: 0° 00.0′ N, 125° 19.0′ E final intersection = greenwich.spherical.intersectionWith( bearing: 61.0, other: const Geographic(lat: 0.0, lon: 179.0), otherBearing: 270.0, ); if (intersection != null) { print(intersection.latLonDms(format: dm)); }
🗺️ Rhumb line paths
Examples using rhumb line paths (loxodromic) on a spherical earth model:
// prints: 17670 km final distanceKm = greenwich.rhumb.distanceTo(sydney) / 1000.0; print('${distanceKm.toStringAsFixed(0)} km');
// prints (bearing remains the same along the rhumb line path): 122° -> 122° final initialBearing = greenwich.rhumb.initialBearingTo(sydney); final finalBearing = greenwich.rhumb.finalBearingTo(sydney); print('${dd.bearing(initialBearing)} -> ${dd.bearing(finalBearing)}');
// prints: 51° 25.8′ N, 0° 07.3′ E final destPoint = greenwich.spherical.destinationPoint(distance: 10000, bearing: 122.0); print(destPoint.latLonDms(format: dm));
// prints: 8° 48.3′ N, 80° 44.0′ E final midPoint = greenwich.rhumb.midPointTo(sydney); print(midPoint.latLonDms(format: dm));
More examples are provided in the API documentation and test cases.