Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

geodesy

1.1.3 • Public • Published

Geodesy functions

These libraries started life (a long time ago) as simple ‘latitude/longitude’ code fragments intended to help people who had little experience of geodesy, and perhaps limited programming experience.

The intention was to have clear, simple illustrative code samples which could be adapted and re-used in other projects (whether those be coded in JavaScript, Java, C++, Excel VBA, Fortran(!), or anything else...). With its untyped C-style syntax, JavaScript reads remarkably close to pseudo-code, exposing the algorithms with a minimum of syntactic distractions

While still valid for that purpose, they have grown since then into considerable libraries, based around:

  • simpler trigonometric functions (distance, bearing, etc) based on a spherical earth model
  • more sophisticated trigonometric functions (distance, bearing, datum conversions, etc) based on a more accurate ellipsoidal earth model
  • vector-based functions based (mostly) on a spherical earth model

Complementing these are various mapping-related functions covering:

  • UTM coordinates & MGRS grid references
  • UK Ordnance Survey grid references

There are also supporting libraries:

  • 3d vector manipulation functions, also used for cartesian (x/y/z) coordinates
  • functions for conversion between decimal degrees and degrees/minutes/seconds

The spherical-earth model provides simple formulae covering most ‘everyday’ accuracy requirements; the ellipsoidal-earth model provides more accurate formulae at the expense of complexity; the vector-based functions provide for an alternative (largely trig-free) approach.

The three core libraries (latlon-spherical.js, latlon-ellipsoidal.js, latlon-vectors.js) are mutually exclusive: only one can be used at a time. The mapping-related libraries depend on the ellipsoidal model.

These functions are as language-agnostic as possible, avoiding (as far as possible) JavaScript-specific language features which would not be recognised by users of other languages (and which might be difficult to translate to other languages). I use Greek letters in variables representing maths symbols conventionally presented as Greek letters: I value the great benefit in legibility over the minor inconvenience in typing.

latlon-spherical.js: latitude/longitude geodesy functions on a spherical earth model

Geodesy functions for working with points and paths (distances, bearings, destinations, etc) on a spherical-model earth, including (orthodromic) great-circle geodesics and (loxodromic) rhumb lines. All calculations are done using simple spherical trigonometric formulae.

LatLon

  • new LatLon(lat, lon)
  • latlon.distanceTo(point[, radius])
  • latlon.bearingTo(point)
  • latlon.finalBearingTo(point)
  • latlon.midpointTo(point)
  • latlon.intermediatePointTo(point, fraction)
  • latlon.destinationPoint(distance, bearing[, radius])
  • LatLon.intersection(point1, bearing1, point2, bearing2)
  • LatLon.crossTrackDistanceTo(pathStart, pathEnd, radius)
  • LatLon.maxLatitude(bearing)
  • LatLon.crossingParallels(point1, point2, latitude)
  • latlon.rhumbDistanceTo(point[, radius])
  • latlon.rhumbBearingTo(point)
  • latlon.rhumbDestinationPoint(distance, bearing[, radius])
  • latlon.rhumbMidpointTo(point)
  • LatLon.areaOf(polygon[, radius])
  • latlon.equals(point)
  • latlon.toString([format[, decimals]])

Further details available at www.movable-type.co.uk/scripts/latlong.html.

Notes: previously named simply latlon.js; radius moved from constructor to distance calculation methods; distances previously in kilometres now default to metres, order of arguments to destination point methods reversed.

latlon-ellipsoidal.js: latitude/longitude geodesy functions on an ellipsoidal earth model

Datum conversions etc on an ellipsoidal-model earth.

LatLon

  • new LatLon(lat, lon[, datum])
  • LatLon.datum
  • LatLon.ellipsoid
  • latlon.convertDatum(datum)
  • latlon.toCartesian()
  • latlon.toString([format[, decimals]])
  • vector3d.toLatLon([datum])

Notes: LatLonE now simply LatLon.

Further details available at www.movable-type.co.uk/scripts/latlong-convert-coords.html.

latlon-vincenty.js: distances & bearings on geodesics

Direct and inverse solutions of geodesics on the ellipsoid using Vincenty formulae (accurate to within 0.5mm distance, 0.000015″ bearing).

LatLon extends latlon-ellipsoidal.js

  • latlon.distanceTo(point)
  • latlon.bearingTo(point)
  • latlon.finalBearingTo(point)
  • latlon.destinationPoint(distance, bearing)
  • latlon.finalBearingOn(distance, initialBearing)

Further details available at www.movable-type.co.uk/scripts/latlong-vincenty.html.

latlon-vectors.js: latitude/longitude geodesy functions using vector calculations

Sometimes geodesy calculations can be easier using vectors rather than spherical trigonometry; this provides some basic functions. The toVector and toLatLon functions are equally applicable to a spherical model and an ellipsoidal model (using ‘n-vectors’); other functions are applicable to a spherical earth model only.

LatLon

  • new LatLon(lat, lon)
  • latlon.toVector()
  • vector3d.toLatLonS()
  • latlon.greatCircle(bearing)
  • latlon.distanceTo(point[, radius])
  • latlon.bearingTo(point)
  • latlon.midpointTo(point)
  • latlon.intermediatePointTo(point, fraction)
  • latlon.intermediatePointOnChordTo(point, fraction)
  • latlon.destinationPoint(distance, bearing[, radius])
  • LatLon.intersection(path1start, path1brngEnd, path2start, path2brngEnd)
  • latlon.crossTrackDistanceTo(pathStart, pathBrngEnd[, radius])
  • latlon.nearestPointOnSegment(point1, point2)
  • latlon.isBetween(point1, point2)
  • latlon.enclosedBy(points)
  • LatLon.areaOf(polygon[, radius])
  • LatLon.meanOf(points)
  • latlon.equals(point)
  • latlon.toString([format[, decimals]])

Notes: LatLonE now simply LatLon; order of arguments to destination point method reversed. More thought is required on which of these functions operate on spherical model, which on n-vector (geodetic) ellipsoidal model, and which equally on either.

Further details available at www.movable-type.co.uk/scripts/latlong-vectors.html.

vector3d.js: 3-d vector handling functions

Generic 3-d vector functions, not tied to geodesy applications.

Vector3d

  • new Vector3d(x, y, z)
  • vector3d.plus(v)
  • vector3d.minus(v)
  • vector3d.times(x)
  • vector3d.dividedBy(x)
  • vector3d.dot(v)
  • vector3d.cross(v)
  • vector3d.negate()
  • vector3d.length()
  • vector3d.unit()
  • vector3d.angleTo(v, vSign)
  • vector3d.rotateAround(axis, theta)
  • vector3d.toString(decimals)

utm.js: Universal Transverse Mercator / Latitude-Longitude conversions

Conversions between UTM coordinates and latitude-longitude points using Karney’s calculations (accurate to 5nm).

Utm

  • new Utm(zone, hemisphere, easting, northing[, datum[, convergence, scale]])
  • latlon.toUtm()
  • utm.toLatLonE()
  • Utm.parse([utmCoord])
  • utm.toString([digits])

Further details available at www.movable-type.co.uk/scripts/latlong-utm-mgrs.html.

mgrs.js: MGRS/NATO grid references

Conversions between MGRS/NATO grid references and UTM coordinates.

Mgrs

  • new Mgrs(zone, band, e100k, n100k, easting, northing[, datum])
  • Utm.toMgrs()
  • mgrs.toUtm()
  • Mgrs.parse(mgrsGridRef)
  • mgrs.toString([digits])

Further details available at www.movable-type.co.uk/scripts/latlong-utm-mgrs.html.

osgridref.js: UK Ordnance Survey grid references

Conversions between UK OS grid references and (OSGB36) latitude/longitude points (based on Ordnance Survey formulae).

OsGridRef

  • new OsGridRef(easting, northing)
  • OsGridRef.latLonToOsGrid(point)
  • OsGridRef.osGridToLatLon(gridref, datum)
  • OsGridRef.parse(gridref)
  • osGridRef.toString([digits])

Further details available at www.movable-type.co.uk/scripts/latlong-gridref.html.

dms.js: conversion routines for degrees, minutes, seconds

Conversions between decimal degrees and (sexagesimal) degrees-minutes-seconds (and compass points).

Dms

  • Dms.parseDMS(dmsStr)
  • Dms.toDms(degrees[, format[, decimals]])
  • Dms.toLat(degrees[, format[, decimals]])
  • Dms.toLon(degrees[, format[, decimals]])
  • Dms.toBrng(degrees[, format[, decimals]])
  • Dms.compassPoint(bearing[, precision])

Notes: renamed from Geo (geo.js)

Documentation

Documentation for all these methods is available at www.movable-type.co.uk/scripts/js/geodesy/docs.

Usage

While originally intended as illustrative code fragments, these functions can be used ‘as-is’, either client-side in-browser or with Node.js.

Usage in browser

The scripts can be used in the browser simply by including them within <script> tags. This involves an appreciation of dependencies, the order of loading is significant. I believe browserify, bower, etc can use npm and/or github directly, but I have no experience of using front-end package managers.

eg for various calculations on a spherical model earth:

<!doctype html><title>spherical</title><meta charset="utf-8">
<script src="js/geodesy/latlon-spherical.js"></script>
<script src="js/geodesy/dms.js"></script>
<script>
    var p1 = new LatLon(50.06632, -5.71475);
    var p2 = new LatLon(58.64402, -3.07009);
    var d = p1.distanceTo(p2);
    console.assert(d.toFixed(3) == '968874.704');
    var mid = p1.midpointTo(p2);
    console.assert(mid.toString() == '54°21′44″N, 004°31′51″W');
</script>

eg for geodesic distance using Vincenty’s algorithm:

<!doctype html><title>vincenty</title><meta charset="utf-8">
<script src="js/geodesy/vector3d.js"></script>
<script src="js/geodesy/latlon-ellipsoidal.js"></script>
<script src="js/geodesy/latlon-vincenty.js"></script>
<script src="js/geodesy/dms.js"></script>
<script>
    var p1 = new LatLon(50.06632, -5.71475);
    var p2 = new LatLon(58.64402, -3.07009);
    var d = p1.distanceTo(p2);
    console.assert(d.toFixed(3) == '969954.166');
</script>

eg for UTM conversions:

<!doctype html><title>utm</title><meta charset="utf-8">
<script src="js/geodesy/vector3d.js"></script>
<script src="js/geodesy/latlon-ellipsoidal.js"></script>
<script src="js/geodesy/utm.js"></script>
<script src="js/geodesy/dms.js"></script>
<script>
    var utm = Utm.parse('48 N 377298.745 1483034.794');
    var latlon = utm.toLatLonE();
    console.assert(latlon.toString('dms', 2) == '13°24′45.00″N, 103°52′00.00″E');
</script>

eg for OS grid references:

<!doctype html><title>osgridref</title><meta charset="utf-8">
<script src="js/geodesy/vector3d.js"></script>
<script src="js/geodesy/latlon-ellipsoidal.js"></script>
<script src="js/geodesy/osgridref.js"></script>
<script src="js/geodesy/dms.js"></script>
<script>
    var gridref = new OsGridRef(651409.903, 313177.270);

    var pWgs84 = OsGridRef.osGridToLatLon(gridref);
    console.assert(pWgs84.toString('dms', 4) == '52°39′28.7230″N, 001°42′57.7870″E');

    var pOsgb = OsGridRef.osGridToLatLon(gridref, LatLon.datum.OSGB36);
    console.assert(pOsgb.toString('dms', 4) == '52°39′27.2531″N, 001°43′04.5177″E');
</script>

Usage in Node.js

I’ve also made a packaged-up npm package available:

npm install geodesy

eg for various calculations on a spherical model earth:

var LatLon = require('geodesy').LatLonSpherical;

var p1 = new LatLon(50.06632, -5.71475);
var p2 = new LatLon(58.64402, -3.07009);
var d = p1.distanceTo(p2);
console.assert(d.toFixed(3) == '968874.704');
var mid = p1.midpointTo(p2);
console.assert(mid.toString() == '54°21′44″N, 004°31′51″W');

eg for geodesic distance:

var LatLon = require('geodesy').LatLonEllipsoidal;

var p1 = new LatLon(50.06632, -5.71475);
var p2 = new LatLon(58.64402, -3.07009);
var d = p1.distanceTo(p2);
console.assert(d.toFixed(3) == '969954.166');

eg for UTM conversions:

var LatLon = require('geodesy').LatLonEllipsoidal;
var Utm    = require('geodesy').Utm;
var Dms    = require('geodesy').Dms;

var utm = Utm.parse('48 N 377298.745 1483034.794');
var latlon = utm.toLatLonE();
console.assert(latlon.toString('dms', 2) == '13°24′45.00″N, 103°52′00.00″E');

eg for OS grid references:

var OsGridRef = require('geodesy').OsGridRef;

var gridref = new OsGridRef(651409.903, 313177.270);

var pWgs84 = OsGridRef.osGridToLatLon(gridref);
console.assert(pWgs84.toString('dms', 4) == '52°39′28.7230″N, 001°42′57.7870″E');

var pOsgb = OsGridRef.osGridToLatLon(gridref, LatLon.datum.OSGB36);
console.assert(pOsgb.toString('dms', 4) == '52°39′27.2531″N, 001°43′04.5177″E');

install

npm i geodesy

Downloadsweekly downloads

3,911

version

1.1.3

license

MIT

repository

Gitgithub

last publish

collaborators

  • avatar
Report a vulnerability