Calculer la distance entre deux points dans google maps V3

Réponses:

460

Si vous souhaitez le calculer vous-même, vous pouvez utiliser la formule Haversine:

var rad = function(x) {
  return x * Math.PI / 180;
};

var getDistance = function(p1, p2) {
  var R = 6378137; // Earth’s mean radius in meter
  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; // returns the distance in meter
};
Mike Williams
la source
4
Pourquoi vous suggérez d'utiliser Math.atan2 (Math.sqrt (a), Math.sqrt (1-a)) au lieu du Math.asin le plus simple (Math.sqrt (a))?
Emanuele Paolini
3
@EmanuelePaolini - Mathématiquement, atan2 (sqrt (a), sqrt (1-a)) = asin (sqrt (a)) = acos (sqrt (1-a)), mais la version atan2 reste numériquement mieux conditionnée pour toutes les valeurs de une.
ChrisV
23
Les mecs. Question. Pourquoi aimez-vous tellement utiliser des noms de variables à 1 lettre pour résoudre des problèmes qui nécessitent de l'imagination, où un bon nom de variable pourrait être utile? Je demande juste :)
pie6k
2
Cela ne devrait-il pas être var R = 6371; pour Km?
Alexander Fradiani du
5
Les fonctions p1.lat()et p1.lng()supposent que vos données d'entrée sont des google.maps.LatLngobjets. Si vous n'avez que des données brutes comme celles-ci, {lat: __, lon: __}vous les utiliserez à la place p1.lat, par exemple.
Don McCurdy
309

Il semble en fait y avoir une méthode dans GMap3. C'est une méthode statique de l' google.maps.geometry.sphericalespace de noms.

Il prend comme arguments deux LatLngobjets et utilisera un rayon terrestre par défaut de 6378137 mètres, bien que le rayon par défaut puisse être remplacé avec une valeur personnalisée si nécessaire.

Assurez-vous d'inclure:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"></script>

dans votre tête.

L'appel sera:

google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);
Emil Badh
la source
10
Alors, pourquoi y a-t-il une différence de 1% dans la réponse donnée par le calcul sphérique de Google et la formule de distance Haversine?
Matt S
7
@RamenRecon Je ne suis pas certain, mais une question serait qu'ils utilisent des valeurs différentes pour le rayon terrestre.
Emil Badh
11
@RamenRecon oui, Emil a raison sur ce point. La documentation dit: Le rayon par défaut est le rayon de la Terre de 6378137 mètres. Mais Mike dans le Haversine ci-dessus utilise 6371 km à la place.
Laszlo
Le lien ci-dessus est maintenant rompu, mais l'explication de la méthode ne pose pas grand problème.
GChorn
2
@ ABCD.ca Ce n'est pas mon numéro. Cette question concerne la version 3 de la bibliothèque Google Maps. Vous avez demandé pourquoi votre calcul différait du leur. C'est parce qu'ils utilisent pour le rayon de la Terre une valeur différente de la vôtre. La référence du numéro? developers.google.com/maps/documentation/javascript/… Juste en dessous du titre.
Emil Badh
30

Exemple utilisant la latitude / longitude GPS de 2 points.

var latitude1 = 39.46;
var longitude1 = -0.36;
var latitude2 = 40.40;
var longitude2 = -3.68;

var distance = google.maps.geometry.spherical.computeDistanceBetween(new google.maps.LatLng(latitude1, longitude1), new google.maps.LatLng(latitude2, longitude2));       
joan16v
la source
3
Les résultats de distance sont exprimés en mètres.
joan16v
1
@ joan16v comment exiger google.maps.geometry dans node.js. je veux utiliser le code ci-dessus dans node.js. quel module dois-je installer et quels fichiers dois-je exiger.
kisor
15

Ajoutez simplement ceci au début de votre code JavaScript:

google.maps.LatLng.prototype.distanceFrom = function(latlng) {
  var lat = [this.lat(), latlng.lat()]
  var lng = [this.lng(), latlng.lng()]
  var R = 6378137;
  var dLat = (lat[1]-lat[0]) * Math.PI / 180;
  var dLng = (lng[1]-lng[0]) * Math.PI / 180;
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
  Math.cos(lat[0] * Math.PI / 180 ) * Math.cos(lat[1] * Math.PI / 180 ) *
  Math.sin(dLng/2) * Math.sin(dLng/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return Math.round(d);
}

puis utilisez la fonction comme ceci:

var loc1 = new GLatLng(52.5773139, 1.3712427);
var loc2 = new GLatLng(52.4788314, 1.7577444);
var dist = loc2.distanceFrom(loc1);
alert(dist/1000);
Plamen Todorov
la source
Excellente solution mais je veux savoir dans quelles unités il retourne le résultat. J'ai obtenu 3.013 .. est-ce qu'en miles, km ??
Gowthami Gattineni
La valeur retournée est en mètres. Ainsi dist / 1000 vous donne la valeur en km.
Praveen Janakarajan
13
//p1 and p2 are google.maps.LatLng(x,y) objects

function calcDistance(p1, p2) {
          var d = (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
          console.log(d);              
}
Aishwat Singh
la source
3
C'est la meilleure réponse. Pourquoi ajouter une fonction alors que l'API Google a déjà les fonctions
felixfbecker
Existe-t-il une variante java disponible pour cette API? Je n'ai pas pu le trouver après beaucoup de recherches.
Sanketh
@felixfbecker, car vous travaillez peut-être dans un environnement où vous ne pouvez pas insérer l'API Google Maps dans une scriptbalise et appeler ces méthodes. Comme réagir natif.
Nnanyielugo
11

Voici l'implémentation c # de ce forumula

 public class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIO = 6378.16;

    /// <summary>
    /// This class cannot be instantiated.
    /// </summary>
    private DistanceAlgorithm() { }

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(
        double lon1,
        double lat1,
        double lon2,
        double lat2)
    {
        double dlon =  Radians(lon2 - lon1);
        double dlat =  Radians(lat2 - lat1);

        double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
        double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        return (angle * RADIO) * 0.62137;//distance in miles
    }

}    
Naveed Ahmad
la source
5
Cela ne s'applique pas à la question initiale de savoir comment le faire dans Google Maps.
Niklas Wulff
Il n'y a pas de fonction intégrée pour calculer directement la distance, vous devez utiliser les services d'annuaire pour deux points et extraire la distance du XML / JSON renvoyé.
Naveed Ahmad
1
Mon commentaire portait sur le fait qu'il aurait été préférable de fournir une solution en javascript, car le démarreur de fil n'a pas dit s'il utilisait php, .net ou html statique.
Niklas Wulff
11

Avec google, vous pouvez le faire en utilisant l' api sphérique ,google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB); .

Cependant, si la précision d'une projection sphérique ou d'une solution haversine n'est pas assez précise pour vous (par exemple, si vous êtes près du pôle ou si vous calculez de plus longues distances), vous devez utiliser une bibliothèque différente.

La plupart des informations sur le sujet que j'ai trouvées sur Wikipedia ici .

Une astuce pour voir si la précision d'un algorithme donné est adéquate consiste à remplir le rayon maximum et minimum de la terre et à voir si la différence pourrait causer des problèmes pour votre cas d'utilisation. Beaucoup plus de détails peuvent être trouvés dans cet article

En fin de compte, l'API Google ou haversine servira la plupart des objectifs sans problème.

iwein
la source
9

En utilisant PHP, vous pouvez calculer la distance en utilisant cette fonction simple:

// pour calculer la distance entre deux lat & lon

fonction Calculate_distance ($ lat1, $ lon1, $ lat2, $ lon2, $ unit = 'N') 
{ 
  $ thêta = $ lon1 - $ lon2; 
  $ dist = sin (deg2rad ($ lat1)) * sin (deg2rad ($ lat2)) + cos (deg2rad ($ lat1)) * cos (deg2rad ($ lat2)) * cos (deg2rad ($ theta)); 
  $ dist = acos ($ dist); 
  $ dist = rad2deg ($ dist); 
  $ miles = $ dist * 60 * 1,1515;
  $ unit = strtoupper ($ unit);

  if ($ unit == "K") {
    retour ($ miles * 1.609344); 
  } else if ($ unit == "N") {
      retour ($ miles * 0,8684);
    } autre {
        retourner $ miles;
      }
}

// la fonction se termine ici
Ravinder Singh
la source
2
Il y a une condition dans la fonction selon laquelle si vous passez devant l'unité, Kcela vous donnera la distance en km. Vérifie ça.
Dead Man
cette fonction fonctionne très bien et donne la distance de l'emplacement des étoiles à tous les emplacements. peut-il traverser en quelque sorte d'abord trouver le premier emplacement le plus proche et il devient comme la source ou commencer et ensuite trouver son prochain plus proche mais pas la première source et ainsi de suite pour tous?
Waheed ur Rehman
8

SOLUTION HORS LIGNE - Algorithme Haversine

En Javascript

var _eQuatorialEarthRadius = 6378.1370;
var _d2r = (Math.PI / 180.0);

function HaversineInM(lat1, long1, lat2, long2)
{
    return (1000.0 * HaversineInKM(lat1, long1, lat2, long2));
}

function HaversineInKM(lat1, long1, lat2, long2)
{
    var dlong = (long2 - long1) * _d2r;
    var dlat = (lat2 - lat1) * _d2r;
    var a = Math.pow(Math.sin(dlat / 2.0), 2.0) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r) * Math.pow(Math.sin(dlong / 2.0), 2.0);
    var c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
    var d = _eQuatorialEarthRadius * c;

    return d;
}

var meLat = -33.922982;
var meLong = 151.083853;


var result1 = HaversineInKM(meLat, meLong, -32.236457779983745, 148.69094705162837);
var result2 = HaversineInKM(meLat, meLong, -33.609020205923713, 150.77061469270831);

C #

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");

        var meLat = -33.922982;
        double meLong = 151.083853;


        var result1 = HaversineInM(meLat, meLong, -32.236457779983745, 148.69094705162837);
        var result2 = HaversineInM(meLat, meLong, -33.609020205923713, 150.77061469270831);

        Console.WriteLine(result1);
        Console.WriteLine(result2);
    }

    static double _eQuatorialEarthRadius = 6378.1370D;
    static double _d2r = (Math.PI / 180D);

    private static int HaversineInM(double lat1, double long1, double lat2, double long2)
    {
        return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
    }

    private static  double HaversineInKM(double lat1, double long1, double lat2, double long2)
    {
        double dlong = (long2 - long1) * _d2r;
        double dlat = (lat2 - lat1) * _d2r;
        double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
        double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
        double d = _eQuatorialEarthRadius * c;

        return d;
    }
}

Référence: https://en.wikipedia.org/wiki/Great-circle_distance

MarceloBarbosa
la source
3

Je devais le faire ... La manière du script d'action

//just make sure you pass a number to the function because it would accept you mother in law...
public var rad = function(x:*) {return x*Math.PI/180;}

protected  function distHaversine(p1:Object, p2:Object):Number {
    var R:int = 6371; // earth's mean radius in km
    var dLat:Number = rad(p2.lat() - p1.lat());
    var dLong:Number = rad(p2.lng() - p1.lng());

    var a:Number = 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:Number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d:Number = R * c;

    return d;
}
Netcfmx
la source
3

Dans mon cas, il était préférable de calculer cela dans SQL Server, car je voulais prendre l'emplacement actuel, puis rechercher tous les codes postaux à une certaine distance de l'emplacement actuel. J'avais aussi une base de données qui contenait une liste de codes postaux et leurs lat longs. À votre santé

--will return the radius for a given number
create function getRad(@variable float)--function to return rad
returns float
as
begin
declare @retval float 
select @retval=(@variable * PI()/180)
--print @retval
return @retval
end
go

--calc distance
--drop function dbo.getDistance
create function getDistance(@cLat float,@cLong float, @tLat float, @tLong float)
returns float
as
begin
declare @emr float
declare @dLat float
declare @dLong float
declare @a float
declare @distance float
declare @c float

set @emr = 6371--earth mean 
set @dLat = dbo.getRad(@tLat - @cLat);
set @dLong = dbo.getRad(@tLong - @cLong);
set @a = sin(@dLat/2)*sin(@dLat/2)+cos(dbo.getRad(@cLat))*cos(dbo.getRad(@tLat))*sin(@dLong/2)*sin(@dLong/2);
set @c = 2*atn2(sqrt(@a),sqrt(1-@a))
set @distance = @emr*@c;
set @distance = @distance * 0.621371 -- i needed it in miles
--print @distance
return @distance;
end 
go


--get all zipcodes within 2 miles, the hardcoded #'s would be passed in by C#
select *
from cityzips a where dbo.getDistance(29.76,-95.38,a.lat,a.long) <3
order by zipcode
user2004796
la source
Pas sûr que ce soit efficace pour une utilisation côté client.
Nizar B.
Peut-être pas une solution frontale, mais certainement ce que je cherchais. Merci.
st_stefanov
3
//JAVA
    public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
    final int RADIUS_EARTH = 6371;

    double dLat = getRad(latitude2 - latitude1);
    double dLong = getRad(longitude2 - longitude1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return (RADIUS_EARTH * c) * 1000;
    }

    private Double getRad(Double x) {
    return x * Math.PI / 180;
    }
borchvm
la source
1

C'est assez simple à utiliser Google Distance Matrix

La première étape consiste à activer le service Distance Matrix à partir de la console API Google. il renvoie des distances entre un ensemble d'emplacements. Et appliquez cette fonction simple

function initMap() {
        var bounds = new google.maps.LatLngBounds;
        var markersArray = [];

        var origin1 = {lat:23.0203, lng: 72.5562};
        //var origin2 = 'Ahmedabad, India';
        var destinationA = {lat:23.0436503, lng: 72.55008939999993};
        //var destinationB = {lat: 23.2156, lng: 72.6369};

        var destinationIcon = 'https://chart.googleapis.com/chart?' +
            'chst=d_map_pin_letter&chld=D|FF0000|000000';
        var originIcon = 'https://chart.googleapis.com/chart?' +
            'chst=d_map_pin_letter&chld=O|FFFF00|000000';
        var map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: 55.53, lng: 9.4},
          zoom: 10
        });
        var geocoder = new google.maps.Geocoder;

        var service = new google.maps.DistanceMatrixService;
        service.getDistanceMatrix({
          origins: [origin1],
          destinations: [destinationA],
          travelMode: 'DRIVING',
          unitSystem: google.maps.UnitSystem.METRIC,
          avoidHighways: false,
          avoidTolls: false
        }, function(response, status) {
          if (status !== 'OK') {
            alert('Error was: ' + status);
          } else {
            var originList = response.originAddresses;
            var destinationList = response.destinationAddresses;
            var outputDiv = document.getElementById('output');
            outputDiv.innerHTML = '';
            deleteMarkers(markersArray);

            var showGeocodedAddressOnMap = function(asDestination) {
              var icon = asDestination ? destinationIcon : originIcon;
              return function(results, status) {
                if (status === 'OK') {
                  map.fitBounds(bounds.extend(results[0].geometry.location));
                  markersArray.push(new google.maps.Marker({
                    map: map,
                    position: results[0].geometry.location,
                    icon: icon
                  }));
                } else {
                  alert('Geocode was not successful due to: ' + status);
                }
              };
            };

            for (var i = 0; i < originList.length; i++) {
              var results = response.rows[i].elements;
              geocoder.geocode({'address': originList[i]},
                  showGeocodedAddressOnMap(false));
              for (var j = 0; j < results.length; j++) {
                geocoder.geocode({'address': destinationList[j]},
                    showGeocodedAddressOnMap(true));
                //outputDiv.innerHTML += originList[i] + ' to ' + destinationList[j] + ': ' + results[j].distance.text + ' in ' +                    results[j].duration.text + '<br>';
                outputDiv.innerHTML += results[j].distance.text + '<br>';
              }
            }

          }
        });
      }

Où origin1 est votre emplacement et destinationA est l'emplacement de destination.vous pouvez ajouter au-dessus de deux données ou plus.

Rad Documentation complète avec un exemple

TarangP
la source
1
  /**
   * 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 squared = x => x * x;
    const toRad = x => (x * Math.PI) / 180;
    const R = 6371; // Earth’s mean radius in km

    const dLat = toRad(latlngB[0] - latlngA[0]);
    const dLon = toRad(latlngB[1] - latlngA[1]);

    const dLatSin = squared(Math.sin(dLat / 2));
    const dLonSin = squared(Math.sin(dLon / 2));

    const a = dLatSin +
              (Math.cos(toRad(latlngA[0])) * Math.cos(toRad(latlngB[0])) * dLonSin);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    let distance = R * c;

    if (isMiles) distance /= 1.609344;

    return distance;
  }

J'ai trouvé une version en ligne qui est correcte à 80% mais branchée sur le mauvais paramètre et qui n'est pas cohérente dans l'utilisation des entrées, cette version a corrigé cela complètement

Vérification au crayon
la source
0

Pour calculer la distance sur Google Maps, vous pouvez utiliser l'API Directions. Ce sera l'un des moyens les plus simples de le faire. Pour obtenir des données de Google Server, vous pouvez utiliser Retrofit ou Volley. Les deux ont leur propre avantage. Jetez un œil au code suivant où j'ai utilisé la modification pour l'implémenter:

private void build_retrofit_and_get_response(String type) {

    String url = "https://maps.googleapis.com/maps/";

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    RetrofitMaps service = retrofit.create(RetrofitMaps.class);

    Call<Example> call = service.getDistanceDuration("metric", origin.latitude + "," + origin.longitude,dest.latitude + "," + dest.longitude, type);

    call.enqueue(new Callback<Example>() {
        @Override
        public void onResponse(Response<Example> response, Retrofit retrofit) {

            try {
                //Remove previous line from map
                if (line != null) {
                    line.remove();
                }
                // This loop will go through all the results and add marker on each location.
                for (int i = 0; i < response.body().getRoutes().size(); i++) {
                    String distance = response.body().getRoutes().get(i).getLegs().get(i).getDistance().getText();
                    String time = response.body().getRoutes().get(i).getLegs().get(i).getDuration().getText();
                    ShowDistanceDuration.setText("Distance:" + distance + ", Duration:" + time);
                    String encodedString = response.body().getRoutes().get(0).getOverviewPolyline().getPoints();
                    List<LatLng> list = decodePoly(encodedString);
                    line = mMap.addPolyline(new PolylineOptions()
                                    .addAll(list)
                                    .width(20)
                                    .color(Color.RED)
                                    .geodesic(true)
                    );
                }
            } catch (Exception e) {
                Log.d("onResponse", "There is an error");
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d("onFailure", t.toString());
        }
    });

}

Ci-dessus, le code de la fonction build_retrofit_and_get_response pour calculer la distance. Ci-dessous, l'interface de mise à niveau correspondante:

package com.androidtutorialpoint.googlemapsdistancecalculator;


import com.androidtutorialpoint.googlemapsdistancecalculator.POJO.Example;

import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Query;

public interface RetrofitMaps {


/*
 * Retrofit get annotation with our URL
 * And our method that will return us details of student.
 */
@GET("api/directions/json?key=AIzaSyC22GfkHu9FdgT9SwdCWMwKX1a4aohGifM")
Call<Example> getDistanceDuration(@Query("units") String units, @Query("origin") String origin, @Query("destination") String destination, @Query("mode") String mode);

}

J'espère que cela explique votre requête. Bonne chance :)

Source: Calculateur de distance Google Maps

Navneet Goel
la source
Non, cela calcule la distance de déplacement (sur les routes, etc.), pas la distance géodésique point à point.
Yarin