Hitung jarak antara dua titik di google maps V3

Jawaban:

460

Jika Anda ingin menghitungnya sendiri, maka Anda bisa menggunakan rumus 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
sumber
4
Mengapa Anda menyarankan menggunakan Math.atan2 (Math.sqrt (a), Math.sqrt (1-a)) alih-alih Math.asin (Math.sqrt (a)) yang paling sederhana?
Emanuele Paolini
3
@EmanuelePaolini - Secara matematis, atan2 (sqrt (a), sqrt (1-a)) = asin (sqrt (a)) = acos (sqrt (1-a)), tetapi versi atan2 tetap dikondisikan secara numerik lebih baik untuk semua nilai dari Sebuah.
ChrisV
23
Kawan Pertanyaan. Mengapa Anda sangat suka menggunakan 1 huruf nama variabel untuk menyelesaikan masalah yang memerlukan imajinasi di mana nama variabel yang baik bisa membantu? Hanya bertanya :)
pie6k
2
Bukankah var R = 6371; untuk Km?
Alexander Fradiani
5
Fungsi p1.lat()dan p1.lng()menganggap bahwa input data Anda adalah google.maps.LatLngobjek. Jika Anda hanya memiliki data mentah seperti {lat: __, lon: __}maka Anda akan menggunakan p1.lat, misalnya.
Don McCurdy
309

Sebenarnya ada metode di GMap3. Ini adalah metode statis google.maps.geometry.sphericalnamespace.

Dibutuhkan sebagai argumen dua LatLngobjek dan akan menggunakan jari-jari Earth default 6378137 meter, meskipun jari-jari default dapat diganti dengan nilai khusus jika perlu.

Pastikan Anda memasukkan:

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

di bagian kepala Anda.

Panggilannya adalah:

google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);
Emil Badh
sumber
10
Jadi mengapa ada perbedaan 1% dalam jawaban yang diberikan oleh komputasi bulat Google dan antara rumus jarak Haversine?
Matt S
7
@RamenRecon Saya tidak yakin tetapi quess akan menggunakan nilai yang berbeda untuk jari-jari bumi.
Emil Badh
11
@RamenRecon ya, Emil benar tentang ini. Dokumentasi mengatakan: Jari-jari default adalah jari-jari bumi 6378137 meter. Tapi Mike di Haversine di atas menggunakan 6371km sebagai gantinya.
Laszlo
Tautan di atas sekarang rusak, tetapi penjelasan metode ini tidak terlalu menjadi masalah.
GChorn
2
@ ABCD.ca Ini bukan nomor saya. Pertanyaan ini adalah tentang versi 3 dari Perpustakaan Google Maps. Anda bertanya mengapa perhitungan Anda berbeda dari mereka. Itu karena mereka menggunakan nilai yang berbeda untuk jari-jari bumi daripada Anda. Referensi untuk nomornya? developers.google.com/maps/documentation/javascript/… Tepat di bawah tajuk utama.
Emil Badh
30

Contoh menggunakan GPS lintang / bujur 2 titik.

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
sumber
3
Hasil jarak dinyatakan dalam meter.
joan16v
1
@ joan16v cara meminta google.maps.geometry di node.js. saya ingin menggunakan kode di atas dalam node.js. modul mana yang harus saya instal dan file apa yang harus saya butuhkan.
Kisor
15

Cukup tambahkan ini ke awal kode JavaScript Anda:

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

dan kemudian gunakan fungsi seperti ini:

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
sumber
Solusi intelek tapi saya ingin tahu di unit apa ia mengembalikan hasilnya. Saya mendapat 3.013 .. apakah dalam mil, km ??
Gowthami Gattineni
Nilai yang dikembalikan adalah dalam meter. Karenanya dist / 1000 memberi Anda nilai dalam 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
sumber
3
ini jawaban terbaik Mengapa menambahkan fungsi ketika Google API sudah memiliki fungsi
felixfbecker
Apakah ada varian java yang tersedia untuk API ini? Saya tidak dapat menemukannya setelah banyak pencarian.
Sanketh
@felixfbecker, karena Anda mungkin bekerja di lingkungan di mana Anda tidak dapat memasukkan Google maps API ke dalam scripttag dan memanggil metode-metode itu. Suka bereaksi asli.
Nnanyielugo
11

Berikut ini adalah implementasi c # dari forumula ini

 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
sumber
5
Ini tidak berlaku untuk pertanyaan awal tentang bagaimana melakukannya di Google Maps.
Niklas Wulff
Tidak ada fungsi bawaan untuk menghitung jarak secara langsung, Anda harus menggunakan layanan direktori untuk dua titik dan mengekstrak jarak keluar dari XML / JSON yang dikembalikan.
Naveed Ahmad
1
Komentar saya adalah pada kenyataan bahwa akan lebih baik untuk menyediakan solusi dalam javascript, karena thread starter tidak mengatakan apakah dia menggunakan php, .net atau html statis.
Niklas Wulff
11

Dengan google Anda dapat melakukannya dengan menggunakan api bulat , google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);.

Namun, jika ketepatan proyeksi bola atau solusi haversine tidak cukup tepat untuk Anda (misalnya jika Anda dekat dengan kutub atau menghitung jarak yang lebih jauh), Anda harus menggunakan perpustakaan yang berbeda.

Sebagian besar informasi tentang subjek saya temukan di Wikipedia di sini .

Trik untuk melihat apakah presisi dari algoritma yang diberikan memadai adalah dengan mengisi radius maksimum dan minimum bumi dan melihat apakah perbedaannya dapat menyebabkan masalah untuk use case Anda. Banyak detail lainnya dapat ditemukan di artikel ini

Pada akhirnya google api atau haversine akan melayani sebagian besar tujuan tanpa masalah.

iwein
sumber
9

Menggunakan PHP, Anda dapat menghitung jarak menggunakan fungsi sederhana ini:

// untuk menghitung jarak antara dua lat & lon

function calcul_distance ($ lat1, $ lon1, $ lat2, $ lon2, $ unit = 'N') 
{ 
  $ theta = $ 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") {
    return ($ miles * 1.609344); 
  } lain jika ($ unit == "N") {
      return ($ miles * 0.8684);
    } lain {
        mengembalikan $ mil;
      }
}

// fungsi berakhir di sini
Ravinder Singh
sumber
2
Ada kondisi dalam fungsi yang jika Anda melewati unit Ksaat itu akan memberi Anda jarak dalam Km. Periksa.
Dead Man
fungsi ini bekerja dengan sangat baik dan memberikan jarak dari lokasi bintang ke semua lokasi. bisakah ia melintasi dengan cara pertama kali menemukan lokasi yang paling nyaman dan menjadi sebagai sumber atau memulai dan kemudian menemukan itu terdekat berikutnya tetapi bukan sumber pertama dan seterusnya untuk semua?
Waheed ur Rehman
8

SOLUSI OFFLINE - Algoritma Haversine

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

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

MarceloBarbosa
sumber
3

Harus melakukannya ... Cara skrip tindakan

//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
sumber
3

Dalam kasus saya, yang terbaik adalah menghitung ini dalam SQL Server, karena saya ingin mengambil lokasi saat ini dan kemudian mencari semua kode pos dalam jarak tertentu dari lokasi saat ini. Saya juga punya DB yang berisi daftar kode pos dan panjang lat mereka. Bersulang

--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
pengguna2004796
sumber
Tidak yakin ini efisien untuk penggunaan sisi klien.
Nizar B.
Mungkin bukan solusi ujung depan, tapi jelas apa yang saya cari. Terima kasih.
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
sumber
1

Cukup mudah menggunakan layanan Google Distance Matrix

Langkah pertama adalah mengaktifkan layanan Distance Matrix dari google API console. mengembalikan jarak antara satu set lokasi. Dan terapkan fungsi sederhana ini

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

          }
        });
      }

Di mana origin1 adalah lokasi dan tujuan AndaA adalah lokasi tujuan. Anda dapat menambahkan dua atau lebih data di atas.

Rad Dokumentasi Lengkap dengan sebuah contoh

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

Saya menemukan versi online yang 80% benar tetapi terhubung dengan parameter yang salah dan tidak konsisten dalam menggunakan input, versi ini memperbaiki yang sepenuhnya

Periksa pensil
sumber
0

Untuk menghitung jarak di Google Maps, Anda dapat menggunakan API Arah. Itu akan menjadi salah satu cara termudah untuk melakukannya. Untuk mendapatkan data dari Google Server, Anda dapat menggunakan Retrofit atau Volley. Keduanya memiliki keunggulan masing-masing. Lihatlah kode berikut di mana saya telah menggunakan retrofit untuk mengimplementasikannya:

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

}

Di atas adalah kode fungsi build_retrofit_and_get_response untuk menghitung jarak. Di bawah ini adalah Retrofit Interface yang sesuai:

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

}

Saya harap ini menjelaskan pertanyaan Anda. Semua yang terbaik :)

Sumber: Kalkulator Jarak Google Maps

Navneet Goel
sumber
Tidak- ini menghitung jarak tempuh (di jalan dll), bukan jarak geodesik point-to-point.
Yarin