javascript haversine

Usando la fórmula Haversine en Javascript



(8)

cuando pongo esto debajo de la función

Solo necesita ponerlo sobre el punto donde llama a test() . Donde la función de test sí es declarada no importa.

Intento usar la fórmula Haversine Distance (que se encuentra aquí: http://www.movable-type.co.uk/scripts/latlong.html ) pero no puedo hacer que funcione, por favor, consulte el siguiente 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); }

Y el error es:

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

Lo cual entiendo que es porque necesita hacer lo siguiente:

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

Pero cuando pongo esto debajo de la función, sigue apareciendo con el mismo mensaje de error. ¿Cómo hago que use el método de ayuda? ¿O hay una forma alternativa de codificar esto para que funcione? ¡Gracias!


¡Aquí hay una función refactorizada basada en 3 de las otras respuestas!

Tenga en cuenta que los argumentos de los coords son [longitud, latitud].

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 qué no probar la solución directa? En lugar de extender el prototipo de Número, simplemente defina toRad como una función normal:

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

y luego llama a toRad todas partes:

var dLat = toRad(lat2-lat1);

La ampliación del prototipo de Número no siempre funciona como se esperaba. Por ejemplo, llamar 123.toRad () no funciona. Creo que si haces var x1 = lat2 - lat1; x1.toRad(); var x1 = lat2 - lat1; x1.toRad(); funciona mejor que hacerlo (lat2-lat1).toRad()


Esta es una implementación java de la solución de talkol anterior. Su solución funcionó muy bien para nosotros. No estoy tratando de responder la pregunta, ya que la pregunta original era para javascript. Solo estoy compartiendo nuestra implementación java de la solución javascript dada en caso de que otros la encuentren de uso.

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


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 cómo definí x1 y x2. Juegue con él en: https://tinker.io/3f794


Necesita extender el prototipo de Número, antes de llamar a esas extensiones en una función.

Así que solo asegúrate

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

se llama antes de que se llame a su función.


Otra variante para reducir la redundancia y también compatible con los objetos LatLng de Google:

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


Versión refactorizada 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; }