Enlem boylamı kullanarak iki nokta arasındaki mesafeyi hesaplamak?


94

İşte denemem, sadece kodumun bir parçası:

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;

Enlem ve boylamı elde etmek için bu formülleri kullanıyorum:

x = Deg + (Min + Sec / 60) / 60)

Yanıtlar:


221

Yukarıda Dommer tarafından verilen Java kodu biraz yanlış sonuçlar verir, ancak bir GPS izi işliyorsanız küçük hatalar toplanır. Burada, iki nokta arasındaki yükseklik farklarını da hesaba katan Haversine yönteminin Java'daki bir uygulaması.

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

7
Neden deg2rad () yerine Math.toRadians () değil? Gerçekten kendi kendine yeten bir şey olurdu.
Aron Lorincz

2
@Bala - Benim hatam, bilgisayarımdaki kodun yorumunda ama burada eksik. Metre cinsinden mesafe.
David George

4
@ ÁronNemmondommegavezetéknevem Çok iyi önerinizi kullanmak için yöntemi güncelledim.
David George


Değişken isimleri Belli bir alaka ave c? Bu geleneksel etiketle bir dik üçgenin kenarları misiniz a, bve c?
AlainD

76

Aşağıda, tekrar kaybolması ihtimaline karşı, iki enlem / boylam noktası arasındaki mesafeyi hesaplayan bir Java işlevi verilmiştir.

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

1
Google Harita, 12.915700, 77.632046, 11.665154, 78.145657 için 200 Kms gösterir; burada yukarıdaki kod 149.82 Kms gösterir. Hala bir şeyler yanlış.
Samy

1
@Samy yukarıdaki işlev size düz bir çizgi mesafesi verir.
Rahul_Pawar

1
Benim krallığım geliştiricilerin değişkenlerini Birimlerle etiketlemeleri . double dist => double distInMiles (veya benzeri) (Bu cevabı gönderen kişiyi çalmıyorum, oy veriyorum ....... yerine kodun orijinal uygulayıcısı)
granadaCoder

14

Not: Bu çözüm yalnızca kısa mesafelerde işe yarar.

Bir uygulama için dommer'ın yayınladığı formülünü kullanmaya çalıştım ve uzun mesafeler için iyi iş çıkardığını buldum, ancak verilerimde çok kısa mesafeleri kullanıyordum ve dommer'ın gönderisi çok zayıftı. Hıza ihtiyacım vardı ve daha karmaşık coğrafi hesaplamalar iyi çalıştı ama çok yavaştı. Yani, hıza ihtiyacınız olması ve yaptığınız tüm hesaplamaların kısa olması durumunda (belki <100m veya daha fazla). Bu küçük yaklaşımı harika çalıştığını buldum. dünyanın sizi dümdüz düşündüğünü varsayar, bu yüzden onu uzun mesafeler için kullanmayın, verilen Enlemdeki tek bir Enlem ve Boylam mesafesini yaklaşık olarak belirleyerek ve Pisagor mesafesini metre cinsinden döndürerek çalışır.

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

14

Bu SOF makalesine rastlayan gelecekteki okuyucular.

Açıkçası, soru 2010'da sorulmuştu ve şimdi 2019'da. Asıl soru üçüncü taraf kitaplık kullanımını azaltmıyor (bu cevabı yazdığımda).

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

ve

<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

Lütfen dalmadan önce "SloppyMath" hakkındaki belgeleri okuyun!

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


Bunun doğru olduğundan emin misin? bu jar dosyasında ".util" yok, sadece kontrol ettim.
Adnan Ali

Bu yüzden versiyonu her zaman bir cevapla yayınlıyorum. 8.2.0 aldığınızdan emin olun. 13 olumlu oy da bir cevabın doğru olduğunu gösteriyor.
granadaCoder

5

İşte çeşitli küresel hesaplamalar için javascript örnekleri içeren bir sayfa. Sayfadaki ilki size ihtiyacınız olanı vermelidir.

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

İşte Javascript kodu

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;

'D'nin mesafeyi tutacağı yer.


"A" negatif olabilir mi?
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);
        }


    }

1

Çok sayıda harika cevap sağlandı, ancak bazı performans eksiklikleri buldum, bu yüzden performansı göz önünde bulunduran bir versiyon sunmama izin verin. Her sabit önceden hesaplanır ve aynı değerin iki kez hesaplanmasını önlemek için x, y değişkenleri eklenir. Umarım yardımcı olur

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

0

@ David George'dan biraz yükseltilmiş cevap:

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

mesafe işlevi aynı, ancak 2 Konum nesnesi alan küçük bir sarmalayıcı işlevi oluşturdum . Bu sayede mesafe işlevini yalnızca her iki konumun da rakımı varsa kullanıyorum, çünkü bazen olmuyorlar. Ve tuhaf sonuçlara yol açabilir (konumun rakımını bilmemesi durumunda 0 döndürülür). Bu durumda, klasik distanceTo işlevine geri dönüyorum .


-1

Bu wikipedia makalesi , formüller ve bir örnek sağlar. Metin Almancadır, ancak hesaplamalar kendi adına konuşur.

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.