Comparing version 1.1.7 to 1.1.8
671
geolib.js
/** | ||
* A small library to provide some basic geo functions like distance calculation, | ||
* conversion of decimal coordinates to sexagesimal and vice versa, etc. | ||
* WGS 84 (World Geodetic System 1984) | ||
* | ||
* @author Manuel Bieh | ||
* @url http://www.manuelbieh.com/ | ||
* @version 1.1.7 | ||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPL | ||
* | ||
*/ | ||
* A small library to provide some basic geo functions like distance calculation, | ||
* conversion of decimal coordinates to sexagesimal and vice versa, etc. | ||
* WGS 84 (World Geodetic System 1984) | ||
* | ||
* @author Manuel Bieh | ||
* @url http://www.manuelbieh.com/ | ||
* @version 1.1.8 | ||
* @license LGPL | ||
**/ | ||
@@ -27,29 +26,62 @@ (function (window, undefined) { | ||
/** | ||
* 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) | ||
*/ | ||
* Get the key names for a geo point. | ||
* | ||
* @param object Point position {latitude: 123, longitude: 123, elevation: 123} | ||
* @return object { | ||
* longitude: 'lng|long|longitude', | ||
* latitude: 'lat|latitude', | ||
* elevation: 'alt|altitude|elev|elevation' | ||
* } | ||
*/ | ||
getKeys: function(point) { | ||
var latitude = point.hasOwnProperty('lat') ? 'lat' : 'latitude'; | ||
var longitude = (point.hasOwnProperty('lng') ? 'lng' : false) || | ||
(point.hasOwnProperty('long') ? 'long' : false) || | ||
'longitude'; | ||
var elevation = (point.hasOwnProperty('alt') ? 'alt' : false) || | ||
(point.hasOwnProperty('altitude') ? 'altitude' : false) || | ||
(point.hasOwnProperty('elev') ? 'elev' : false) || | ||
'elevation'; | ||
return { | ||
latitude: latitude, | ||
longitude: longitude, | ||
elevation: elevation | ||
}; | ||
}, | ||
/** | ||
* 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 = parseInt(accuracy, 10) || 1; | ||
var keys = geolib.getKeys(start); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
var elevation = keys.elevation; | ||
accuracy = Math.floor(accuracy) || 1; | ||
var coord1 = {}, coord2 = {}; | ||
coord1.latitude = geolib.useDecimal(start.latitude); | ||
coord1.longitude = geolib.useDecimal(start.longitude); | ||
coord1[latitude] = geolib.useDecimal(start[latitude]); | ||
coord1[longitude] = geolib.useDecimal(start[longitude]); | ||
coord2.latitude = geolib.useDecimal(end.latitude); | ||
coord2.longitude = geolib.useDecimal(end.longitude); | ||
coord2[latitude] = geolib.useDecimal(end[latitude]); | ||
coord2[longitude] = geolib.useDecimal(end[longitude]); | ||
var a = 6378137, b = 6356752.314245, f = 1/298.257223563; // WGS-84 ellipsoid params | ||
var L = (coord2.longitude-coord1.longitude).toRad(); | ||
var L = (coord2[longitude]-coord1[longitude]).toRad(); | ||
var U1 = Math.atan((1-f) * Math.tan(parseFloat(coord1.latitude).toRad())); | ||
var U2 = Math.atan((1-f) * Math.tan(parseFloat(coord2.latitude).toRad())); | ||
var cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, sinSigma; | ||
var U1 = Math.atan((1-f) * Math.tan(parseFloat(coord1[latitude]).toRad())); | ||
var U2 = Math.atan((1-f) * Math.tan(parseFloat(coord2[latitude]).toRad())); | ||
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); | ||
@@ -61,3 +93,3 @@ var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); | ||
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); | ||
var sinSigma = ( | ||
sinSigma = ( | ||
Math.sqrt( | ||
@@ -75,10 +107,12 @@ ( | ||
); | ||
if (sinSigma==0) { | ||
if (sinSigma === 0) { | ||
return geolib.distance = 0; // co-incident points | ||
} | ||
var cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; | ||
var sigma = Math.atan2(sinSigma, cosSigma); | ||
var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; | ||
var cosSqAlpha = 1 - sinAlpha * sinAlpha; | ||
var 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)) { | ||
@@ -109,4 +143,4 @@ cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) | ||
if (iterLimit==0) { | ||
return NaN // formula failed to converge | ||
if (iterLimit === 0) { | ||
return NaN; // formula failed to converge | ||
} | ||
@@ -159,4 +193,10 @@ | ||
distance = distance.toFixed(3); // round to 1mm precision | ||
return geolib.distance = parseInt(Math.round(distance/accuracy)*accuracy, 10) | ||
if (start.hasOwnProperty(elevation) && end.hasOwnProperty(elevation)) { | ||
var climb = Math.abs(start[elevation] - end[elevation]); | ||
distance = Math.sqrt(distance*distance + climb*climb); | ||
} | ||
return geolib.distance = Math.floor(Math.round(distance/accuracy)*accuracy); | ||
/* | ||
@@ -174,20 +214,24 @@ // note: to return initial/final bearings in addition to distance, use something like: | ||
/** | ||
* Calculates the distance between two spots. | ||
* This method is more simple but also 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) | ||
*/ | ||
* Calculates the distance between two spots. | ||
* This method is more simple but also 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 = parseInt(accuracy, 10) || 1; | ||
var keys = geolib.getKeys(start); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
accuracy = Math.floor(accuracy) || 1; | ||
var coord1 = {}, coord2 = {}; | ||
coord1.latitude = parseFloat(geolib.useDecimal(start.latitude)).toRad(); | ||
coord1.longitude = parseFloat(geolib.useDecimal(start.longitude)).toRad(); | ||
coord1[latitude] = parseFloat(geolib.useDecimal(start[latitude])).toRad(); | ||
coord1[longitude] = parseFloat(geolib.useDecimal(start[longitude])).toRad(); | ||
coord2.latitude = parseFloat(geolib.useDecimal(end.latitude)).toRad(); | ||
coord2.longitude = parseFloat(geolib.useDecimal(end.longitude)).toRad(); | ||
coord2[latitude] = parseFloat(geolib.useDecimal(end[latitude])).toRad(); | ||
coord2[longitude] = parseFloat(geolib.useDecimal(end[longitude])).toRad(); | ||
@@ -198,15 +242,15 @@ var distance = | ||
Math.sin( | ||
coord2.latitude | ||
coord2[latitude] | ||
) * | ||
Math.sin( | ||
coord1.latitude | ||
coord1[latitude] | ||
) + | ||
Math.cos( | ||
coord2.latitude | ||
coord2[latitude] | ||
) * | ||
Math.cos( | ||
coord1.latitude | ||
coord1[latitude] | ||
) * | ||
Math.cos( | ||
coord1.longitude - coord2.longitude | ||
coord1[longitude] - coord2[longitude] | ||
) | ||
@@ -216,3 +260,3 @@ ) * radius | ||
return geolib.distance = parseInt(Math.round(distance/accuracy)*accuracy, 10); | ||
return geolib.distance = Math.floor(Math.round(distance/accuracy)*accuracy); | ||
@@ -223,9 +267,17 @@ }, | ||
/** | ||
* 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, distance: diagonalDistance} | ||
*/ | ||
* 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, distance: diagonalDistance} | ||
*/ | ||
getCenter: function(coords) { | ||
if (!coords.length) { | ||
return false; | ||
} | ||
var keys = geolib.getKeys(coords[0]); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
var max = function( array ){ | ||
@@ -242,4 +294,4 @@ return Math.max.apply( Math, array ); | ||
for(var coord in coords) { | ||
splitCoords.lat.push(geolib.useDecimal(coords[coord].latitude)); | ||
splitCoords.lng.push(geolib.useDecimal(coords[coord].longitude)); | ||
splitCoords.lat.push(geolib.useDecimal(coords[coord][latitude])); | ||
splitCoords.lng.push(geolib.useDecimal(coords[coord][longitude])); | ||
} | ||
@@ -256,3 +308,3 @@ | ||
// distance from the deepest left to the highest right point (diagonal distance) | ||
var distance = geolib.convertUnit('km', geolib.getDistance(minLat, minLng, maxLat, maxLng)); | ||
var distance = geolib.convertUnit('km', geolib.getDistance({lat:minLat, lng:minLng}, {lat:maxLat, lng:maxLng})); | ||
@@ -263,23 +315,78 @@ return {"latitude": lat, "longitude": lng, "distance": distance}; | ||
/** | ||
* 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 (!coords.length) { | ||
return false; | ||
} | ||
var keys = geolib.getKeys(coords[0]); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
var elevation = keys.elevation; | ||
var useElevation = coords[0].hasOwnProperty(elevation); | ||
var stats = { | ||
maxLat: 0, | ||
minLat: Infinity, | ||
maxLng: 0, | ||
minLng: Infinity | ||
}; | ||
if (useElevation) { | ||
stats.maxElev = 0; | ||
stats.minElev = Infinity; | ||
} | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
stats.maxLat = Math.max(coords[i][latitude], stats.maxLat); | ||
stats.minLat = Math.min(coords[i][latitude], stats.minLat); | ||
stats.maxLng = Math.max(coords[i][longitude], stats.maxLng); | ||
stats.minLng = Math.min(coords[i][longitude], stats.minLng); | ||
if (useElevation) { | ||
stats.maxElev = Math.max(coords[i][elevation], stats.maxElev); | ||
stats.minElev = Math.min(coords[i][elevation], stats.minElev); | ||
} | ||
} | ||
return stats; | ||
}, | ||
/** | ||
* 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 | ||
*/ | ||
* 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) { | ||
var keys = geolib.getKeys(latlng); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
for(var c = false, i = -1, l = coords.length, j = l - 1; ++i < l; j = i) { | ||
( | ||
(coords[i].longitude <= latlng.longitude && latlng.longitude < coords[j].longitude) || | ||
(coords[j].longitude <= latlng.longitude && latlng.longitude < coords[i].longitude) | ||
) | ||
&& (latlng.latitude < (coords[j].latitude - coords[i].latitude) | ||
* (latlng.longitude - coords[i].longitude) | ||
/ (coords[j].longitude - coords[i].longitude) + coords[i].latitude) | ||
&& (c = !c); | ||
if( | ||
( | ||
(coords[i][longitude] <= latlng[longitude] && latlng[longitude] < coords[j][longitude]) || | ||
(coords[j][longitude] <= latlng[longitude] && latlng[longitude] < coords[i][longitude]) | ||
) && | ||
( | ||
latlng[latitude] < (coords[j][latitude] - coords[i][latitude]) * | ||
(latlng[longitude] - coords[i][longitude]) / | ||
(coords[j][longitude] - coords[i][longitude]) + | ||
coords[i][latitude] | ||
) | ||
) { | ||
c = !c; | ||
} | ||
@@ -294,9 +401,9 @@ } | ||
/** | ||
* 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 inside the given 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 inside the given radius | ||
*/ | ||
isPointInCircle: function(latlng, center, radius) { | ||
@@ -310,21 +417,25 @@ | ||
/** | ||
* 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 | ||
*/ | ||
* 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) { | ||
var keys = geolib.getKeys(originLL); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
// difference of longitude coords | ||
var diffLon = geolib.useDecimal(destLL.longitude).toRad() - geolib.useDecimal(originLL.longitude).toRad(); | ||
var diffLon = geolib.useDecimal(destLL[longitude]).toRad() - geolib.useDecimal(originLL[longitude]).toRad(); | ||
// difference latitude coords phi | ||
var diffPhi = Math.log(Math.tan(geolib.useDecimal(destLL.latitude).toRad() / 2 + Math.PI / 4) / Math.tan(geolib.useDecimal(originLL.latitude).toRad() / 2 + Math.PI / 4)); | ||
var diffPhi = Math.log(Math.tan(geolib.useDecimal(destLL[latitude]).toRad() / 2 + Math.PI / 4) / Math.tan(geolib.useDecimal(originLL[latitude]).toRad() / 2 + Math.PI / 4)); | ||
@@ -348,15 +459,19 @@ // recalculate diffLon if it is greater than pi | ||
/** | ||
* 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 | ||
*/ | ||
* 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 = geolib.useDecimal(destLL.latitude); | ||
destLL.longitude = geolib.useDecimal(destLL.longitude); | ||
originLL.latitude = geolib.useDecimal(originLL.latitude); | ||
originLL.longitude = geolib.useDecimal(originLL.longitude); | ||
var keys = geolib.getKeys(originLL); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
destLL[latitude] = geolib.useDecimal(destLL[latitude]); | ||
destLL[longitude] = geolib.useDecimal(destLL[longitude]); | ||
originLL[latitude] = geolib.useDecimal(originLL[latitude]); | ||
originLL[longitude] = geolib.useDecimal(originLL[longitude]); | ||
var bearing = ( | ||
@@ -366,22 +481,22 @@ ( | ||
Math.sin( | ||
destLL.longitude.toRad() - | ||
originLL.longitude.toRad() | ||
destLL[longitude].toRad() - | ||
originLL[longitude].toRad() | ||
) * | ||
Math.cos( | ||
destLL.latitude.toRad() | ||
destLL[latitude].toRad() | ||
), | ||
Math.cos( | ||
originLL.latitude.toRad() | ||
originLL[latitude].toRad() | ||
) * | ||
Math.sin( | ||
destLL.latitude.toRad() | ||
destLL[latitude].toRad() | ||
) - | ||
Math.sin( | ||
originLL.latitude.toRad() | ||
originLL[latitude].toRad() | ||
) * | ||
Math.cos( | ||
destLL.latitude.toRad() | ||
destLL[latitude].toRad() | ||
) * | ||
Math.cos( | ||
destLL.longitude.toRad() - originLL.longitude.toRad() | ||
destLL[longitude].toRad() - originLL[longitude].toRad() | ||
) | ||
@@ -398,16 +513,16 @@ ) | ||
/** | ||
* 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). | ||
*/ | ||
* 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 direction, bearing; | ||
if(bearingMode == 'circle') { // use great circle bearing | ||
var bearing = geolib.getBearing(originLL, destLL); | ||
bearing = geolib.getBearing(originLL, destLL); | ||
} else { // default is rhumb line bearing | ||
var bearing = geolib.getRhumbLineBearing(originLL, destLL); | ||
bearing = geolib.getRhumbLineBearing(originLL, destLL); | ||
} | ||
@@ -420,45 +535,45 @@ | ||
case 2: | ||
direction = {exact: "NE", rough: "N"} | ||
direction = {exact: "NE", rough: "N"}; | ||
break; | ||
case 3: | ||
direction = {exact: "ENE", rough: "E"} | ||
direction = {exact: "ENE", rough: "E"}; | ||
break; | ||
case 4: | ||
direction = {exact: "E", rough: "E"} | ||
direction = {exact: "E", rough: "E"}; | ||
break; | ||
case 5: | ||
direction = {exact: "ESE", rough: "E"} | ||
direction = {exact: "ESE", rough: "E"}; | ||
break; | ||
case 6: | ||
direction = {exact: "SE", rough: "E"} | ||
direction = {exact: "SE", rough: "E"}; | ||
break; | ||
case 7: | ||
direction = {exact: "SSE", rough: "S"} | ||
direction = {exact: "SSE", rough: "S"}; | ||
break; | ||
case 8: | ||
direction = {exact: "S", rough: "S"} | ||
direction = {exact: "S", rough: "S"}; | ||
break; | ||
case 9: | ||
direction = {exact: "SSW", rough: "S"} | ||
direction = {exact: "SSW", rough: "S"}; | ||
break; | ||
case 10: | ||
direction = {exact: "SW", rough: "S"} | ||
direction = {exact: "SW", rough: "S"}; | ||
break; | ||
case 11: | ||
direction = {exact: "WSW", rough: "W"} | ||
direction = {exact: "WSW", rough: "W"}; | ||
break; | ||
case 12: | ||
direction = {exact: "W", rough: "W"} | ||
direction = {exact: "W", rough: "W"}; | ||
break; | ||
case 13: | ||
direction = {exact: "WNW", rough: "W"} | ||
direction = {exact: "WNW", rough: "W"}; | ||
break; | ||
case 14: | ||
direction = {exact: "NW", rough: "W"} | ||
direction = {exact: "NW", rough: "W"}; | ||
break; | ||
case 15: | ||
direction = {exact: "NNW", rough: "N"} | ||
direction = {exact: "NNW", rough: "N"}; | ||
break; | ||
default: | ||
direction = {exact: "N", rough: "N"} | ||
direction = {exact: "N", rough: "N"}; | ||
} | ||
@@ -472,14 +587,18 @@ | ||
/** | ||
* 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 | ||
*/ | ||
* 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 keys = geolib.getKeys(latlng); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
var coordsArray = []; | ||
for(var coord in coords) { | ||
var d = geolib.getDistance(latlng, coords[coord]); | ||
coordsArray.push({key: coord, latitude: coords[coord].latitude, longitude: coords[coord].longitude, distance: d}); | ||
coordsArray.push({key: coord, latitude: coords[coord][latitude], longitude: coords[coord][longitude], distance: d}); | ||
} | ||
@@ -493,8 +612,8 @@ | ||
/** | ||
* 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 | ||
*/ | ||
* 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) { | ||
@@ -510,33 +629,165 @@ | ||
/** | ||
* 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) | ||
*/ | ||
* 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 l = 0, last; | ||
for(var coord in coords) { | ||
var dist = 0, last; | ||
for (var i = 0, l = coords.length; i < l; ++i) { | ||
if(last) { | ||
l += geolib.getDistance(coords[coord], last); | ||
dist += geolib.getDistance(coords[i], last); | ||
} | ||
last = coords[coord]; | ||
last = coords[i]; | ||
} | ||
return l; | ||
return dist; | ||
}, | ||
/*global google:true require:true module:true elevationResult*/ | ||
/** | ||
* Converts a distance from meters to km, mm, cm, mi, ft, in or yd | ||
* | ||
* @param string Format to be converted in | ||
* @param float Distance | ||
* @return float Converted distance | ||
*/ | ||
* @param Array Collection of coords [{latitude: 51.510, longitude: 7.1321}, {latitude: 49.1238, longitude: "8° 30' W"}, ...] | ||
* | ||
* @return Array [{lat:#lat, lng:#lng, elev:#elev},....]} | ||
*/ | ||
getElevation: function() { | ||
if (typeof window.navigator !== 'undefined') { | ||
geolib.getElevationClient.apply(this, arguments); | ||
} else { | ||
geolib.getElevationServer.apply(this, arguments); | ||
} | ||
}, | ||
getElevationClient: function(coords, cb) { | ||
if (!window.google) { | ||
throw new Error("Google maps api not loaded"); | ||
} | ||
if (coords.length === 0) { | ||
return cb(null, null); | ||
} | ||
if (coords.length === 1) { | ||
return cb(new Error("getElevation requires at least 2 points.")); | ||
} | ||
var path = []; | ||
var keys = geolib.getKeys(coords[0]); | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
for(var i = 0; i < coords.length; i++) { | ||
path.push(new google.maps.LatLng( | ||
geolib.useDecimal(coords[i][latitude]), | ||
geolib.useDecimal(coords[i][longitude]) | ||
)); | ||
} | ||
var positionalRequest = { | ||
'path': path, | ||
'samples': path.length | ||
}; | ||
var elevationService = new google.maps.ElevationService(); | ||
elevationService.getElevationAlongPath(positionalRequest,function (results, status){ | ||
geolib.elevationHandler(results, status, coords, keys, cb); | ||
}); | ||
}, | ||
getElevationServer: function(coords, cb) { | ||
if (coords.length === 0) { | ||
return cb(null, null); | ||
} | ||
if (coords.length === 1) { | ||
return cb(new Error("getElevation requires at least 2 points.")); | ||
} | ||
var gm = require('googlemaps'); | ||
var path = []; | ||
var keys = geolib.getKeys(coords[0]); | ||
//coords[0] | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
for(var i = 0; i < coords.length; i++) { | ||
path.push(geolib.useDecimal(coords[i][latitude]) + ',' + | ||
geolib.useDecimal(coords[i][longitude])); | ||
} | ||
gm.elevationFromPath(path.join('|'), path.length, function(err, results) { | ||
geolib.elevationHandler(results.results, results.status, coords, keys, cb); | ||
}); | ||
}, | ||
elevationHandler: function(results, status, coords, keys, cb){ | ||
var latsLngsElevs = []; | ||
var latitude = keys.latitude; | ||
var longitude = keys.longitude; | ||
if (status == "OK" ) { | ||
for (var i = 0; i < results.length; i++) { | ||
latsLngsElevs.push({ | ||
"lat":coords[i][latitude], | ||
"lng":coords[i][longitude], | ||
"elev":results[i].elevation | ||
}); | ||
} | ||
cb(null, latsLngsElevs); | ||
} else { | ||
cb(new Error("Could not get elevation using Google's API"), elevationResult.status); | ||
} | ||
}, | ||
/** | ||
* @param Array [{lat:#lat, lng:#lng, elev:#elev},....]} | ||
* | ||
* @return Number % grade | ||
*/ | ||
getGrade: function(coords){ | ||
var keys = geolib.getKeys(coords[0]); | ||
var elevation = keys.elevation; | ||
var rise = Math.abs(coords[coords.length-1][elevation] - coords[0][elevation]); | ||
var run = geolib.getPathLength(coords); | ||
return Math.floor((rise/run)*100); | ||
}, | ||
/** | ||
* @param Array [{lat:#lat, lng:#lng, elev:#elev},....]} | ||
* | ||
* @return Object {gain:#gain, loss:#loss} | ||
*/ | ||
getTotalElevationGainAndLoss: function(coords){ | ||
var keys = geolib.getKeys(coords[0]); | ||
var elevation = keys.elevation; | ||
var gain = 0; | ||
var loss = 0; | ||
for(var i = 0; i < coords.length - 1; i++){ | ||
var deltaElev = coords[i][elevation] - coords[i + 1][elevation]; | ||
if (deltaElev > 0) { | ||
loss += deltaElev; | ||
} else { | ||
gain += Math.abs(deltaElev); | ||
} | ||
} | ||
return { | ||
"gain": gain, | ||
"loss": loss | ||
}; | ||
}, | ||
/** | ||
* 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 || typeof distance == 'undefined') { | ||
if(geolib.distance == 0) { | ||
if(geolib.distance === 0) { | ||
// throw 'No distance given.'; | ||
@@ -551,3 +802,3 @@ return 0; | ||
unit = unit || 'm'; | ||
round = round || 4; | ||
round = (null == round ? 4 : round); | ||
@@ -558,27 +809,18 @@ switch(unit) { | ||
return geolib.round(distance, round); | ||
break; | ||
case 'km': // Kilometer | ||
return geolib.round(distance / 1000, round); | ||
break; | ||
case 'cm': // Centimeter | ||
return geolib.round(distance * 100, round); | ||
break; | ||
case 'mm': // Millimeter | ||
return geolib.round(distance * 1000, round); | ||
break; | ||
case 'mi': // Miles | ||
return geolib.round(distance * (1 / 1609.344), round); | ||
break; | ||
case 'sm': // Seamiles | ||
return geolib.round(distance * (1 / 1852.216), round); | ||
break; | ||
case 'ft': // Feet | ||
return geolib.round(distance * (100 / 30.48), round); | ||
break; | ||
case 'in': // Inch | ||
return geolib.round(distance * 100 / 2.54, round); | ||
break; | ||
case 'yd': // Yards | ||
return geolib.round(distance * (1 / 0.9144), round); | ||
break; | ||
} | ||
@@ -592,7 +834,7 @@ | ||
/** | ||
* Checks if a value is in decimal format or, if neccessary, converts to decimal | ||
* | ||
* @param mixed Value to be checked/converted | ||
* @return float Coordinate in decimal format | ||
*/ | ||
* Checks if a value is in decimal format or, if neccessary, converts to decimal | ||
* | ||
* @param mixed Value to be checked/converted | ||
* @return float Coordinate in decimal format | ||
*/ | ||
useDecimal: function(value) { | ||
@@ -607,3 +849,3 @@ | ||
// checks if it's sexagesimal format (HHH° MM' SS" (NESW)) | ||
} else if(geolib.isSexagesimal(value) == true) { | ||
} else if(geolib.isSexagesimal(value) === true) { | ||
return parseFloat(geolib.sexagesimal2decimal(value)); | ||
@@ -618,7 +860,7 @@ } else { | ||
/** | ||
* Converts a decimal coordinate value to sexagesimal format | ||
* | ||
* @param float decimal | ||
* @return string Sexagesimal value (XX° YY' ZZ") | ||
*/ | ||
* Converts a decimal coordinate value to sexagesimal format | ||
* | ||
* @param float decimal | ||
* @return string Sexagesimal value (XX° YY' ZZ") | ||
*/ | ||
decimal2sexagesimal: function(dec) { | ||
@@ -632,7 +874,7 @@ | ||
var deg = tmp[0]; | ||
var deg = Math.abs(tmp[0]); | ||
var min = ('0.' + tmp[1])*60; | ||
var sec = min.toString().split('.'); | ||
min = parseInt(min, 10); | ||
min = Math.floor(min); | ||
sec = (('0.' + sec[1]) * 60).toFixed(2); | ||
@@ -648,7 +890,7 @@ | ||
/** | ||
* Converts a sexagesimal coordinate to decimal format | ||
* | ||
* @param float Sexagesimal coordinate | ||
* @return string Decimal value (XX.XXXXXXXX) | ||
*/ | ||
* Converts a sexagesimal coordinate to decimal format | ||
* | ||
* @param float Sexagesimal coordinate | ||
* @return string Decimal value (XX.XXXXXXXX) | ||
*/ | ||
sexagesimal2decimal: function(sexagesimal) { | ||
@@ -662,6 +904,7 @@ | ||
var data = regEx.exec(sexagesimal); | ||
var min = 0, sec = 0; | ||
if(data) { | ||
var min = parseFloat(data[2]/60); | ||
var sec = parseFloat(data[4]/3600) || 0; | ||
min = parseFloat(data[2]/60); | ||
sec = parseFloat(data[4]/3600) || 0; | ||
} | ||
@@ -681,7 +924,7 @@ | ||
/** | ||
* Checks if a value is in sexagesimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
* Checks if a value is in sexagesimal format | ||
* | ||
* @param string Value to be checked | ||
* @return bool True if in sexagesimal format | ||
*/ | ||
isSexagesimal: function(value) { | ||
@@ -698,3 +941,3 @@ | ||
} | ||
}; | ||
@@ -704,3 +947,3 @@ if (typeof(Number.prototype.toRad) === "undefined") { | ||
return this * Math.PI / 180; | ||
} | ||
}; | ||
} | ||
@@ -711,3 +954,3 @@ | ||
return this * 180 / Math.PI; | ||
} | ||
}; | ||
} | ||
@@ -724,2 +967,2 @@ | ||
})(this); | ||
}(this)); |
@@ -5,17 +5,35 @@ { | ||
"author": { | ||
"name": "Manuel Bieh", | ||
"url": "http://www.manuelbieh.com/" | ||
"name": "Manuel Bieh", | ||
"url": "http://www.manuelbieh.com/" | ||
}, | ||
"bin": { | ||
"geolib" : "./geolib.js" | ||
"geolib": "./geolib.js" | ||
}, | ||
"repository": { | ||
"type" : "git", | ||
"url" : "http://github.com/manuelbieh/geolib.git" | ||
}, | ||
"files": ["geolib.js"], | ||
"description": "Growing library to perform geo specific tasks", | ||
"keywords": ["geolocation", "geo", "distance"], | ||
"version": "1.1.7", | ||
"type": "git", | ||
"url": "http://github.com/manuelbieh/geolib.git" | ||
}, | ||
"dependencies": { | ||
"googlemaps": ">= 0.1.6" | ||
}, | ||
"devDependencies": { | ||
"mocha": "*" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "LGPL", | ||
"url": "http://www.gnu.org/licenses/lgpl-3.0.txt" | ||
} | ||
], | ||
"files": [ | ||
"geolib.js" | ||
], | ||
"description": "Library to perform geo specific tasks", | ||
"keywords": [ | ||
"geolocation", | ||
"geo", | ||
"distance" | ||
], | ||
"version": "1.1.8", | ||
"main": "./geolib" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
27498
770
0
1
1
1
+ Addedgooglemaps@>= 0.1.6
+ Addedajv@6.12.6(transitive)
+ Addedasn1@0.2.6(transitive)
+ Addedassert-plus@1.0.0(transitive)
+ Addedasynckit@0.4.0(transitive)
+ Addedaws-sign2@0.7.0(transitive)
+ Addedaws4@1.13.2(transitive)
+ Addedbcrypt-pbkdf@1.0.2(transitive)
+ Addedcaseless@0.12.0(transitive)
+ Addedcheck-types@1.3.2(transitive)
+ Addedcombined-stream@1.0.8(transitive)
+ Addedcore-util-is@1.0.2(transitive)
+ Addeddashdash@1.14.1(transitive)
+ Addeddelayed-stream@1.0.0(transitive)
+ Addedecc-jsbn@0.1.2(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedextsprintf@1.3.0(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedfast-json-stable-stringify@2.1.0(transitive)
+ Addedforever-agent@0.6.1(transitive)
+ Addedform-data@2.3.3(transitive)
+ Addedgetpass@0.1.7(transitive)
+ Addedgooglemaps@1.12.0(transitive)
+ Addedhar-schema@2.0.0(transitive)
+ Addedhar-validator@5.1.5(transitive)
+ Addedhttp-signature@1.2.0(transitive)
+ Addedis-typedarray@1.0.0(transitive)
+ Addedisstream@0.1.2(transitive)
+ Addedjsbn@0.1.1(transitive)
+ Addedjson-schema@0.4.0(transitive)
+ Addedjson-schema-traverse@0.4.1(transitive)
+ Addedjson-stringify-safe@5.0.1(transitive)
+ Addedjsprim@1.4.2(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedoauth-sign@0.9.0(transitive)
+ Addedperformance-now@2.1.0(transitive)
+ Addedpsl@1.15.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedqs@4.0.06.5.3(transitive)
+ Addedrequest@2.88.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsshpk@1.18.0(transitive)
+ Addedtough-cookie@2.5.0(transitive)
+ Addedtunnel-agent@0.6.0(transitive)
+ Addedtweetnacl@0.14.5(transitive)
+ Addeduri-js@4.4.1(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedverror@1.10.0(transitive)
+ Addedwaitress@0.1.5(transitive)