Tính khoảng cách giữa hai điểm, sử dụng kinh độ?


94

Đây là thử của tôi, đó chỉ là một đoạn mã của tôi:

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;

Tôi đang sử dụng công thức này để lấy vĩ độ và kinh độ:

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

Câu trả lời:


217

Mã Java do Dommer đưa ra ở trên cho kết quả hơi không chính xác nhưng các lỗi nhỏ sẽ tăng lên nếu bạn đang xử lý, ví dụ như đường đi GPS. Đây là một triển khai của phương pháp Haversine trong Java cũng tính đến sự khác biệt về độ cao giữa hai điểm.

/**
 * 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
Tại sao không phải là Math.toRadians () thay vì deg2rad ()? Nó sẽ thực sự tự chứa đựng.
Aron Lorincz

2
@Bala - Tôi xấu, nó nằm trong phần bình luận trên mã trên máy tính của tôi nhưng bị thiếu ở đây. Khoảng cách tính bằng mét.
David George

4
@ ÁronNemmondommegavezetéknevem Tôi đã cập nhật phương pháp để sử dụng gợi ý rất tốt của bạn.
David George

2
Một số ý kiến ở đây: stackoverflow.com/questions/28510115/...
David George

Bất kỳ liên quan cụ thể nào đến tên biến ac? Là những mặt của một tam giác vuông góc với nhãn truyền thống a, bc?
AlainD

76

Đây là một hàm Java tính toán khoảng cách giữa hai điểm vĩ độ / kinh độ , được đăng bên dưới, đề phòng trường hợp nó lại biến mất.

    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 Map hiển thị 200 km cho 12.915700, 77.632046, 11.665154, 78.145657 trong đó như mã trên hiển thị 149,82 km. Có điều gì đó vẫn chưa chính xác.
Samy

1
@Samy hàm trên cung cấp cho bạn khoảng cách đường thẳng.
Rahul_Pawar

1
Vương quốc của tôi cho các nhà phát triển gắn nhãn các biến của họ với các Đơn vị . quận đôi => distInMiles đôi (hoặc tương tự) (Tôi không gõ cửa người đăng câu trả lời này, tôi upvoting ....... mà là đơn vị thực hiện ban đầu của code)
granadaCoder

13

Lưu ý: giải pháp này chỉ hoạt động với khoảng cách ngắn.

Tôi đã cố gắng sử dụng công thức đã đăng của dommer cho một ứng dụng và thấy nó hoạt động tốt trong khoảng cách dài nhưng trong dữ liệu của tôi, tôi đang sử dụng tất cả các khoảng cách rất ngắn và bài đăng của dommer hoạt động rất kém. Tôi cần tốc độ và các calc địa lý phức tạp hơn hoạt động tốt nhưng quá chậm. Vì vậy, trong trường hợp bạn cần tốc độ và tất cả các phép tính bạn đang thực hiện đều ngắn (có thể <100m hoặc lâu hơn). Tôi thấy ước tính nhỏ này hoạt động tốt. nó giả định rằng thế giới là phẳng trong tâm trí bạn, vì vậy đừng sử dụng nó cho những khoảng cách xa, nó hoạt động bằng cách ước lượng khoảng cách của một Vĩ độ và Kinh độ duy nhất tại Vĩ độ đã cho và trả về khoảng cách Pitago theo mét.

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

13

Những độc giả tương lai tình cờ gặp bài viết SOF này.

Rõ ràng, câu hỏi đã được đặt ra vào năm 2010 và bây giờ là năm 2019. Nhưng nó xuất hiện sớm trong một cuộc tìm kiếm trên internet. Câu hỏi ban đầu không giảm giá trị sử dụng thư viện của bên thứ ba (khi tôi viết câu trả lời này).

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

<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

Vui lòng đọc tài liệu về "SloppyMath" trước khi tìm hiểu!

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


5

Đây là một trang với các ví dụ về javascript cho các phép tính hình cầu khác nhau. Cái đầu tiên trên trang sẽ cung cấp cho bạn những gì bạn cần.

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

Đây là mã Javascript

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;

Trường hợp 'd' sẽ giữ khoảng cách.


"A" có bao giờ là âm không?
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

rất nhiều câu trả lời tuyệt vời được cung cấp tuy nhiên tôi thấy một số thiếu sót về hiệu suất, vì vậy hãy để tôi cung cấp một phiên bản có lưu ý đến hiệu suất. Mọi hằng số đều được tính toán trước và các biến x, y được đưa vào để tránh tính toán cùng một giá trị hai lần. Hy vọng nó giúp

    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

Câu trả lời được nâng cấp một chút từ @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);
}

Hàm khoảng cách giống nhau, nhưng tôi đã tạo hàm trình bao bọc nhỏ, có 2 đối tượng Vị trí . Nhờ đó, tôi chỉ sử dụng khoảng cách chức năng nếu cả hai vị trí thực sự có độ cao, vì đôi khi chúng không có. Và nó có thể dẫn đến kết quả kỳ lạ (nếu vị trí không biết độ cao 0 của nó sẽ được trả về). Trong trường hợp này, tôi quay trở lại chức năng distanceTo cổ điển .


-1

Bài viết wikipedia này cung cấp các công thức và một ví dụ. Văn bản bằng tiếng Đức, nhưng các phép tính tự nói lên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.