在Javascript中使用Haversine公式
我试图使用哈弗森距离公式(如这里所示:),但我无法让它工作,请参阅以下代码在Javascript中使用Haversine公式,javascript,haversine,Javascript,Haversine,我试图使用哈弗森距离公式(如这里所示:),但我无法让它工作,请参阅以下代码 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. va
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;
}
但当我把它放在函数下面时,它仍然返回相同的错误消息。如何使用helper方法?或者有没有其他方法来编写代码以使其正常工作?谢谢 为什么不试试直截了当的解决方案呢?不要扩展数字原型,只需将toRad定义为常规函数:
function toRad(x) {
return x * Math.PI / 180;
}
然后到处调用toRad
:
var dLat = toRad(lat2-lat1);
扩展数字原型并不总是像预期的那样工作。例如,调用123.toRad()不起作用。我认为如果你做
varx1=lat2-lat1;x1.toRad()代码>比执行(lat2-lat1)工作得更好。toRad()
在函数中调用这些扩展之前,需要扩展数字原型
所以只要确保
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
在调用函数之前调用
当我把它放在函数下面时
您只需要将它放在调用test()
的点上方。声明测试
函数本身的位置无关紧要。此代码正在工作:
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的。
在以下位置使用它:这是上面talkol解决方案的java实现。他或她的解决方案对我们很有效。我不想回答这个问题,因为最初的问题是针对javascript的。我只是在分享给定javascript解决方案的java实现,以防其他人发现它有用
// this was a pojo class we used internally...
public class GisPostalCode {
private String country;
private String postalCode;
private double latitude;
private double longitude;
// getters/setters, etc.
}
public static double distanceBetweenCoordinatesInMiles2(GisPostalCode c1, GisPostalCode c2) {
double lat2 = c2.getLatitude();
double lon2 = c2.getLongitude();
double lat1 = c1.getLatitude();
double lon1 = c1.getLongitude();
double R = 6371; // km
double x1 = lat2 - lat1;
double dLat = x1 * Math.PI / 180;
double x2 = lon2 - lon1;
double dLon = x2 * Math.PI / 180;
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1*Math.PI/180) * Math.cos(lat2*Math.PI/180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
// convert to miles
return d / 1.60934;
}
这是一个基于其他3个答案的重构函数
请注意,coords参数是[经度,纬度]
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 LatLng对象兼容的变体:
function haversine_distance(coords1, coords2) {
function toRad(x) {
return x * Math.PI / 180;
}
var dLat = toRad(coords2.latitude - coords1.latitude);
var dLon = toRad(coords2.longitude - coords1.longitude)
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(coords1.latitude)) *
Math.cos(toRad(coords2.latitude)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
return 12742 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
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以获取针对已接受答案的测试:以下是JavaScript中的另一个重构答案:
getHaversineDistance = (firstLocation, secondLocation) => {
const earthRadius = 6371; // km
const diffLat = (secondLocation.lat-firstLocation.lat) * Math.PI / 180;
const diffLng = (secondLocation.lng-firstLocation.lng) * Math.PI / 180;
const arc = Math.cos(
firstLocation.lat * Math.PI / 180) * Math.cos(secondLocation.lat * Math.PI / 180)
* Math.sin(diffLng/2) * Math.sin(diffLng/2)
+ Math.sin(diffLat/2) * Math.sin(diffLat/2);
const line = 2 * Math.atan2(Math.sqrt(arc), Math.sqrt(1-arc));
const distance = earthRadius * line;
return distance;
}
const philly = { lat: 39.9526, lng: -75.1652 }
const nyc = { lat: 40.7128, lng: -74.0060 }
const losAngeles = { lat: 34.0522, lng: -118.2437 }
console.log(getHaversineDistance(philly, nyc)) //129.61277152662188
console.log(getHaversineDistance(philly, losAngeles)) //3843.4534005980404
不,它不需要放在函数定义之前。@bergi-很抱歉,你是对的-它需要在调用函数之前定义-将编辑我的答案。我遇到了同样的问题。我将一个toRadians()定义为一个实用函数,并像这样计算dLat和dLon:toRadians(lat1-lat2)。。。这给了我错误的答案,而不是先显式地计算差异,然后将其存储在变量中。为什么会这样?我也不知道为什么会这样@Parijat Kalia,我也有同样的问题。有一件事让我对你的函数感到困惑,你期望:haversineddance([lng,lat],[lng,lat],isMiles)代码>同样,不确定我是否实现了错误,但是这个答案给出了一个不准确的结果,而当前接受的答案,没有重构,给出了与谷歌地图相同的结果。更多细节请参见我对@Harry Mumford Turner答案的评论。这是否仍在km中?应该这样注释,以及使其返回英里数所需的更改。您正在访问latlngA
和latlngB
参数的第一个元素,以计算纬度的增量,但是函数的docblock声明第一个元素是经度。在针对以下坐标对Google Maps进行测试时,我使用此解决方案得到了一个不准确的结果:const latlngA=[52.375603,4.903206];常量latlngB=[52.366059,4.926692];此解决方案返回2.8km,而当前接受的答案正确返回1.92km(与Google Maps给出的1.91km非常匹配)。@Bigse谢谢,我已经修正了公式,使其更加准确和易于理解。这是我在stack上看到的最准确的结果,与Google Maps完美匹配,嗯,这是一些很好的干净的代码。我期待着回家后对它进行测试。关于OP给出的相同链接,这个问题的公认答案似乎很好地回答了这个问题: