Menghitung jarak antara dua titik, menggunakan garis bujur lintang?

95

Ini percobaan saya, itu hanya cuplikan kode saya:

final double RADIUS = 6371.01;
double temp = Math.cos(Math.toRadians(latA))
            * Math.cos(Math.toRadians(latB))
            * Math.cos(Math.toRadians((latB) - (latA)))
            + Math.sin(Math.toRadians(latA))
            * Math.sin(Math.toRadians(latB));
    return temp * RADIUS * Math.PI / 180;

Saya menggunakan rumus ini untuk mendapatkan lintang dan bujur:

x = Deg + (Min + Sec / 60) / 60)
m4design.dll
sumber

Jawaban:

221

Kode Java yang diberikan oleh Dommer di atas memberikan hasil yang sedikit salah tetapi kesalahan kecil bertambah jika Anda memproses, katakanlah trek GPS. Berikut adalah implementasi metode Haversine di Java yang juga memperhitungkan perbedaan ketinggian antara dua titik.

/**
 * Calculate distance between two points in latitude and longitude taking
 * into account height difference. If you are not interested in height
 * difference pass 0.0. Uses Haversine method as its base.
 * 
 * lat1, lon1 Start point lat2, lon2 End point el1 Start altitude in meters
 * el2 End altitude in meters
 * @returns Distance in Meters
 */
public static double distance(double lat1, double lat2, double lon1,
        double lon2, double el1, double el2) {

    final int R = 6371; // Radius of the earth

    double latDistance = Math.toRadians(lat2 - lat1);
    double lonDistance = Math.toRadians(lon2 - lon1);
    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
            + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
            * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double distance = R * c * 1000; // convert to meters

    double height = el1 - el2;

    distance = Math.pow(distance, 2) + Math.pow(height, 2);

    return Math.sqrt(distance);
}
David George
sumber
7
Mengapa tidak Math.toRadians () dan bukan deg2rad ()? Itu akan sangat mandiri.
Aron Lorincz
2
@Bala - Saya buruk, ada di komentar di kode di komputer saya tetapi hilang di sini. Jarak dalam meter.
David George
4
@ ÁronNemmondommegavezetéknevem Saya telah memperbarui metode untuk menggunakan saran Anda yang sangat bagus.
David George
2
Beberapa komentar di sini: stackoverflow.com/questions/28510115/…
David George
Ada relevansi khusus dengan nama variabel adan c? Apakah ini sisi segitiga siku-siku dengan label tradisional a, bdan c?
AlainD
76

Berikut adalah fungsi Java yang menghitung jarak antara dua titik lintang / bujur , diposting di bawah ini, untuk berjaga-jaga jika ia menghilang lagi.

    private double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
      double theta = lon1 - lon2;
      double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
      dist = Math.acos(dist);
      dist = rad2deg(dist);
      dist = dist * 60 * 1.1515;
      if (unit == 'K') {
        dist = dist * 1.609344;
      } else if (unit == 'N') {
        dist = dist * 0.8684;
        }
      return (dist);
    }
    
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::  This function converts decimal degrees to radians             :*/
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    private double deg2rad(double deg) {
      return (deg * Math.PI / 180.0);
    }
    
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::  This function converts radians to decimal degrees             :*/
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    private double rad2deg(double rad) {
      return (rad * 180.0 / Math.PI);
    }
    
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'M') + " Miles\n");
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'K') + " Kilometers\n");
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'N') + " Nautical Miles\n");
dommer
sumber
1
Google Map menunjukkan 200 Kms untuk 12.915700, 77.632046, 11.665154, 78.145657 dimana kode di atas menunjukkan 149.82 Kms. Ada yang masih salah.
Samy
1
@ Samy fungsi di atas memberi Anda jarak garis lurus.
Rahul_Pawar
1
Kerajaan saya bagi pengembang untuk memberi label variabel mereka dengan Unit . double dist => double distInMiles (atau sejenisnya) (Saya tidak mengetuk orang yang memposting jawaban ini, saya upvoting ....... melainkan pelaksana asli kode)
granadaCoder
14

Catatan: solusi ini hanya berfungsi untuk jarak pendek.

Saya mencoba menggunakan rumus dommer yang diposting untuk aplikasi dan menemukan bahwa itu bekerja dengan baik untuk jarak jauh tetapi dalam data saya, saya menggunakan semua jarak yang sangat pendek, dan posting dommer melakukannya dengan sangat buruk. Saya membutuhkan kecepatan, dan geo calcs yang lebih kompleks bekerja dengan baik tetapi terlalu lambat. Jadi, jika Anda membutuhkan kecepatan dan semua kalkulasi yang Anda buat pendek (mungkin <100m atau lebih). Saya menemukan pendekatan kecil ini bekerja dengan baik. Ini mengasumsikan dunia adalah pikiran datar Anda, jadi jangan menggunakannya untuk jarak jauh, ini bekerja dengan mendekati jarak satu Lintang dan Bujur pada Lintang tertentu dan mengembalikan jarak Pythagoras dalam meter.

public class FlatEarthDist {
    //returns distance in meters
    public static double distance(double lat1, double lng1, 
                                      double lat2, double lng2){
     double a = (lat1-lat2)*FlatEarthDist.distPerLat(lat1);
     double b = (lng1-lng2)*FlatEarthDist.distPerLng(lat1);
     return Math.sqrt(a*a+b*b);
    }

    private static double distPerLng(double lat){
      return 0.0003121092*Math.pow(lat, 4)
             +0.0101182384*Math.pow(lat, 3)
                 -17.2385140059*lat*lat
             +5.5485277537*lat+111301.967182595;
    }

    private static double distPerLat(double lat){
            return -0.000000487305676*Math.pow(lat, 4)
                -0.0033668574*Math.pow(lat, 3)
                +0.4601181791*lat*lat
                -1.4558127346*lat+110579.25662316;
    }
}
zahmde
sumber
14

Pembaca masa depan yang menemukan artikel SOF ini.

Jelas, pertanyaan itu ditanyakan pada 2010 dan sekarang 2019. Tapi itu muncul di awal pencarian internet. Pertanyaan asli tidak mengabaikan penggunaan perpustakaan pihak ketiga (ketika saya menulis jawaban ini).

public double calculateDistanceInMeters(double lat1, double long1, double lat2,
                                     double long2) {


    double dist = org.apache.lucene.util.SloppyMath.haversinMeters(lat1, long1, lat2, long2);
    return dist;
}

dan

<dependency>
  <groupId>org.apache.lucene</groupId>
  <artifactId>lucene-spatial</artifactId>
  <version>8.2.0</version>
</dependency>

https://mvnrepository.com/artifact/org.apache.lucene/lucene-spatial/8.2.0

Silakan baca dokumentasi tentang "SloppyMath" sebelum menyelam!

https://lucene.apache.org/core/8_2_0/core/org/apache/lucene/util/SloppyMath.html

granadaCoder
sumber
Apakah Anda yakin ini benar? file jar ini tidak memiliki ".util" saya baru saja memeriksanya.
Adnan Ali
Itu sebabnya saya selalu menerbitkan versi dengan jawaban. Pastikan Anda mendapatkan 8.2.0. 13 suara positif juga menunjukkan bahwa jawaban tersebut akurat.
granadaCoder
5

Berikut adalah halaman dengan contoh javascript untuk berbagai kalkulasi bola. Yang pertama di halaman akan memberikan apa yang Anda butuhkan.

http://www.movable-type.co.uk/scripts/latlong.html

Berikut adalah kode Javascriptnya

var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad(); 
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
        Math.sin(dLon/2) * Math.sin(dLon/2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c;

Dimana 'd' akan menahan jarak.

Chris Taylor
sumber
Bisakah "a" menjadi negatif?
Xi Wei
1
package distanceAlgorithm;

public class CalDistance {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    CalDistance obj=new CalDistance();
    /*obj.distance(38.898556, -77.037852, 38.897147, -77.043934);*/
        System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "M") + " Miles\n");
        System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "K") + " Kilometers\n");
        System.out.println(obj.distance(32.9697, -96.80322, 29.46786, -98.53506, "N") + " Nautical Miles\n");       
    }   
    public double distance(double lat1, double lon1, double lat2, double lon2, String sr) {


          double theta = lon1 - lon2;
          double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
          dist = Math.acos(dist);
          dist = rad2deg(dist);
          dist = dist * 60 * 1.1515;
          if (sr.equals("K")) {
            dist = dist * 1.609344;
          } else if (sr.equals("N")) {
            dist = dist * 0.8684;
            }
          return (dist);
        }
    public double deg2rad(double deg) {
          return (deg * Math.PI / 180.0);
        }
    public double rad2deg(double rad) {
          return (rad * 180.0 / Math.PI);
        }


    }
MAnoj Sarnaik
sumber
1

Ada banyak jawaban bagus yang diberikan, namun saya menemukan beberapa kekurangan kinerja, jadi izinkan saya menawarkan versi dengan mempertimbangkan kinerja. Setiap konstanta telah dihitung sebelumnya dan variabel x, y diperkenalkan untuk menghindari penghitungan nilai yang sama dua kali. Semoga membantu

    private static final double r2d = 180.0D / 3.141592653589793D;
    private static final double d2r = 3.141592653589793D / 180.0D;
    private static final double d2km = 111189.57696D * r2d;
    public static double meters(double lt1, double ln1, double lt2, double ln2) {
        final double x = lt1 * d2r;
        final double y = lt2 * d2r;
        return Math.acos( Math.sin(x) * Math.sin(y) + Math.cos(x) * Math.cos(y) * Math.cos(d2r * (ln1 - ln2))) * d2km;
    }
Stan Sokolov
sumber
1

Jawaban yang sedikit ditingkatkan dari @David George:

public static double distance(double lat1, double lat2, double lon1,
                              double lon2, double el1, double el2) {

    final int R = 6371; // Radius of the earth

    double latDistance = Math.toRadians(lat2 - lat1);
    double lonDistance = Math.toRadians(lon2 - lon1);
    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
            + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
            * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double distance = R * c * 1000; // convert to meters

    double height = el1 - el2;

    distance = Math.pow(distance, 2) + Math.pow(height, 2);

    return Math.sqrt(distance);
}

public static double distanceBetweenLocations(Location l1, Location l2) {
    if(l1.hasAltitude() && l2.hasAltitude()) {
        return distance(l1.getLatitude(), l2.getLatitude(), l1.getLongitude(), l2.getLongitude(), l1.getAltitude(), l2.getAltitude());
    }
    return l1.distanceTo(l2);
}

fungsi jarak adalah sama, tetapi saya telah membuat fungsi pembungkus kecil, yang mengambil 2 objek Lokasi . Berkat ini, saya hanya menggunakan fungsi jarak jika kedua lokasi benar-benar memiliki ketinggian, karena terkadang tidak. Dan itu dapat menyebabkan hasil yang aneh (jika lokasi tidak tahu ketinggiannya 0 akan dikembalikan). Dalam hal ini, saya kembali ke fungsi distanceTo klasik .

Makalele
sumber
-1

Artikel wikipedia ini memberikan rumus dan contoh. Teksnya dalam bahasa Jerman, tetapi perhitungannya berbicara sendiri.

zellus
sumber