Hitung jarak antara dua titik lintang-bujur? (Formula Haversine)

908

Bagaimana cara menghitung jarak antara dua titik yang ditentukan oleh lintang dan bujur?

Untuk klarifikasi, saya ingin jarak dalam kilometer; poin menggunakan sistem WGS84 dan saya ingin memahami akurasi relatif dari pendekatan yang tersedia.

Robin Minto
sumber
Untuk akurasi yang lebih baik - lihat stackoverflow.com/questions/1420045/…
Lior Kogan
3
Perhatikan bahwa Anda tidak dapat menerapkan rumus Haversine pada ellipsoid revolusi seperti WGS 84. Anda hanya dapat menerapkan metode ini pada bola dengan jari-jari.
Mike T
3
Sebagian besar jawaban di sini menggunakan trigonometri bola sederhana, sehingga hasilnya agak kasar dibandingkan dengan jarak ellipsoid WGS84 yang digunakan dalam sistem GPS. Beberapa jawaban merujuk pada rumus Vincenty untuk ellipsoids, tetapi algoritma itu dirancang untuk digunakan pada kalkulator era era 1960-an dan memiliki masalah stabilitas & akurasi; kami memiliki perangkat keras dan perangkat lunak yang lebih baik sekarang. Silakan lihat GeographicLib untuk perpustakaan berkualitas tinggi dengan implementasi dalam berbagai bahasa.
PM 2Ring
@ MikeT - benar meskipun banyak jawaban di sini tampaknya berguna untuk jarak kecil : Jika Anda mengambil lat / long dari WGS 84, dan menerapkan Haversine seolah-olah itu adalah titik - titik pada bola, jangan Anda mendapatkan jawaban yang kesalahannya hanya disebabkan oleh faktor perataan bumi, jadi mungkin dalam 1% dari formula yang lebih akurat? Dengan peringatan bahwa ini adalah jarak kecil, katakanlah dalam satu kota.
ToolmakerSteve
1
Untuk bentuk pelat ini: Mono / .NET 4.5 / .NET Core / Windows Phone 8.x / Platform Windows Universal / Xamarin iOS / Xamarin Android, lihat stackoverflow.com/a/54296314/2736742
A. Morel

Jawaban:

1148

Tautan ini mungkin bermanfaat bagi Anda, karena merinci penggunaan rumus Haversine untuk menghitung jarak.

Kutipan:

Skrip ini [dalam Javascript] menghitung jarak lingkaran besar antara dua titik - yaitu, jarak terpendek di atas permukaan bumi - menggunakan rumus 'Haversine'.

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(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; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}
Membuang
sumber
51
Apakah perhitungan / metode ini menjelaskan bahwa Bumi adalah sebuah bola (bukan bola yang sempurna)? Pertanyaan asli menanyakan jarak antara titik-titik pada bola dunia WGS84. Tidak yakin berapa banyak kesalahan yang terjadi dengan menggunakan bola yang sempurna, tapi saya menduga itu bisa sangat tergantung pada titik di dunia, sehingga perbedaannya perlu diingat.
redcalx
15
Rumus Haversine tidak menjelaskan bahwa Bumi adalah spheroid, jadi Anda akan mendapatkan beberapa kesalahan karena fakta itu. Tidak dapat dijamin benar lebih baik dari 0,5%. Itu mungkin tingkat kesalahan yang bisa diterima atau tidak.
Brandon
24
Apakah ada alasan untuk menggunakan, Math.atan2(Math.sqrt(a), Math.sqrt(1-a))bukan Math.asin(Math.sqrt(h)), yang akan menjadi implementasi langsung dari formula yang digunakan artikel Wikipedia? Apakah lebih efisien dan / atau lebih stabil secara numerik?
musiphil
16
@ UsmanMutawakil Nah, 38 mil yang Anda dapatkan adalah jarak di jalan. Algoritma ini menghitung jarak garis lurus pada permukaan bumi. Google Maps memiliki alat jarak (kiri bawah, "Labs") yang melakukan hal yang sama, gunakan itu untuk membandingkan.
Pascal
4
@ Forte_201092: Karena itu tidak perlu - (sin(x))²sederajat(sin(-x))²
Jean Hominal
360

Saya perlu menghitung banyak jarak antara titik-titik untuk proyek saya, jadi saya melanjutkan dan mencoba mengoptimalkan kode, saya temukan di sini. Rata-rata di berbagai browser implementasi saya yang baru berjalan 2 kali lebih cepat daripada jawaban yang paling banyak dipilih.

function distance(lat1, lon1, lat2, lon2) {
  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((lat2 - lat1) * p)/2 + 
          c(lat1 * p) * c(lat2 * p) * 
          (1 - c((lon2 - lon1) * p))/2;

  return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

Anda dapat bermain dengan jsPerf saya dan lihat hasilnya di sini .

Baru-baru ini saya perlu melakukan hal yang sama di python, jadi di sini adalah implementasi python :

from math import cos, asin, sqrt, pi

def distance(lat1, lon1, lat2, lon2):
    p = pi/180
    a = 0.5 - cos((lat2-lat1)*p)/2 + cos(lat1*p) * cos(lat2*p) * (1-cos((lon2-lon1)*p))/2
    return 12742 * asin(sqrt(a)) #2*R*asin...

Dan demi kelengkapan: Haversine on wiki.

Salvador Dali
sumber
13
@ AngularM dan ada kemungkinan besar Google menghitung jarak jika Anda akan mengambil beberapa jalan dan bukan garis lurus.
Salvador Dali
3
Google menghitung jarak mengemudi, ini menghitung "seperti burung gagak terbang"
Hobbyist
4
@Ouadie dan apakah ini akan meningkatkan kecepatan? Kemungkinan besar tidak, tapi saya akan berakhir dengan banyak 'barang Anda tidak bekerja' untuk orang-orang yang menyalinnya di browser lama
Salvador Dali
4
baik ya tapi apa artinya // 2 * R; R = 6371 km? dan metode saat ini memberikan jawaban dalam km atau mil? membutuhkan dokumentasi yang lebih baik. Terima kasih
Khalil Khalaf
20
@KhalilKhalaf apakah Anda bercanda atau mencoba untuk troll di sini? km adalah singkatan dari kilometer. Menurut Anda, apa artinya R (terutama jika kita berbicara tentang seorang shpere)? Tebak dalam satuan apa jawabannya akan jika Anda sudah melihat km. Apa jenis dokumentasi yang Anda cari di sini: ada 4 baris di sana.
Salvador Dali
69

Berikut ini adalah Implementasi C #:

static class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIUS = 6378.16;

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

}
akun lama-jaircazarin
sumber
14
Anda menggunakan jari-jari khatulistiwa, tetapi Anda harus menggunakan rata-rata jari-jari, yang 6371 km
Philippe Leybaert
7
Bukankah ini seharusnya double dlon = Radians(lon2 - lon1);dandouble dlat = Radians(lat2 - lat1);
Chris Marisic
Saya setuju dengan Chris Marisic. Saya menggunakan kode asli dan perhitungannya salah. Saya menambahkan panggilan untuk mengubah delta menjadi radian dan berfungsi dengan baik sekarang. Saya mengirimkan suntingan dan menunggu untuk ditinjau oleh rekan sejawat.
Bryan Bedard
Saya mengirimkan suntingan lain karena lat1 & lat2 juga perlu dikonversi ke radian. Saya juga merevisi rumus untuk penugasan ke sesuai dengan rumus dan kode yang ditemukan di sini: movable-type.co.uk/scripts/latlong.html
Bryan Bedard
apakah RADIUSnilainya harus 6371 seperti pada jawaban lainnya?
Chris Hayes
66

Berikut ini adalah implementasi java dari formula Haversine.

public final static double AVERAGE_RADIUS_OF_EARTH_KM = 6371;
public int calculateDistanceInKilometer(double userLat, double userLng,
  double venueLat, double venueLng) {

    double latDistance = Math.toRadians(userLat - venueLat);
    double lngDistance = Math.toRadians(userLng - venueLng);

    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
      + Math.cos(Math.toRadians(userLat)) * Math.cos(Math.toRadians(venueLat))
      * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);

    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return (int) (Math.round(AVERAGE_RADIUS_OF_EARTH_KM * c));
}

Perhatikan bahwa di sini kita membulatkan jawaban ke km terdekat.

katak siapa
sumber
2
Jika kita ingin menghitung jarak antara dua titik dalam meter, apa cara yang lebih akurat? Untuk digunakan 6371000sebagai jari-jari bumi? (rata-rata jari-jari bumi adalah 6371000 meter) atau mengkonversi kilometer ke meter dari fungsi Anda?
Micro
Jika Anda ingin miles, 0.621371
gandakan
42

Terima kasih banyak untuk semua ini. Saya menggunakan kode berikut dalam aplikasi iPhone Objective-C saya:

const double PIx = 3.141592653589793;
const double RADIO = 6371; // Mean radius of Earth in Km

double convertToRadians(double val) {

   return val * PIx / 180;
}

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

        double dlon = convertToRadians(place2.longitude - place1.longitude);
        double dlat = convertToRadians(place2.latitude - place1.latitude);

        double a = ( pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))) * cos(convertToRadians(place2.latitude)) * pow(sin(dlon / 2), 2);
        double angle = 2 * asin(sqrt(a));

        return angle * RADIO;
}

Lintang dan Bujur berada dalam desimal. Saya tidak menggunakan panggilan min () untuk asin () karena jarak yang saya gunakan sangat kecil sehingga mereka tidak memerlukannya.

Itu memberikan jawaban yang salah sampai saya memberikan nilai dalam radian - sekarang ini hampir sama dengan nilai yang diperoleh dari aplikasi Peta Apple :-)

Pembaruan ekstra:

Jika Anda menggunakan iOS4 atau lebih baru maka Apple memberikan beberapa metode untuk melakukan ini sehingga fungsionalitas yang sama akan tercapai dengan:

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

    MKMapPoint  start, finish;


    start = MKMapPointForCoordinate(place1);
    finish = MKMapPointForCoordinate(place2);

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}
Stephen Watson
sumber
1
iOS SDK memiliki implementasinya sendiri: developer.apple.com/library/ios/documentation/CoreLocation/… :
tuler
Saya pikir kurung di sekitar pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))tidak benar. Hapus itu, dan hasilnya cocok dengan yang saya dapatkan ketika saya menggunakan implementasi lain pada halaman ini, atau menerapkan formula Haversine dari Wikipedia dari awal.
zanedp
Menggunakan koordinat (40.7127837, -74.0059413) untuk NYC dan (34.052234, -118.243685) untuk LA, dengan jumlah ()sekitar itu, saya mendapatkan 3869.75. Tanpa mereka, saya mendapatkan 3935,75, yang merupakan hasil pencarian web.
zanedp
40

Ini adalah fungsi PHP sederhana yang akan memberikan perkiraan yang sangat masuk akal (di bawah +/- 1% margin error).

<?php
function distance($lat1, $lon1, $lat2, $lon2) {

    $pi80 = M_PI / 180;
    $lat1 *= $pi80;
    $lon1 *= $pi80;
    $lat2 *= $pi80;
    $lon2 *= $pi80;

    $r = 6372.797; // mean radius of Earth in km
    $dlat = $lat2 - $lat1;
    $dlon = $lon2 - $lon1;
    $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2);
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    $km = $r * $c;

    //echo '<br/>'.$km;
    return $km;
}
?>

Seperti dikatakan di atas; bumi BUKAN bola. Ini seperti bola bisbol tua yang Mark McGwire putuskan untuk praktikkan - penuh penyok dan gundukan. Perhitungan yang lebih sederhana (seperti ini) memperlakukannya seperti bola.

Metode yang berbeda mungkin lebih atau kurang tepat sesuai dengan posisi Anda pada ovoid tidak teratur ini DAN seberapa jauh jarak poin Anda (semakin dekat semakin kecil margin kesalahan absolutnya). Semakin tepat harapan Anda, semakin kompleks matematika.

Untuk info lebih lanjut: jarak geografis wikipedia

tony gil
sumber
4
Ini bekerja dengan sempurna! Saya baru saja menambahkan $ distance_miles = $ km * 0.621371; dan itu yang saya butuhkan untuk perkiraan jarak dalam mil! Terima kasih tony.
31

Saya memposting di sini contoh kerja saya.

Daftar semua titik dalam tabel yang memiliki jarak antara titik yang ditunjuk (kami menggunakan titik acak - lat: 45.20327, panjang: 23.7806) kurang dari 50 KM, dengan lintang & bujur, di MySQL (bidang tabel adalah coord_lat dan coord_long):

Daftar semua yang memiliki JARAK <50, dalam Kilometer (dianggap radius Bumi 6371 KM):

SELECT denumire, (6371 * acos( cos( radians(45.20327) ) * cos( radians( coord_lat ) ) * cos( radians( 23.7806 ) - radians(coord_long) ) + sin( radians(45.20327) ) * sin( radians(coord_lat) ) )) AS distanta 
FROM obiective 
WHERE coord_lat<>'' 
    AND coord_long<>'' 
HAVING distanta<50 
ORDER BY distanta desc

Contoh di atas diuji dalam MySQL 5.0.95 dan 5.5.16 (Linux).

Conualfy
sumber
Saya pikir pendekatan yang baik mungkin pra menyaring hasil menggunakan aproximation, jadi rumus yang berat hanya diterapkan untuk beberapa kasus. Bermanfaat khusus jika Anda memiliki kondisi lain. Saya menggunakan ini untuk aprox awal: stackoverflow.com/questions/1253499/…
Pato
28

Di jawaban lain implementasi di hilang.

Menghitung jarak antara dua titik cukup mudah dengan distmfungsi dari geospherepaket:

distm(p1, p2, fun = distHaversine)

dimana:

p1 = longitude/latitude for point(s)
p2 = longitude/latitude for point(s)
# type of distance calculation
fun = distCosine / distHaversine / distVincentySphere / distVincentyEllipsoid 

Karena bumi tidak bulat sempurna, rumus Vincenty untuk ellipsoid mungkin merupakan cara terbaik untuk menghitung jarak. Jadi dalam geospherepaket yang Anda gunakan kemudian:

distm(p1, p2, fun = distVincentyEllipsoid)

Tentunya Anda tidak harus menggunakan geospherepaket, Anda juga dapat menghitung jarak di dasar Rdengan fungsi:

hav.dist <- function(long1, lat1, long2, lat2) {
  R <- 6371
  diff.long <- (long2 - long1)
  diff.lat <- (lat2 - lat1)
  a <- sin(diff.lat/2)^2 + cos(lat1) * cos(lat2) * sin(diff.long/2)^2
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}
Jaap
sumber
Untuk memastikan saya jelas tentang apa yang Anda katakan: Kode yang Anda berikan di akhir posting: Apakah itu implementasi rumus Vincenty? Sejauh yang Anda tahu, itu harus memberikan jawaban yang sama dengan memanggil Vincenty di geosphere? [Saya tidak punya geosfer atau perpustakaan lain; hanya mencari beberapa kode untuk dimasukkan dalam aplikasi lintas platform. Saya tentu saja akan memverifikasi beberapa kasus uji terhadap kalkulator yang dikenal baik.]
ToolmakerSteve
1
@ToolmakerSteve fungsi pada akhir jawaban saya adalah implementasi dari metode Haversine
Jaap
Hai @ Jaap, bisakah saya bertanya berapa satuan pengukuran untuk formula? Apakah dalam meter?
Jackson
11

The haversine jelas merupakan formula yang baik untuk sebagian besar kasus, jawaban lain sudah termasuk jadi saya tidak akan mengambil ruang. Tetapi penting untuk dicatat bahwa apa pun formula yang digunakan (ya, bukan hanya satu). Karena rentang akurasi yang sangat besar serta waktu komputasi yang diperlukan. Pilihan formula membutuhkan sedikit lebih banyak pemikiran daripada jawaban sederhana tanpa otak.

Posting ini dari seseorang di nasa, adalah yang terbaik yang saya temukan ketika membahas opsi

http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html

Misalnya, jika Anda hanya menyortir baris berdasarkan jarak dalam radius 100 mil. Formula bumi datar akan jauh lebih cepat daripada haversine.

HalfPi = 1.5707963;
R = 3956; /* the radius gives you the measurement unit*/

a = HalfPi - latoriginrad;
b = HalfPi - latdestrad;
u = a * a + b * b;
v = - 2 * a * b * cos(longdestrad - longoriginrad);
c = sqrt(abs(u + v));
return R * c;

Perhatikan hanya ada satu cosinus dan satu akar kuadrat. Vs 9 dari mereka menggunakan formula Haversine.

Arturo Hernandez
sumber
Itu kemungkinan yang bagus. Perlu diketahui bahwa jarak maksimum yang disarankan dalam diskusi adalah 12 mil, bukan 100 , dan meskipun demikian, kesalahan mungkin merayap hingga 30 meter (100 kaki), tergantung pada posisi globe.
Eric Wu
7

Anda bisa menggunakan build di CLLocationDistance untuk menghitung ini:

CLLocation *location1 = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
[self distanceInMetersFromLocation:location1 toLocation:location2]

- (int)distanceInMetersFromLocation:(CLLocation*)location1 toLocation:(CLLocation*)location2 {
    CLLocationDistance distanceInMeters = [location1 distanceFromLocation:location2];
    return distanceInMeters;
}

Dalam kasus Anda jika Anda ingin kilometer, bagilah dengan 1000.

Andre Cytryn
sumber
7

Saya tidak suka menambahkan jawaban lain, tetapi Google maps API v.3 memiliki geometri bola (dan banyak lagi). Setelah mengonversi WGS84 Anda ke derajat desimal, Anda dapat melakukan ini:

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

distance = google.maps.geometry.spherical.computeDistanceBetween(
    new google.maps.LatLng(fromLat, fromLng), 
    new google.maps.LatLng(toLat, toLng));

Tidak ada kata tentang seberapa akurat perhitungan Google atau bahkan model apa yang digunakan (meskipun ia mengatakan "bola" daripada "geoid". Ngomong-ngomong, jarak "garis lurus" jelas akan berbeda dari jarak jika seseorang melakukan perjalanan di permukaan bumi yang dianggap oleh semua orang.

Steven Christenson
sumber
jarak dalam meter. sebagai alternatif seseorang dapat menggunakan computeLength ()
electrobabe
7

Asal-usul Python Asal adalah pusat dari Amerika Serikat yang berdekatan.

from haversine import haversine
origin = (39.50, 98.35)
paris = (48.8567, 2.3508)
haversine(origin, paris, miles=True)

Untuk mendapatkan jawaban dalam kilometer cukup atur miles = false.

invoketheshell
sumber
1
Anda mengimpor paket non-standar yang melakukan semua pekerjaan. Saya tidak tahu apakah itu yang paling bermanfaat.
Teepeemm
Paket ini di PyPI, Indeks Paket Python, sebagai paket python 3 bersama dengan numpy dan scikit-belajar. Tidak yakin mengapa kita menambahkan paket. Mereka cenderung sangat berguna. Sebagai sumber terbuka, orang juga dapat memeriksa metode yang terkandung. Saya pikir banyak orang akan menemukan paket ini berguna jadi saya akan meninggalkan posting meskipun downvote. Bersulang. :)
invoketheshell
7

Mungkin ada solusi yang lebih sederhana, dan lebih tepat: Garis keliling bumi adalah 40.000 km di garis khatulistiwa, sekitar 37.000 pada siklus Greenwich (atau bujur). Jadi:

pythagoras = function (lat1, lon1, lat2, lon2) {
   function sqr(x) {return x * x;}
   function cosDeg(x) {return Math.cos(x * Math.PI / 180.0);}

   var earthCyclePerimeter = 40000000.0 * cosDeg((lat1 + lat2) / 2.0);
   var dx = (lon1 - lon2) * earthCyclePerimeter / 360.0;
   var dy = 37000000.0 * (lat1 - lat2) / 360.0;

   return Math.sqrt(sqr(dx) + sqr(dy));
};

Saya setuju bahwa itu harus disetel dengan baik, saya sendiri mengatakan bahwa itu adalah ellipsoid, jadi jari-jari yang akan dikalikan dengan cosinus bervariasi. Tapi ini sedikit lebih akurat. Dibandingkan dengan Google Maps dan itu mengurangi kesalahan secara signifikan.

Meymann
sumber
Apakah fungsi ini mengembalikan jarak dalam km?
Wikki
Yaitu, hanya karena siklus khatulistiwa dan garis bujur berada dalam Km. Untuk miles, bagilah 40000 dan 37000 dengan 1,6. Merasa culun, Anda dapat mengubahnya menjadi Ris, digandakan dengan sekitar 7 atau ke parasang, bagi dengan 2.2 ;-)
Meymann
Ini sepertinya jawaban terbaik yang ditawarkan di sini. Saya ingin menggunakannya tetapi saya hanya ingin tahu apakah ada cara untuk memverifikasi kebenaran dari algoritma ini. Saya menguji f (50,5,58,3). Ini memberikan 832km, sedangkan movable-type.co.uk/scripts/latlong.html menggunakan rumus 'haversine' menghasilkan 899km. Apakah ada perbedaan besar?
Chong Lip Phang
Selain itu, saya pikir nilai yang dikembalikan oleh kode di atas adalah dalam m, dan bukan km.
Chong Lip Phang
@ChongLipPhang - PERHATIAN: Teorema Pythagoras hanya perkiraan yang wajar untuk area kecil , karena teorema ini mengasumsikan bumi itu datar. Sebagai kasus ekstrem, mulailah dari garis khatulistiwa, dan bergerak 90 derajat ke timur dan 90 derajat ke utara. Hasil akhirnya tentu saja adalah kutub utara, dan sama dengan bergerak 0 derajat ke timur dan 90 derajat ke utara; melakukannya sqrt (sqr (dx) + sqr (dy)) akan menjadi liar dalam kasus pertama. ~ sqrt (10km sqr + 10km sqr) ~ = 14,4 km vs jarak yang benar ~ 10km.
ToolmakerSteve
7

Semua jawaban di atas menganggap bumi adalah bola. Namun, perkiraan yang lebih akurat adalah spheroid oblate.

a= 6378.137#equitorial radius in km
b= 6356.752#polar radius in km

def Distance(lat1, lons1, lat2, lons2):
    lat1=math.radians(lat1)
    lons1=math.radians(lons1)
    R1=(((((a**2)*math.cos(lat1))**2)+(((b**2)*math.sin(lat1))**2))/((a*math.cos(lat1))**2+(b*math.sin(lat1))**2))**0.5 #radius of earth at lat1
    x1=R*math.cos(lat1)*math.cos(lons1)
    y1=R*math.cos(lat1)*math.sin(lons1)
    z1=R*math.sin(lat1)

    lat2=math.radians(lat2)
    lons2=math.radians(lons2)
    R1=(((((a**2)*math.cos(lat2))**2)+(((b**2)*math.sin(lat2))**2))/((a*math.cos(lat2))**2+(b*math.sin(lat2))**2))**0.5 #radius of earth at lat2
    x2=R*math.cos(lat2)*math.cos(lons2)
    y2=R*math.cos(lat2)*math.sin(lons2)
    z2=R*math.sin(lat2)

    return ((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)**0.5
Keerthana Gopalakrishnan
sumber
6

Berikut ini adalah Implementasi SQL untuk menghitung jarak dalam km,

SELECT UserId, ( 3959 * acos( cos( radians( your latitude here ) ) * cos( radians(latitude) ) * 
cos( radians(longitude) - radians( your longitude here ) ) + sin( radians( your latitude here ) ) * 
sin( radians(latitude) ) ) ) AS distance FROM user HAVING
distance < 5  ORDER BY distance LIMIT 0 , 5;

Untuk perincian lebih lanjut dalam implementasi dengan pemrograman bahasa, Anda bisa langsung melalui skrip php yang diberikan di sini

Kiran Maniya
sumber
5

Berikut ini adalah implementasi naskah formula Haversine

static getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
    var deg2Rad = deg => {
        return deg * Math.PI / 180;
    }

    var r = 6371; // Radius of the earth in km
    var dLat = deg2Rad(lat2 - lat1);   
    var dLon = deg2Rad(lon2 - lon1);
    var a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(deg2Rad(lat1)) * Math.cos(deg2Rad(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; // Distance in km
    return d;
}
Sel
sumber
5

Sebagaimana ditunjukkan, perhitungan yang akurat harus memperhitungkan bahwa bumi bukanlah bola yang sempurna. Berikut adalah beberapa perbandingan dari berbagai algoritma yang ditawarkan di sini:

geoDistance(50,5,58,3)
Haversine: 899 km
Maymenn: 833 km
Keerthana: 897 km
google.maps.geometry.spherical.computeDistanceBetween(): 900 km

geoDistance(50,5,-58,-3)
Haversine: 12030 km
Maymenn: 11135 km
Keerthana: 10310 km
google.maps.geometry.spherical.computeDistanceBetween(): 12044 km

geoDistance(.05,.005,.058,.003)
Haversine: 0.9169 km
Maymenn: 0.851723 km
Keerthana: 0.917964 km
google.maps.geometry.spherical.computeDistanceBetween(): 0.917964 km

geoDistance(.05,80,.058,80.3)
Haversine: 33.37 km
Maymenn: 33.34 km
Keerthana: 33.40767 km
google.maps.geometry.spherical.computeDistanceBetween(): 33.40770 km

Pada jarak kecil, algoritma Keerthana tampaknya bertepatan dengan Google Maps. Google Maps tampaknya tidak mengikuti algoritma sederhana apa pun, menunjukkan bahwa itu mungkin metode yang paling akurat di sini.

Bagaimanapun, ini adalah implementasi Javascript dari algoritma Keerthana:

function geoDistance(lat1, lng1, lat2, lng2){
    const a = 6378.137; // equitorial radius in km
    const b = 6356.752; // polar radius in km

    var sq = x => (x*x);
    var sqr = x => Math.sqrt(x);
    var cos = x => Math.cos(x);
    var sin = x => Math.sin(x);
    var radius = lat => sqr((sq(a*a*cos(lat))+sq(b*b*sin(lat)))/(sq(a*cos(lat))+sq(b*sin(lat))));

    lat1 = lat1 * Math.PI / 180;
    lng1 = lng1 * Math.PI / 180;
    lat2 = lat2 * Math.PI / 180;
    lng2 = lng2 * Math.PI / 180;

    var R1 = radius(lat1);
    var x1 = R1*cos(lat1)*cos(lng1);
    var y1 = R1*cos(lat1)*sin(lng1);
    var z1 = R1*sin(lat1);

    var R2 = radius(lat2);
    var x2 = R2*cos(lat2)*cos(lng2);
    var y2 = R2*cos(lat2)*sin(lng2);
    var z2 = R2*sin(lat2);

    return sqr(sq(x1-x2)+sq(y1-y2)+sq(z1-z2));
}
Chong Lip Phang
sumber
4

Skrip ini [dalam PHP] menghitung jarak antara dua titik.

public static function getDistanceOfTwoPoints($source, $dest, $unit='K') {
        $lat1 = $source[0];
        $lon1 = $source[1];
        $lat2 = $dest[0];
        $lon2 = $dest[1];

        $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);
        }
        else if ($unit == "M")
        {
            return ($miles * 1.609344 * 1000);
        }
        else if ($unit == "N") {
            return ($miles * 0.8684);
        } 
        else {
            return $miles;
        }
    }
Er.Subhendu Kumar Pati
sumber
4

Implementasi Java dalam formula Haversine sesuai

double calculateDistance(double latPoint1, double lngPoint1, 
                         double latPoint2, double lngPoint2) {
    if(latPoint1 == latPoint2 && lngPoint1 == lngPoint2) {
        return 0d;
    }

    final double EARTH_RADIUS = 6371.0; //km value;

    //converting to radians
    latPoint1 = Math.toRadians(latPoint1);
    lngPoint1 = Math.toRadians(lngPoint1);
    latPoint2 = Math.toRadians(latPoint2);
    lngPoint2 = Math.toRadians(lngPoint2);

    double distance = Math.pow(Math.sin((latPoint2 - latPoint1) / 2.0), 2) 
            + Math.cos(latPoint1) * Math.cos(latPoint2)
            * Math.pow(Math.sin((lngPoint2 - lngPoint1) / 2.0), 2);
    distance = 2.0 * EARTH_RADIUS * Math.asin(Math.sqrt(distance));

    return distance; //km value
}
ak-j
sumber
3

Untuk menghitung jarak antara dua titik pada bola Anda perlu melakukan perhitungan Lingkaran Besar .

Ada sejumlah pustaka C / C ++ untuk membantu proyeksi peta di MapTools jika Anda perlu memproyeksikan ulang jarak Anda ke permukaan datar. Untuk melakukan ini, Anda akan memerlukan string proyeksi dari berbagai sistem koordinat.

Anda juga dapat menemukan MapWindow alat yang berguna untuk memvisualisasikan poin. Juga sebagai open source-nya panduan yang berguna untuk bagaimana menggunakan perpustakaan proj.dll, yang tampaknya menjadi perpustakaan proyeksi open source inti.


sumber
3

Inilah jawaban yang diterima implementasi yang diporting ke Jawa jika ada yang membutuhkannya.

package com.project529.garage.util;


/**
 * Mean radius.
 */
private static double EARTH_RADIUS = 6371;

/**
 * Returns the distance between two sets of latitudes and longitudes in meters.
 * <p/>
 * Based from the following JavaScript SO answer:
 * http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
 * which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
 */
public double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) {
    double dLat = toRadians(lat2 - lat1);
    double dLon = toRadians(lon2 - lon1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
                    Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = EARTH_RADIUS * c;

    return d;
}

public double toRadians(double degrees) {
    return degrees * (Math.PI / 180);
}
Eduardo Naveda
sumber
2

Berikut ini adalah implementasi VB.NET, implementasi ini akan memberi Anda hasil dalam KM atau Miles berdasarkan nilai Enum yang Anda berikan.

Public Enum DistanceType
    Miles
    KiloMeters
End Enum

Public Structure Position
    Public Latitude As Double
    Public Longitude As Double
End Structure

Public Class Haversine

    Public Function Distance(Pos1 As Position,
                             Pos2 As Position,
                             DistType As DistanceType) As Double

        Dim R As Double = If((DistType = DistanceType.Miles), 3960, 6371)

        Dim dLat As Double = Me.toRadian(Pos2.Latitude - Pos1.Latitude)

        Dim dLon As Double = Me.toRadian(Pos2.Longitude - Pos1.Longitude)

        Dim a As Double = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(Me.toRadian(Pos1.Latitude)) * Math.Cos(Me.toRadian(Pos2.Latitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2)

        Dim c As Double = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)))

        Dim result As Double = R * c

        Return result

    End Function

    Private Function toRadian(val As Double) As Double

        Return (Math.PI / 180) * val

    End Function

End Class
Taiseer Joudeh
sumber
Setelah menghitung "a", apakah Anda menulis Math.Sin ( dLat ..) dua kali karena kesalahan?
Marco Ottina
2

Saya menyingkat perhitungan dengan menyederhanakan rumus.

Ini dia di Ruby:

include Math
earth_radius_mi = 3959
radians = lambda { |deg| deg * PI / 180 }
coord_radians = lambda { |c| { :lat => radians[c[:lat]], :lng => radians[c[:lng]] } }

# from/to = { :lat => (latitude_in_degrees), :lng => (longitude_in_degrees) }
def haversine_distance(from, to)
  from, to = coord_radians[from], coord_radians[to]
  cosines_product = cos(to[:lat]) * cos(from[:lat]) * cos(from[:lng] - to[:lng])
  sines_product = sin(to[:lat]) * sin(from[:lat])
  return earth_radius_mi * acos(cosines_product + sines_product)
end
Kache
sumber
2
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2,units) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(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; 
  var miles = d / 1.609344; 

if ( units == 'km' ) {  
return d; 
 } else {
return miles;
}}

Solusi Chuck, berlaku untuk miles juga.

MPaulo
sumber
2

Berikut ini adalah implementasi java saya untuk jarak perhitungan melalui derajat desimal setelah beberapa pencarian. Saya menggunakan radius rata-rata dunia (dari wikipedia) dalam km. Jika Anda ingin hasil mil kemudian gunakan radius dunia dalam mil.

public static double distanceLatLong2(double lat1, double lng1, double lat2, double lng2) 
{
  double earthRadius = 6371.0d; // KM: use mile here if you want mile result

  double dLat = toRadian(lat2 - lat1);
  double dLng = toRadian(lng2 - lng1);

  double a = Math.pow(Math.sin(dLat/2), 2)  + 
          Math.cos(toRadian(lat1)) * Math.cos(toRadian(lat2)) * 
          Math.pow(Math.sin(dLng/2), 2);

  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

  return earthRadius * c; // returns result kilometers
}

public static double toRadian(double degrees) 
{
  return (degrees * Math.PI) / 180.0d;
}

sumber
2

Dalam Mysql gunakan fungsi berikut lulus parameter menggunakan POINT(LONG,LAT)

CREATE FUNCTION `distance`(a POINT, b POINT)
 RETURNS double
    DETERMINISTIC
BEGIN

RETURN

GLength( LineString(( PointFromWKB(a)), (PointFromWKB(b)))) * 100000; -- To Make the distance in meters

END;
shanavascet
sumber
2
function getDistanceFromLatLonInKm(position1, position2) {
    "use strict";
    var deg2rad = function (deg) { return deg * (Math.PI / 180); },
        R = 6371,
        dLat = deg2rad(position2.lat - position1.lat),
        dLng = deg2rad(position2.lng - position1.lng),
        a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(position1.lat))
            * Math.cos(deg2rad(position1.lat))
            * Math.sin(dLng / 2) * Math.sin(dLng / 2),
        c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
}

console.log(getDistanceFromLatLonInKm(
    {lat: 48.7931459, lng: 1.9483572},
    {lat: 48.827167, lng: 2.2459745}
));
Raphael C
sumber
2

di sini adalah contoh dalam postgres sql (dalam km, untuk versi miles, ganti 1.609344 dengan versi 0.8684)

CREATE OR REPLACE FUNCTION public.geodistance(alat float, alng float, blat  

float, blng  float)
  RETURNS float AS
$BODY$
DECLARE
    v_distance float;
BEGIN

    v_distance = asin( sqrt(
            sin(radians(blat-alat)/2)^2 
                + (
                    (sin(radians(blng-alng)/2)^2) *
                    cos(radians(alat)) *
                    cos(radians(blat))
                )
          )
        ) * cast('7926.3352' as float) * cast('1.609344' as float) ;


    RETURN v_distance;
END 
$BODY$
language plpgsql VOLATILE SECURITY DEFINER;
alter function geodistance(alat float, alng float, blat float, blng float)
owner to postgres;
fisc
sumber
2

Berikut ini dikonversi menjadi kode Ruby :

include Math
#Note: from/to = [lat, long]

def get_distance_in_km(from, to)
  radians = lambda { |deg| deg * Math.PI / 180 }
  radius = 6371 # Radius of the earth in kilometer
  dLat = radians[to[0]-from[0]]
  dLon = radians[to[1]-from[1]]

  cosines_product = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(radians[from[0]]) * Math.cos(radians[to[1]]) * Math.sin(dLon/2) * Math.sin(dLon/2)

  c = 2 * Math.atan2(Math.sqrt(cosines_product), Math.sqrt(1-cosines_product)) 
  return radius * c # Distance in kilometer
end
aldrien.h
sumber
1

ada contoh yang bagus di sini untuk menghitung jarak dengan PHP http://www.geodatasource.com/developers/php :

 function distance($lat1, $lon1, $lat2, $lon2, $unit) {

     $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);
     } else if ($unit == "N") {
          return ($miles * 0.8684);
     } else {
          return $miles;
     }
 }
ayalcinkaya
sumber