在LBS(基于位置服务)的一些应用中,有时我们会需要计算两个用户或两个坐标点之间的距离。要解决这类问题,就要了解空间几何的概念并结合数学中在三角函数公式计算两点之间的值。本文介绍基于经度/纬度的,两个坐标点之间的距离计算,与 JavaScript 的实现代码。
一、解决思路
问题:已知两个GPS坐标点A和B,其坐标值分别为(φ1, λ1)和(φ2, λ2)(φ表示纬度,λ表示经度),计算两个坐标点之间的直线距离。
解决这个问题时,我们可以将经度想象成平面几何中的x轴,将纬度想象成平面几何中的y轴。并利用这两个点,构造出一个∠C=90°的直角三角型,如下所示:
在这个三角型中,我们可以根据坐标点A和B计算出坐标点C的坐标为(φ2, λ1),并可以坐标点A和B的经/纬度计算出边a和边b的距离。
经过这一系列的推导和计算,坐标点之间的距离计算,已经转换为利用三角函数计算勾股值的问题。
二、计算公式
根据上面的问题分析,在这个计算中,我们应该包括以下推导过程:
经纬度转换为10进制
在 GPS 坐中,使用度/分/秒的形式表示,我们首先应该将其转换为10进制表示。如,点A坐标为(北纬39°54'27",东经116°23'17"),可以将其表示为 (39.5427, 116.2317)。
经纬度转换为弧度
三角函数中使用弧度值进行计算,还需要将经纬度转换为弧度。转换公式为 N*PI/180,如将点 A 的纬度值 39.5427 转换为弧度 39.5427*PI/180(PI为圆周率)。A/B 两点的经/纬度转为弧度后分别用 φA、λA、φB、λB。
计算边a和边b的弦度
利用纬度差,我们可得到边a的弧度 Δa;利用经度差,我们可得到边b的弧度 Δb(计算时注意取绝对值)。
计算边两点间的正弦值和余弦值
计算出以上一系列变量后,计算出半正矢值a,其计算公式为 sin²(Δa/2)+cos(φA)*cos(φA)*sin²(Δb/2)。
计算边正切值
c = 2*atan2(√a, √(1−a))
返回距离
d = R*c(R表示地球半径)
三、代码实现
综上所述,JavaScript实现计算两个坐标点之间的距离方法如下:
- function getDistance(lat1, lon1, lat2, lon2) {
- var R = 6378137; // 地球长半径
- var φ1 = toRadians(lat1);
- var φ2 = toRadians(lat2);
- var Δφ = toRadians(lat2-lat1);
- var Δλ = toRadians(lon2-lon1);
- 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;
- // 转为弧度
- function toRadians(d) {
- return d * Math.PI / 180;
- }
- }
或者,我们可以写成更易读的方式:
- // 计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度
- function getDistance( lat1, lng1, lat2, lng2){
- var radLat1 = lat1*Math.PI / 180.0;
- var radLat2 = lat2*Math.PI / 180.0;
- var a = radLat1 - radLat2;
- var b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
- var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
- Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
- s = s *6378.137 ; // EARTH_RADIUS 赤道半径
- s = Math.round(s * 10000) / 10000; // 输出为KM
- // s = s.toFixed(4); // 保留4位小数点
- return s;
- }
使用这个公式计算坐标点(北纬39°54'00",东经116°23'00")与坐标点(北纬38°38'00",东经115°48'00")之间的距离:
- getDistance(39.54, 116.23, 38.85, 115.48) // 100.4307
博主只是一名前端的小白,只是把自己用到的知识分享一下,要是有什么不对的地方,欢迎大家提出~~
评论