Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Mods to elevation and async service #11

Closed
wants to merge 32 commits into from

6 participants

@grobot

Made some improvements and additions.

  • Added the ability to set google business specific parameters. Like your client_id and private_key. That is then piped in the googlemaps node module so they can encode your request to the Google.
  • The async methods now pass errors through callbacks instead of throwing them.
  • Fixed some minor bugs.
@grobot

These features require an update to the googlemaps module. We will resubmit this pull request when that is published to the latest version.

@grobot grobot closed this
@grobot grobot reopened this
@grobot

googleMaps updated. Looks better. Plz publish to npm.

you're great

@manuelbieh
Owner

I have made some major improvements to the library so that your changes cannot be merged automatically. Could you pull and re-implement your changes again? I will then publish your changes to npm as soon as everything is merged and tested.

@manuelbieh manuelbieh closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 15, 2012
  1. @regality

    fixed bug with getBounds

    regality authored
Commits on Apr 5, 2012
  1. @grobot

    Added ability to set business specific parameters. So you can enocde

    grobot authored
    your elevation request from the server with client_id and private_key
  2. @regality
  3. @regality

    Merge branch 'master' of github.com:ifit/Geolib

    regality authored
    Conflicts:
    	geolib.js
  4. @regality

    minified geolib.js

    regality authored
Commits on Apr 12, 2012
  1. @regality
Commits on Apr 17, 2012
  1. @regality
Commits on Apr 18, 2012
  1. @grobot

    getGrade was returning the opposite of what we wanted. Changed

    grobot authored
    how we were calculating it. Works now.
Commits on May 6, 2012
  1. @grobot

    Changed so we use the changes made in node-googlemaps.

    grobot authored
    Uses config instead of setBusinessSpecificParameters.
Commits on May 7, 2012
  1. @regality
  2. @regality
Commits on Jul 17, 2012
  1. @grobot

    Merge branch 'master' of git://github.com/manuelbieh/Geolib

    grobot authored
    Conflicts:
    	geolib.js
    	geolib.min.js
    	package.json
    	tests/geolib.test.html
Commits on Aug 20, 2012
  1. @grobot

    change dependency

    grobot authored
  2. @grobot

    herpderp

    grobot authored
Commits on Oct 18, 2012
  1. @cbrammer

    updating npm

    cbrammer authored
Commits on Oct 19, 2012
  1. @cbrammer

    bundled

    cbrammer authored
  2. @jduh

    Update package.json

    jduh authored
  3. @cbrammer
  4. @cbrammer
  5. @cbrammer

    Merge branch 'npmsucks'

    cbrammer authored
Commits on Oct 21, 2012
  1. @cbrammer

    fixing git ignore

    cbrammer authored
Commits on Nov 14, 2012
  1. @grobot
  2. @grobot
Commits on Dec 17, 2013
  1. @grobot

    using haversine equation for getDistance

    grobot authored
    When comparing distances between two lat/lngs geolib was returning
    a different distance than google was. Google is using haversine
    formula to get their distances. It is a much easier equation and
    simpler to read.
  2. @grobot
  3. @grobot
  4. @grobot
  5. @grobot

    adds back in test I removed

    grobot authored
  6. @grobot

    hur

    grobot authored
  7. @grobot

    setting default to haversine

    grobot authored
  8. @grobot

    uses accuracy in the right way

    grobot authored
Commits on Dec 31, 2013
  1. @freddyC

    Merge pull request #1 from ifit/haversine

    freddyC authored
    Haversine for getDistance
This page is out of date. Refresh to see the latest.
View
33 .gitignore
@@ -0,0 +1,33 @@
+lib-cov
+*.seed
+*.log
+*.node
+*.o
+*.o.d
+*.mk
+*.gypi
+*.cache.py
+*.wafpickle-7
+*.lock-wscript
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+*.swp
+.DS_Store
+dump.rdb
+.jshintrc
+
+pids
+logs
+results
+
+/public/js/app.js
+/public/css/style.css
+npm-debug.log
+/client/config.js
+.build
+/docs
+
+/node_modules
View
244 geolib.js 100644 → 100755
@@ -13,8 +13,14 @@
var radius = 6378137; // Earth radius
var sexagesimalPattern = /^([0-9]{1,3}\s*([0-9]{1,3})'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/;
+ var googleClientId;
+ var googlePrivateKey;
+ if (typeof window.navigator === 'undefined') {
+ var gm = require('googlemaps');
+ }
var geolib = {
+ distanceFormula: 'haversine',
decimal: {},
@@ -48,6 +54,37 @@
};
},
+ setDistanceFormula: function(formula) {
+ formula = formula ? formula.toLowerCase() : 'vincenty';
+ geolib.distanceFormula = formula;
+ },
+
+ /**
+ * Calculates geodetic distance between two points specified by latitude/longitude using
+ * haversine by default, but can be changed in config
+ *
+ * @param object Start position {latitude: 123, longitude: 123}
+ * @param object End position {latitude: 123, longitude: 123}
+ * @param integer Accuracy (in meters)
+ * @return float Distance (in meters)
+ */
+
+ getDistance: function(start, end, accuracy) {
+ switch (geolib.distanceFormula) {
+ case 'haversine':
+ return geolib.getDistanceHaversine(start, end, accuracy);
+ break;
+ case 'simple':
+ return geolib.getDistanceSimple(start, end, accuracy);
+ break;
+ case 'vincenty':
+ default:
+ return geolib.getDistanceVincenty(start, end, accuracy);
+ break;
+ }
+ },
+
+
/**
* Calculates geodetic distance between two points specified by latitude/longitude using
* Vincenty inverse formula for ellipsoids
@@ -60,7 +97,7 @@
* @return integer Distance (in meters)
*/
- getDistance: function(start, end, accuracy) {
+ getDistanceVincenty: function(start, end, accuracy) {
var keys = geolib.getKeys(start);
var latitude = keys.latitude;
@@ -204,6 +241,41 @@
},
+ /**
+ * Calculates geodetic distance between two points specified by latitude/longitude using
+ * haversine equation
+ *
+ * @param object Start position {latitude: 123, longitude: 123}
+ * @param object End position {latitude: 123, longitude: 123}
+ * @return float Distance (in meters)
+ */
+
+ getDistanceHaversine: function(start, end, accuracy) {
+ var keys = geolib.getKeys(start);
+ var latitude = keys.latitude;
+ var longitude = keys.longitude;
+ var elevation = keys.elevation;
+
+ var coord1 = {}, coord2 = {};
+ coord1[latitude] = geolib.useDecimal(start[latitude]);
+ coord1[longitude] = geolib.useDecimal(start[longitude]);
+
+ coord2[latitude] = geolib.useDecimal(end[latitude]);
+ coord2[longitude] = geolib.useDecimal(end[longitude]);
+
+ accuracy = accuracy || 0.00000001;
+
+ var R = 6378137 // Radius of earth in meters
+ var dLat = (coord2[latitude] - coord1[latitude]).toRad()
+ var dLng = (coord2[longitude] - coord1[longitude]).toRad()
+ var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+ Math.cos((coord1[latitude]).toRad()) * Math.cos((coord2[latitude].toRad())) *
+ Math.sin(dLng/2) * Math.sin(dLng/2);
+ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+ var d = R * c; // Distance in meters
+ return geolib.distance = Math.round(d/accuracy)*accuracy;
+ },
+
/**
* Calculates the distance between two spots.
@@ -323,14 +395,14 @@
var useElevation = coords[0].hasOwnProperty(elevation);
var stats = {
- maxLat: 0,
+ maxLat: Infinity * -1,
minLat: Infinity,
- maxLng: 0,
- minLng: Infinity
+ maxLng: Infinity * -1,
+ minLng: Infinity,
};
if (useElevation) {
- stats.maxElev = 0;
+ stats.maxElev = Infinity * -1;
stats.minElev = Infinity;
}
@@ -627,10 +699,20 @@
/*global google:true require:true module:true elevationResult*/
/**
- * @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},....]}
- */
+ * @params client_id and private_key for Google Enterprise Accounts
+ *
+ * @return Array [{lat:#lat, lng:#lng, elev:#elev},....]}
+ */
+ setBusinessSpecificParameters: function(clientId, privateKey){
+ gm.config('google-client-id', clientId);
+ gm.config('google-private-key', privateKey);
+ },
+
+ /**
+ * @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);
@@ -640,65 +722,63 @@
},
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])
- ));
+ try {
+ if (!window.google) {
+ return cb(new Error("Geolib: Google maps api not loaded"));
+ }
+ if (coords.length == 0) {
+ return cb(null, null);
+ }
+ if (coords.length == 1) {
+ return cb(new Error("Geolib: 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);
+ });
+ } catch (e) {
+ return cb(e);
}
-
- 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]));
+ try {
+ if (coords.length == 0) {
+ return cb(null, null);
+ }
+ if (coords.length == 1) {
+ return cb(new Error("Geolib: getElevation requires at least 2 points."));
+ }
+ 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)
+ });
+ } catch (e) {
+ return cb(e);
}
- 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){
@@ -715,29 +795,36 @@
}
cb(null, latsLngsElevs);
} else {
- cb(new Error("Could not get elevation using Google's API"), elevationResult.status);
+ console.log('RESULTS FROM WONKY GOOGLE REQUEST' + results);
+ cb(new Error("Geolib: Could not get elevation using Google's API: Status: " + status));
}
},
/**
- * @param Array [{lat:#lat, lng:#lng, elev:#elev},....]}
- *
- * @return Number % grade
- */
- getGrade: function(coords){
+ * @param Array [{lat:#lat, lng:#lng, elev:#elev},....]}
+ * @param integer digits Decimal places to round to
+ *
+ * @return Number % grade
+ */
+ getGrade: function(coords, digits) {
var keys = geolib.getKeys(coords[0]);
var elevation = keys.elevation;
- var rise = Math.abs(coords[coords.length-1][elevation] - coords[0][elevation]);
+ var rise = coords[coords.length-1][elevation] - coords[0][elevation];
var run = geolib.getPathLength(coords);
- return Math.floor((rise/run)*100);
+ var grade = (rise/run)*100;
+ if (typeof digits === "number") {
+ var d = Math.pow(10,digits);
+ grade = Math.floor(grade * d) / d;
+ }
+ return grade;
},
/**
- * @param Array [{lat:#lat, lng:#lng, elev:#elev},....]}
- *
- * @return Object {gain:#gain, loss:#loss}
- */
- getTotalElevationGainAndLoss: function(coords){
+ * @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;
@@ -768,8 +855,7 @@
if(distance === 0 || typeof distance == 'undefined') {
- if(geolib.distance === 0) {
- // throw 'No distance given.';
+ if(geolib.distance == 0) {
return 0;
} else {
distance = geolib.distance;
@@ -825,7 +911,7 @@
} else if(geolib.isSexagesimal(value) === true) {
return parseFloat(geolib.sexagesimal2decimal(value));
} else {
- throw 'Unknown format.';
+ throw new Error('Geolib: Unknown format.');
}
},
View
15 geolib.min.js
@@ -1,4 +1,16 @@
/**
+<<<<<<< HEAD
+ * 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
+ *
+ */(function(a,b){var c=6378137,d=/^([0-9]{1,3})°\s*([0-9]{1,3})'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/,e,f;if(typeof a.navigator=="undefined")var g=require("googlemaps");var h={decimal:{},sexagesimal:{},distance:0,getKeys:function(a){var b=a.hasOwnProperty("lat")?"lat":"latitude",c=(a.hasOwnProperty("lng")?"lng":!1)||(a.hasOwnProperty("long")?"long":!1)||"longitude",d=(a.hasOwnProperty("alt")?"alt":!1)||(a.hasOwnProperty("altitude")?"altitude":!1)||(a.hasOwnProperty("elev")?"elev":!1)||"elevation";return{latitude:b,longitude:c,elevation:d}},getDistance:function(a,b,c){var d=h.getKeys(a),e=d.latitude,f=d.longitude,g=d.elevation;c=Math.floor(c)||1;var i={},j={};i[e]=h.useDecimal(a[e]),i[f]=h.useDecimal(a[f]),j[e]=h.useDecimal(b[e]),j[f]=h.useDecimal(b[f]);var k=6378137,l=6356752.314245,m=1/298.257223563,n=(j[f]-i[f]).toRad(),o=Math.atan((1-m)*Math.tan(parseFloat(i[e]).toRad())),p=Math.atan((1-m)*Math.tan(parseFloat(j[e]).toRad())),q=Math.sin(o),r=Math.cos(o),s=Math.sin(p),t=Math.cos(p),u=n,v,w=100;do{var x=Math.sin(u),y=Math.cos(u),z=Math.sqrt(t*x*t*x+(r*s-q*t*y)*(r*s-q*t*y));if(z==0)return h.distance=0;var A=q*s+r*t*y,B=Math.atan2(z,A),C=r*t*x/z,D=1-C*C,E=A-2*q*s/D;isNaN(E)&&(E=0);var F=m/16*D*(4+m*(4-3*D));v=u,u=n+(1-F)*m*C*(B+F*z*(E+F*A*(-1+2*E*E)))}while(Math.abs(u-v)>1e-12&&--w>0);if(w==0)return NaN;var G=D*(k*k-l*l)/(l*l),H=1+G/16384*(4096+G*(-768+G*(320-175*G))),I=G/1024*(256+G*(-128+G*(74-47*G))),J=I*z*(E+I/4*(A*(-1+2*E*E)-I/6*E*(-3+4*z*z)*(-3+4*E*E))),K=l*H*(B-J);K=K.toFixed(3);if(a.hasOwnProperty(g)&&b.hasOwnProperty(g)){var L=Math.abs(a[g]-b[g]);K=Math.sqrt(K*K+L*L)}return h.distance=Math.floor(Math.round(K/c)*c)},getDistanceSimple:function(a,b,d){var e=h.getKeys(a),f=e.latitude,g=e.longitude;d=Math.floor(d)||1;var i={},j={};i[f]=parseFloat(h.useDecimal(a[f])).toRad(),i[g]=parseFloat(h.useDecimal(a[g])).toRad(),j[f]=parseFloat(h.useDecimal(b[f])).toRad(),j[g]=parseFloat(h.useDecimal(b[g])).toRad();var k=Math.round(Math.acos(Math.sin(j[f])*Math.sin(i[f])+Math.cos(j[f])*Math.cos(i[f])*Math.cos(i[g]-j[g]))*c);return h.distance=Math.floor(Math.round(k/d)*d)},getCenter:function(a){if(!a.length)return!1;var b=h.getKeys(a[0]),c=b.latitude,d=b.longitude,e=function(a){return Math.max.apply(Math,a)},f=function(a){return Math.min.apply(Math,a)},g,i,j={lat:[],lng:[]};for(var k in a)j.lat.push(h.useDecimal(a[k][c])),j.lng.push(h.useDecimal(a[k][d]));var l=f(j.lat),m=f(j.lng),n=e(j.lat),o=e(j.lng);g=((l+n)/2).toFixed(6),i=((m+o)/2).toFixed(6);var p=h.convertUnit("km",h.getDistance({lat:l,lng:m},{lat:n,lng:o}));return{latitude:g,longitude:i,distance:p}},getBounds:function(a){if(!a.length)return!1;var b=h.getKeys(a[0]),c=b.latitude,d=b.longitude,e=b.elevation,f=a[0].hasOwnProperty(e),g={maxLat:Infinity*-1,minLat:Infinity,maxLng:Infinity*-1,minLng:Infinity};f&&(g.maxElev=Infinity*-1,g.minElev=Infinity);for(var i=0,j=a.length;i<j;++i)g.maxLat=Math.max(a[i][c],g.maxLat),g.minLat=Math.min(a[i][c],g.minLat),g.maxLng=Math.max(a[i][d],g.maxLng),g.minLng=Math.min(a[i][d],g.minLng),f&&(g.maxElev=Math.max(a[i][e],g.maxElev),g.minElev=Math.min(a[i][e],g.minElev));return g},isPointInside:function(a,b){var c=h.getKeys(a),d=c.latitude,e=c.longitude;for(var f=!1,g=-1,i=b.length,j=i-1;++g<i;j=g)(b[g][e]<=a[e]&&a[e]<b[j][e]||b[j][e]<=a[e]&&a[e]<b[g][e])&&a[d]<(b[j][d]-b[g][d])*(a[e]-b[g][e])/(b[j][e]-b[g][e])+b[g][d]&&(f=!f);return f},isPointInCircle:function(a,b,c){return h.getDistance(a,b)<c},getRhumbLineBearing:function(a,b){var c=h.getKeys(a),d=c.latitude,e=c.longitude,f=h.useDecimal(b[e]).toRad()-h.useDecimal(a[e]).toRad(),g=Math.log(Math.tan(h.useDecimal(b[d]).toRad()/2+Math.PI/4)/Math.tan(h.useDecimal(a[d]).toRad()/2+Math.PI/4));return Math.abs(f)>Math.PI&&(f>0?f=(2*Math.PI-f)*-1:f=2*Math.PI+f),(Math.atan2(f,g).toDeg()+360)%360},getBearing:function(a,b){var c=h.getKeys(a),d=c.latitude,e=c.longitude;b[d]=h.useDecimal(b[d]),b[e]=h.useDecimal(b[e]),a[d]=h.useDecimal(a[d]),a[e]=h.useDecimal(a[e]);var f=(Math.atan2(Math.sin(b[e].toRad()-a[e].toRad())*Math.cos(b[d].toRad()),Math.cos(a[d].toRad())*Math.sin(b[d].toRad())-Math.sin(a[d].toRad())*Math.cos(b[d].toRad())*Math.cos(b[e].toRad()-a[e].toRad())).toDeg()+360)%360;return f},getCompassDirection:function(a,b,c){var d;if(c=="circle")var e=h.getBearing(a,b);else var e=h.getRhumbLineBearing(a,b);switch(Math.round(e/22.5)){case 1:d={exact:"NNE",rough:"N"};break;case 2:d={exact:"NE",rough:"N"};break;case 3:d={exact:"ENE",rough:"E"};break;case 4:d={exact:"E",rough:"E"};break;case 5:d={exact:"ESE",rough:"E"};break;case 6:d={exact:"SE",rough:"E"};break;case 7:d={exact:"SSE",rough:"S"};break;case 8:d={exact:"S",rough:"S"};break;case 9:d={exact:"SSW",rough:"S"};break;case 10:d={exact:"SW",rough:"S"};break;case 11:d={exact:"WSW",rough:"W"};break;case 12:d={exact:"W",rough:"W"};break;case 13:d={exact:"WNW",rough:"W"};break;case 14:d={exact:"NW",rough:"W"};break;case 15:d={exact:"NNW",rough:"N"};break;default:d={exact:"N",rough:"N"}}return d},orderByDistance:function(a,b){var c=h.getKeys(a),d=c.latitude,e=c.longitude,f=[];for(var g in b){var i=h.getDistance(a,b[g]);f.push({key:g,latitude:b[g][d],longitude:b[g][e],distance:i})}return f.sort(function(a,b){return a.distance-b.distance})},findNearest:function(a,b,c){c=c||0;var d=h.orderByDistance(a,b);return d[c]},getPathLength:function(a){var b=0,c;for(var d=0,e=a.length;d<e;++d)c&&(b+=h.getDistance(a[d],c)),c=a[d];return b},setBusinessSpecificParameters:function(a,b){g.config("google-client-id",a),g.config("google-private-key",b)},getElevation:function(){typeof a.navigator!="undefined"?h.getElevationClient.apply(this,arguments):h.getElevationServer.apply(this,arguments)},getElevationClient:function(b,c){try{if(!a.google)return c(new Error("Geolib: Google maps api not loaded"));if(b.length==0)return c(null,null);if(b.length==1)return c(new Error("Geolib: getElevation requires at least 2 points."));var d=[],e=h.getKeys(b[0]),f=e.latitude,g=e.longitude;for(var i=0;i<b.length;i++)d.push(new google.maps.LatLng(h.useDecimal(b[i][f]),h.useDecimal(b[i][g])));var j={path:d,samples:d.length},k=new google.maps.ElevationService;k.getElevationAlongPath(j,function(a,d){h.elevationHandler(a,d,b,e,c)})}catch(l){return c(l)}},getElevationServer:function(a,b){try{if(a.length==0)return b(null,null);if(a.length==1)return b(new Error("Geolib: getElevation requires at least 2 points."));var c=[],d=h.getKeys(a[0]);a[0];var e=d.latitude,f=d.longitude;for(var i=0;i<a.length;i++)c.push(h.useDecimal(a[i][e])+","+h.useDecimal(a[i][f]));g.elevationFromPath(c.join("|"),c.length,function(c,e){h.elevationHandler(e.results,e.status,a,d,b)})}catch(j){return b(j)}},elevationHandler:function(a,b,c,d,e){var f=[],g=d.latitude,h=d.longitude;if(b=="OK"){for(var i=0;i<a.length;i++)f.push({lat:c[i][g],lng:c[i][h],elev:a[i].elevation});e(null,f)}else e(new Error("Geolib: Could not get elevation using Google's API: Status: "+b))},getGrade:function(a,b){var c=h.getKeys(a[0]),d=c.elevation,e=a[a.length-1][d]-a[0][d],f=h.getPathLength(a),g=e/f*100;if(typeof b=="number"){var i=Math.pow(10,b);g=Math.floor(g*i)/i}return g},getTotalElevationGainAndLoss:function(a){var b=h.getKeys(a[0]),c=b.elevation,d=0,e=0;for(var f=0;f<a.length-1;f++){var g=a[f][c]-a[f+1][c];g>0?e+=g:d+=Math.abs(g)}return{gain:d,loss:e}},convertUnit:function(a,b,c){if(b==0||typeof b=="undefined"){if(h.distance==0)return 0;b=h.distance}a=a||"m",c=c||4;switch(a){case"m":return h.round(b,c);case"km":return h.round(b/1e3,c);case"cm":return h.round(b*100,c);case"mm":return h.round(b*1e3,c);case"mi":return h.round(b*(1/1609.344),c);case"sm":return h.round(b*(1/1852.216),c);case"ft":return h.round(b*(100/30.48),c);case"in":return h.round(b*100/2.54,c);case"yd":return h.round(b*(1/.9144),c)}return b},useDecimal:function(a){a=a.toString().replace(/\s*/,"");if(!isNaN(parseFloat(a))&&parseFloat(a).toString()==a)return parseFloat(a);if(h.isSexagesimal(a)==1)return parseFloat(h.sexagesimal2decimal(a));throw new Error("Geolib: Unknown format.")},decimal2sexagesimal:function(a){if(a in h.sexagesimal)return h.sexagesimal[a];var b=a.toString().split("."),c=Math.abs(b[0]),d=("0."+b[1])*60,e=d.toString().split(".");return d=Math.floor(d),e=(("0."+e[1])*60).toFixed(2),h.sexagesimal[a]=c+"° "+d+"' "+e+'"',h.sexagesimal[a]},sexagesimal2decimal:function(a){if(a in h.decimal)return h.decimal[a];var b=new RegExp(d),c=b.exec(a);if(c)var e=parseFloat(c[2]/60),f=parseFloat(c[4]/3600)||0;var g=(parseFloat(c[1])+e+f).toFixed(8);return g=c[7]=="S"||c[7]=="W"?g*-1:g,h.decimal[a]=g,g},isSexagesimal:function(a){return d.test(a)},round:function(a,b){var c=Math.pow(10,b);return Math.round(a*c)/c}};typeof Number.prototype.toRad=="undefined"&&(Number.prototype.toRad=function(){return this*Math.PI/180}),typeof Number.prototype.toDeg=="undefined"&&(Number.prototype.toDeg=function(){return this*180/Math.PI}),typeof a.navigator!="undefined"?a.geolib=h:module.exports=h})(this);
+=======
* 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)
@@ -8,4 +20,5 @@
* @version 1.1.8
* @license LGPL
**/
-(function(a,b){var c=6378137,d=/^([0-9]{1,3})°\s*([0-9]{1,3})'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/,e={decimal:{},sexagesimal:{},distance:0,getKeys:function(a){var b=a.hasOwnProperty("lat")?"lat":"latitude",c=(a.hasOwnProperty("lng")?"lng":!1)||(a.hasOwnProperty("long")?"long":!1)||"longitude",d=(a.hasOwnProperty("alt")?"alt":!1)||(a.hasOwnProperty("altitude")?"altitude":!1)||(a.hasOwnProperty("elev")?"elev":!1)||"elevation";return{latitude:b,longitude:c,elevation:d}},getDistance:function(a,b,c){var d=e.getKeys(a),f=d.latitude,g=d.longitude,h=d.elevation;c=Math.floor(c)||1;var i={},j={};i[f]=e.useDecimal(a[f]),i[g]=e.useDecimal(a[g]),j[f]=e.useDecimal(b[f]),j[g]=e.useDecimal(b[g]);var k=6378137,l=6356752.314245,m=1/298.257223563,n=(j[g]-i[g]).toRad(),o,p,q,r,s,t,u=Math.atan((1-m)*Math.tan(parseFloat(i[f]).toRad())),v=Math.atan((1-m)*Math.tan(parseFloat(j[f]).toRad())),w=Math.sin(u),x=Math.cos(u),y=Math.sin(v),z=Math.cos(v),A=n,B,C=100;do{var D=Math.sin(A),E=Math.cos(A);t=Math.sqrt(z*D*z*D+(x*y-w*z*E)*(x*y-w*z*E));if(t===0)return e.distance=0;o=w*y+x*z*E,p=Math.atan2(t,o),q=x*z*D/t,r=1-q*q,s=o-2*w*y/r,isNaN(s)&&(s=0);var F=m/16*r*(4+m*(4-3*r));B=A,A=n+(1-F)*m*q*(p+F*t*(s+F*o*(-1+2*s*s)))}while(Math.abs(A-B)>1e-12&&--C>0);if(C===0)return NaN;var G=r*(k*k-l*l)/(l*l),H=1+G/16384*(4096+G*(-768+G*(320-175*G))),I=G/1024*(256+G*(-128+G*(74-47*G))),J=I*t*(s+I/4*(o*(-1+2*s*s)-I/6*s*(-3+4*t*t)*(-3+4*s*s))),K=l*H*(p-J);K=K.toFixed(3);if(a.hasOwnProperty(h)&&b.hasOwnProperty(h)){var L=Math.abs(a[h]-b[h]);K=Math.sqrt(K*K+L*L)}return e.distance=Math.floor(Math.round(K/c)*c)},getDistanceSimple:function(a,b,d){var f=e.getKeys(a),g=f.latitude,h=f.longitude;d=Math.floor(d)||1;var i={},j={};i[g]=parseFloat(e.useDecimal(a[g])).toRad(),i[h]=parseFloat(e.useDecimal(a[h])).toRad(),j[g]=parseFloat(e.useDecimal(b[g])).toRad(),j[h]=parseFloat(e.useDecimal(b[h])).toRad();var k=Math.round(Math.acos(Math.sin(j[g])*Math.sin(i[g])+Math.cos(j[g])*Math.cos(i[g])*Math.cos(i[h]-j[h]))*c);return e.distance=Math.floor(Math.round(k/d)*d)},getCenter:function(a){if(!a.length)return!1;var b=e.getKeys(a[0]),c=b.latitude,d=b.longitude,f=function(a){return Math.max.apply(Math,a)},g=function(a){return Math.min.apply(Math,a)},h,i,j={lat:[],lng:[]};for(var k in a)j.lat.push(e.useDecimal(a[k][c])),j.lng.push(e.useDecimal(a[k][d]));var l=g(j.lat),m=g(j.lng),n=f(j.lat),o=f(j.lng);h=((l+n)/2).toFixed(6),i=((m+o)/2).toFixed(6);var p=e.convertUnit("km",e.getDistance({lat:l,lng:m},{lat:n,lng:o}));return{latitude:h,longitude:i,distance:p}},getBounds:function(a){if(!a.length)return!1;var b=e.getKeys(a[0]),c=b.latitude,d=b.longitude,f=b.elevation,g=a[0].hasOwnProperty(f),h={maxLat:0,minLat:Infinity,maxLng:0,minLng:Infinity};g&&(h.maxElev=0,h.minElev=Infinity);for(var i=0,j=a.length;i<j;++i)h.maxLat=Math.max(a[i][c],h.maxLat),h.minLat=Math.min(a[i][c],h.minLat),h.maxLng=Math.max(a[i][d],h.maxLng),h.minLng=Math.min(a[i][d],h.minLng),g&&(h.maxElev=Math.max(a[i][f],h.maxElev),h.minElev=Math.min(a[i][f],h.minElev));return h},isPointInside:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude;for(var g=!1,h=-1,i=b.length,j=i-1;++h<i;j=h)(b[h][f]<=a[f]&&a[f]<b[j][f]||b[j][f]<=a[f]&&a[f]<b[h][f])&&a[d]<(b[j][d]-b[h][d])*(a[f]-b[h][f])/(b[j][f]-b[h][f])+b[h][d]&&(g=!g);return g},isPointInCircle:function(a,b,c){return e.getDistance(a,b)<c},getRhumbLineBearing:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude,g=e.useDecimal(b[f]).toRad()-e.useDecimal(a[f]).toRad(),h=Math.log(Math.tan(e.useDecimal(b[d]).toRad()/2+Math.PI/4)/Math.tan(e.useDecimal(a[d]).toRad()/2+Math.PI/4));return Math.abs(g)>Math.PI&&(g>0?g=(2*Math.PI-g)*-1:g=2*Math.PI+g),(Math.atan2(g,h).toDeg()+360)%360},getBearing:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude;b[d]=e.useDecimal(b[d]),b[f]=e.useDecimal(b[f]),a[d]=e.useDecimal(a[d]),a[f]=e.useDecimal(a[f]);var g=(Math.atan2(Math.sin(b[f].toRad()-a[f].toRad())*Math.cos(b[d].toRad()),Math.cos(a[d].toRad())*Math.sin(b[d].toRad())-Math.sin(a[d].toRad())*Math.cos(b[d].toRad())*Math.cos(b[f].toRad()-a[f].toRad())).toDeg()+360)%360;return g},getCompassDirection:function(a,b,c){var d,f;c=="circle"?f=e.getBearing(a,b):f=e.getRhumbLineBearing(a,b);switch(Math.round(f/22.5)){case 1:d={exact:"NNE",rough:"N"};break;case 2:d={exact:"NE",rough:"N"};break;case 3:d={exact:"ENE",rough:"E"};break;case 4:d={exact:"E",rough:"E"};break;case 5:d={exact:"ESE",rough:"E"};break;case 6:d={exact:"SE",rough:"E"};break;case 7:d={exact:"SSE",rough:"S"};break;case 8:d={exact:"S",rough:"S"};break;case 9:d={exact:"SSW",rough:"S"};break;case 10:d={exact:"SW",rough:"S"};break;case 11:d={exact:"WSW",rough:"W"};break;case 12:d={exact:"W",rough:"W"};break;case 13:d={exact:"WNW",rough:"W"};break;case 14:d={exact:"NW",rough:"W"};break;case 15:d={exact:"NNW",rough:"N"};break;default:d={exact:"N",rough:"N"}}return d},orderByDistance:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude,g=[];for(var h in b){var i=e.getDistance(a,b[h]);g.push({key:h,latitude:b[h][d],longitude:b[h][f],distance:i})}return g.sort(function(a,b){return a.distance-b.distance})},findNearest:function(a,b,c){c=c||0;var d=e.orderByDistance(a,b);return d[c]},getPathLength:function(a){var b=0,c;for(var d=0,f=a.length;d<f;++d)c&&(b+=e.getDistance(a[d],c)),c=a[d];return b},getElevation:function(){typeof a.navigator!="undefined"?e.getElevationClient.apply(this,arguments):e.getElevationServer.apply(this,arguments)},getElevationClient:function(b,c){if(!a.google)throw new Error("Google maps api not loaded");if(b.length===0)return c(null,null);if(b.length===1)return c(new Error("getElevation requires at least 2 points."));var d=[],f=e.getKeys(b[0]),g=f.latitude,h=f.longitude;for(var i=0;i<b.length;i++)d.push(new google.maps.LatLng(e.useDecimal(b[i][g]),e.useDecimal(b[i][h])));var j={path:d,samples:d.length},k=new google.maps.ElevationService;k.getElevationAlongPath(j,function(a,d){e.elevationHandler(a,d,b,f,c)})},getElevationServer:function(a,b){if(a.length===0)return b(null,null);if(a.length===1)return b(new Error("getElevation requires at least 2 points."));var c=require("googlemaps"),d=[],f=e.getKeys(a[0]),g=f.latitude,h=f.longitude;for(var i=0;i<a.length;i++)d.push(e.useDecimal(a[i][g])+","+e.useDecimal(a[i][h]));c.elevationFromPath(d.join("|"),d.length,function(c,d){e.elevationHandler(d.results,d.status,a,f,b)})},elevationHandler:function(a,b,c,d,e){var f=[],g=d.latitude,h=d.longitude;if(b=="OK"){for(var i=0;i<a.length;i++)f.push({lat:c[i][g],lng:c[i][h],elev:a[i].elevation});e(null,f)}else e(new Error("Could not get elevation using Google's API"),elevationResult.status)},getGrade:function(a){var b=e.getKeys(a[0]),c=b.elevation,d=Math.abs(a[a.length-1][c]-a[0][c]),f=e.getPathLength(a);return Math.floor(d/f*100)},getTotalElevationGainAndLoss:function(a){var b=e.getKeys(a[0]),c=b.elevation,d=0,f=0;for(var g=0;g<a.length-1;g++){var h=a[g][c]-a[g+1][c];h>0?f+=h:d+=Math.abs(h)}return{gain:d,loss:f}},convertUnit:function(a,b,c){if(b===0||typeof b=="undefined"){if(e.distance===0)return 0;b=e.distance}a=a||"m",c=null==c?4:c;switch(a){case"m":return e.round(b,c);case"km":return e.round(b/1e3,c);case"cm":return e.round(b*100,c);case"mm":return e.round(b*1e3,c);case"mi":return e.round(b*(1/1609.344),c);case"sm":return e.round(b*(1/1852.216),c);case"ft":return e.round(b*(100/30.48),c);case"in":return e.round(b*100/2.54,c);case"yd":return e.round(b*(1/.9144),c)}return b},useDecimal:function(a){a=a.toString().replace(/\s*/,"");if(!isNaN(parseFloat(a))&&parseFloat(a).toString()==a)return parseFloat(a);if(e.isSexagesimal(a)===!0)return parseFloat(e.sexagesimal2decimal(a));throw"Unknown format."},decimal2sexagesimal:function(a){if(a in e.sexagesimal)return e.sexagesimal[a];var b=a.toString().split("."),c=Math.abs(b[0]),d=("0."+b[1])*60,f=d.toString().split(".");return d=Math.floor(d),f=(("0."+f[1])*60).toFixed(2),e.sexagesimal[a]=c+"° "+d+"' "+f+'"',e.sexagesimal[a]},sexagesimal2decimal:function(a){if(a in e.decimal)return e.decimal[a];var b=new RegExp(d),c=b.exec(a),f=0,g=0;c&&(f=parseFloat(c[2]/60),g=parseFloat(c[4]/3600)||0);var h=(parseFloat(c[1])+f+g).toFixed(8);return h=c[7]=="S"||c[7]=="W"?h*-1:h,e.decimal[a]=h,h},isSexagesimal:function(a){return d.test(a)},round:function(a,b){var c=Math.pow(10,b);return Math.round(a*c)/c}};typeof Number.prototype.toRad=="undefined"&&(Number.prototype.toRad=function(){return this*Math.PI/180}),typeof Number.prototype.toDeg=="undefined"&&(Number.prototype.toDeg=function(){return this*180/Math.PI}),typeof a.navigator!="undefined"?a.geolib=e:module.exports=e})(this);
+(function(a,b){var c=6378137,d=/^([0-9]{1,3})°\s*([0-9]{1,3})'\s*(([0-9]{1,3}(\.([0-9]{1,2}))?)"\s*)?([NEOSW]?)$/,e={decimal:{},sexagesimal:{},distance:0,getKeys:function(a){var b=a.hasOwnProperty("lat")?"lat":"latitude",c=(a.hasOwnProperty("lng")?"lng":!1)||(a.hasOwnProperty("long")?"long":!1)||"longitude",d=(a.hasOwnProperty("alt")?"alt":!1)||(a.hasOwnProperty("altitude")?"altitude":!1)||(a.hasOwnProperty("elev")?"elev":!1)||"elevation";return{latitude:b,longitude:c,elevation:d}},getDistance:function(a,b,c){var d=e.getKeys(a),f=d.latitude,g=d.longitude,h=d.elevation;c=Math.floor(c)||1;var i={},j={};i[f]=e.useDecimal(a[f]),i[g]=e.useDecimal(a[g]),j[f]=e.useDecimal(b[f]),j[g]=e.useDecimal(b[g]);var k=6378137,l=6356752.314245,m=1/298.257223563,n=(j[g]-i[g]).toRad(),o,p,q,r,s,t,u=Math.atan((1-m)*Math.tan(parseFloat(i[f]).toRad())),v=Math.atan((1-m)*Math.tan(parseFloat(j[f]).toRad())),w=Math.sin(u),x=Math.cos(u),y=Math.sin(v),z=Math.cos(v),A=n,B,C=100;do{var D=Math.sin(A),E=Math.cos(A);t=Math.sqrt(z*D*z*D+(x*y-w*z*E)*(x*y-w*z*E));if(t===0)return e.distance=0;o=w*y+x*z*E,p=Math.atan2(t,o),q=x*z*D/t,r=1-q*q,s=o-2*w*y/r,isNaN(s)&&(s=0);var F=m/16*r*(4+m*(4-3*r));B=A,A=n+(1-F)*m*q*(p+F*t*(s+F*o*(-1+2*s*s)))}while(Math.abs(A-B)>1e-12&&--C>0);if(C===0)return NaN;var G=r*(k*k-l*l)/(l*l),H=1+G/16384*(4096+G*(-768+G*(320-175*G))),I=G/1024*(256+G*(-128+G*(74-47*G))),J=I*t*(s+I/4*(o*(-1+2*s*s)-I/6*s*(-3+4*t*t)*(-3+4*s*s))),K=l*H*(p-J);K=K.toFixed(3);if(a.hasOwnProperty(h)&&b.hasOwnProperty(h)){var L=Math.abs(a[h]-b[h]);K=Math.sqrt(K*K+L*L)}return e.distance=Math.floor(Math.round(K/c)*c)},getDistanceSimple:function(a,b,d){var f=e.getKeys(a),g=f.latitude,h=f.longitude;d=Math.floor(d)||1;var i={},j={};i[g]=parseFloat(e.useDecimal(a[g])).toRad(),i[h]=parseFloat(e.useDecimal(a[h])).toRad(),j[g]=parseFloat(e.useDecimal(b[g])).toRad(),j[h]=parseFloat(e.useDecimal(b[h])).toRad();var k=Math.round(Math.acos(Math.sin(j[g])*Math.sin(i[g])+Math.cos(j[g])*Math.cos(i[g])*Math.cos(i[h]-j[h]))*c);return e.distance=Math.floor(Math.round(k/d)*d)},getCenter:function(a){if(!a.length)return!1;var b=e.getKeys(a[0]),c=b.latitude,d=b.longitude,f=function(a){return Math.max.apply(Math,a)},g=function(a){return Math.min.apply(Math,a)},h,i,j={lat:[],lng:[]};for(var k in a)j.lat.push(e.useDecimal(a[k][c])),j.lng.push(e.useDecimal(a[k][d]));var l=g(j.lat),m=g(j.lng),n=f(j.lat),o=f(j.lng);h=((l+n)/2).toFixed(6),i=((m+o)/2).toFixed(6);var p=e.convertUnit("km",e.getDistance({lat:l,lng:m},{lat:n,lng:o}));return{latitude:h,longitude:i,distance:p}},getBounds:function(a){if(!a.length)return!1;var b=e.getKeys(a[0]),c=b.latitude,d=b.longitude,f=b.elevation,g=a[0].hasOwnProperty(f),h={maxLat:0,minLat:Infinity,maxLng:0,minLng:Infinity};g&&(h.maxElev=0,h.minElev=Infinity);for(var i=0,j=a.length;i<j;++i)h.maxLat=Math.max(a[i][c],h.maxLat),h.minLat=Math.min(a[i][c],h.minLat),h.maxLng=Math.max(a[i][d],h.maxLng),h.minLng=Math.min(a[i][d],h.minLng),g&&(h.maxElev=Math.max(a[i][f],h.maxElev),h.minElev=Math.min(a[i][f],h.minElev));return h},isPointInside:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude;for(var g=!1,h=-1,i=b.length,j=i-1;++h<i;j=h)(b[h][f]<=a[f]&&a[f]<b[j][f]||b[j][f]<=a[f]&&a[f]<b[h][f])&&a[d]<(b[j][d]-b[h][d])*(a[f]-b[h][f])/(b[j][f]-b[h][f])+b[h][d]&&(g=!g);return g},isPointInCircle:function(a,b,c){return e.getDistance(a,b)<c},getRhumbLineBearing:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude,g=e.useDecimal(b[f]).toRad()-e.useDecimal(a[f]).toRad(),h=Math.log(Math.tan(e.useDecimal(b[d]).toRad()/2+Math.PI/4)/Math.tan(e.useDecimal(a[d]).toRad()/2+Math.PI/4));return Math.abs(g)>Math.PI&&(g>0?g=(2*Math.PI-g)*-1:g=2*Math.PI+g),(Math.atan2(g,h).toDeg()+360)%360},getBearing:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude;b[d]=e.useDecimal(b[d]),b[f]=e.useDecimal(b[f]),a[d]=e.useDecimal(a[d]),a[f]=e.useDecimal(a[f]);var g=(Math.atan2(Math.sin(b[f].toRad()-a[f].toRad())*Math.cos(b[d].toRad()),Math.cos(a[d].toRad())*Math.sin(b[d].toRad())-Math.sin(a[d].toRad())*Math.cos(b[d].toRad())*Math.cos(b[f].toRad()-a[f].toRad())).toDeg()+360)%360;return g},getCompassDirection:function(a,b,c){var d,f;c=="circle"?f=e.getBearing(a,b):f=e.getRhumbLineBearing(a,b);switch(Math.round(f/22.5)){case 1:d={exact:"NNE",rough:"N"};break;case 2:d={exact:"NE",rough:"N"};break;case 3:d={exact:"ENE",rough:"E"};break;case 4:d={exact:"E",rough:"E"};break;case 5:d={exact:"ESE",rough:"E"};break;case 6:d={exact:"SE",rough:"E"};break;case 7:d={exact:"SSE",rough:"S"};break;case 8:d={exact:"S",rough:"S"};break;case 9:d={exact:"SSW",rough:"S"};break;case 10:d={exact:"SW",rough:"S"};break;case 11:d={exact:"WSW",rough:"W"};break;case 12:d={exact:"W",rough:"W"};break;case 13:d={exact:"WNW",rough:"W"};break;case 14:d={exact:"NW",rough:"W"};break;case 15:d={exact:"NNW",rough:"N"};break;default:d={exact:"N",rough:"N"}}return d},orderByDistance:function(a,b){var c=e.getKeys(a),d=c.latitude,f=c.longitude,g=[];for(var h in b){var i=e.getDistance(a,b[h]);g.push({key:h,latitude:b[h][d],longitude:b[h][f],distance:i})}return g.sort(function(a,b){return a.distance-b.distance})},findNearest:function(a,b,c){c=c||0;var d=e.orderByDistance(a,b);return d[c]},getPathLength:function(a){var b=0,c;for(var d=0,f=a.length;d<f;++d)c&&(b+=e.getDistance(a[d],c)),c=a[d];return b},getElevation:function(){typeof a.navigator!="undefined"?e.getElevationClient.apply(this,arguments):e.getElevationServer.apply(this,arguments)},getElevationClient:function(b,c){if(!a.google)throw new Error("Google maps api not loaded");if(b.length===0)return c(null,null);if(b.length===1)return c(new Error("getElevation requires at least 2 points."));var d=[],f=e.getKeys(b[0]),g=f.latitude,h=f.longitude;for(var i=0;i<b.length;i++)d.push(new google.maps.LatLng(e.useDecimal(b[i][g]),e.useDecimal(b[i][h])));var j={path:d,samples:d.length},k=new google.maps.ElevationService;k.getElevationAlongPath(j,function(a,d){e.elevationHandler(a,d,b,f,c)})},getElevationServer:function(a,b){if(a.length===0)return b(null,null);if(a.length===1)return b(new Error("getElevation requires at least 2 points."));var c=require("googlemaps"),d=[],f=e.getKeys(a[0]),g=f.latitude,h=f.longitude;for(var i=0;i<a.length;i++)d.push(e.useDecimal(a[i][g])+","+e.useDecimal(a[i][h]));c.elevationFromPath(d.join("|"),d.length,function(c,d){e.elevationHandler(d.results,d.status,a,f,b)})},elevationHandler:function(a,b,c,d,e){var f=[],g=d.latitude,h=d.longitude;if(b=="OK"){for(var i=0;i<a.length;i++)f.push({lat:c[i][g],lng:c[i][h],elev:a[i].elevation});e(null,f)}else e(new Error("Could not get elevation using Google's API"),elevationResult.status)},getGrade:function(a){var b=e.getKeys(a[0]),c=b.elevation,d=Math.abs(a[a.length-1][c]-a[0][c]),f=e.getPathLength(a);return Math.floor(d/f*100)},getTotalElevationGainAndLoss:function(a){var b=e.getKeys(a[0]),c=b.elevation,d=0,f=0;for(var g=0;g<a.length-1;g++){var h=a[g][c]-a[g+1][c];h>0?f+=h:d+=Math.abs(h)}return{gain:d,loss:f}},convertUnit:function(a,b,c){if(b===0||typeof b=="undefined"){if(e.distance===0)return 0;b=e.distance}a=a||"m",c=null==c?4:c;switch(a){case"m":return e.round(b,c);case"km":return e.round(b/1e3,c);case"cm":return e.round(b*100,c);case"mm":return e.round(b*1e3,c);case"mi":return e.round(b*(1/1609.344),c);case"sm":return e.round(b*(1/1852.216),c);case"ft":return e.round(b*(100/30.48),c);case"in":return e.round(b*100/2.54,c);case"yd":return e.round(b*(1/.9144),c)}return b},useDecimal:function(a){a=a.toString().replace(/\s*/,"");if(!isNaN(parseFloat(a))&&parseFloat(a).toString()==a)return parseFloat(a);if(e.isSexagesimal(a)===!0)return parseFloat(e.sexagesimal2decimal(a));throw"Unknown format."},decimal2sexagesimal:function(a){if(a in e.sexagesimal)return e.sexagesimal[a];var b=a.toString().split("."),c=Math.abs(b[0]),d=("0."+b[1])*60,f=d.toString().split(".");return d=Math.floor(d),f=(("0."+f[1])*60).toFixed(2),e.sexagesimal[a]=c+"° "+d+"' "+f+'"',e.sexagesimal[a]},sexagesimal2decimal:function(a){if(a in e.decimal)return e.decimal[a];var b=new RegExp(d),c=b.exec(a),f=0,g=0;c&&(f=parseFloat(c[2]/60),g=parseFloat(c[4]/3600)||0);var h=(parseFloat(c[1])+f+g).toFixed(8);return h=c[7]=="S"||c[7]=="W"?h*-1:h,e.decimal[a]=h,h},isSexagesimal:function(a){return d.test(a)},round:function(a,b){var c=Math.pow(10,b);return Math.round(a*c)/c}};typeof Number.prototype.toRad=="undefined"&&(Number.prototype.toRad=function(){return this*Math.PI/180}),typeof Number.prototype.toDeg=="undefined"&&(Number.prototype.toDeg=function(){return this*180/Math.PI}),typeof a.navigator!="undefined"?a.geolib=e:module.exports=e})(this);
+>>>>>>> be8a06b5ea2d693d6ad8447ecd1c859bf2e52cfc
View
72 package.json
@@ -1,38 +1,38 @@
{
- "name": "geolib",
- "homepage": "http://github.com/manuelbieh/Geolib",
- "author": {
- "name": "Manuel Bieh",
- "url": "http://www.manuelbieh.com/"
- },
- "bin": {
- "geolib": "./geolib.js"
- },
- "repository": {
- "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"
+ "name": "geolib",
+ "homepage": "http://github.com/manuelbieh/Geolib",
+ "author": {
+ "name": "Manuel Bieh",
+ "url": "http://www.manuelbieh.com/"
+ },
+ "bin": {
+ "geolib": "./geolib.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/manuelbieh/geolib.git"
+ },
+ "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",
+ "dependencies": {
+ "googlemaps": "git+ssh://git@github.com:ifit/node-googlemaps.git#master"
+ },
+ "devDependencies": {
+ "mocha": "*"
+ }
}
View
4 tests/geolib.test.html
@@ -7,10 +7,10 @@
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!-- script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=AIzaSyDxikL7zFrgea3gBya8OECSsOgvKuuFLb8&sensor=true"></script-->
<script type="text/javascript" src='http://maps.googleapis.com/maps/api/js?sensor=true'></script>
-<script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
+<script type="text/javascript" src="http://code.jquery.com/qunit/qunit-git.js"></script>
<script type="text/javascript" src="../geolib.js"></script>
<script type="text/javascript" src="geolib.test.js"></script>
-<link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen" />
+<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" media="screen" />
</head>
<body>
View
61 tests/geolib.test.js
@@ -47,6 +47,8 @@
expect(3);
+ geolib.setDistanceFormula('vincenty');
+
var distance1 = geolib.getDistance({latitude: 52.518611, longitude: 13.408056}, {latitude: 51.519475, longitude: 7.46694444});
var distance2 = geolib.getDistance({latitude: 52.518611, longitude: 13.408056}, {latitude: 51.519475, longitude: 7.46694444}, 100);
var distance3 = geolib.getDistance({latitude: 37.774514, longitude: -122.418079}, {latitude: 51.519475, longitude: 7.46694444});
@@ -115,8 +117,8 @@
throw err;
}
latsLngsElevs = results;
- equal(latsLngsElevs[0].elev, 297.8508605957031, "1st elev should be 297.8508605957031");
- equal(latsLngsElevs[1].elev, 281.1884155273438, "2nd elev should be 281.1884155273438");
+ equal(latsLngsElevs[0].elev, 299.4249877929688, "1st elev should be 299.4249877929688");
+ equal(latsLngsElevs[1].elev, 280.3750305175781, "2nd elev should be 280.3750305175781");
done();
});
@@ -139,11 +141,11 @@
var coords2 = [{"lat":40.75402,"lng":-111.75475,"elev":2209.137451171875},
{"lat":40.76481,"lng":-111.76778999999999,"elev":1660.49609375}];
- var grade = geolib.getGrade(coords1);
- equal(grade, 51, "grade should be 51");
+ var grade = geolib.getGrade(coords1, 1);
+ equal(grade, 51.4, "grade should be 51.4");
- grade = geolib.getGrade(coords2);
- equal(grade, 31, "grade should be 31");
+ grade = geolib.getGrade(coords2, 0);
+ equal(grade, -32, "grade should be -32");
});
test("Testing elevation gain and loss: getTotalElevationGainAndLoss()", function() {
@@ -263,3 +265,50 @@
//ok(geolib.isSexagesimal('51° N'), '51°'); // coming soon
});
+
+ test("Testing haversine distance calculation: getDistance()", function() {
+
+ expect(2);
+
+ geolib.setDistanceFormula('haversine');
+
+ var distance1 = geolib.getDistance({latitude: 52.518611, longitude: 13.408056}, {latitude: 51.519475, longitude: 7.46694444});
+ var distance2 = geolib.getDistance({latitude: 37.774514, longitude: -122.418079}, {latitude: 51.519475, longitude: 7.46694444});
+
+ equal(distance1, 421786.46369863, "Distance 1 should be 421786.46369863" );
+ equal(distance2, 8967171.799418671, "Distance 2 should be 8967171.799418671" );
+
+ });
+
+ test("Testing grade with haversine: getGrade()", function() {
+ expect(2);
+ var coords1 = [{"lat":41.72977,"lng":-111.77621999999997,"elev":1702.72412109375},
+ {"lat":41.73198,"lng":-111.77636999999999,"elev":1849.7333984375}];
+ var coords2 = [{"lat":40.75402,"lng":-111.75475,"elev":2209.137451171875},
+ {"lat":40.76481,"lng":-111.76778999999999,"elev":1660.49609375}];
+
+ var grade = geolib.getGrade(coords1, 1);
+ equal(grade, 59.6, "grade should be 59.6");
+
+ grade = geolib.getGrade(coords2, 0);
+ equal(grade, -34, "grade should be -34");
+ });
+
+ test("Testing with haversine: findNearest()", function() {
+
+ expect(4);
+ var near1 = geolib.findNearest({latitude: 36.1168, longitude: -115.173798}, cities);
+
+ equal(near1.key, 'San Francisco', 'Nearest city to Las Vegas from predefined set should be San Francisco');
+ equal(near1.distance, 670193.90912238, 'Distance should be 670193.90912238');
+ equal(near1.latitude, 37.774514, 'Latitude should be 37.774514');
+ equal(near1.longitude, -122.418079, 'Latitude should be -122.418079');
+
+ });
+
+ test("Testing with haversine: getPathLength()", function() {
+
+ var pathLength = geolib.getPathLength(polygon);
+ equal(pathLength, 3372.85519878, 'Path length should be 3372.85519878');
+
+ });
Something went wrong with that request. Please try again.