Comparing version 2.0.16 to 2.0.17
@@ -1,2 +0,2 @@ | ||
/*! geolib.elevation 2.0.16 by Manuel Bieh | ||
/*! geolib.elevation 2.0.17 by Manuel Bieh | ||
* | ||
@@ -7,3 +7,3 @@ * Elevation Addon for Geolib.js | ||
* @url http://www.manuelbieh.com/ | ||
* @version 2.0.16 | ||
* @version 2.0.17 | ||
* @license MIT | ||
@@ -10,0 +10,0 @@ */ |
1852
dist/geolib.js
@@ -1,2 +0,2 @@ | ||
/*! geolib 2.0.16 by Manuel Bieh | ||
/*! geolib 2.0.17 by Manuel Bieh | ||
* Library to provide geo functions like distance calculation, | ||
@@ -8,599 +8,602 @@ * conversion of decimal coordinates to sexagesimal and vice versa, etc. | ||
* @url http://www.manuelbieh.com/ | ||
* @version 2.0.16 | ||
* @version 2.0.17 | ||
* @license MIT | ||
**/;(function(global, undefined) { | ||
"use strict"; | ||
"use strict"; | ||
function Geolib() {} | ||
function Geolib() {} | ||
// Setting readonly defaults | ||
var geolib = Object.create(Geolib.prototype, { | ||
version: { | ||
value: "2.0.16" | ||
}, | ||
radius: { | ||
value: 6378137 | ||
}, | ||
minLat: { | ||
value: -90 | ||
}, | ||
maxLat: { | ||
value: 90 | ||
}, | ||
minLon: { | ||
value: -180 | ||
}, | ||
maxLon: { | ||
value: 180 | ||
}, | ||
sexagesimalPattern: { | ||
value: /^([0-9]{1,3})°\s*([0-9]{1,3}(?:\.(?:[0-9]{1,2}))?)'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/ | ||
}, | ||
measures: { | ||
value: Object.create(Object.prototype, { | ||
"m" : {value: 1}, | ||
"km": {value: 0.001}, | ||
"cm": {value: 100}, | ||
"mm": {value: 1000}, | ||
"mi": {value: (1 / 1609.344)}, | ||
"sm": {value: (1 / 1852.216)}, | ||
"ft": {value: (100 / 30.48)}, | ||
"in": {value: (100 / 2.54)}, | ||
"yd": {value: (1 / 0.9144)} | ||
}) | ||
}, | ||
prototype: { | ||
value: Geolib.prototype | ||
}, | ||
extend: { | ||
value: function(methods, overwrite) { | ||
for(var prop in methods) { | ||
if(typeof geolib.prototype[prop] === 'undefined' || overwrite === true) { | ||
if(typeof methods[prop] === 'function' && typeof methods[prop].bind === 'function') { | ||
// Setting readonly defaults | ||
var geolib = Object.create(Geolib.prototype, { | ||
version: { | ||
value: "2.0.17" | ||
}, | ||
radius: { | ||
value: 6378137 | ||
}, | ||
minLat: { | ||
value: -90 | ||
}, | ||
maxLat: { | ||
value: 90 | ||
}, | ||
minLon: { | ||
value: -180 | ||
}, | ||
maxLon: { | ||
value: 180 | ||
}, | ||
sexagesimalPattern: { | ||
value: /^([0-9]{1,3})°\s*([0-9]{1,3}(?:\.(?:[0-9]{1,2}))?)'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/ | ||
}, | ||
measures: { | ||
value: Object.create(Object.prototype, { | ||
"m" : {value: 1}, | ||
"km": {value: 0.001}, | ||
"cm": {value: 100}, | ||
"mm": {value: 1000}, | ||
"mi": {value: (1 / 1609.344)}, | ||
"sm": {value: (1 / 1852.216)}, | ||
"ft": {value: (100 / 30.48)}, | ||
"in": {value: (100 / 2.54)}, | ||
"yd": {value: (1 / 0.9144)} | ||
}) | ||
}, | ||
prototype: { | ||
value: Geolib.prototype | ||
}, | ||
extend: { | ||
value: function(methods, overwrite) { | ||
for(var prop in methods) { | ||
if(typeof geolib.prototype[prop] === 'undefined' || overwrite === true) { | ||
if(typeof methods[prop] === 'function' && typeof methods[prop].bind === 'function') { | ||
geolib.prototype[prop] = methods[prop].bind(geolib); | ||
} else { | ||
} else { | ||
geolib.prototype[prop] = methods[prop]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
if (typeof(Number.prototype.toRad) === 'undefined') { | ||
Number.prototype.toRad = function() { | ||
return this * Math.PI / 180; | ||
}; | ||
} | ||
if (typeof(Number.prototype.toRad) === 'undefined') { | ||
Number.prototype.toRad = function() { | ||
return this * Math.PI / 180; | ||
}; | ||
} | ||
if (typeof(Number.prototype.toDeg) === 'undefined') { | ||
Number.prototype.toDeg = function() { | ||
return this * 180 / Math.PI; | ||
}; | ||
} | ||
if (typeof(Number.prototype.toDeg) === 'undefined') { | ||
Number.prototype.toDeg = function() { | ||
return this * 180 / Math.PI; | ||
}; | ||
} | ||
// Here comes the magic | ||
geolib.extend({ | ||
// Here comes the magic | ||
geolib.extend({ | ||
decimal: {}, | ||
decimal: {}, | ||
sexagesimal: {}, | ||
sexagesimal: {}, | ||
distance: null, | ||
distance: null, | ||
getKeys: function(point) { | ||
getKeys: function(point) { | ||
// GeoJSON Array [longitude, latitude(, elevation)] | ||
if(Object.prototype.toString.call(point) == '[object Array]') { | ||
// GeoJSON Array [longitude, latitude(, elevation)] | ||
if(Object.prototype.toString.call(point) == '[object Array]') { | ||
return { | ||
longitude: point.length >= 1 ? 0 : undefined, | ||
latitude: point.length >= 2 ? 1 : undefined, | ||
elevation: point.length >= 3 ? 2 : undefined | ||
}; | ||
return { | ||
longitude: point.length >= 1 ? 0 : undefined, | ||
latitude: point.length >= 2 ? 1 : undefined, | ||
elevation: point.length >= 3 ? 2 : undefined | ||
}; | ||
} | ||
} | ||
var getKey = function(possibleValues) { | ||
var getKey = function(possibleValues) { | ||
var key; | ||
var key; | ||
possibleValues.every(function(val) { | ||
// TODO: check if point is an object | ||
if(typeof point != 'object') { | ||
return true; | ||
} | ||
return point.hasOwnProperty(val) ? (function() { key = val; return false; }()) : true; | ||
}); | ||
possibleValues.every(function(val) { | ||
// TODO: check if point is an object | ||
if(typeof point != 'object') { | ||
return true; | ||
} | ||
return point.hasOwnProperty(val) ? (function() { key = val; return false; }()) : true; | ||
}); | ||
return key; | ||
return key; | ||
}; | ||
}; | ||
var longitude = getKey(['lng', 'lon', 'longitude']); | ||
var latitude = getKey(['lat', 'latitude']); | ||
var elevation = getKey(['alt', 'altitude', 'elevation', 'elev']); | ||
var longitude = getKey(['lng', 'lon', 'longitude']); | ||
var latitude = getKey(['lat', 'latitude']); | ||
var elevation = getKey(['alt', 'altitude', 'elevation', 'elev']); | ||
// return undefined if not at least one valid property was found | ||
if(typeof latitude == 'undefined' && | ||
typeof longitude == 'undefined' && | ||
typeof elevation == 'undefined') { | ||
return undefined; | ||
} | ||
// return undefined if not at least one valid property was found | ||
if(typeof latitude == 'undefined' && | ||
typeof longitude == 'undefined' && | ||
typeof elevation == 'undefined') { | ||
return undefined; | ||
} | ||
return { | ||
latitude: latitude, | ||
longitude: longitude, | ||
elevation: elevation | ||
}; | ||
return { | ||
latitude: latitude, | ||
longitude: longitude, | ||
elevation: elevation | ||
}; | ||
}, | ||
}, | ||
// returns latitude of a given point, converted to decimal | ||
// set raw to true to avoid conversion | ||
getLat: function(point, raw) { | ||
return raw === true ? point[this.getKeys(point).latitude] : this.useDecimal(point[this.getKeys(point).latitude]); | ||
}, | ||
// returns latitude of a given point, converted to decimal | ||
// set raw to true to avoid conversion | ||
getLat: function(point, raw) { | ||
return raw === true ? point[this.getKeys(point).latitude] : this.useDecimal(point[this.getKeys(point).latitude]); | ||
}, | ||
// Alias for getLat | ||
latitude: function(point) { | ||
return this.getLat.call(this, point); | ||
}, | ||
// Alias for getLat | ||
latitude: function(point) { | ||
return this.getLat.call(this, point); | ||
}, | ||
// returns longitude of a given point, converted to decimal | ||
// set raw to true to avoid conversion | ||
getLon: function(point, raw) { | ||
return raw === true ? point[this.getKeys(point).longitude] : this.useDecimal(point[this.getKeys(point).longitude]); | ||
}, | ||
// returns longitude of a given point, converted to decimal | ||
// set raw to true to avoid conversion | ||
getLon: function(point, raw) { | ||
return raw === true ? point[this.getKeys(point).longitude] : this.useDecimal(point[this.getKeys(point).longitude]); | ||
}, | ||
// Alias for getLon | ||
longitude: function(point) { | ||
return this.getLon.call(this, point); | ||
}, | ||
// Alias for getLon | ||
longitude: function(point) { | ||
return this.getLon.call(this, point); | ||
}, | ||
getElev: function(point) { | ||
return point[this.getKeys(point).elevation]; | ||
}, | ||
getElev: function(point) { | ||
return point[this.getKeys(point).elevation]; | ||
}, | ||
// Alias for getElev | ||
elevation: function(point) { | ||
return this.getElev.call(this, point); | ||
}, | ||
// Alias for getElev | ||
elevation: function(point) { | ||
return this.getElev.call(this, point); | ||
}, | ||
coords: function(point, raw) { | ||
coords: function(point, raw) { | ||
var retval = { | ||
latitude: raw === true ? point[this.getKeys(point).latitude] : this.useDecimal(point[this.getKeys(point).latitude]), | ||
longitude: raw === true ? point[this.getKeys(point).longitude] : this.useDecimal(point[this.getKeys(point).longitude]) | ||
}; | ||
var retval = { | ||
latitude: raw === true ? point[this.getKeys(point).latitude] : this.useDecimal(point[this.getKeys(point).latitude]), | ||
longitude: raw === true ? point[this.getKeys(point).longitude] : this.useDecimal(point[this.getKeys(point).longitude]) | ||
}; | ||
var elev = point[this.getKeys(point).elevation]; | ||
var elev = point[this.getKeys(point).elevation]; | ||
if(typeof elev !== 'undefined') { | ||
retval['elevation'] = elev; | ||
} | ||
if(typeof elev !== 'undefined') { | ||
retval['elevation'] = elev; | ||
} | ||
return retval; | ||
return retval; | ||
}, | ||
}, | ||
// Alias for coords | ||
ll: function(point, raw) { | ||
return this.coords.call(this, point, raw); | ||
}, | ||
// Alias for coords | ||
ll: function(point, raw) { | ||
return this.coords.call(this, point, raw); | ||
}, | ||
// checks if a variable contains a valid latlong object | ||
validate: function(point) { | ||
// checks if a variable contains a valid latlong object | ||
validate: function(point) { | ||
var keys = this.getKeys(point); | ||
var keys = this.getKeys(point); | ||
if(typeof keys === 'undefined' || typeof keys.latitude === 'undefined' || keys.longitude === 'undefined') { | ||
return false; | ||
} | ||
if(typeof keys === 'undefined' || typeof keys.latitude === 'undefined' || keys.longitude === 'undefined') { | ||
return false; | ||
} | ||
var lat = point[keys.latitude]; | ||
var lng = point[keys.longitude]; | ||
var lat = point[keys.latitude]; | ||
var lng = point[keys.longitude]; | ||
if(typeof lat === 'undefined' || !this.isDecimal(lat) && !this.isSexagesimal(lat)) { | ||
return false; | ||
} | ||
if(typeof lat === 'undefined' || !this.isDecimal(lat) && !this.isSexagesimal(lat)) { | ||
return false; | ||
} | ||
if(typeof lng === 'undefined' || !this.isDecimal(lng) && !this.isSexagesimal(lng)) { | ||
return false; | ||
} | ||
if(typeof lng === 'undefined' || !this.isDecimal(lng) && !this.isSexagesimal(lng)) { | ||
return false; | ||
} | ||
lat = this.useDecimal(lat); | ||
lng = this.useDecimal(lng); | ||
lat = this.useDecimal(lat); | ||
lng = this.useDecimal(lng); | ||
if(lat < this.minLat || lat > this.maxLat || lng < this.minLon || lng > this.maxLon) { | ||
return false; | ||
} | ||
if(lat < this.minLat || lat > this.maxLat || lng < this.minLon || lng > this.maxLon) { | ||
return false; | ||
} | ||
return true; | ||
return true; | ||
}, | ||
}, | ||
/** | ||
* Calculates geodetic distance between two points specified by latitude/longitude using | ||
* Vincenty inverse formula for ellipsoids | ||
* Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2010 | ||
* (Licensed under CC BY 3.0) | ||
* | ||
* @param object Start position {latitude: 123, longitude: 123} | ||
* @param object End position {latitude: 123, longitude: 123} | ||
* @param integer Accuracy (in meters) | ||
* @return integer Distance (in meters) | ||
*/ | ||
getDistance: function(start, end, accuracy) { | ||
/** | ||
* Calculates geodetic distance between two points specified by latitude/longitude using | ||
* Vincenty inverse formula for ellipsoids | ||
* Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2010 | ||
* (Licensed under CC BY 3.0) | ||
* | ||
* @param object Start position {latitude: 123, longitude: 123} | ||
* @param object End position {latitude: 123, longitude: 123} | ||
* @param integer Accuracy (in meters) | ||
* @return integer Distance (in meters) | ||
*/ | ||
getDistance: function(start, end, accuracy) { | ||
accuracy = Math.floor(accuracy) || 1; | ||
accuracy = Math.floor(accuracy) || 1; | ||
var s = this.coords(start); | ||
var e = this.coords(end); | ||
var s = this.coords(start); | ||
var e = this.coords(end); | ||
var a = 6378137, b = 6356752.314245, f = 1/298.257223563; // WGS-84 ellipsoid params | ||
var L = (e['longitude']-s['longitude']).toRad(); | ||
var a = 6378137, b = 6356752.314245, f = 1/298.257223563; // WGS-84 ellipsoid params | ||
var L = (e['longitude']-s['longitude']).toRad(); | ||
var cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, sinSigma; | ||
var cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, sinSigma; | ||
var U1 = Math.atan((1-f) * Math.tan(parseFloat(s['latitude']).toRad())); | ||
var U2 = Math.atan((1-f) * Math.tan(parseFloat(e['latitude']).toRad())); | ||
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); | ||
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); | ||
var U1 = Math.atan((1-f) * Math.tan(parseFloat(s['latitude']).toRad())); | ||
var U2 = Math.atan((1-f) * Math.tan(parseFloat(e['latitude']).toRad())); | ||
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); | ||
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); | ||
var lambda = L, lambdaP, iterLimit = 100; | ||
do { | ||
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); | ||
sinSigma = ( | ||
Math.sqrt( | ||
( | ||
cosU2 * sinLambda | ||
) * ( | ||
cosU2 * sinLambda | ||
) + ( | ||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda | ||
) * ( | ||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda | ||
) | ||
) | ||
); | ||
if (sinSigma === 0) { | ||
return geolib.distance = 0; // co-incident points | ||
} | ||
var lambda = L, lambdaP, iterLimit = 100; | ||
do { | ||
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); | ||
sinSigma = ( | ||
Math.sqrt( | ||
( | ||
cosU2 * sinLambda | ||
) * ( | ||
cosU2 * sinLambda | ||
) + ( | ||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda | ||
) * ( | ||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda | ||
) | ||
) | ||
); | ||
if (sinSigma === 0) { | ||
return geolib.distance = 0; // co-incident points | ||
} | ||
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; | ||
sigma = Math.atan2(sinSigma, cosSigma); | ||
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; | ||
cosSqAlpha = 1 - sinAlpha * sinAlpha; | ||
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; | ||
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; | ||
sigma = Math.atan2(sinSigma, cosSigma); | ||
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; | ||
cosSqAlpha = 1 - sinAlpha * sinAlpha; | ||
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; | ||
if (isNaN(cos2SigmaM)) { | ||
cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) | ||
} | ||
var C = ( | ||
f / 16 * cosSqAlpha * ( | ||
4 + f * ( | ||
4 - 3 * cosSqAlpha | ||
) | ||
) | ||
); | ||
lambdaP = lambda; | ||
lambda = ( | ||
L + ( | ||
1 - C | ||
) * f * sinAlpha * ( | ||
sigma + C * sinSigma * ( | ||
cos2SigmaM + C * cosSigma * ( | ||
-1 + 2 * cos2SigmaM * cos2SigmaM | ||
) | ||
) | ||
) | ||
); | ||
if (isNaN(cos2SigmaM)) { | ||
cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) | ||
} | ||
var C = ( | ||
f / 16 * cosSqAlpha * ( | ||
4 + f * ( | ||
4 - 3 * cosSqAlpha | ||
) | ||
) | ||
); | ||
lambdaP = lambda; | ||
lambda = ( | ||
L + ( | ||
1 - C | ||
) * f * sinAlpha * ( | ||
sigma + C * sinSigma * ( | ||
cos2SigmaM + C * cosSigma * ( | ||
-1 + 2 * cos2SigmaM * cos2SigmaM | ||
) | ||
) | ||
) | ||
); | ||
} while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0); | ||
} while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0); | ||
if (iterLimit === 0) { | ||
return NaN; // formula failed to converge | ||
} | ||
if (iterLimit === 0) { | ||
return NaN; // formula failed to converge | ||
} | ||
var uSq = ( | ||
cosSqAlpha * ( | ||
a * a - b * b | ||
) / ( | ||
b*b | ||
) | ||
); | ||
var uSq = ( | ||
cosSqAlpha * ( | ||
a * a - b * b | ||
) / ( | ||
b*b | ||
) | ||
); | ||
var A = ( | ||
1 + uSq / 16384 * ( | ||
4096 + uSq * ( | ||
-768 + uSq * ( | ||
320 - 175 * uSq | ||
) | ||
) | ||
) | ||
); | ||
var A = ( | ||
1 + uSq / 16384 * ( | ||
4096 + uSq * ( | ||
-768 + uSq * ( | ||
320 - 175 * uSq | ||
) | ||
) | ||
) | ||
); | ||
var B = ( | ||
uSq / 1024 * ( | ||
256 + uSq * ( | ||
-128 + uSq * ( | ||
74-47 * uSq | ||
) | ||
) | ||
) | ||
); | ||
var B = ( | ||
uSq / 1024 * ( | ||
256 + uSq * ( | ||
-128 + uSq * ( | ||
74-47 * uSq | ||
) | ||
) | ||
) | ||
); | ||
var deltaSigma = ( | ||
B * sinSigma * ( | ||
cos2SigmaM + B / 4 * ( | ||
cosSigma * ( | ||
-1 + 2 * cos2SigmaM * cos2SigmaM | ||
) -B / 6 * cos2SigmaM * ( | ||
-3 + 4 * sinSigma * sinSigma | ||
) * ( | ||
-3 + 4 * cos2SigmaM * cos2SigmaM | ||
) | ||
) | ||
) | ||
); | ||
var deltaSigma = ( | ||
B * sinSigma * ( | ||
cos2SigmaM + B / 4 * ( | ||
cosSigma * ( | ||
-1 + 2 * cos2SigmaM * cos2SigmaM | ||
) -B / 6 * cos2SigmaM * ( | ||
-3 + 4 * sinSigma * sinSigma | ||
) * ( | ||
-3 + 4 * cos2SigmaM * cos2SigmaM | ||
) | ||
) | ||
) | ||
); | ||
var distance = b * A * (sigma - deltaSigma); | ||
var distance = b * A * (sigma - deltaSigma); | ||
distance = distance.toFixed(3); // round to 1mm precision | ||
distance = distance.toFixed(3); // round to 1mm precision | ||
//if (start.hasOwnProperty(elevation) && end.hasOwnProperty(elevation)) { | ||
if (typeof this.elevation(start) !== 'undefined' && typeof this.elevation(end) !== 'undefined') { | ||
var climb = Math.abs(this.elevation(start) - this.elevation(end)); | ||
distance = Math.sqrt(distance * distance + climb * climb); | ||
} | ||
//if (start.hasOwnProperty(elevation) && end.hasOwnProperty(elevation)) { | ||
if (typeof this.elevation(start) !== 'undefined' && typeof this.elevation(end) !== 'undefined') { | ||
var climb = Math.abs(this.elevation(start) - this.elevation(end)); | ||
distance = Math.sqrt(distance * distance + climb * climb); | ||
} | ||
return this.distance = Math.floor( | ||
Math.round(distance / accuracy) * accuracy | ||
); | ||
return this.distance = Math.floor( | ||
Math.round(distance / accuracy) * accuracy | ||
); | ||
/* | ||
// note: to return initial/final bearings in addition to distance, use something like: | ||
var fwdAz = Math.atan2(cosU2*sinLambda, cosU1*sinU2-sinU1*cosU2*cosLambda); | ||
var revAz = Math.atan2(cosU1*sinLambda, -sinU1*cosU2+cosU1*sinU2*cosLambda); | ||
/* | ||
// note: to return initial/final bearings in addition to distance, use something like: | ||
var fwdAz = Math.atan2(cosU2*sinLambda, cosU1*sinU2-sinU1*cosU2*cosLambda); | ||
var revAz = Math.atan2(cosU1*sinLambda, -sinU1*cosU2+cosU1*sinU2*cosLambda); | ||
return { distance: s, initialBearing: fwdAz.toDeg(), finalBearing: revAz.toDeg() }; | ||
*/ | ||
return { distance: s, initialBearing: fwdAz.toDeg(), finalBearing: revAz.toDeg() }; | ||
*/ | ||
}, | ||
}, | ||
/** | ||
* Calculates the distance between two spots. | ||
* This method is more simple but also far more inaccurate | ||
* | ||
* @param object Start position {latitude: 123, longitude: 123} | ||
* @param object End position {latitude: 123, longitude: 123} | ||
* @param integer Accuracy (in meters) | ||
* @return integer Distance (in meters) | ||
*/ | ||
getDistanceSimple: function(start, end, accuracy) { | ||
/** | ||
* Calculates the distance between two spots. | ||
* This method is more simple but also far more inaccurate | ||
* | ||
* @param object Start position {latitude: 123, longitude: 123} | ||
* @param object End position {latitude: 123, longitude: 123} | ||
* @param integer Accuracy (in meters) | ||
* @return integer Distance (in meters) | ||
*/ | ||
getDistanceSimple: function(start, end, accuracy) { | ||
accuracy = Math.floor(accuracy) || 1; | ||
accuracy = Math.floor(accuracy) || 1; | ||
var distance = | ||
Math.round( | ||
Math.acos( | ||
Math.sin( | ||
this.latitude(end).toRad() | ||
) * | ||
Math.sin( | ||
this.latitude(start).toRad() | ||
) + | ||
Math.cos( | ||
this.latitude(end).toRad() | ||
) * | ||
Math.cos( | ||
this.latitude(start).toRad() | ||
) * | ||
Math.cos( | ||
this.longitude(start).toRad() - this.longitude(end).toRad() | ||
) | ||
) * this.radius | ||
); | ||
var distance = | ||
Math.round( | ||
Math.acos( | ||
Math.sin( | ||
this.latitude(end).toRad() | ||
) * | ||
Math.sin( | ||
this.latitude(start).toRad() | ||
) + | ||
Math.cos( | ||
this.latitude(end).toRad() | ||
) * | ||
Math.cos( | ||
this.latitude(start).toRad() | ||
) * | ||
Math.cos( | ||
this.longitude(start).toRad() - this.longitude(end).toRad() | ||
) | ||
) * this.radius | ||
); | ||
return geolib.distance = Math.floor(Math.round(distance/accuracy)*accuracy); | ||
return geolib.distance = Math.floor(Math.round(distance/accuracy)*accuracy); | ||
}, | ||
}, | ||
/** | ||
* Calculates the center of a collection of geo coordinates | ||
* | ||
* @param array Collection of coords [{latitude: 51.510, longitude: 7.1321}, {latitude: 49.1238, longitude: "8° 30' W"}, ...] | ||
* @return object {latitude: centerLat, longitude: centerLng} | ||
*/ | ||
getCenter: function(coords) { | ||
* Calculates the center of a collection of geo coordinates | ||
* | ||
* @param array Collection of coords [{latitude: 51.510, longitude: 7.1321}, {latitude: 49.1238, longitude: "8° 30' W"}, ...] | ||
* @return object {latitude: centerLat, longitude: centerLng} | ||
*/ | ||
getCenter: function(coords) { | ||
if (!coords.length) { | ||
return false; | ||
} | ||
if (!coords.length) { | ||
return false; | ||
} | ||
var X = 0.0; | ||
var Y = 0.0; | ||
var Z = 0.0; | ||
var lat, lon, hyp; | ||
var X = 0.0; | ||
var Y = 0.0; | ||
var Z = 0.0; | ||
var lat, lon, hyp; | ||
coords.forEach(function(coord) { | ||
lat = coord.latitude * Math.PI / 180; | ||
lon = coord.longitude * Math.PI / 180; | ||
coords.forEach(function(coord) { | ||
X += Math.cos(lat) * Math.cos(lon); | ||
Y += Math.cos(lat) * Math.sin(lon); | ||
Z += Math.sin(lat); | ||
}); | ||
lat = coord.latitude * Math.PI / 180; | ||
lon = coord.longitude * Math.PI / 180; | ||
var nb_coords = coords.length; | ||
X = X / nb_coords; | ||
Y = Y / nb_coords; | ||
Z = Z / nb_coords; | ||
X += Math.cos(lat) * Math.cos(lon); | ||
Y += Math.cos(lat) * Math.sin(lon); | ||
Z += Math.sin(lat); | ||
lon = Math.atan2(Y, X); | ||
hyp = Math.sqrt(X * X + Y * Y); | ||
lat = Math.atan2(Z, hyp); | ||
}); | ||
return { | ||
latitude: (lat * 180 / Math.PI).toFixed(6), | ||
longitude: (lon * 180 / Math.PI).toFixed(6) | ||
}; | ||
}, | ||
var nb_coords = coords.length; | ||
X = X / nb_coords; | ||
Y = Y / nb_coords; | ||
Z = Z / nb_coords; | ||
lon = Math.atan2(Y, X); | ||
hyp = Math.sqrt(X * X + Y * Y); | ||
lat = Math.atan2(Z, hyp); | ||
/** | ||
* Gets the max and min, latitude, longitude, and elevation (if provided). | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return object {maxLat: maxLat, | ||
* minLat: minLat | ||
* maxLng: maxLng, | ||
* minLng: minLng, | ||
* maxElev: maxElev, | ||
* minElev: minElev} | ||
*/ | ||
getBounds: function(coords) { | ||
return { | ||
latitude: (lat * 180 / Math.PI).toFixed(6), | ||
longitude: (lon * 180 / Math.PI).toFixed(6) | ||
}; | ||
if (!coords.length) { | ||
return false; | ||
} | ||
}, | ||
var useElevation = this.elevation(coords[0]); | ||
var stats = { | ||
maxLat: -Infinity, | ||
minLat: Infinity, | ||
maxLng: -Infinity, | ||
minLng: Infinity | ||
}; | ||
/** | ||
* Gets the max and min, latitude, longitude, and elevation (if provided). | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return object {maxLat: maxLat, | ||
* minLat: minLat | ||
* maxLng: maxLng, | ||
* minLng: minLng, | ||
* maxElev: maxElev, | ||
* minElev: minElev} | ||
*/ | ||
getBounds: function(coords) { | ||
if (typeof useElevation != 'undefined') { | ||
stats.maxElev = 0; | ||
stats.minElev = Infinity; | ||
} | ||
if (!coords.length) { | ||
return false; | ||
} | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
var useElevation = this.elevation(coords[0]); | ||
stats.maxLat = Math.max(this.latitude(coords[i]), stats.maxLat); | ||
stats.minLat = Math.min(this.latitude(coords[i]), stats.minLat); | ||
stats.maxLng = Math.max(this.longitude(coords[i]), stats.maxLng); | ||
stats.minLng = Math.min(this.longitude(coords[i]), stats.minLng); | ||
var stats = { | ||
maxLat: -Infinity, | ||
minLat: Infinity, | ||
maxLng: -Infinity, | ||
minLng: Infinity | ||
}; | ||
if (useElevation) { | ||
stats.maxElev = Math.max(this.elevation(coords[i]), stats.maxElev); | ||
stats.minElev = Math.min(this.elevation(coords[i]), stats.minElev); | ||
} | ||
if (typeof useElevation != 'undefined') { | ||
stats.maxElev = 0; | ||
stats.minElev = Infinity; | ||
} | ||
} | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
return stats; | ||
stats.maxLat = Math.max(this.latitude(coords[i]), stats.maxLat); | ||
stats.minLat = Math.min(this.latitude(coords[i]), stats.minLat); | ||
stats.maxLng = Math.max(this.longitude(coords[i]), stats.maxLng); | ||
stats.minLng = Math.min(this.longitude(coords[i]), stats.minLng); | ||
}, | ||
if (useElevation) { | ||
stats.maxElev = Math.max(this.elevation(coords[i]), stats.maxElev); | ||
stats.minElev = Math.min(this.elevation(coords[i]), stats.minElev); | ||
} | ||
} | ||
/** | ||
* Computes the bounding coordinates of all points on the surface | ||
* of the earth less than or equal to the specified great circle | ||
* distance. | ||
* | ||
* @param object Point position {latitude: 123, longitude: 123} | ||
* @param number Distance (in meters). | ||
* @return array Collection of two points defining the SW and NE corners. | ||
*/ | ||
getBoundsOfDistance: function(point, distance) { | ||
return stats; | ||
var latitude = this.latitude(point); | ||
var longitude = this.longitude(point); | ||
}, | ||
var radLat = latitude.toRad(); | ||
var radLon = longitude.toRad(); | ||
var radDist = distance / this.radius; | ||
var minLat = radLat - radDist; | ||
var maxLat = radLat + radDist; | ||
/** | ||
* Computes the bounding coordinates of all points on the surface | ||
* of the earth less than or equal to the specified great circle | ||
* distance. | ||
* | ||
* @param object Point position {latitude: 123, longitude: 123} | ||
* @param number Distance (in meters). | ||
* @return array Collection of two points defining the SW and NE corners. | ||
*/ | ||
getBoundsOfDistance: function(point, distance) { | ||
var MAX_LAT_RAD = this.maxLat.toRad(); | ||
var MIN_LAT_RAD = this.minLat.toRad(); | ||
var MAX_LON_RAD = this.maxLon.toRad(); | ||
var MIN_LON_RAD = this.minLon.toRad(); | ||
var latitude = this.latitude(point); | ||
var longitude = this.longitude(point); | ||
var minLon; | ||
var maxLon; | ||
var radLat = latitude.toRad(); | ||
var radLon = longitude.toRad(); | ||
if (minLat > MIN_LAT_RAD && maxLat < MAX_LAT_RAD) { | ||
var radDist = distance / this.radius; | ||
var minLat = radLat - radDist; | ||
var maxLat = radLat + radDist; | ||
var deltaLon = Math.asin(Math.sin(radDist) / Math.cos(radLat)); | ||
minLon = radLon - deltaLon; | ||
var MAX_LAT_RAD = this.maxLat.toRad(); | ||
var MIN_LAT_RAD = this.minLat.toRad(); | ||
var MAX_LON_RAD = this.maxLon.toRad(); | ||
var MIN_LON_RAD = this.minLon.toRad(); | ||
if (minLon < MIN_LON_RAD) { | ||
minLon += 2 * Math.PI; | ||
} | ||
var minLon; | ||
var maxLon; | ||
maxLon = radLon + deltaLon; | ||
if (minLat > MIN_LAT_RAD && maxLat < MAX_LAT_RAD) { | ||
if (maxLon > MAX_LON_RAD) { | ||
maxLon -= 2 * Math.PI; | ||
} | ||
var deltaLon = Math.asin(Math.sin(radDist) / Math.cos(radLat)); | ||
minLon = radLon - deltaLon; | ||
} else { | ||
// A pole is within the distance. | ||
minLat = Math.max(minLat, MIN_LAT_RAD); | ||
maxLat = Math.min(maxLat, MAX_LAT_RAD); | ||
minLon = MIN_LON_RAD; | ||
maxLon = MAX_LON_RAD; | ||
} | ||
if (minLon < MIN_LON_RAD) { | ||
minLon += 2 * Math.PI; | ||
} | ||
return [ | ||
// Southwest | ||
{ | ||
latitude: minLat.toDeg(), | ||
longitude: minLon.toDeg() | ||
}, | ||
// Northeast | ||
{ | ||
latitude: maxLat.toDeg(), | ||
longitude: maxLon.toDeg() | ||
} | ||
]; | ||
maxLon = radLon + deltaLon; | ||
}, | ||
if (maxLon > MAX_LON_RAD) { | ||
maxLon -= 2 * Math.PI; | ||
} | ||
} else { | ||
// A pole is within the distance. | ||
minLat = Math.max(minLat, MIN_LAT_RAD); | ||
maxLat = Math.min(maxLat, MAX_LAT_RAD); | ||
minLon = MIN_LON_RAD; | ||
maxLon = MAX_LON_RAD; | ||
} | ||
/** | ||
* Checks whether a point is inside of a polygon or not. | ||
* Note that the polygon coords must be in correct order! | ||
* | ||
* @param object coordinate to check e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return bool true if the coordinate is inside the given polygon | ||
*/ | ||
isPointInside: function(latlng, coords) { | ||
return [ | ||
// Southwest | ||
{ | ||
latitude: minLat.toDeg(), | ||
longitude: minLon.toDeg() | ||
}, | ||
// Northeast | ||
{ | ||
latitude: maxLat.toDeg(), | ||
longitude: maxLon.toDeg() | ||
} | ||
]; | ||
for(var c = false, i = -1, l = coords.length, j = l - 1; ++i < l; j = i) { | ||
}, | ||
if( | ||
( | ||
(this.longitude(coords[i]) <= this.longitude(latlng) && this.longitude(latlng) < this.longitude(coords[j])) || | ||
(this.longitude(coords[j]) <= this.longitude(latlng) && this.longitude(latlng) < this.longitude(coords[i])) | ||
) && | ||
( | ||
this.latitude(latlng) < (this.latitude(coords[j]) - this.latitude(coords[i])) * | ||
(this.longitude(latlng) - this.longitude(coords[i])) / | ||
(this.longitude(coords[j]) - this.longitude(coords[i])) + | ||
this.latitude(coords[i]) | ||
) | ||
) { | ||
c = !c; | ||
} | ||
} | ||
/** | ||
* Checks whether a point is inside of a polygon or not. | ||
* Note that the polygon coords must be in correct order! | ||
* | ||
* @param object coordinate to check e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return bool true if the coordinate is inside the given polygon | ||
*/ | ||
isPointInside: function(latlng, coords) { | ||
return c; | ||
for(var c = false, i = -1, l = coords.length, j = l - 1; ++i < l; j = i) { | ||
}, | ||
if( | ||
( | ||
(this.longitude(coords[i]) <= this.longitude(latlng) && this.longitude(latlng) < this.longitude(coords[j])) || | ||
(this.longitude(coords[j]) <= this.longitude(latlng) && this.longitude(latlng) < this.longitude(coords[i])) | ||
) && | ||
( | ||
this.latitude(latlng) < (this.latitude(coords[j]) - this.latitude(coords[i])) * | ||
(this.longitude(latlng) - this.longitude(coords[i])) / | ||
(this.longitude(coords[j]) - this.longitude(coords[i])) + | ||
this.latitude(coords[i]) | ||
) | ||
) { | ||
c = !c; | ||
} | ||
} | ||
return c; | ||
}, | ||
/** | ||
@@ -610,38 +613,38 @@ * Pre calculate the polygon coords, to speed up the point inside check. | ||
* @see Algorythm from http://alienryderflex.com/polygon/ | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
*/ | ||
preparePolygonForIsPointInsideOptimized: function(coords) { | ||
preparePolygonForIsPointInsideOptimized: function(coords) { | ||
for(var i = 0, j = coords.length-1; i < coords.length; i++) { | ||
for(var i = 0, j = coords.length-1; i < coords.length; i++) { | ||
if(this.longitude(coords[j]) === this.longitude(coords[i])) { | ||
if(this.longitude(coords[j]) === this.longitude(coords[i])) { | ||
coords[i].constant = this.latitude(coords[i]); | ||
coords[i].multiple = 0; | ||
coords[i].constant = this.latitude(coords[i]); | ||
coords[i].multiple = 0; | ||
} else { | ||
} else { | ||
coords[i].constant = this.latitude(coords[i]) - ( | ||
this.longitude(coords[i]) * this.latitude(coords[j]) | ||
) / ( | ||
this.longitude(coords[j]) - this.longitude(coords[i]) | ||
) + ( | ||
this.longitude(coords[i])*this.latitude(coords[i]) | ||
) / ( | ||
this.longitude(coords[j])-this.longitude(coords[i]) | ||
); | ||
coords[i].constant = this.latitude(coords[i]) - ( | ||
this.longitude(coords[i]) * this.latitude(coords[j]) | ||
) / ( | ||
this.longitude(coords[j]) - this.longitude(coords[i]) | ||
) + ( | ||
this.longitude(coords[i])*this.latitude(coords[i]) | ||
) / ( | ||
this.longitude(coords[j])-this.longitude(coords[i]) | ||
); | ||
coords[i].multiple = ( | ||
this.latitude(coords[j])-this.latitude(coords[i]) | ||
) / ( | ||
this.longitude(coords[j])-this.longitude(coords[i]) | ||
); | ||
coords[i].multiple = ( | ||
this.latitude(coords[j])-this.latitude(coords[i]) | ||
) / ( | ||
this.longitude(coords[j])-this.longitude(coords[i]) | ||
); | ||
} | ||
} | ||
j=i; | ||
j=i; | ||
} | ||
} | ||
}, | ||
}, | ||
@@ -656,569 +659,574 @@ /** | ||
* | ||
* @param object coordinate to check e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return bool true if the coordinate is inside the given polygon | ||
* @param object coordinate to check e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return bool true if the coordinate is inside the given polygon | ||
*/ | ||
isPointInsideWithPreparedPolygon: function(point, coords) { | ||
isPointInsideWithPreparedPolygon: function(point, coords) { | ||
var flgPointInside = false, | ||
y = this.longitude(point), | ||
x = this.latitude(point); | ||
var flgPointInside = false, | ||
y = this.longitude(point), | ||
x = this.latitude(point); | ||
for(var i = 0, j = coords.length-1; i < coords.length; i++) { | ||
for(var i = 0, j = coords.length-1; i < coords.length; i++) { | ||
if ((this.longitude(coords[i]) < y && this.longitude(coords[j]) >=y || | ||
this.longitude(coords[j]) < y && this.longitude(coords[i]) >= y)) { | ||
if ((this.longitude(coords[i]) < y && this.longitude(coords[j]) >=y || | ||
this.longitude(coords[j]) < y && this.longitude(coords[i]) >= y)) { | ||
flgPointInside^=(y*coords[i].multiple+coords[i].constant < x); | ||
flgPointInside^=(y*coords[i].multiple+coords[i].constant < x); | ||
} | ||
} | ||
j=i; | ||
j=i; | ||
} | ||
} | ||
return flgPointInside; | ||
return flgPointInside; | ||
}, | ||
}, | ||
/** | ||
* Shortcut for geolib.isPointInside() | ||
*/ | ||
isInside: function() { | ||
return this.isPointInside.apply(this, arguments); | ||
}, | ||
/** | ||
* Shortcut for geolib.isPointInside() | ||
*/ | ||
isInside: function() { | ||
return this.isPointInside.apply(this, arguments); | ||
}, | ||
/** | ||
* Checks whether a point is inside of a circle or not. | ||
* | ||
* @param object coordinate to check (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object coordinate of the circle's center (e.g. {latitude: 51.4812, longitude: 7.4025}) | ||
* @param integer maximum radius in meters | ||
* @return bool true if the coordinate is within the given radius | ||
*/ | ||
isPointInCircle: function(latlng, center, radius) { | ||
return this.getDistance(latlng, center) < radius; | ||
}, | ||
/** | ||
* Checks whether a point is inside of a circle or not. | ||
* | ||
* @param object coordinate to check (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object coordinate of the circle's center (e.g. {latitude: 51.4812, longitude: 7.4025}) | ||
* @param integer maximum radius in meters | ||
* @return bool true if the coordinate is within the given radius | ||
*/ | ||
isPointInCircle: function(latlng, center, radius) { | ||
return this.getDistance(latlng, center) < radius; | ||
}, | ||
/** | ||
* Shortcut for geolib.isPointInCircle() | ||
*/ | ||
withinRadius: function() { | ||
return this.isPointInCircle.apply(this, arguments); | ||
}, | ||
/** | ||
* Shortcut for geolib.isPointInCircle() | ||
*/ | ||
withinRadius: function() { | ||
return this.isPointInCircle.apply(this, arguments); | ||
}, | ||
/** | ||
* Gets rhumb line bearing of two points. Find out about the difference between rhumb line and | ||
* great circle bearing on Wikipedia. It's quite complicated. Rhumb line should be fine in most cases: | ||
* | ||
* http://en.wikipedia.org/wiki/Rhumb_line#General_and_mathematical_description | ||
* | ||
* Function heavily based on Doug Vanderweide's great PHP version (licensed under GPL 3.0) | ||
* http://www.dougv.com/2009/07/13/calculating-the-bearing-and-compass-rose-direction-between-two-latitude-longitude-coordinates-in-php/ | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @return integer calculated bearing | ||
*/ | ||
getRhumbLineBearing: function(originLL, destLL) { | ||
/** | ||
* Gets rhumb line bearing of two points. Find out about the difference between rhumb line and | ||
* great circle bearing on Wikipedia. It's quite complicated. Rhumb line should be fine in most cases: | ||
* | ||
* http://en.wikipedia.org/wiki/Rhumb_line#General_and_mathematical_description | ||
* | ||
* Function heavily based on Doug Vanderweide's great PHP version (licensed under GPL 3.0) | ||
* http://www.dougv.com/2009/07/13/calculating-the-bearing-and-compass-rose-direction-between-two-latitude-longitude-coordinates-in-php/ | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @return integer calculated bearing | ||
*/ | ||
getRhumbLineBearing: function(originLL, destLL) { | ||
// difference of longitude coords | ||
var diffLon = this.longitude(destLL).toRad() - this.longitude(originLL).toRad(); | ||
// difference of longitude coords | ||
var diffLon = this.longitude(destLL).toRad() - this.longitude(originLL).toRad(); | ||
// difference latitude coords phi | ||
var diffPhi = Math.log( | ||
Math.tan( | ||
this.latitude(destLL).toRad() / 2 + Math.PI / 4 | ||
) / | ||
Math.tan( | ||
this.latitude(originLL).toRad() / 2 + Math.PI / 4 | ||
) | ||
); | ||
// difference latitude coords phi | ||
var diffPhi = Math.log( | ||
Math.tan( | ||
this.latitude(destLL).toRad() / 2 + Math.PI / 4 | ||
) / | ||
Math.tan( | ||
this.latitude(originLL).toRad() / 2 + Math.PI / 4 | ||
) | ||
); | ||
// recalculate diffLon if it is greater than pi | ||
if(Math.abs(diffLon) > Math.PI) { | ||
if(diffLon > 0) { | ||
diffLon = (2 * Math.PI - diffLon) * -1; | ||
} | ||
else { | ||
diffLon = 2 * Math.PI + diffLon; | ||
} | ||
} | ||
// recalculate diffLon if it is greater than pi | ||
if(Math.abs(diffLon) > Math.PI) { | ||
if(diffLon > 0) { | ||
diffLon = (2 * Math.PI - diffLon) * -1; | ||
} | ||
else { | ||
diffLon = 2 * Math.PI + diffLon; | ||
} | ||
} | ||
//return the angle, normalized | ||
return (Math.atan2(diffLon, diffPhi).toDeg() + 360) % 360; | ||
//return the angle, normalized | ||
return (Math.atan2(diffLon, diffPhi).toDeg() + 360) % 360; | ||
}, | ||
}, | ||
/** | ||
* Gets great circle bearing of two points. See description of getRhumbLineBearing for more information | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @return integer calculated bearing | ||
*/ | ||
getBearing: function(originLL, destLL) { | ||
/** | ||
* Gets great circle bearing of two points. See description of getRhumbLineBearing for more information | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @return integer calculated bearing | ||
*/ | ||
getBearing: function(originLL, destLL) { | ||
destLL['latitude'] = this.latitude(destLL); | ||
destLL['longitude'] = this.longitude(destLL); | ||
originLL['latitude'] = this.latitude(originLL); | ||
originLL['longitude'] = this.longitude(originLL); | ||
destLL['latitude'] = this.latitude(destLL); | ||
destLL['longitude'] = this.longitude(destLL); | ||
originLL['latitude'] = this.latitude(originLL); | ||
originLL['longitude'] = this.longitude(originLL); | ||
var bearing = ( | ||
( | ||
Math.atan2( | ||
Math.sin( | ||
destLL['longitude'].toRad() - | ||
originLL['longitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['latitude'].toRad() | ||
), | ||
Math.cos( | ||
originLL['latitude'].toRad() | ||
) * | ||
Math.sin( | ||
destLL['latitude'].toRad() | ||
) - | ||
Math.sin( | ||
originLL['latitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['latitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['longitude'].toRad() - originLL['longitude'].toRad() | ||
) | ||
) | ||
).toDeg() + 360 | ||
) % 360; | ||
var bearing = ( | ||
( | ||
Math.atan2( | ||
Math.sin( | ||
destLL['longitude'].toRad() - | ||
originLL['longitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['latitude'].toRad() | ||
), | ||
Math.cos( | ||
originLL['latitude'].toRad() | ||
) * | ||
Math.sin( | ||
destLL['latitude'].toRad() | ||
) - | ||
Math.sin( | ||
originLL['latitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['latitude'].toRad() | ||
) * | ||
Math.cos( | ||
destLL['longitude'].toRad() - originLL['longitude'].toRad() | ||
) | ||
) | ||
).toDeg() + 360 | ||
) % 360; | ||
return bearing; | ||
return bearing; | ||
}, | ||
}, | ||
/** | ||
* Gets the compass direction from an origin coordinate to a destination coordinate. | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @param string Bearing mode. Can be either circle or rhumbline | ||
* @return object Returns an object with a rough (NESW) and an exact direction (NNE, NE, ENE, E, ESE, etc). | ||
*/ | ||
getCompassDirection: function(originLL, destLL, bearingMode) { | ||
/** | ||
* Gets the compass direction from an origin coordinate to a destination coordinate. | ||
* | ||
* @param object origin coordinate (e.g. {latitude: 51.5023, longitude: 7.3815}) | ||
* @param object destination coordinate | ||
* @param string Bearing mode. Can be either circle or rhumbline | ||
* @return object Returns an object with a rough (NESW) and an exact direction (NNE, NE, ENE, E, ESE, etc). | ||
*/ | ||
getCompassDirection: function(originLL, destLL, bearingMode) { | ||
var direction; | ||
var bearing; | ||
var direction; | ||
var bearing; | ||
if(bearingMode == 'circle') { | ||
// use great circle bearing | ||
bearing = this.getBearing(originLL, destLL); | ||
} else { | ||
// default is rhumb line bearing | ||
bearing = this.getRhumbLineBearing(originLL, destLL); | ||
} | ||
if(bearingMode == 'circle') { | ||
// use great circle bearing | ||
bearing = this.getBearing(originLL, destLL); | ||
} else { | ||
// default is rhumb line bearing | ||
bearing = this.getRhumbLineBearing(originLL, destLL); | ||
} | ||
switch(Math.round(bearing/22.5)) { | ||
case 1: | ||
direction = {exact: "NNE", rough: "N"}; | ||
break; | ||
case 2: | ||
direction = {exact: "NE", rough: "N"}; | ||
break; | ||
case 3: | ||
direction = {exact: "ENE", rough: "E"}; | ||
break; | ||
case 4: | ||
direction = {exact: "E", rough: "E"}; | ||
break; | ||
case 5: | ||
direction = {exact: "ESE", rough: "E"}; | ||
break; | ||
case 6: | ||
direction = {exact: "SE", rough: "E"}; | ||
break; | ||
case 7: | ||
direction = {exact: "SSE", rough: "S"}; | ||
break; | ||
case 8: | ||
direction = {exact: "S", rough: "S"}; | ||
break; | ||
case 9: | ||
direction = {exact: "SSW", rough: "S"}; | ||
break; | ||
case 10: | ||
direction = {exact: "SW", rough: "S"}; | ||
break; | ||
case 11: | ||
direction = {exact: "WSW", rough: "W"}; | ||
break; | ||
case 12: | ||
direction = {exact: "W", rough: "W"}; | ||
break; | ||
case 13: | ||
direction = {exact: "WNW", rough: "W"}; | ||
break; | ||
case 14: | ||
direction = {exact: "NW", rough: "W"}; | ||
break; | ||
case 15: | ||
direction = {exact: "NNW", rough: "N"}; | ||
break; | ||
default: | ||
direction = {exact: "N", rough: "N"}; | ||
} | ||
switch(Math.round(bearing/22.5)) { | ||
case 1: | ||
direction = {exact: "NNE", rough: "N"}; | ||
break; | ||
case 2: | ||
direction = {exact: "NE", rough: "N"}; | ||
break; | ||
case 3: | ||
direction = {exact: "ENE", rough: "E"}; | ||
break; | ||
case 4: | ||
direction = {exact: "E", rough: "E"}; | ||
break; | ||
case 5: | ||
direction = {exact: "ESE", rough: "E"}; | ||
break; | ||
case 6: | ||
direction = {exact: "SE", rough: "E"}; | ||
break; | ||
case 7: | ||
direction = {exact: "SSE", rough: "S"}; | ||
break; | ||
case 8: | ||
direction = {exact: "S", rough: "S"}; | ||
break; | ||
case 9: | ||
direction = {exact: "SSW", rough: "S"}; | ||
break; | ||
case 10: | ||
direction = {exact: "SW", rough: "S"}; | ||
break; | ||
case 11: | ||
direction = {exact: "WSW", rough: "W"}; | ||
break; | ||
case 12: | ||
direction = {exact: "W", rough: "W"}; | ||
break; | ||
case 13: | ||
direction = {exact: "WNW", rough: "W"}; | ||
break; | ||
case 14: | ||
direction = {exact: "NW", rough: "W"}; | ||
break; | ||
case 15: | ||
direction = {exact: "NNW", rough: "N"}; | ||
break; | ||
default: | ||
direction = {exact: "N", rough: "N"}; | ||
} | ||
direction['bearing'] = bearing; | ||
return direction; | ||
direction['bearing'] = bearing; | ||
return direction; | ||
}, | ||
}, | ||
/** | ||
* Shortcut for getCompassDirection | ||
*/ | ||
getDirection: function(originLL, destLL, bearingMode) { | ||
return this.getCompassDirection.apply(this, arguments); | ||
}, | ||
/** | ||
* Shortcut for getCompassDirection | ||
*/ | ||
getDirection: function(originLL, destLL, bearingMode) { | ||
return this.getCompassDirection.apply(this, arguments); | ||
}, | ||
/** | ||
* Sorts an array of coords by distance from a reference coordinate | ||
* | ||
* @param object reference coordinate e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return array ordered array | ||
*/ | ||
orderByDistance: function(latlng, coords) { | ||
/** | ||
* Sorts an array of coords by distance from a reference coordinate | ||
* | ||
* @param object reference coordinate e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return array ordered array | ||
*/ | ||
orderByDistance: function(latlng, coords) { | ||
var coordsArray = []; | ||
var coordsArray = []; | ||
for(var coord in coords) { | ||
for(var coord in coords) { | ||
var d = this.getDistance(latlng, coords[coord]); | ||
var d = this.getDistance(latlng, coords[coord]); | ||
coordsArray.push({ | ||
key: coord, | ||
latitude: this.latitude(coords[coord]), | ||
longitude: this.longitude(coords[coord]), | ||
distance: d | ||
}); | ||
coordsArray.push({ | ||
key: coord, | ||
latitude: this.latitude(coords[coord]), | ||
longitude: this.longitude(coords[coord]), | ||
distance: d | ||
}); | ||
} | ||
} | ||
return coordsArray.sort(function(a, b) { return a.distance - b.distance; }); | ||
return coordsArray.sort(function(a, b) { return a.distance - b.distance; }); | ||
}, | ||
}, | ||
/** | ||
* Finds the nearest coordinate to a reference coordinate | ||
* | ||
* @param object reference coordinate e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return array ordered array | ||
*/ | ||
findNearest: function(latlng, coords, offset, limit) { | ||
/** | ||
* Finds the nearest coordinate to a reference coordinate | ||
* | ||
* @param object reference coordinate e.g. {latitude: 51.5023, longitude: 7.3815} | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return array ordered array | ||
*/ | ||
findNearest: function(latlng, coords, offset, limit) { | ||
offset = offset || 0; | ||
limit = limit || 1; | ||
var ordered = this.orderByDistance(latlng, coords); | ||
offset = offset || 0; | ||
limit = limit || 1; | ||
var ordered = this.orderByDistance(latlng, coords); | ||
if(limit === 1) { | ||
return ordered[offset]; | ||
} else { | ||
return ordered.splice(offset, limit); | ||
} | ||
if(limit === 1) { | ||
return ordered[offset]; | ||
} else { | ||
return ordered.splice(offset, limit); | ||
} | ||
}, | ||
}, | ||
/** | ||
* Calculates the length of a given path | ||
* | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return integer length of the path (in meters) | ||
*/ | ||
getPathLength: function(coords) { | ||
/** | ||
* Calculates the length of a given path | ||
* | ||
* @param mixed array or object with coords [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...] | ||
* @return integer length of the path (in meters) | ||
*/ | ||
getPathLength: function(coords) { | ||
var dist = 0; | ||
var last; | ||
var dist = 0; | ||
var last; | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
if(last) { | ||
//console.log(coords[i], last, this.getDistance(coords[i], last)); | ||
dist += this.getDistance(this.coords(coords[i]), last); | ||
} | ||
last = this.coords(coords[i]); | ||
} | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
if(last) { | ||
//console.log(coords[i], last, this.getDistance(coords[i], last)); | ||
dist += this.getDistance(this.coords(coords[i]), last); | ||
} | ||
last = this.coords(coords[i]); | ||
} | ||
return dist; | ||
return dist; | ||
}, | ||
}, | ||
/** | ||
* Calculates the speed between to points within a given time span. | ||
* | ||
* @param object coords with javascript timestamp {latitude: 51.5143, longitude: 7.4138, time: 1360231200880} | ||
* @param object coords with javascript timestamp {latitude: 51.5502, longitude: 7.4323, time: 1360245600460} | ||
* @param object options (currently "unit" is the only option. Default: km(h)); | ||
* @return float speed in unit per hour | ||
*/ | ||
getSpeed: function(start, end, options) { | ||
/** | ||
* Calculates the speed between to points within a given time span. | ||
* | ||
* @param object coords with javascript timestamp {latitude: 51.5143, longitude: 7.4138, time: 1360231200880} | ||
* @param object coords with javascript timestamp {latitude: 51.5502, longitude: 7.4323, time: 1360245600460} | ||
* @param object options (currently "unit" is the only option. Default: km(h)); | ||
* @return float speed in unit per hour | ||
*/ | ||
getSpeed: function(start, end, options) { | ||
var unit = options && options.unit || 'km'; | ||
var unit = options && options.unit || 'km'; | ||
if(unit == 'mph') { | ||
unit = 'mi'; | ||
} else if(unit == 'kmh') { | ||
unit = 'km'; | ||
} | ||
if(unit == 'mph') { | ||
unit = 'mi'; | ||
} else if(unit == 'kmh') { | ||
unit = 'km'; | ||
} | ||
var distance = geolib.getDistance(start, end); | ||
var time = ((end.time*1)/1000) - ((start.time*1)/1000); | ||
var mPerHr = (distance/time)*3600; | ||
var speed = Math.round(mPerHr * this.measures[unit] * 10000)/10000; | ||
return speed; | ||
var distance = geolib.getDistance(start, end); | ||
var time = ((end.time*1)/1000) - ((start.time*1)/1000); | ||
var mPerHr = (distance/time)*3600; | ||
var speed = Math.round(mPerHr * this.measures[unit] * 10000)/10000; | ||
return speed; | ||
}, | ||
}, | ||
/** | ||
* Converts a distance from meters to km, mm, cm, mi, ft, in or yd | ||
* | ||
* @param string Format to be converted in | ||
* @param float Distance in meters | ||
* @param float Decimal places for rounding (default: 4) | ||
* @return float Converted distance | ||
*/ | ||
convertUnit: function(unit, distance, round) { | ||
/** | ||
* Converts a distance from meters to km, mm, cm, mi, ft, in or yd | ||
* | ||
* @param string Format to be converted in | ||
* @param float Distance in meters | ||
* @param float Decimal places for rounding (default: 4) | ||
* @return float Converted distance | ||
*/ | ||
convertUnit: function(unit, distance, round) { | ||
if(distance === 0 || typeof distance === 'undefined') { | ||
if(distance === 0) { | ||
if(this.distance === 0) { | ||
// throw 'No distance given.'; | ||
return 0; | ||
} else { | ||
distance = this.distance; | ||
} | ||
return 0; | ||
} | ||
} else if(typeof distance === 'undefined') { | ||
unit = unit || 'm'; | ||
round = (null == round ? 4 : round); | ||
if(this.distance === null) { | ||
throw new Error('No distance was given'); | ||
} else if(this.distance === 0) { | ||
return 0; | ||
} else { | ||
distance = this.distance; | ||
} | ||
if(typeof this.measures[unit] !== 'undefined') { | ||
return this.round(distance * this.measures[unit], round); | ||
} else { | ||
throw new Error('Unknown unit for conversion.'); | ||
} | ||
} | ||
}, | ||
unit = unit || 'm'; | ||
round = (null == round ? 4 : round); | ||
if(typeof this.measures[unit] !== 'undefined') { | ||
return this.round(distance * this.measures[unit], round); | ||
} else { | ||
throw new Error('Unknown unit for conversion.'); | ||
} | ||
/** | ||
* Checks if a value is in decimal format or, if neccessary, converts to decimal | ||
* | ||
* @param mixed Value(s) to be checked/converted (array of latlng objects, latlng object, sexagesimal string, float) | ||
* @return float Input data in decimal format | ||
*/ | ||
useDecimal: function(value) { | ||
}, | ||
if(Object.prototype.toString.call(value) === '[object Array]') { | ||
var geolib = this; | ||
/** | ||
* Checks if a value is in decimal format or, if neccessary, converts to decimal | ||
* | ||
* @param mixed Value(s) to be checked/converted (array of latlng objects, latlng object, sexagesimal string, float) | ||
* @return float Input data in decimal format | ||
*/ | ||
useDecimal: function(value) { | ||
value = value.map(function(val) { | ||
if(Object.prototype.toString.call(value) === '[object Array]') { | ||
//if(!isNaN(parseFloat(val))) { | ||
if(geolib.isDecimal(val)) { | ||
var geolib = this; | ||
return geolib.useDecimal(val); | ||
value = value.map(function(val) { | ||
} else if(typeof val == 'object') { | ||
//if(!isNaN(parseFloat(val))) { | ||
if(geolib.isDecimal(val)) { | ||
if(geolib.validate(val)) { | ||
return geolib.useDecimal(val); | ||
return geolib.coords(val); | ||
} else if(typeof val == 'object') { | ||
} else { | ||
if(geolib.validate(val)) { | ||
for(var prop in val) { | ||
val[prop] = geolib.useDecimal(val[prop]); | ||
} | ||
return geolib.coords(val); | ||
return val; | ||
} else { | ||
} | ||
for(var prop in val) { | ||
val[prop] = geolib.useDecimal(val[prop]); | ||
} | ||
} else if(geolib.isSexagesimal(val)) { | ||
return val; | ||
return geolib.sexagesimal2decimal(val); | ||
} | ||
} else { | ||
} else if(geolib.isSexagesimal(val)) { | ||
return val; | ||
return geolib.sexagesimal2decimal(val); | ||
} | ||
} else { | ||
}); | ||
return val; | ||
return value; | ||
} | ||
} else if(typeof value === 'object' && this.validate(value)) { | ||
}); | ||
return this.coords(value); | ||
return value; | ||
} else if(typeof value === 'object') { | ||
} else if(typeof value === 'object' && this.validate(value)) { | ||
for(var prop in value) { | ||
value[prop] = this.useDecimal(value[prop]); | ||
} | ||
return this.coords(value); | ||
return value; | ||
} else if(typeof value === 'object') { | ||
} | ||
for(var prop in value) { | ||
value[prop] = this.useDecimal(value[prop]); | ||
} | ||
return value; | ||
if (this.isDecimal(value)) { | ||
} | ||
return parseFloat(value); | ||
} else if(this.isSexagesimal(value) === true) { | ||
if (this.isDecimal(value)) { | ||
return parseFloat(this.sexagesimal2decimal(value)); | ||
return parseFloat(value); | ||
} | ||
} else if(this.isSexagesimal(value) === true) { | ||
throw new Error('Unknown format.'); | ||
return parseFloat(this.sexagesimal2decimal(value)); | ||
}, | ||
} | ||
/** | ||
* Converts a decimal coordinate value to sexagesimal format | ||
* | ||
* @param float decimal | ||
* @return string Sexagesimal value (XX° YY' ZZ") | ||
*/ | ||
decimal2sexagesimal: function(dec) { | ||
throw new Error('Unknown format.'); | ||
if (dec in this.sexagesimal) { | ||
return this.sexagesimal[dec]; | ||
} | ||
}, | ||
var tmp = dec.toString().split('.'); | ||
/** | ||
* Converts a decimal coordinate value to sexagesimal format | ||
* | ||
* @param float decimal | ||
* @return string Sexagesimal value (XX° YY' ZZ") | ||
*/ | ||
decimal2sexagesimal: function(dec) { | ||
var deg = Math.abs(tmp[0]); | ||
var min = ('0.' + tmp[1])*60; | ||
var sec = min.toString().split('.'); | ||
if (dec in this.sexagesimal) { | ||
return this.sexagesimal[dec]; | ||
} | ||
min = Math.floor(min); | ||
sec = (('0.' + sec[1]) * 60).toFixed(2); | ||
var tmp = dec.toString().split('.'); | ||
this.sexagesimal[dec] = (deg + '° ' + min + "' " + sec + '"'); | ||
var deg = Math.abs(tmp[0]); | ||
var min = ('0.' + tmp[1])*60; | ||
var sec = min.toString().split('.'); | ||
return this.sexagesimal[dec]; | ||
min = Math.floor(min); | ||
sec = (('0.' + sec[1]) * 60).toFixed(2); | ||
}, | ||
this.sexagesimal[dec] = (deg + '° ' + min + "' " + sec + '"'); | ||
return this.sexagesimal[dec]; | ||
/** | ||
* Converts a sexagesimal coordinate to decimal format | ||
* | ||
* @param float Sexagesimal coordinate | ||
* @return string Decimal value (XX.XXXXXXXX) | ||
*/ | ||
sexagesimal2decimal: function(sexagesimal) { | ||
}, | ||
if (sexagesimal in this.decimal) { | ||
return this.decimal[sexagesimal]; | ||
} | ||
var regEx = new RegExp(this.sexagesimalPattern); | ||
var data = regEx.exec(sexagesimal); | ||
var min = 0, sec = 0; | ||
/** | ||
* Converts a sexagesimal coordinate to decimal format | ||
* | ||
* @param float Sexagesimal coordinate | ||
* @return string Decimal value (XX.XXXXXXXX) | ||
*/ | ||
sexagesimal2decimal: function(sexagesimal) { | ||
if(data) { | ||
min = parseFloat(data[2]/60); | ||
sec = parseFloat(data[4]/3600) || 0; | ||
} | ||
if (sexagesimal in this.decimal) { | ||
return this.decimal[sexagesimal]; | ||
} | ||
var dec = ((parseFloat(data[1]) + min + sec)).toFixed(8); | ||
//var dec = ((parseFloat(data[1]) + min + sec)); | ||
var regEx = new RegExp(this.sexagesimalPattern); | ||
var data = regEx.exec(sexagesimal); | ||
var min = 0, sec = 0; | ||
// South and West are negative decimals | ||
dec = (data[7] == 'S' || data[7] == 'W') ? parseFloat(-dec) : parseFloat(dec); | ||
//dec = (data[7] == 'S' || data[7] == 'W') ? -dec : dec; | ||
if(data) { | ||
min = parseFloat(data[2]/60); | ||
sec = parseFloat(data[4]/3600) || 0; | ||
} | ||
this.decimal[sexagesimal] = dec; | ||
var dec = ((parseFloat(data[1]) + min + sec)).toFixed(8); | ||
//var dec = ((parseFloat(data[1]) + min + sec)); | ||
return dec; | ||
// South and West are negative decimals | ||
dec = (data[7] == 'S' || data[7] == 'W') ? parseFloat(-dec) : parseFloat(dec); | ||
//dec = (data[7] == 'S' || data[7] == 'W') ? -dec : dec; | ||
}, | ||
this.decimal[sexagesimal] = dec; | ||
return dec; | ||
/** | ||
* Checks if a value is in decimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
isDecimal: function(value) { | ||
}, | ||
value = value.toString().replace(/\s*/, ''); | ||
// looks silly but works as expected | ||
// checks if value is in decimal format | ||
return (!isNaN(parseFloat(value)) && parseFloat(value) == value); | ||
/** | ||
* Checks if a value is in decimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
isDecimal: function(value) { | ||
}, | ||
value = value.toString().replace(/\s*/, ''); | ||
// looks silly but works as expected | ||
// checks if value is in decimal format | ||
return (!isNaN(parseFloat(value)) && parseFloat(value) == value); | ||
/** | ||
* Checks if a value is in sexagesimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
isSexagesimal: function(value) { | ||
}, | ||
value = value.toString().replace(/\s*/, ''); | ||
return this.sexagesimalPattern.test(value); | ||
/** | ||
* Checks if a value is in sexagesimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
isSexagesimal: function(value) { | ||
}, | ||
value = value.toString().replace(/\s*/, ''); | ||
round: function(value, n) { | ||
var decPlace = Math.pow(10, n); | ||
return Math.round(value * decPlace)/decPlace; | ||
} | ||
return this.sexagesimalPattern.test(value); | ||
}); | ||
}, | ||
// Node module | ||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { | ||
round: function(value, n) { | ||
var decPlace = Math.pow(10, n); | ||
return Math.round(value * decPlace)/decPlace; | ||
} | ||
global.geolib = module.exports = geolib; | ||
}); | ||
// AMD module | ||
} else if (typeof define === "function" && define.amd) { | ||
// Node module | ||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { | ||
define("geolib", [], function () { | ||
return geolib; | ||
}); | ||
global.geolib = module.exports = geolib; | ||
// we're in a browser | ||
} else { | ||
// AMD module | ||
} else if (typeof define === "function" && define.amd) { | ||
global.geolib = geolib; | ||
define("geolib", [], function () { | ||
return geolib; | ||
}); | ||
} | ||
// we're in a browser | ||
} else { | ||
global.geolib = geolib; | ||
} | ||
}(this)); |
@@ -50,4 +50,4 @@ { | ||
}, | ||
"version": "2.0.16", | ||
"version": "2.0.17", | ||
"main": "dist/geolib.js" | ||
} |
@@ -1,2 +0,2 @@ | ||
# Geolib v2.0.16 | ||
# Geolib v2.0.17 | ||
[![Build Status](https://secure.travis-ci.org/manuelbieh/Geolib.png?branch=master)](http://travis-ci.org/manuelbieh/Geolib) | ||
@@ -3,0 +3,0 @@ |
56687
1083