Google Maps V3'teki iki nokta arasındaki mesafeyi hesaplayın


Yanıtlar:


460

Bunu kendiniz hesaplamak istiyorsanız, Haversine formülünü kullanabilirsiniz:

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

4
Neden en basit Math.asin (Math.sqrt (a)) yerine Math.atan2 (Math.sqrt (a), Math.sqrt (1-a)) kullanılmasını öneriyorsunuz?
Emanuele Paolini

3
@EmanuelePaolini - Matematiksel olarak atan2 (sqrt (a), sqrt (1-a)) = asin (sqrt (a)) = acos (sqrt (1-a)), ancak atan2 sürümü tüm değerleri için sayısal olarak daha iyi koşullandırılmış olarak kalır a.
ChrisV

23
Adamlar. Soru. Neden iyi değişken isminin yardımcı olabileceği hayal gücü gerektiren problemleri çözen 1 harfli değişken isimlerini kullanmaktan çok hoşlanıyorsunuz? Just asking :)
pie6k

2
Var olmamalı R = 6371; Km için mi?
Alexander Fradiani

5
p1.lat()Ve p1.lng()işlevleri giriş veri olduğunu varsayalım google.maps.LatLngnesneler. {lat: __, lon: __}Bunun gibi ham verileriniz varsa p1.lat, örneğin kullanabilirsiniz .
Don McCurdy

308

Aslında GMap3'te bir yöntem var gibi görünüyor. Ad alanının statik bir yöntemidir google.maps.geometry.spherical.

İki LatLngnesneyi bağımsız değişken olarak alır ve varsayılan yarıçap gerekirse özel bir değerle geçersiz kılınabilmesine rağmen 6378137 metrelik varsayılan Dünya yarıçapını kullanır.

Eklediğinizden emin olun:

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

baş bölümünüzde.

Çağrı:

google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);

10
Peki neden Google'ın küresel computeDistanceBetween ve Haversine mesafe formülü tarafından verilen cevapta% 1 fark var?
Matt S

7
@RamenRecon Emin değilim ama bir tahmin onların dünya yarıçapı için farklı değerler kullanmak olacaktır.
Emil Badh

11
@RamenRecon evet, Emil bu konuda doğru. Belgeler: Varsayılan yarıçap Dünya'nın 6378137 metrelik yarıçapıdır . Ancak yukarıdaki Haversine'deki Mike bunun yerine 6371km kullanıyor.
Laszlo

Yukarıdaki bağlantı şimdi kesilmiştir, ancak yöntemin açıklaması bunu fazla bir sorun haline getirmez.
GChorn

2
@ ABCD.ca Bu benim numaram değil. Bu soru Google Haritalar Kütüphanesi'nin 3. sürümü hakkındadır. Hesaplamanızın neden onlardan farklı olduğunu sordunuz. Çünkü dünya yarıçapı için sizden farklı bir değer kullanıyorlar. Numara için referans? developers.google.com/maps/documentation/javascript/… Başlığın hemen altında.
Emil Badh

30

2 enlem / boylam GPS enlem / boylamını kullanan örnek.

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

3
Mesafe sonuçları metre cinsinden ifade edilir.
joan16v

1
@ joan16v node.js'de google.maps.geometry nasıl gereklidir? ide.js yukarıdaki kodu kullanmak istiyorum. hangi modülü kurmalıyım ve hangi dosyaları gerektirmeliyim.
kisor

15

Bunu JavaScript kodunuzun başına ekleyin:

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

ve sonra işlevi şu şekilde kullanın:

var loc1 = new GLatLng(52.5773139, 1.3712427);
var loc2 = new GLatLng(52.4788314, 1.7577444);
var dist = loc2.distanceFrom(loc1);
alert(dist/1000);

Mükemmel çözüm ama sonucu hangi birimleri döndürdüğünü bilmek istiyorum. 3.013 aldım .. mil mi, km ??
Gowthami Gattineni

Döndürülen değer metre cinsindendir. Bu nedenle dist / 1000, km cinsinden değeri verir.
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);              
}

3
bu en iyi cevap. Google API zaten işlevlere
sahipken

Bu API için kullanılabilir bir java varyantı var mı? Çok fazla arama yaptıktan sonra bulamadım.
Sanketh

@felixfbecker, çünkü google maps API'sını bir scriptetikete ekleyemeyeceğiniz ve bu yöntemleri çağıramayacağınız bir ortamda çalışıyor olabilirsiniz . Tepki-yerli gibi.
Nnanyielugo

11

İşte bu forumula c # uygulaması

 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
    }

}    

5
Bu, Google Haritalar'da nasıl yapılacağı konusunda orijinal soru için geçerli değildir.
Niklas Wulff

Mesafeyi doğrudan hesaplamak için dahili bir işlev yoktur, iki nokta için dizin hizmetlerini kullanmanız ve döndürülen XML / JSON'dan uzaklığı çıkarmanız gerekir.
Nefret Ahmed

1
Benim yorumum iplik marş php, .net veya statik html kullanıp kullanmadığını söylemediğinden, javascript'te bir çözüm sağlamanın daha iyi olacağı gerçeğiyle ilgiliydi.
Niklas Wulff

11

Google ile küresel API kullanarak yapabilirsiniz ,google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB); .

Bununla birlikte, küresel bir projeksiyon veya haversin çözümünün hassasiyeti sizin için yeterince kesin değilse (örneğin, direğe yakınsanız veya daha uzun mesafeleri hesaplıyorsanız), farklı bir kütüphane kullanmalısınız.

Vikipedi'de bulduğum konuyla ilgili çoğu bilgi burada .

Herhangi bir algoritmanın hassasiyetinin yeterli olup olmadığını görmek için bir hile, dünyanın maksimum ve minimum yarıçapını doldurmak ve farkın kullanım durumunuz için sorunlara neden olup olmadığını görmek. Bu makalede daha fazla ayrıntı bulunabilir

Sonunda google api veya haversine çoğu amaca sorunsuz hizmet edecektir.


9

PHP kullanarak, bu basit işlevi kullanarak mesafeyi hesaplayabilirsiniz:

// iki lat & lon arasındaki mesafeyi hesaplamak için

function calculate_distance ($ lat1, $ lon1, $ lat2, $ lon2, $ birim = 'N') 
{ 
  $ teta = $ lon1 - $ lon2; 
  $ dist = sin (deg2rad ($ lat1)) * sin (deg2rad ($ lat2)) + cos (deg2rad ($ lat1)) * cos (deg2rad ($ lat2)) * cos (deg2rad ($ teta)); 
  $ dist = acos ($ dist); 
  $ dist = rad2deg ($ dist); 
  $ mil = $ dist * 60 * 1.1515;
  $ birim = strtoupper ($ birim);

  eğer ($ birim == "K") {
    dönüş (mil $ * 1.609344); 
  } else if ($ unit == "N") {
      dönüş (mil $ * 0.8684);
    } Başka {
        $ mil;
      }
}

// işlev burada bitiyor

2
Fonksiyonda, üniteyi Ko şekilde geçirirseniz, size Km olarak mesafe vermesi koşulu vardır . Kontrol et.
Ölü Adam

Bu işlev çok iyi çalışır ve yıldız konumundan tüm konumlara mesafe verir. b ilk şekilde en cloasest yerini bulabilir ve kaynak ya da başlangıç ​​olarak olur ve sonra bir sonraki en yakın ama ilk kaynak olanı bulamaz ve bu şekilde devam edebilir mi?
Waheed ur Rehman

8

ÇEVRİMDIŞI ÇÖZÜM - Haversine Algoritması

Javascript'te

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

Referans: https://en.wikipedia.org/wiki/Great-circle_distance


3

Bunu yapmak zorunda kaldım ... Aksiyon komut dosyası yolu

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

3

Benim durumumda, geçerli konumu almak ve sonra geçerli konumdan belirli bir mesafe içinde tüm posta kodlarını aramak istedim çünkü bu SQL Server'da hesaplamak en iyisiydi. Ayrıca posta kodları ve onların lat uzun ürün listesini içeren bir db vardı. Şerefe

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

Bunun istemci tarafında kullanım için etkili olduğundan emin değilim.
Nizar B.

Bir ön uç çözüm olmayabilir, ama kesinlikle aradığım şey olabilir. Teşekkürler.
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;
    }

1

Google Distance Matrix hizmetini kullanmak oldukça kolay

İlk adım, Google Maps konsolundan Distance Matrix hizmetini etkinleştirmektir. bir konum kümesi arasındaki mesafeleri döndürür. Ve bu basit işlevi uygulayın

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

          }
        });
      }

Orijin1, konumunuz ve hedefA, hedef konumdur. İki veya daha fazla veri ekleyebilirsiniz.

Bir örnekle Rad Tam Dokümantasyon


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

Çevrimiçi olarak% 80 doğru ancak yanlış parametreye takılı ve girişleri kullanırken tutarsız bir sürüm buldum, bu sürüm tamamen


0

Google Haritalar'daki mesafeyi hesaplamak için Yol Tarifi API'sını kullanabilirsiniz. Bunu yapmanın en kolay yollarından biri bu olacak. Google Server'dan veri almak için Retrofit veya Volley kullanabilirsiniz. Her ikisinin de kendi avantajları vardır. Uygulamak için güçlendirme kullandığım aşağıdaki koda bir göz atın:

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

}

Yukarıda mesafe hesaplamak için build_retrofit_and_get_response fonksiyonunun kodu verilmiştir. Aşağıda karşılık gelen Retrofit Arayüzü:

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

}

Umarım bu sorgunuzu açıklar. Herşey gönlünce olsun :)

Kaynak: Google Haritalar Mesafe Hesaplayıcı


Hayır- bu noktadan noktaya jeodezik mesafeyi değil, yol mesafesini (yollarda vb.) Hesaplar.
Yarin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.