JavaScript 实现 GPS 坐标点距离计算

Admin
Admin
Admin
52
文章
6
评论
2019年1月3日21:39:35 评论 15,496 2078字阅读6分55秒

在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实现计算两个坐标点之间的距离方法如下:

  1. function  getDistance(lat1, lon1, lat2, lon2) {
  2.     var R = 6378137; // 地球长半径
  3.     var φ1 = toRadians(lat1);
  4.     var φ2 = toRadians(lat2);
  5.     var Δφ = toRadians(lat2-lat1);
  6.     var Δλ = toRadians(lon2-lon1);
  7.     var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
  8.             Math.cos(φ1) * Math.cos(φ2) *
  9.             Math.sin(Δλ/2) * Math.sin(Δλ/2);
  10.     var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  11.     var d = R * c;
  12.     return d;
  13.     // 转为弧度
  14.     function toRadians(d) {
  15.         return d * Math.PI / 180;
  16.     }
  17. }

或者,我们可以写成更易读的方式:

  1.  // 计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度 
  2. function getDistance( lat1,  lng1,  lat2,  lng2){
  3.     var radLat1 = lat1*Math.PI / 180.0;
  4.     var radLat2 = lat2*Math.PI / 180.0;
  5.     var a = radLat1 - radLat2;
  6.     var  b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
  7.     var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
  8.     Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
  9.     s = s *6378.137 ; // EARTH_RADIUS 赤道半径
  10.     s = Math.round(s * 10000) / 10000; //  输出为KM
  11.     // s = s.toFixed(4); // 保留4位小数点
  12.     return s;
  13. }

使用这个公式计算坐标点(北纬39°54'00",东经116°23'00")与坐标点(北纬38°38'00",东经115°48'00")之间的距离:

  1. getDistance(39.54, 116.23, 38.85, 115.48)   // 100.4307

博主只是一名前端的小白,只是把自己用到的知识分享一下,要是有什么不对的地方,欢迎大家提出~~

继续阅读
Admin
  • 本文由 发表于 2019年1月3日21:39:35
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
Vue 中计算属性和侦听器 前端开发

Vue 中计算属性和侦听器

在 Vue 中通常我们会在模板绑定表达式,模板是用来描述视图结构的。如果模板中的表达式存在过多的逻辑性语句,那么整个模板就会变得特别的臃肿,可读性和维护性将会降低,因此为了简化逻辑,我们可以使用计算属...
浅谈 JS 中的防抖和节流操作 前端开发

浅谈 JS 中的防抖和节流操作

一般在进行窗口的 resize、scroll 等输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用 debounce(防抖)和 thr...
JS中的「import」和「require 」的区别 前端开发

JS中的「import」和「require 」的区别

import 和 require 是 JS 模块化编程使用的,模块化是一种将系统分离成独立功能部分的方法,一个模块是为完成一个功能的一段程序或子程序,"模块"是系统中功能单一且可替换的部分。模块化思想...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: