使用地理位置api cordova / phonegap查找距离,速度和加速度 [英] Find distance , speed and acceleration using geolocation api cordova/phonegap

查看:254
本文介绍了使用地理位置api cordova / phonegap查找距离,速度和加速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开发一个使用cordova / phonegap的移动应用程序,它将查找距离,avg。特定的固定时间帧的速度和加速度,例如20秒。由用户提供。

我已经读过phonegap的地理位置或加速度计api可以在那里使用,但我很困惑,无法理解要使用哪种公式或方法,如何计算这些值?



请帮助我实现此功能。

解决方案

此页面底部的Javascript库真的是真的对于使用纬度/经度坐标非常有用。它允许您轻松计算点之间的距离,从而计算速度,加速度等。然后,使用Phonegap地理定位API,您可以执行下面的操作: / p>

  var currentUpdate,lastUpdate; 

函数onPositionUpdate(position){
if(currentUpdate)lastUpdate = currentUpdate;

currentUpdate = {
position:new LatLon(position.coords.latitude,position.coords.longitude),
time:new Date()
};

if(!lastUpdate)return;

currentUpdate.deltaDistMetres = lastUpdate.position.distanceTo(currentUpdate.position)* 1000;
currentUpdate.deltaTimeSecs =(currentUpdate.time - lastUpdate.time)* 1000;
currentUpdate.speed =(currentUpdate.deltaDistMetres / currentUpdate.deltaTimeSecs);
currentUpdate.accelerationGPS =(currentUpdate.speed - lastUpdate.speed)/ currentUpdate.deltaTimeSecs;

console.log(Distance moved:+ currentUpdate.deltaDistMetres +m; Avg speed:+ currentUpdate.speed +m / s; Acceleration:+ currentUpdate.accelerationGPS +m / s / S);



函数onPositionError(error){
console.log(Error:+ error.message);

$ b $(document).on(deviceready,function(){
navigator.geolocation.watchPosition(onPositionUpdate,onPositionError,{timeout:30000,enableHighAccuracy:true });
});


$ b / * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
/ *纬度/经度球形大地测量公式&脚本(c)Chris Veness 2002-2012 * /
/ * - www.movable-type.co.uk/scripts/latlong.html * /
/ * * /
/ *样本用法:* /
/ * var p1 =新LatLon(51.5136,-0.0983); * /
/ * var p2 =新LatLon(51.4778,-0.0015); * /
/ * var dist = p1.distanceTo(p2); // in km * /
/ * var brng = p1.bearingTo(p2); //以度数顺时针从北* /
/ * ...等* /
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /

/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
/ *请注意,在此执行最小错误检查示例代码! * /
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /


/ **
*对象LatLon:用于大地测量计算的工具
*
* @requires Geo
* /


/ **
*在提供的纬度/经度
*
* @constructor $ b处创建一个点在地球表面上$ b * @param {Number} lat:以度为单位的纬度
* @param {Number} lon:以度为单位的经度
* @param {数字} [半径= 6371]标准6,371km
* /
函数LatLon(lat,lon,radius){
if(typeof(radius)=='undefined')radius = 6371; //地球的平均半径以公里为单位

this.lat = Number(lat);
this.lon = Number(lon);
this.radius =数字(半径);
}


/ **
*返回从此点到提供点的距离,单位为公里
*(使用Haversine公式)
*
*:Haversine公式 - RW Sinnott,Haversine的美德,
* Sky and Telescope,vol 68,no 2,1984
*
* @这个{LatLon}原点的纬度/经度
* @param {LatLon}点:目标点的纬度/经度
* @param {Number} [precision = 4]:使用的有效数字位数返回值
* @returns {Number}此点与目标点之间的距离(单位为km)
* /
LatLon.prototype.distanceTo =函数(point,precision){
/ / default 4 sig figs反映了典型的0.3%精度的球形模型
if(typeof precision =='undefined')precision = 4;

var R = this.radius;
varφ1= this.lat.toRadians(),λ1= this.lon.toRadians();
varφ2= point.lat.toRadians(),λ2= point.lon.toRadians();
varΔφ=φ2 - φ1;
varΔλ=λ2 - λ1;

var a = Math.sin(Δφ/ 2)* Math.sin(Δφ/ 2)+
Math.cos(φ1)* Math.cos(φ2)*
Math.sin(Δλ/ 2)* Math.sin(Δλ/ 2);
var c = 2 * Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
var d = R * c;

return d.toPrecisionFixed(Number(precision));
}


/ **
*返回从这一点到提供点的(初始)方位,单位为度b $ b *见http:/ /williams.best.vwh.net/avform.htm#Crs
*
* @this {LatLon}原点的纬度/经度
* @param {LatLon}点:纬度/经度的目标点
* @returns {Number}以北美为单位的初始方位角度b $ b * /
LatLon.prototype.bearingTo =函数(点){
varφ1= this.lat .toRadians(),φ2= point.lat.toRadians();
varΔλ=(point.lon-this.lon).toRadians();

var y = Math.sin(Δλ)* Math.cos(φ2);
var x = Math.cos(φ1)* Math.sin(φ2) -
Math.sin(φ1)* Math.cos(φ2)* Math.cos(Δλ);
varθ= Math.atan2(y,x);

return(θ.toDegrees()+ 360)%360;
}


/ **
*从这一点返回到达提供目的点的最终方位;最终的轴承
*将根据距离和纬度的不同而与初始轴承不同程度地变化
*
* @this {LatLon}原点的纬度/经度
* @param {LatLon}点:目标点的纬度/经度
* @returns {Number}以北美为单位的最终方位角(以度为单位)b $ b * /
LatLon.prototype.finalBearingTo = function(point){
//获得提供点的初始轴承回到这个点...
varφ1= point.lat.toRadians(),φ2= this.lat.toRadians();
varΔλ=(this.lon-point.lon).toRadians();

var y = Math.sin(Δλ)* Math.cos(φ2);
var x = Math.cos(φ1)* Math.sin(φ2) -
Math.sin(φ1)* Math.cos(φ2)* Math.cos(Δλ);
varθ= Math.atan2(y,x);

// ...&通过增加180°
回报(θ.toDegrees()+ 180)%360来逆转它;
}


/ **
*返回此点与提供点之间的中点。
*参见http://mathforum.org/library/drmath/view/51822.html衍生
*
* @this {LatLon}原点纬度/经度
* @param {LatLon}点:目标点的经度/纬度
* @returns {LatLon}此点与提供的点之间的中点
* /
LatLon.prototype.midpointTo = function(点){
varφ1= this.lat.toRadians(),λ1= this.lon.toRadians();
varφ2= point.lat.toRadians();
varΔλ=(point.lon-this.lon).toRadians();

var Bx = Math.cos(φ2)* Math.cos(Δλ);
var By = Math.cos(φ2)* Math.sin(Δλ); (Math.cos(φ1)+ Bx)*(数学公式(φ1)+ Math.sin(φ2),
) .cos(φ1)+ Bx)+ By * By));
varλ3=λ1+ Math.atan2(By,Math.cos(φ1)+ Bx);
λ3=(λ3+ 3 * Math.PI)%(2 * Math.PI) - Math.PI; // normalize to -180 .. +180º

返回新的LatLon(φ3.toDegrees(),λ3.toDegrees());
}


/ **
*从给定距离(以km计)在给定初始值的
*上返回目的点轴承(轴承可能在到达目的地之前有所不同)
*
*请参阅http://williams.best.vwh.net/avform.htm#LL
*
* @this {LatLon}原点经度/纬度
* @param {Number} brng:以度为单位的初始方位
* @param {数字} dist:以km为单位的距离
* @returns {LatLon}目标点
* /
LatLon.prototype.destinationPoint =函数(brng,dist){
varθ= Number(brng).toRadians();
varδ= Number(dist)/ this.radius; //以弧度表示的角距离

varφ1= this.lat.toRadians();
varλ1= this.lon.toRadians();

varφ2= Math.asin(Math.sin(φ1)* Math.cos(δ)+
Math.cos(φ1)* Math.sin(δ)* Math.cos (θ));
varλ2=λ1+ Math.atan2(Math.sin(θ)* Math.sin(δ)* Math.cos(φ1),
Math.cos(δ)-Math.sin(φ1 )* Math.sin(φ2));
λ2=(λ2+ 3 * Math.PI)%(2 * Math.PI) - Math.PI; // normalize to -180 .. +180º

返回新的LatLon(φ2.toDegrees(),λ2.toDegrees());
}


/ **
*返回由点和轴承定义的两条路径的交点
*
*参见http ://williams.best.vwh.net/avform.htm#Intersection
*
* @param {LatLon} p1:第一点
* @param {Number} brng1:初始方位第一点
* @param {LatLon} p2:第二点
* @param {Number} brng2:第二点的初始方位
* @returns {LatLon}目标点(如果没有唯一的交点定义)
* /
LatLon.intersection =函数(p1,brng1,p2,brng2){
varφ1= p1.lat.toRadians(),λ1= p1.lon.toRadians ();
varφ2= p2.lat.toRadians(),λ2= p2.lon.toRadians();
varθ13= Number(brng1).toRadians(),θ23= Number(brng2).toRadians();
varΔφ=φ2-φ1,Δλ=λ2-λ1;

varδ12= 2 * Math.asin(Math.sqrt(Math.sin(Δφ/ 2)* Math.sin(Δφ/ 2)+
Math.cos(φ1)* Math.cos(φ2)* Math.sin(Δλ/ 2)* Math.sin(Δλ/ 2)));
if(δ12== 0)返回null;

//点之间的初始/最终轴承
varθ1= Math.acos((Math.sin(φ2) - Math.sin(φ1)* Math.cos(δ12))/
(Math.sin(δ12)* Math.cos(φ1)));
if(isNaN(θ1))θ1= 0; (Math.sin(φ1) - Math.sin(φ2)* Math.cos(δ12))/
(Math.sin(δ12))//避免四舍五入
varθ2= Math.acos * Math.cos(φ2)));

if(Math.sin(λ2-λ1)> 0){
θ12=θ1;
θ21= 2 * Math.PI - θ2;
} else {
θ12= 2 * Math.PI - θ1;
θ21=θ2;
}

varα1=(θ13 - θ12+ Math.PI)%(2 * Math.PI) - Math.PI; //角度2-1-3
varα2=(θ21 - θ23+ Math.PI)%(2 * Math.PI) - Math.PI; //角度1-2-3

if(Math.sin(α1)== 0&& Math'sin(α2)== 0)return null; //无限交点
if(Math.sin(α1)* Math.sin(α2)<0)返回null; //模糊交点

//α1= Math.abs(α1);
//α2= Math.abs(α2);
// ...艾德威廉姆斯吸收α1/α2的绝对值,但似乎打破计算?

varα3= Math.acos(-Math.cos(α1)* Math.cos(α2)+
Math.sin(α1)* Math.sin(α2)* Math。 cos(δ12));
varδ13= Math.atan2(Math.sin(δ12)* Math.sin(α1)* Math.sin(α2),
Math.cos(α2)+ Math.cos(α1)* Math.cos(α3))
varφ3= Math.asin(Math.sin(φ1)* Math.cos(δ13)+
Math.cos(φ1)* Math.sin(δ13)* Math.cos(θ13)); (b13)* Math.scos(δ13)* Math.scos Math.sin(φ3));
varλ3=λ1+Δλ13;
λ3=(λ3+ 3 * Math.PI)%(2 * Math.PI) - Math.PI; // normalize to -180 .. +180º

返回新的LatLon(φ3.toDegrees(),λ3.toDegrees());
}


/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /

/ **
*返回从该点到提供点的距离,单位为km, a rhumb line
*
*参见http://williams.best.vwh.net/avform.htm#Rhumb
*
* @this {LatLon}纬度/经度起点
* @param {LatLon}点:目标点的纬度/经度
* @returns {数字}此点与目的地点之间的距离(单位:公里)
* /
LatLon .prototype.rhumbDistanceTo = function(point){
var R = this.radius;
varφ1= this.lat.toRadians(),φ2= point.lat.toRadians();
varΔφ=φ2 - φ1;
varΔλ= Math.abs(point.lon-this.lon).toRadians();
//如果超过180°的dLon在反子午线上取较短的曲线:
if(Math.abs(Δλ)> Math.PI)Δλ=Δλ> 0 - (2 * Math.PI-Δλ):(2 * Math.PI +Δλ);

//在墨卡托投影上,经度因纬度而增加; q是'伸展因子'

varΔψ= Math.log(Math.tan(φ2/ 2 + Math.PI / 4)/Math.tan(φ1/ 2 + Math.PI / 4 ));

//伸展因子沿着E-W线(0/0)变得病态。使用经验公差来避免它
var q = Math.abs(Δψ)> 10e-12? Δφ/Δψ:Math.cos(φ1);

//距离是延伸的pythagoras墨卡托投影
varδ= Math.sqrt(Δφ*Δφ+ q * q *Δλ*Δλ); //以弧度表示的角距离
var dist =δ* R;

return dist.toPrecisionFixed(4); // 4 sig figs反映了典型的0.3%精确度的球形模型
}


/ **
*返回从这一点到提供点的方位沿a rhumb线,以度为单位
*
* @this {LatLon}原始点的纬度/经度
* @param {LatLon}点:目标点的经度/经度
* @返回{Number}以北美
* /
为单位的轴承度数,LatLon.prototype.rhumbBearingTo =函数(点){
varφ1= this.lat.toRadians(),φ2= point.lat .toRadians();
varΔλ=(point.lon-this.lon).toRadians();
//如果超过180°的dLon在反子午线上取较短的曲线:
if(Math.abs(Δλ)> Math.PI)Δλ=Δλ> 0 - (2 * Math.PI-Δλ):(2 * Math.PI +Δλ);

varΔψ= Math.log(Math.tan(φ2/ 2 + Math.PI / 4)/Math.tan(φ1/ 2 + Math.PI / 4));

varθ= Math.atan2(Δλ,Δψ);

return(θ.toDegrees()+ 360)%360;
}


/ **
*返回从给定距离(以km计)到达给定距离沿着一条斜线
*
* @this {LatLon}原点的纬度/经度
* @param {Number} brng:以北美为单位的度数b $ b * @param {数量} dist:以km为单位的距离
* @returns {LatLon}目标点
* /
LatLon.prototype.rhumbDestinationPoint =函数(brng,dist){
varδ= Number (dist)/ this.radius; //以弧度表示的角距离
varφ1= this.lat.toRadians(),λ1= this.lon.toRadians();
varθ= Number(brng).toRadians();

varΔφ=δ* Math.cos(θ);

varφ2=φ1+Δφ;
//检查是否有某个笨拙的bug子手通过极点,如果是这样,则标准化纬度
if(Math.abs(φ2)> Math.PI / 2)φ2=φ2> 0? Math.PI-φ2:-Math.PI-φ2;

varΔψ= Math.log(Math.tan(φ2/ 2 + Math.PI / 4)/Math.tan(φ1/ 2 + Math.PI / 4));
var q = Math.abs(Δψ)> 10e-12? Δφ/Δψ:Math.cos(φ1); // E-W当然会因为0/0

varΔλ=δ* Math.sin(θ)/ q;

varλ2=λ1+Δλ;

λ2=(λ2+ 3 * Math.PI)%(2 * Math.PI) - Math.PI; // normalize to -180 .. +180º

返回新的LatLon(φ2.toDegrees(),λ2.toDegrees());
}


/ **
*返回此点与提供点之间的右旋中点(沿着斜线)。
*见http://mathforum.org/kb/message.jspa?messageID=148837
*
* @this {LatLon}原点经度/纬度
* @ param {LatLon}点:目标点的经度/纬度
* @returns {LatLon}此点与提供点之间的中点
* /
LatLon.prototype.rhumbMidpointTo =函数(点) {
varφ1= this.lat.toRadians(),λ1= this.lon.toRadians();
varφ2= point.lat.toRadians(),λ2= point.lon.toRadians(); (Math.abs(λ2-λ1)> Math.PI)λ1+ = 2 * Math.PI; //穿过反子午线

varφ3=(φ1+φ2)/ 2;
var f1 = Math.tan(Math.PI / 4 +φ1/ 2);
var f2 = Math.tan(Math.PI / 4 +φ2/ 2);
var f3 = Math.tan(Math.PI / 4 +φ3/ 2); (数学公式(f2)-λ2* Math.log(f1))/ Math.log(f2 / f1);如果(!isFinite(λ3))λ3=(λ1+λ2)/ 2,则

; //纬度平行

λ3=(λ3+ 3 * Math.PI)%(2 * Math.PI) - Math.PI; // normalize to -180 .. +180º

返回新的LatLon(φ3.toDegrees(),λ3.toDegrees());
}


/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /


/ **
*返回此点的字符串表示形式;格式和dp根据lat()/ lon()
*
* @this {LatLon}原点的纬度/经度
* @param {字符串} [格式]:返回值为'd','dm','dms'
* @param {Number} [dp = 0 | 2 | 4]:显示的小数位数
* @returns {String}逗号分隔纬度/经度
* /
LatLon.prototype.toString = function(format,dp){
if(typeof format =='undefined')format ='dms';

返回Geo.toLat(this.lat,format,dp)+','+ Geo.toLon(this.lon,format,dp);
}


/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /


// - 扩展数字对象,方法转换度/弧度

$ b $ **将数值度数转换为弧度* /
if(typeof Number.prototype.toRadians =='undefined'){
Number.prototype.toRadians = function() {
返回这个* Math.PI / 180;



$ b $ **将弧度转换为数字(带符号)度* /
if(typeof Number.prototype.toDegrees =='未定义'){
Number.prototype.toDegrees = function(){
return this * 180 / Math.PI;
}
}


/ **
*仅使用定点表示法(无指数)格式化数字的有效数字
*
* @param {Number} precision:在返回字符串中出现的有效数字位数
* @returns {String}包含精度有效数字的字符串表示形式
* /
if(typeof Number.prototype.toPrecisionFixed =='undefined'){
Number.prototype.toPrecisionFixed = function(precision){

//使用标准toPrecision方法
var n = this.toPrecision(precision);

// ...但用尾部零代替+ ve指数格式
n = n.replace(/(.+)e \ +(。+)/,function(n, sig,exp){
sig = sig.replace(/\./,''); //从有效数字中删除小数
l = sig.length - 1;
while(exp- - > l)sig = sig +'0'; //从指数
返回sig;
});

// ...并替换-ve指数格式,前导零
n = n.replace(/(.+)e - (。+)/,function(n,sig, exp){
sig = sig.replace(/\./,''); //从有效数字中删除小数
while(exp--> 1)sig ='0'+ sig; //预先从指数中取零
返回'0.'+ sig;
});

return n;



$ b $ **从字符串中删除空格(qv blog.stevenlevithan.com/archives/faster-trim-javascript)* / $ b $ (typeof String.prototype.trim =='undefined'){
String.prototype.trim = function(){
return String(this).replace(/ ^ \s\s * /,'').replace(/ \s\s * $ /,'');
}
}


/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
if(!window.console)window.console = {log:function(){}};
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /
/ *大地测量转换函数(c)Chris Veness 2002-2012 * /
/ * - www.movable-type.co.uk/scripts/latlong.html * /
/ * * /
/ *示例用法:* /
/ * var lat = Geo.parseDMS('51°28'40.12'N'); * /
/ * var lon = Geo.parseDMS('000°00'05.31W'); * /
/ * var p1 =新LatLon(lat,lon); * /
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * /


var Geo = {}; // Geo命名空间,表示静态类

$ b $ ** ** b $ b *将表示度/分/秒的字符串解析为数字度
*
*在格式上非常灵活,允许带符号的十进制度数或deg-min-sec(可选)
*后接指南针方向(NSEW)。可接受多种分隔符(例如3º37'09W)
*或不带分隔符的固定宽度格式(例如0033709W),可省略秒和分钟
*(注意最小验证完成)。
*
* @param {String | Number} dmsStr:各种格式的度或度/分/秒
* @returns {数字}度作为十进制数
* @throws {TypeError} dmsStr是一个对象,也许DOM对象没有.value?
* /
Geo.parseDMS = function(dmsStr){
if(typeof deg =='object' )throw new TypeError('Geo.parseDMS - dmsStr is [DOM?] object');

//检查没有NSEW的带符号的十进制度数,如果是的话直接返回
if(typeof dmsStr ==='number'&&& isFinite(dmsStr))return Number(dmsStr);

//剥离任何符号或指南针dir'n& split split out d / m / s / b $ b var dms = String(dmsStr).trim()。replace(/ ^ - /,'')。replace(/ [NSEW] $ / i,'')。split(/ [^ 0-9 。,] + /);
if(dms [dms.length-1] =='')d ms.splice(dms.length-1); //尾随符号

if(dms =='')return NaN;

//并转换为十进制度...
switch(dms.length){
case 3://将三部分结果解释为d / m / s
var deg = dms [0] / 1 + dms [1] / 60 + dms [2] / 3600;
休息;
案例2://将两部分结果解释为d / m
var deg = dms [0] / 1 + dms [1] / 60;
休息;
案例1://只是d(可能是十进制)或不可分隔dddmmss
var deg = dms [0];
//检查固定宽度的未分离格式,例如0033709W
// if(/[NS]/i.test(dmsStr))deg ='0'+ deg; // - 将N / S标准化为3位数度数
// if(/[0-9]{7}/.test(deg))deg = deg.slice(0,3)/ 1 + deg .slice(3,5)/ 60 + deg.slice(5)/ 3600;
休息;
默认值:
返回NaN; $(

if(/ ^ - | [WS] $ / i.test(dmsStr.trim()))deg = -deg; //将' - ',西部和南部作为-ve
返回Number(deg);


$ b / **
*将十进制度转换为deg / min / sec格式
* - 度,素数,双素数符号虽然没有指南针
*方向被添加,但是标志被丢弃了
*
* @private
* @param {数字} deg:度
* @param {String} [format = dms]:返回值为'd','dm','dms'
* @param {Number} [dp = 0 | 2 | 4]默认0为dms,2为dm,4为d
* @returns {String} deg按照指定格式以deg / min / secs格式化
* @throws {TypeError} deg是一个对象,也许没有.value的DOM对象?
* /
Geo.toDMS =函数(deg,format,dp){
if(typeof deg =='object')throw new TypeError('Geo.toDMS - deg is [DOM ?] object');
if(isNaN(deg))返回null; //如果我们不能从deg

// //默认值
创建一个数字,就放弃这里if(typeof format =='undefined')format ='dms';
if(typeof dp =='undefined'){
switch(format){
case'd':dp = 4;打破;
案例'dm':dp = 2;打破;
案例'dms':dp = 0;打破;
default:format ='dms'; dp = 0; //以无效格式宽恕
}
}

deg = Math.abs(deg); //(无符号结果准备添加指南针dir'n)

switch(格式){
case'd':
d = deg.toFixed(dp); //圆度
if(d <100)d ='0'+ d; //填充前导零
if(d <10)d ='0'+ d;
dms = d +'\\\°'; //添加符号
break;
case'dm':
var min =(deg * 60).toFixed(dp); //将度数转换为分钟&整数
var d = Math.floor(min / 60); //获得组件deg / min
var m =(min%60).toFixed(dp); //填充尾随零
if(d <100)d ='0'+ d; //填充前导零
if(d <10)d ='0'+ d; $ m $ b如果(m <10)m ='0'+ m;
dms = d +'\\\°'+ m +'\\\′'; //添加º,'符号
break;
case'dms':
var sec =(deg * 3600).toFixed(dp); //将度数转换为秒数&整数
var d = Math.floor(秒/ 3600); //获得组分deg / min / sec
var m = Math.floor(sec / 60)%60;
var s =(sec%60).toFixed(dp); //填充尾随零
if(d <100)d ='0'+ d; //填充前导零
if(d <10)d ='0'+ d; $ m $ b如果(m <10)m ='0'+ m;
if(s <10)s ='0'+ s;
dms = d +'\\\°'+ m +'\\\′'+ s +'\\\″'; //添加º,','符号
break;
}

返回dms;
}


/ * *
*将数值转换为deg / min / sec纬度(后缀为N / S)
*
* @param {数字} deg:度数
* @param {String } [format = dms]:返回值为'd','dm','dms'
* @param {Number} [dp = 0 | 2 | 4]:小数位数要使用 - 默认为0 dm,2为dm,4为d
* @returns {String} Deg / min / seconds
* /
Geo.toLat =函数(deg,format,dp){
var lat = Geo.toDMS(deg,format,dp);
return lat == null?' - ':lat.slice(1)+(deg <0?'S':'N') ; //将初始值'0'删除!
}


/ **
*将数字度数转换为度/分/秒经度(后缀为E / W)
*
* @param {数字} deg:度数
* @param {String} [format = dms]:返回值为'd','dm',' dms'
* @param {数字} [dp = 0 | 2 | 4]:不使用小数位数 - 默认0 f或dms,2为dm,4为d
* @returns {字符串}度/分钟/秒
* /
Geo.toLon =函数(deg,格式,dp){
var lon = Geo.toDMS(deg,format,dp);
返回lon == null? ' - ':lon +(deg <0?W':'E');


$ b / **
*将数值度转换为deg / min / sec(0º..360º)
*
* @param {Number} deg:度数
* @param {String} [format = dms]:返回值为'd','dm','dms'
* @param {数字} [dp = 0 | 2 | 4]:没有小数位要使用 - 默认为0,dm为2,d为4,d为
* @returns {字符串}度/分钟/秒
* /
Geo.toBrng =函数(deg,format,dp){
deg =(Number(deg)+360)%360; // normalize -ve数值为180º..360º
var brng = Geo.toDMS(deg,format,dp);
返回brng == null? ' - ':brng.replace('360','0'); //为防止四舍五入将我们带到360º!
}


/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 如果(!window.console)window.console = {log:function(){}}; * /
if(!window.console) - - - - - - - - - -


I want to develop one mobile app using cordova/phonegap which will find distance traveled , avg. speed and acceleration for particular fixed time frame say 20 sec. provided by user.

I have read that geolocation or accelerometer api of phonegap can be used over there , but I am confused and unable to understand which formula or method to use and how to calculate those values?

Please help me to achieve this functionality.

解决方案

The Javascript library at the bottom of this page is really useful for working with lat/lon co-ordinates. It allows you to easily calculate distances between points and therefore to calculate speed, acceleration ,etc.

Then, using the Phonegap geolocation API, you can do something like this:

var currentUpdate, lastUpdate;

function onPositionUpdate(position){
    if(currentUpdate) lastUpdate = currentUpdate;

    currentUpdate = {
        position: new LatLon(position.coords.latitude, position.coords.longitude),
        time: new Date()
    };

    if(!lastUpdate) return;

    currentUpdate.deltaDistMetres = lastUpdate.position.distanceTo(currentUpdate.position)*1000;
    currentUpdate.deltaTimeSecs = (currentUpdate.time - lastUpdate.time)*1000;
    currentUpdate.speed = (currentUpdate.deltaDistMetres/currentUpdate.deltaTimeSecs);
    currentUpdate.accelerationGPS = (currentUpdate.speed - lastUpdate.speed) / currentUpdate.deltaTimeSecs;

    console.log("Distance moved: "+currentUpdate.deltaDistMetres+" m; Avg speed: "+currentUpdate.speed+" m/s; Acceleration: "+currentUpdate.accelerationGPS + "m/s/s");

}

function onPositionError(error){
    console.log("Error: "+error.message);
}

$(document).on("deviceready", function() {
    navigator.geolocation.watchPosition(onPositionUpdate, onPositionError, {timeout: 30000, enableHighAccuracy: true});    
});



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Latitude/longitude spherical geodesy formulae & scripts (c) Chris Veness 2002-2012            */
/*   - www.movable-type.co.uk/scripts/latlong.html                                                */
/*                                                                                                */
/*  Sample usage:                                                                                 */
/*    var p1 = new LatLon(51.5136, -0.0983);                                                      */
/*    var p2 = new LatLon(51.4778, -0.0015);                                                      */
/*    var dist = p1.distanceTo(p2);          // in km                                             */
/*    var brng = p1.bearingTo(p2);           // in degrees clockwise from north                   */
/*    ... etc                                                                                     */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Note that minimal error checking is performed in this example code!                           */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


/**
 * Object LatLon: tools for geodetic calculations
 *
 * @requires Geo
 */


/**
 * Creates a point on the earth's surface at the supplied latitude / longitude
 *
 * @constructor
 * @param {Number} lat: latitude in degrees
 * @param {Number} lon: longitude in degrees
 * @param {Number} [radius=6371]: radius of earth if different value is required from standard 6,371km
 */
function LatLon(lat, lon, radius) {
    if (typeof(radius) == 'undefined') radius = 6371;  // earth's mean radius in km

    this.lat    = Number(lat);
    this.lon    = Number(lon);
    this.radius = Number(radius);
}


/**
 * Returns the distance from this point to the supplied point, in km 
 * (using Haversine formula)
 *
 * from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine",
 *       Sky and Telescope, vol 68, no 2, 1984
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @param   {Number} [precision=4]: number of significant digits to use for returned value
 * @returns {Number} distance in km between this point and destination point
 */
LatLon.prototype.distanceTo = function(point, precision) {
    // default 4 sig figs reflects typical 0.3% accuracy of spherical model
    if (typeof precision == 'undefined') precision = 4;

    var R = this.radius;
    var φ1 = this.lat.toRadians(),  λ1 = this.lon.toRadians();
    var φ2 = point.lat.toRadians(), λ2 = point.lon.toRadians();
    var Δφ = φ2 - φ1;
    var Δλ = λ2 - λ1;

    var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ/2) * Math.sin(Δλ/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;

    return d.toPrecisionFixed(Number(precision));
}


/**
 * Returns the (initial) bearing from this point to the supplied point, in degrees
 *   see http://williams.best.vwh.net/avform.htm#Crs
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {Number} initial bearing in degrees from North
 */
LatLon.prototype.bearingTo = function(point) {
    var φ1 = this.lat.toRadians(), φ2 = point.lat.toRadians();
    var Δλ = (point.lon-this.lon).toRadians();

    var y = Math.sin(Δλ) * Math.cos(φ2);
    var x = Math.cos(φ1)*Math.sin(φ2) -
            Math.sin(φ1)*Math.cos(φ2)*Math.cos(Δλ);
    var θ = Math.atan2(y, x);

    return (θ.toDegrees()+360) % 360;
}


/**
 * Returns final bearing arriving at supplied destination point from this point; the final bearing 
 * will differ from the initial bearing by varying degrees according to distance and latitude
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {Number} final bearing in degrees from North
 */
LatLon.prototype.finalBearingTo = function(point) {
    // get initial bearing from supplied point back to this point...
    var φ1 = point.lat.toRadians(), φ2 = this.lat.toRadians();
    var Δλ = (this.lon-point.lon).toRadians();

    var y = Math.sin(Δλ) * Math.cos(φ2);
    var x = Math.cos(φ1)*Math.sin(φ2) -
            Math.sin(φ1)*Math.cos(φ2)*Math.cos(Δλ);
    var θ = Math.atan2(y, x);

    // ... & reverse it by adding 180°
    return (θ.toDegrees()+180) % 360;
}


/**
 * Returns the midpoint between this point and the supplied point.
 *   see http://mathforum.org/library/drmath/view/51822.html for derivation
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {LatLon} midpoint between this point and the supplied point
 */
LatLon.prototype.midpointTo = function(point) {
    var φ1 = this.lat.toRadians(), λ1 = this.lon.toRadians();
    var φ2 = point.lat.toRadians();
    var Δλ = (point.lon-this.lon).toRadians();

    var Bx = Math.cos(φ2) * Math.cos(Δλ);
    var By = Math.cos(φ2) * Math.sin(Δλ);

    var φ3 = Math.atan2(Math.sin(φ1)+Math.sin(φ2),
                    Math.sqrt( (Math.cos(φ1)+Bx)*(Math.cos(φ1)+Bx) + By*By) );
    var λ3 = λ1 + Math.atan2(By, Math.cos(φ1) + Bx);
    λ3 = (λ3+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º

    return new LatLon(φ3.toDegrees(), λ3.toDegrees());
}


/**
 * Returns the destination point from this point having travelled the given distance (in km) on the 
 * given initial bearing (bearing may vary before destination is reached)
 *
 *   see http://williams.best.vwh.net/avform.htm#LL
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {Number} brng: initial bearing in degrees
 * @param   {Number} dist: distance in km
 * @returns {LatLon} destination point
 */
LatLon.prototype.destinationPoint = function(brng, dist) {
    var θ = Number(brng).toRadians();
    var δ = Number(dist) / this.radius; // angular distance in radians

    var φ1 = this.lat.toRadians();
    var λ1 = this.lon.toRadians();

    var φ2 = Math.asin( Math.sin(φ1)*Math.cos(δ) +
                        Math.cos(φ1)*Math.sin(δ)*Math.cos(θ) );
    var λ2 = λ1 + Math.atan2(Math.sin(θ)*Math.sin(δ)*Math.cos(φ1),
                             Math.cos(δ)-Math.sin(φ1)*Math.sin(φ2));
    λ2 = (λ2+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º

    return new LatLon(φ2.toDegrees(), λ2.toDegrees());
}


/**
 * Returns the point of intersection of two paths defined by point and bearing
 *
 *   see http://williams.best.vwh.net/avform.htm#Intersection
 *
 * @param   {LatLon} p1: first point
 * @param   {Number} brng1: initial bearing from first point
 * @param   {LatLon} p2: second point
 * @param   {Number} brng2: initial bearing from second point
 * @returns {LatLon} destination point (null if no unique intersection defined)
 */
LatLon.intersection = function(p1, brng1, p2, brng2) {
    var φ1 = p1.lat.toRadians(), λ1 = p1.lon.toRadians();
    var φ2 = p2.lat.toRadians(), λ2 = p2.lon.toRadians();
    var θ13 = Number(brng1).toRadians(), θ23 = Number(brng2).toRadians();
    var Δφ = φ2-φ1, Δλ = λ2-λ1;

    var δ12 = 2*Math.asin( Math.sqrt( Math.sin(Δφ/2)*Math.sin(Δφ/2) +
        Math.cos(φ1)*Math.cos(φ2)*Math.sin(Δλ/2)*Math.sin(Δλ/2) ) );
    if (δ12 == 0) return null;

    // initial/final bearings between points
    var θ1 = Math.acos( ( Math.sin(φ2) - Math.sin(φ1)*Math.cos(δ12) ) /
           ( Math.sin(δ12)*Math.cos(φ1) ) );
    if (isNaN(θ1)) θ1 = 0; // protect against rounding
    var θ2 = Math.acos( ( Math.sin(φ1) - Math.sin(φ2)*Math.cos(δ12) ) /
           ( Math.sin(δ12)*Math.cos(φ2) ) );

    if (Math.sin(λ2-λ1) > 0) {
        θ12 = θ1;
        θ21 = 2*Math.PI - θ2;
    } else {
        θ12 = 2*Math.PI - θ1;
        θ21 = θ2;
    }

    var α1 = (θ13 - θ12 + Math.PI) % (2*Math.PI) - Math.PI; // angle 2-1-3
    var α2 = (θ21 - θ23 + Math.PI) % (2*Math.PI) - Math.PI; // angle 1-2-3

    if (Math.sin(α1)==0 && Math.sin(α2)==0) return null; // infinite intersections
    if (Math.sin(α1)*Math.sin(α2) < 0) return null;      // ambiguous intersection

    //α1 = Math.abs(α1);
    //α2 = Math.abs(α2);
    // ... Ed Williams takes abs of α1/α2, but seems to break calculation?

    var α3 = Math.acos( -Math.cos(α1)*Math.cos(α2) +
                         Math.sin(α1)*Math.sin(α2)*Math.cos(δ12) );
    var δ13 = Math.atan2( Math.sin(δ12)*Math.sin(α1)*Math.sin(α2),
                          Math.cos(α2)+Math.cos(α1)*Math.cos(α3) )
    var φ3 = Math.asin( Math.sin(φ1)*Math.cos(δ13) +
                        Math.cos(φ1)*Math.sin(δ13)*Math.cos(θ13) );
    var Δλ13 = Math.atan2( Math.sin(θ13)*Math.sin(δ13)*Math.cos(φ1),
                           Math.cos(δ13)-Math.sin(φ1)*Math.sin(φ3) );
    var λ3 = λ1 + Δλ13;
    λ3 = (λ3+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º

    return new LatLon(φ3.toDegrees(), λ3.toDegrees());
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/**
 * Returns the distance from this point to the supplied point, in km, travelling along a rhumb line
 *
 *   see http://williams.best.vwh.net/avform.htm#Rhumb
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {Number} distance in km between this point and destination point
 */
LatLon.prototype.rhumbDistanceTo = function(point) {
    var R = this.radius;
    var φ1 = this.lat.toRadians(), φ2 = point.lat.toRadians();
    var Δφ = φ2 - φ1;
    var Δλ = Math.abs(point.lon-this.lon).toRadians();
    // if dLon over 180° take shorter rhumb line across the anti-meridian:
    if (Math.abs(Δλ) > Math.PI) Δλ = Δλ>0 ? -(2*Math.PI-Δλ) : (2*Math.PI+Δλ);

    // on Mercator projection, longitude gets increasing stretched by latitude; q is the 'stretch factor'

    var Δψ = Math.log(Math.tan(φ2/2+Math.PI/4)/Math.tan(φ1/2+Math.PI/4));

    // the stretch factor becomes ill-conditioned along E-W line (0/0); use empirical tolerance to avoid it
    var q = Math.abs(Δψ) > 10e-12 ? Δφ/Δψ : Math.cos(φ1);

    // distance is pythagoras on 'stretched' Mercator projection
    var δ = Math.sqrt(Δφ*Δφ + q*q*Δλ*Δλ); // angular distance in radians
    var dist = δ * R;

    return dist.toPrecisionFixed(4); // 4 sig figs reflects typical 0.3% accuracy of spherical model
}


/**
 * Returns the bearing from this point to the supplied point along a rhumb line, in degrees
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {Number} bearing in degrees from North
 */
LatLon.prototype.rhumbBearingTo = function(point) {
    var φ1 = this.lat.toRadians(), φ2 = point.lat.toRadians();
    var Δλ = (point.lon-this.lon).toRadians();
    // if dLon over 180° take shorter rhumb line across the anti-meridian:
    if (Math.abs(Δλ) > Math.PI) Δλ = Δλ>0 ? -(2*Math.PI-Δλ) : (2*Math.PI+Δλ);

    var Δψ = Math.log(Math.tan(φ2/2+Math.PI/4)/Math.tan(φ1/2+Math.PI/4));

    var θ = Math.atan2(Δλ, Δψ);

    return (θ.toDegrees()+360) % 360;
}


/**
 * Returns the destination point from this point having travelled the given distance (in km) on the 
 * given bearing along a rhumb line
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {Number} brng: bearing in degrees from North
 * @param   {Number} dist: distance in km
 * @returns {LatLon} destination point
 */
LatLon.prototype.rhumbDestinationPoint = function(brng, dist) {
    var δ = Number(dist) / this.radius; // angular distance in radians
    var φ1 = this.lat.toRadians(), λ1 = this.lon.toRadians();
    var θ = Number(brng).toRadians();

    var Δφ = δ * Math.cos(θ);

    var φ2 = φ1 + Δφ;
    // check for some daft bugger going past the pole, normalise latitude if so
    if (Math.abs(φ2) > Math.PI/2) φ2 = φ2>0 ? Math.PI-φ2 : -Math.PI-φ2;

    var Δψ = Math.log(Math.tan(φ2/2+Math.PI/4)/Math.tan(φ1/2+Math.PI/4));
    var q = Math.abs(Δψ) > 10e-12 ? Δφ / Δψ : Math.cos(φ1); // E-W course becomes ill-conditioned with 0/0

    var Δλ = δ*Math.sin(θ)/q;

    var λ2 = λ1 + Δλ;

    λ2 = (λ2 + 3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º

    return new LatLon(φ2.toDegrees(), λ2.toDegrees());
}


/**
 * Returns the loxodromic midpoint (along a rhumb line) between this point and the supplied point.
 *   see http://mathforum.org/kb/message.jspa?messageID=148837
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {LatLon} point: latitude/longitude of destination point
 * @returns {LatLon} midpoint between this point and the supplied point
 */
LatLon.prototype.rhumbMidpointTo = function(point) {
    var φ1 = this.lat.toRadians(), λ1 = this.lon.toRadians();
    var φ2 = point.lat.toRadians(), λ2 = point.lon.toRadians();

    if (Math.abs(λ2-λ1) > Math.PI) λ1 += 2*Math.PI; // crossing anti-meridian

    var φ3 = (φ1+φ2)/2;
    var f1 = Math.tan(Math.PI/4 + φ1/2);
    var f2 = Math.tan(Math.PI/4 + φ2/2);
    var f3 = Math.tan(Math.PI/4 + φ3/2);
    var λ3 = ( (λ2-λ1)*Math.log(f3) + λ1*Math.log(f2) - λ2*Math.log(f1) ) / Math.log(f2/f1);

    if (!isFinite(λ3)) λ3 = (λ1+λ2)/2; // parallel of latitude

    λ3 = (λ3 + 3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º

    return new LatLon(φ3.toDegrees(), λ3.toDegrees());
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


/**
 * Returns a string representation of this point; format and dp as per lat()/lon()
 *
 * @this    {LatLon} latitude/longitude of origin point
 * @param   {String} [format]: return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: number of decimal places to display
 * @returns {String} comma-separated latitude/longitude
 */
LatLon.prototype.toString = function(format, dp) {
    if (typeof format == 'undefined') format = 'dms';

    return Geo.toLat(this.lat, format, dp) + ', ' + Geo.toLon(this.lon, format, dp);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


// ---- extend Number object with methods for converting degrees/radians


/** Converts numeric degrees to radians */
if (typeof Number.prototype.toRadians == 'undefined') {
    Number.prototype.toRadians = function() {
        return this * Math.PI / 180;
    }
}


/** Converts radians to numeric (signed) degrees */
if (typeof Number.prototype.toDegrees == 'undefined') {
    Number.prototype.toDegrees = function() {
        return this * 180 / Math.PI;
    }
}


/** 
 * Formats the significant digits of a number, using only fixed-point notation (no exponential)
 * 
 * @param   {Number} precision: Number of significant digits to appear in the returned string
 * @returns {String} A string representation of number which contains precision significant digits
 */
if (typeof Number.prototype.toPrecisionFixed == 'undefined') {
    Number.prototype.toPrecisionFixed = function(precision) {

    // use standard toPrecision method
    var n = this.toPrecision(precision);

    // ... but replace +ve exponential format with trailing zeros
    n = n.replace(/(.+)e\+(.+)/, function(n, sig, exp) {
        sig = sig.replace(/\./, '');       // remove decimal from significand
        l = sig.length - 1;
        while (exp-- > l) sig = sig + '0'; // append zeros from exponent
        return sig;
    });

    // ... and replace -ve exponential format with leading zeros
    n = n.replace(/(.+)e-(.+)/, function(n, sig, exp) {
        sig = sig.replace(/\./, '');       // remove decimal from significand
        while (exp-- > 1) sig = '0' + sig; // prepend zeros from exponent
        return '0.' + sig;
    });

    return n;
  }
}


/** Trims whitespace from string (q.v. blog.stevenlevithan.com/archives/faster-trim-javascript) */
if (typeof String.prototype.trim == 'undefined') {
    String.prototype.trim = function() {
        return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    }
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
if (!window.console) window.console = { log: function() {} };
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Geodesy representation conversion functions (c) Chris Veness 2002-2012                        */
/*   - www.movable-type.co.uk/scripts/latlong.html                                                */
/*                                                                                                */
/*  Sample usage:                                                                                 */
/*    var lat = Geo.parseDMS('51° 28′ 40.12″ N');                                                 */
/*    var lon = Geo.parseDMS('000° 00′ 05.31″ W');                                                */
/*    var p1 = new LatLon(lat, lon);                                                              */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */


var Geo = {};  // Geo namespace, representing static class


/**
 * Parses string representing degrees/minutes/seconds into numeric degrees
 *
 * This is very flexible on formats, allowing signed decimal degrees, or deg-min-sec optionally
 * suffixed by compass direction (NSEW). A variety of separators are accepted (eg 3º 37' 09"W) 
 * or fixed-width format without separators (eg 0033709W). Seconds and minutes may be omitted. 
 * (Note minimal validation is done).
 *
 * @param   {String|Number} dmsStr: Degrees or deg/min/sec in variety of formats
 * @returns {Number} Degrees as decimal number
 * @throws  {TypeError} dmsStr is an object, perhaps DOM object without .value?
 */
Geo.parseDMS = function(dmsStr) {
  if (typeof deg == 'object') throw new TypeError('Geo.parseDMS - dmsStr is [DOM?] object');

  // check for signed decimal degrees without NSEW, if so return it directly
  if (typeof dmsStr === 'number' && isFinite(dmsStr)) return Number(dmsStr);

  // strip off any sign or compass dir'n & split out separate d/m/s
  var dms = String(dmsStr).trim().replace(/^-/,'').replace(/[NSEW]$/i,'').split(/[^0-9.,]+/);
  if (dms[dms.length-1]=='') dms.splice(dms.length-1);  // from trailing symbol

  if (dms == '') return NaN;

  // and convert to decimal degrees...
  switch (dms.length) {
    case 3:  // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; 
      break;
    case 2:  // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; 
      break;
    case 1:  // just d (possibly decimal) or non-separated dddmmss
      var deg = dms[0];
      // check for fixed-width unseparated format eg 0033709W
      //if (/[NS]/i.test(dmsStr)) deg = '0' + deg;  // - normalise N/S to 3-digit degrees
      //if (/[0-9]{7}/.test(deg)) deg = deg.slice(0,3)/1 + deg.slice(3,5)/60 + deg.slice(5)/3600; 
      break;
    default:
      return NaN;
  }
  if (/^-|[WS]$/i.test(dmsStr.trim())) deg = -deg; // take '-', west and south as -ve
  return Number(deg);
}


/**
 * Convert decimal degrees to deg/min/sec format
 *  - degree, prime, double-prime symbols are added, but sign is discarded, though no compass
 *    direction is added
 *
 * @private
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} deg formatted as deg/min/secs according to specified format
 * @throws  {TypeError} deg is an object, perhaps DOM object without .value?
 */
Geo.toDMS = function(deg, format, dp) {
  if (typeof deg == 'object') throw new TypeError('Geo.toDMS - deg is [DOM?] object');
  if (isNaN(deg)) return null;  // give up here if we can't make a number from deg

    // default values
  if (typeof format == 'undefined') format = 'dms';
  if (typeof dp == 'undefined') {
    switch (format) {
      case 'd': dp = 4; break;
      case 'dm': dp = 2; break;
      case 'dms': dp = 0; break;
      default: format = 'dms'; dp = 0;  // be forgiving on invalid format
    }
  }

  deg = Math.abs(deg);  // (unsigned result ready for appending compass dir'n)

  switch (format) {
    case 'd':
      d = deg.toFixed(dp);     // round degrees
      if (d<100) d = '0' + d;  // pad with leading zeros
      if (d<10) d = '0' + d;
      dms = d + '\u00B0';      // add º symbol
      break;
    case 'dm':
      var min = (deg*60).toFixed(dp);  // convert degrees to minutes & round
      var d = Math.floor(min / 60);    // get component deg/min
      var m = (min % 60).toFixed(dp);  // pad with trailing zeros
      if (d<100) d = '0' + d;          // pad with leading zeros
      if (d<10) d = '0' + d;
      if (m<10) m = '0' + m;
      dms = d + '\u00B0' + m + '\u2032';  // add º, ' symbols
      break;
    case 'dms':
      var sec = (deg*3600).toFixed(dp);  // convert degrees to seconds & round
      var d = Math.floor(sec / 3600);    // get component deg/min/sec
      var m = Math.floor(sec/60) % 60;
      var s = (sec % 60).toFixed(dp);    // pad with trailing zeros
      if (d<100) d = '0' + d;            // pad with leading zeros
      if (d<10) d = '0' + d;
      if (m<10) m = '0' + m;
      if (s<10) s = '0' + s;
      dms = d + '\u00B0' + m + '\u2032' + s + '\u2033';  // add º, ', " symbols
      break;
  }

  return dms;
}


/**
 * Convert numeric degrees to deg/min/sec latitude (suffixed with N/S)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toLat = function(deg, format, dp) {
  var lat = Geo.toDMS(deg, format, dp);
  return lat==null ? '–' : lat.slice(1) + (deg<0 ? 'S' : 'N');  // knock off initial '0' for lat!
}


/**
 * Convert numeric degrees to deg/min/sec longitude (suffixed with E/W)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toLon = function(deg, format, dp) {
  var lon = Geo.toDMS(deg, format, dp);
  return lon==null ? '–' : lon + (deg<0 ? 'W' : 'E');
}


/**
 * Convert numeric degrees to deg/min/sec as a bearing (0º..360º)
 *
 * @param   {Number} deg: Degrees
 * @param   {String} [format=dms]: Return value as 'd', 'dm', 'dms'
 * @param   {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
 * @returns {String} Deg/min/seconds
 */
Geo.toBrng = function(deg, format, dp) {
  deg = (Number(deg)+360) % 360;  // normalise -ve values to 180º..360º
  var brng =  Geo.toDMS(deg, format, dp);
  return brng==null ? '–' : brng.replace('360', '0');  // just in case rounding took us up to 360º!
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
if (!window.console) window.console = { log: function() {} };

这篇关于使用地理位置api cordova / phonegap查找距离,速度和加速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆