在Javascript中使用Haversine公式

IT技术 javascript haversine
2021-01-20 08:57:17

我正在尝试使用Haversine距离公式(如在此处找到:http : //www.movable-type.co.uk/scripts/latlong.html)但我无法让它工作,请参阅以下代码

    function test() { 
    var lat2 = 42.741; 
    var lon2 = -71.3161; 
    var lat1 = 42.806911; 
    var lon1 = -71.290611; 

    var R = 6371; // km 
    //has a problem with the .toRad() method below.
    var dLat = (lat2-lat1).toRad();  
    var dLon = (lon2-lon1).toRad();  
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
                    Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
                    Math.sin(dLon/2) * Math.sin(dLon/2);  
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
    var d = R * c; 

    alert(d); 
}

错误是:

Uncaught TypeError: Object -0.06591099999999983 has no method 'toRad' 

我理解是因为它需要执行以下操作:

Number.prototype.toRad = function() {
return this * Math.PI / 180;
}

但是当我把它放在函数下面时,它仍然返回相同的错误消息。我如何使它使用辅助方法?或者有没有其他方法可以对此进行编码以使其正常工作?谢谢!

6个回答

此代码正在工作:

Number.prototype.toRad = function() {
   return this * Math.PI / 180;
}

var lat2 = 42.741; 
var lon2 = -71.3161; 
var lat1 = 42.806911; 
var lon1 = -71.290611; 

var R = 6371; // km 
//has a problem with the .toRad() method below.
var x1 = lat2-lat1;
var dLat = x1.toRad();  
var x2 = lon2-lon1;
var dLon = x2.toRad();  
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
                Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
                Math.sin(dLon/2) * Math.sin(dLon/2);  
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c; 

alert(d);

注意我是如何定义 x1 和 x2 的。玩它:https : //tinker.io/3f794

我不知道为什么会发生这种情况@Parijat Kalia,我遇到了同样的问题。
2021-03-14 08:57:17
我遇到了同样的问题。我将 toRadians() 定义为实用函数,并像这样计算 dLat 和 dLon: toRadians(lat1 - lat2) ... 这给了我错误的答案,而不是首先明确计算差异并将其存储在变量中。这是为什么?
2021-04-10 08:57:17

这是基于其他 3 个答案的重构函数!

请注意,坐标参数是 [longitude, latitude]。

function haversineDistance(coords1, coords2, isMiles) {
  function toRad(x) {
    return x * Math.PI / 180;
  }

  var lon1 = coords1[0];
  var lat1 = coords1[1];

  var lon2 = coords2[0];
  var lat2 = coords2[1];

  var R = 6371; // km

  var x1 = lat2 - lat1;
  var dLat = toRad(x1);
  var x2 = lon2 - lon1;
  var dLon = toRad(x2)
  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  var d = R * c;

  if(isMiles) d /= 1.60934;

  return d;
}
同样,不确定我是否实施了错误,但此答案给出了不准确的结果,而当前接受的答案在未重构的情况下给出了与 Google 地图相同的结果。有关更多详细信息,请参阅我对@Harry Mumford-Turner 的回答的评论。
2021-03-18 08:57:17
一件事让我对你的功能感到失望,你期待: haversineDistance([lng, lat], [lng, lat], isMiles);
2021-03-21 08:57:17
万分谢意!作为参考,这是相同的函数,除了压缩并始终返回 KM:function distKM(lat1,lon1,lat2,lon2){var a=Math,r=(lat2-lat1)*a.PI/180,c=(lon2-lon1)*a.PI/180,e=a.sin(r/2)*a.sin(r/2)+a.cos(lat1*a.PI/180)*a.cos(lat2*a.PI/180)*a.sin(c/2)*a.sin(c/2);return d=2*a.atan2(a.sqrt(e),a.sqrt(1-e))*6371}
2021-03-28 08:57:17

ES6 JavaScript/NodeJS 重构版本:

   /**
     * Calculates the haversine distance between point A, and B.
     * @param {number[]} latlngA [lat, lng] point A
     * @param {number[]} latlngB [lat, lng] point B
     * @param {boolean} isMiles If we are using miles, else km.
     */
    const haversineDistance = ([lat1, lon1], [lat2, lon2], isMiles = false) => {
      const toRadian = angle => (Math.PI / 180) * angle;
      const distance = (a, b) => (Math.PI / 180) * (a - b);
      const RADIUS_OF_EARTH_IN_KM = 6371;

      const dLat = distance(lat2, lat1);
      const dLon = distance(lon2, lon1);

      lat1 = toRadian(lat1);
      lat2 = toRadian(lat2);

      // Haversine Formula
      const a =
        Math.pow(Math.sin(dLat / 2), 2) +
        Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
      const c = 2 * Math.asin(Math.sqrt(a));

      let finalDistance = RADIUS_OF_EARTH_IN_KM * c;

      if (isMiles) {
        finalDistance /= 1.60934;
      }

      return finalDistance;
    };

有关已接受答案的测试,请参阅 codepen:https ://codepen.io/harrymt/pen/dyYvLpJ?editors=1011

在针对以下坐标对 Google 地图进行测试时,我使用此解决方案得到了不准确的结果: const latlngA = [52.375603, 4.903206]; const latlngB = [52.366059, 4.926692]; 此解决方案返回 2.8 公里,而当前接受的答案正确返回 1.92 公里(与 Google 地图给出的 1.91 公里非常匹配)。
2021-03-17 08:57:17
@bigsee 谢谢,我已经修正了公式,使其更加准确和易于理解
2021-03-22 08:57:17
这是我在堆栈上看到的最准确的并且与 googlemaps 完美匹配,做得好
2021-04-01 08:57:17
您正在访问latlngAlatlngB参数的第一个元素来计算纬度的增量,但该函数的文档块指出第一个元素是经度。
2021-04-08 08:57:17
那是一些不错的干净代码。我期待在我回家时测试它
2021-04-10 08:57:17

为什么不尝试直接的解决方案?无需扩展 Number 原型,只需将 toRad 定义为常规函数即可:

function toRad(x) {
   return x * Math.PI / 180;
}

然后toRad到处调用

var dLat = toRad(lat2-lat1); 

扩展 Number 原型并不总是按预期工作。例如调用 123.toRad() 不起作用。我认为如果你做的var x1 = lat2 - lat1; x1.toRad();比做的更好(lat2-lat1).toRad()

当我把它放在函数下面时

你只需要把它放在你调用的点之上test()test函数本身在哪里声明并不重要。