Por todos es sabido que la Tierra es “redonda”, así que la distancia que separa 2 puntos en la Tierra describe un arco.
Hay que decir que google nos facilita enormemente la faena para calcular distancias, pero vamos por partes: cómo lo tendríamos que hacer manualmente y cómo hacerlo de manera rápida con google maps.
Para calcular la distancia entre 2 puntos en una esfera se utiliza la fórmula de Haversine. Tened en cuenta que esta fórmula asume que la Tierra es completamente esférica.
Una implementación en Javascript de ésta fórmula (sacada de stackoverflow) es la siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function rad(x) { return x * Math.PI / 180; }; function getDistance(p1, p2) { // http://es.wikipedia.org/wiki/F{1f0778fe2e852b61c79949ce7b4bb677680b76fea251b03768a071033ace27eb}C3{1f0778fe2e852b61c79949ce7b4bb677680b76fea251b03768a071033ace27eb}B3rmula_del_Haversine var R = 6378137; //radio de la tierra en metros var dLat = rad(p2.lat() - p1.lat()); var dLong = rad(p2.lng() - p1.lng()); var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong / 2) * Math.sin(dLong / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var d = R * c; return d; }; |
Vamos a probarla con un mapa.
Primero definimos las 2 posiciones con las que calcularemos la distancia:
1 2 |
var pos_1 = new google.maps.LatLng(41.97837956414176,2.77969550981652); var pos_2 = new google.maps.LatLng(41.97608249594034,2.8631229390157387); |
Le pasamos los dos puntos a la fórmula y obtenemos:
1 |
console.log('obteniendo distancia con formula Haversine:' +getDistance(pos_1,pos_2)); |
*El resultado de ésta fórmula es en metros, porqué el diámetro de la tierra lo hemos puesto en metros.
Bueno, pero es que, como de costumbre, Google dispone de una librería para el cálculo con coordenadas.
Para poder cargar la librería al llamar la API de google maps, agregamos el parámetro libraries=geometry:
1 |
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=es&libraries=geometry"></script> |
Ahora ya podemos operar con coordenadas. ¿Y qué cálculos podemos hacer?:
Calcular la distancia entre 2 coordenadas, calcular el punto medio entre 2 coordenadas, saber qué ángulo hay entre una coordenada y otra (dirección a la que nos tendríamos que dirigir) y más cosas.
Veamos cómo calcular la distancia que hay entre las 2 posiciones que teníamos con la función que nos proporciona google.
La funció : computeDistanceBetween()
Tenemos las 2 posiciones:
1 2 |
var pos_1 = new google.maps.LatLng(41.97837956414176,2.77969550981652); var pos_2 = new google.maps.LatLng(41.97608249594034,2.8631229390157387); |
para calcular:
1 2 |
console.log('obteniendo con Google :'+ google.maps.geometry.spherical.computeDistanceBetween (pos_1, pos_2)); |
Vamos a probarlo con un ejemplo gráfico, con nuestros marcadores.
Creamos un mapa, con un marcador fijo (A) y otro que se pueda arrastrar (B). Al soltar (B), queremos que nos diga la distancia a la que se encuentra de (A).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=es&libraries=geometry"></script> <script type="text/javascript"> window.onload = function(){ var pos_A = new google.maps.LatLng(41.97837956414176,2.77969550981652); var pos_B = new google.maps.LatLng(41.97952806717199,2.8421802510274574); var options = { zoom: 13, center: new google.maps.LatLng(41.97659296270089,2.811624525929801), mapTypeId: google.maps.MapTypeId.SATELLITE, panControl: false, zoomControl: false, mapTypeControl: false, scaleControl: false, streetViewControl: false, overviewMapControl: false }; var map = new google.maps.Map(document.getElementById('map'), options); var marcadorA = new google.maps.Marker({ position: pos_A, map: map, title: 'soy la referencia', animation: google.maps.Animation.DROP, draggable: false }); var marcadorB = new google.maps.Marker({ position: pos_B, map: map, title: 'Arrastrame', animation: google.maps.Animation.DROP, draggable: true, icon : 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png' }); //ponemos evento en marcador B google.maps.event.addListener(marcadorB, 'dragend', function() { console.log('Estas a :'+google.maps.geometry.spherical.computeDistanceBetween (pos_A, marcadorB.getPosition())+'mts. de A'); }); }; </script> |
Vemos como hemos cambiado el icono de marcador B para poderlo diferenciar. Los iconos básicos de colorines de google los tenéis en las siguientes url:
https://maps.google.com/mapfiles/ms/icons/blue-dot.png
https://maps.google.com/mapfiles/ms/icons/red-dot.png
https://maps.google.com/mapfiles/ms/icons/purple-dot.png
https://maps.google.com/mapfiles/ms/icons/yellow-dot.png
https://maps.google.com/mapfiles/ms/icons/green-dot.png
Bueno, a parte de los colorines, los marcadores, el dragable y todo lo que hemos visto, lo que nos interesa es el evento que le hemos colocado a marcador B: al dejar de arrastrarlo, calculamos la distancia entre pos_A (que es fija) y la posición en la que se encuentre en ese momento el marcador B.
1 2 3 4 5 6 |
google.maps.event.addListener(marcadorB, 'dragend', function() { console.log('Estas a :'+google.maps.geometry.spherical.computeDistanceBetween (pos_A, marcadorB.getPosition())+'mts. de A'); }); |
Vamos a modificar el primer ejemplo para calcular la distancia en base a 2 marcadores dragables.
En este caso, crearemos una función que calcule la distancia entre los 2 puntos, que será llamada con el evento ‘dragend’ de ambos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=es&libraries=geometry"></script> <script type="text/javascript"> window.onload = function(){ var pos_A = new google.maps.LatLng(41.97837956414176,2.77969550981652); var pos_B = new google.maps.LatLng(41.97952806717199,2.8421802510274574); var options = { zoom: 13, center: new google.maps.LatLng(41.97659296270089,2.811624525929801), mapTypeId: google.maps.MapTypeId.SATELLITE, panControl: false, zoomControl: false, mapTypeControl: false, scaleControl: false, streetViewControl: false, overviewMapControl: false }; var map = new google.maps.Map(document.getElementById('map'), options); var marcadorA = new google.maps.Marker({ position: pos_A, map: map, title: 'soy la referencia', animation: google.maps.Animation.DROP, draggable: true }); var marcadorB = new google.maps.Marker({ position: pos_B, map: map, title: 'Arrastrame', animation: google.maps.Animation.DROP, draggable: true }); //ponemos evento en marcador A google.maps.event.addListener(marcadorA, 'dragend', function() { console.log(calculaDistanci(marcadorA,marcadorB)); }); //ponemos evento en marcador B google.maps.event.addListener(marcadorB, 'dragend', function() { console.log(calculaDistanci(marcadorA,marcadorB)); }); function calculaDistanci(marcadorA,marcadorB) { return google.maps.geometry.spherical.computeDistanceBetween (marcadorA.getPosition(), marcadorB.getPosition()); } }; |
Otro ejemplo más completo sería tener 2 marcadores, que al moverlos calcule el punto medio entre ambos marcándolo con un 3r marcador no dragable.
El punto medio entre 2 coordenadas lo sacamos con la función interpolate(), que recibe como parámetros LatLng origen, LatLng destino y fracción a calcular.
En nuestro caso, para calcular el punto medio, la fracción será de 0.5
Veamos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=es&libraries=geometry"></script> <script type="text/javascript"> window.onload = function(){ var pos_A = new google.maps.LatLng(41.97837956414176,2.77969550981652); var pos_B = new google.maps.LatLng(41.97952806717199,2.8421802510274574); var options = { zoom: 13, center: new google.maps.LatLng(41.97659296270089,2.811624525929801), mapTypeId: google.maps.MapTypeId.SATELLITE, panControl: false, zoomControl: false, mapTypeControl: false, scaleControl: false, streetViewControl: false, overviewMapControl: false }; var map = new google.maps.Map(document.getElementById('map'), options); var marcadorA = new google.maps.Marker({ position: pos_A, map: map, title: 'soy la referencia', animation: google.maps.Animation.DROP, draggable: true }); var marcadorB = new google.maps.Marker({ position: pos_B, map: map, title: 'Arrastrame', animation: google.maps.Animation.DROP, draggable: true }); //ponemos evento en marcador A google.maps.event.addListener(marcadorA, 'dragend', function() { calculaPuntoMedio(marcadorA.getPosition(),marcadorB.getPosition()); }); //ponemos evento en marcador B google.maps.event.addListener(marcadorB, 'dragend', function() { calculaPuntoMedio(marcadorA.getPosition(),marcadorB.getPosition()); }); function calculaPuntoMedio(marcadorA,marcadorB) { //miramos si existe el marcador o lo hemos creado anteriormente if(typeof(marcador_medio) != "undefined") { // si exite lo borramos marcador_medio.setMap(null); marcador_medio = null; } //y lo creamos var punto_medio = google.maps.geometry.spherical.interpolate(marcadorA,marcadorB,0.5); // guardamos el marcador_medio en variable Global (sib var) marcador_medio = new google.maps.Marker({ position: punto_medio, map: map, icon : 'http://maps.google.com/mapfiles/ms/icons/green-dot.png' }); } }; </script> |
En la función calculaPuntoMedio(), primero miramos si la variable marcador_medio existe, si es el caso se borra del mapa y se pone a null.
1 2 3 4 5 |
if(typeof(marcador_medio) != "undefined") { marcador_medio.setMap(null); marcador_medio = null; } |
Luego calculamos el punto medio de las posiciones de los marcadores que hemos pasado como parámetro con una fracción de 0.5.
1 |
var punto_medio = google.maps.geometry.spherical.interpolate(marcadorA,marcadorB,0.5); |
Y finalmente creamos el marcador, guardándolo en una variable global.
1 2 3 4 5 |
marcador_medio = new google.maps.Marker({ position: punto_medio, map: map, icon : 'http://maps.google.com/mapfiles/ms/icons/green-dot.png' }); |
Si hay algo que no quede suficientemente claro o tenéis otra manera de hacerlo… ¡comentad! 😉