Usando a fórmula Haversine em Javascript

Eu estou tentando usar a fórmula de distância de Haversine (como encontrada aqui: http://www.movable-type.co.uk/scripts/latlong.html ) mas não consigo fazê-la funcionar, por favor, veja o seguinte código

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); } 

E o erro é:

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

O que eu entendo ser porque precisa fazer o seguinte:

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

Mas quando eu coloco isso abaixo da function, ele ainda volta com a mesma mensagem de erro. Como faço para usar o método auxiliar? Ou existe uma maneira alternativa de codificar isso para que funcione? Obrigado!

Este código está funcionando:

 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); 

Observe como defini x1 e x2. Jogue com ele em: https://tinker.io/3f794

Aqui está uma function refatorada baseada em 3 das outras respostas!

Por favor, note que os argumentos de coords são [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; } 

Por que não tentar a solução direta? Em vez de estender o protótipo Number, apenas defina toRad como uma function regular:

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

e depois chamar toRad todos os lugares:

 var dLat = toRad(lat2-lat1); 

Estender o protótipo Number nem sempre funciona como esperado. Por exemplo, chamar 123.toRad () não funciona. Eu acho que se você fizer var x1 = lat2 - lat1; x1.toRad(); var x1 = lat2 - lat1; x1.toRad(); funciona melhor do que fazer (lat2-lat1).toRad()

Versão refatorada 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. */ function haversineDistance(latlngA, latlngB, isMiles) { const toRad = x => (x * Math.PI) / 180; const R = 6371; // km const dLat = toRad(latlngB[1] - latlngA[1]); const dLatSin = Math.sin(dLat / 2); const dLon = toRad(latlngB[0] - latlngA[0]); const dLonSin = Math.sin(dLon / 2); const a = (dLatSin * dLatSin) + (Math.cos(toRad(latlngA[1])) * Math.cos(toRad(latlngB[1])) * dLonSin * dLonSin); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); let distance = R * c; if (isMiles) distance /= 1.60934; return distance; } 

quando eu coloco isso abaixo da function

Você só precisa colocá-lo acima do ponto em que você chama test() . Onde a function de test é declarada não importa.

Você precisa estender o protótipo Number, antes de chamar essas extensões em uma function.

Então apenas garanta

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

é chamado antes que sua function seja chamada.

Outra variante para reduzir a redundância e também compatível com objects do 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)); } 

Esta é uma implementação java da solução do talkol acima. Sua solução funcionou muito bem para nós. Eu não estou tentando responder a pergunta, uma vez que a pergunta original era para javascript. Estou apenas compartilhando nossa implementação Java da solução de javascript fornecida, caso outras pessoas a considerem útil.

 // 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; }