Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Mods to elevation and async service #11

Closed
wants to merge 32 commits into from

6 participants

Greg Allan Manuel Bieh regality Chase Brammer Jessica Fred Christensen
Greg Allan

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.
Greg Allan

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

Greg Allan grobot closed this
Greg Allan grobot reopened this
Greg Allan

googleMaps updated. Looks better. Plz publish to npm.

you're great

Manuel Bieh
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.

Manuel Bieh 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. Greg Allan

    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. Greg Allan

    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. Greg Allan

    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. Greg Allan

    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. Greg Allan

    change dependency

    grobot authored
  2. Greg Allan

    herpderp

    grobot authored
Commits on Oct 18, 2012
  1. Chase Brammer

    updating npm

    cbrammer authored
Commits on Oct 19, 2012
  1. Chase Brammer

    bundled

    cbrammer authored
  2. Jessica

    Update package.json

    jduh authored
  3. Chase Brammer
  4. Chase Brammer
  5. Chase Brammer

    Merge branch 'npmsucks'

    cbrammer authored
Commits on Oct 21, 2012
  1. Chase Brammer

    fixing git ignore

    cbrammer authored
Commits on Nov 14, 2012
  1. Greg Allan
  2. Greg Allan
Commits on Dec 17, 2013
  1. Greg Allan

    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. Greg Allan
  3. Greg Allan
  4. Greg Allan
  5. Greg Allan

    adds back in test I removed

    grobot authored
  6. Greg Allan

    hur

    grobot authored
  7. Greg Allan

    setting default to haversine

    grobot authored
  8. Greg Allan

    uses accuracy in the right way

    grobot authored
Commits on Dec 31, 2013
  1. Fred Christensen

    Merge pull request #1 from ifit/haversine

    freddyC authored
    Haversine for getDistance
This page is out of date. Refresh to see the latest.
33 .gitignore
View
@@ -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
244 geolib.js 100644 → 100755
View
@@ -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.');
}
},
15 geolib.min.js
View
@@ -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
72 package.json
View
@@ -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": "*"
+ }
}
4 tests/geolib.test.html
View
@@ -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>
61 tests/geolib.test.js
View
@@ -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.