/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* Latitude/longitude spherical geodesy formulae & scripts (c) Chris Veness 2002-2010 */ /* - www.movable-type.co.uk/scripts/latlong.html */ /* */ /* Sample usage: */ /* var p1 = new LatLon(51.5136, -0.0983); */ /* var p2 = new LatLon(51.4778, -0.0015); */ /* var dist = p1.distanceTo(p2); // in km */ /* var brng = p1.bearingTo(p2); // in degrees clockwise from north */ /* ... etc */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /** * Creates a point on the earth's surface at the supplied latitude / longitude * * @constructor * @param {Number} lat: latitude in numeric degrees * @param {Number} lon: longitude in numeric degrees * @param {Number} [rad=6371]: radius of earth if different value is required from standard 6,371km */ function LatLon(lat, lon, rad) { if (typeof rad == 'undefined') rad = 6371; // earth's mean radius in km this._lat = lat; this._lon = lon; this._radius = rad; } /** * Returns the distance from this point to the supplied point, in km * (using Haversine formula) * * from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine", * Sky and Telescope, vol 68, no 2, 1984 * * @param {LatLon} point: Latitude/longitude of destination point * @param {Number} [precision=4]: no of significant digits to use for returned value * @returns {Number} Distance in km between this point and destination point */ LatLon.prototype.distanceTo = function(point, precision) { // default 4 sig figs reflects typical 0.3% accuracy of spherical model if (typeof precision == 'undefined') precision = 4; var R = this._radius; var lat1 = this._lat.toRad(), lon1 = this._lon.toRad(); var lat2 = point._lat.toRad(), lon2 = point._lon.toRad(); var dLat = lat2 - lat1; var dLon = lon2 - lon1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; return d.toPrecisionFixed(precision); } /** * Returns the (initial) bearing from this point to the supplied point, in degrees * see http://williams.best.vwh.net/avform.htm#Crs * * @param {LatLon} point: Latitude/longitude of destination point * @returns {Number} Initial bearing in degrees from North */ LatLon.prototype.bearingTo = function(point) { var lat1 = this._lat.toRad(), lat2 = point._lat.toRad(); var dLon = (point._lon-this._lon).toRad(); var y = Math.sin(dLon) * Math.cos(lat2); var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); var brng = Math.atan2(y, x); return (brng.toDeg()+360) % 360; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // extend Number object with methods for converting degrees/radians /** Convert numeric degrees to radians */ if (typeof(String.prototype.toRad) === "undefined") { Number.prototype.toRad = function() { return this * Math.PI / 180; } } /** Convert radians to numeric (signed) degrees */ if (typeof(String.prototype.toDeg) === "undefined") { Number.prototype.toDeg = function() { return this * 180 / Math.PI; } } /** * Format the significant digits of a number, using only fixed-point notation (no exponential) * * @param {Number} precision: Number of significant digits to appear in the returned string * @returns {String} A string representation of number which contains precision significant digits */ if (typeof(Number.prototype.toPrecisionFixed) === "undefined") { Number.prototype.toPrecisionFixed = function(precision) { var numb = this < 0 ? -this : this; // can't take log of -ve number... var sign = this < 0 ? '-' : ''; if (numb == 0) { n = '0.'; while (precision--) n += '0'; return n }; // can't take log of zero var scale = Math.ceil(Math.log(numb)*Math.LOG10E); // no of digits before decimal var n = String(Math.round(numb * Math.pow(10, precision-scale))); if (scale > 0) { // add trailing zeros & insert decimal as required l = scale - n.length; while (l-- > 0) n = n + '0'; if (scale < n.length) n = n.slice(0,scale) + '.' + n.slice(scale); } else { // prefix decimal and leading zeros if required while (scale++ < 0) n = '0' + n; n = '0.' + n; } return sign + n; } } 
