Uso de la fórmula Haversine en Javascript
Estoy tratando de usar la Fórmula de distancia Haversine (como se encuentra aquí: http://www.movable-type.co.uk/scripts/latlong.html ) pero no puedo hacer que funcione, 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'
Que 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, todavía vuelve con el mismo mensaje de error. ¿Cómo hago que use el método helper? O hay una forma alternativa de código esto para que funcione? ¡Gracias!
8 answers
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. Jugar con él en: https://tinker.io/3f794
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 11:51:52
Aquí hay una función refactorizada basada en 3 de las otras respuestas!
Tenga en cuenta que los argumentos 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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-19 03:57:42
¿Por qué no probar la solución directa? En lugar de extender el prototipo de número, simplemente defina toRad como una función regular:
function toRad(x) {
return x * Math.PI / 180;
}
Y luego llama toRad
a todas partes:
var dLat = toRad(lat2-lat1);
Extender el prototipo de número no siempre funciona como se esperaba. Por ejemplo, llamando al 123.toRad() no funciona. Creo que si haces var x1 = lat2 - lat1; x1.toRad();
funciona mejor que haciendo (lat2-lat1).toRad()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 11:55:10
ES6 JavaScript / NodeJS versión refactorizada:
/**
* 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 = (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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-10 16:34:28
Cuando pongo esto debajo de la función
Solo necesitas ponerlo por encima del punto donde llamas test()
. No importa dónde se declare la propia función test
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 11:46:55
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 se llama a su función.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 12:03:44
Otra variante para reducir la redundancia y también compatible con Google LatLng objects:
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));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-20 19:26:54
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 a 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 ú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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-17 14:27:29