위도 경도를 사용하여 두 지점 사이의 거리를 계산합니까?


94

내 시도는 다음과 같습니다. 내 코드의 일부입니다.

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;

위도와 경도를 구하기 위해이 공식을 사용하고 있습니다.

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

답변:


220

위의 Dommer에서 제공 한 Java 코드는 약간 잘못된 결과를 제공하지만 GPS 트랙을 처리하는 경우 작은 오류가 추가됩니다. 다음은 두 지점 사이의 높이 차이도 고려하는 Java의 Haversine 메소드 구현입니다.

/**
 * 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
deg2rad () 대신 Math.toRadians ()가 아닌 이유는 무엇입니까? 그것은 정말로 자급 자족 할 것입니다.
Aron Lorincz

2
@Bala-내 나쁜, 내 컴퓨터의 코드에 대한 주석에 있지만 여기에서 누락되었습니다. 미터 단위의 거리.
David George

4
@ ÁronNemmondommegavezetéknevem 귀하의 좋은 제안을 사용하기 위해 방법을 업데이트했습니다.
David George


변수 이름 ac? 이러한 기존의 레이블 직각 삼각형의 측면인가 a, b그리고 c?
AlainD

76

다음 은 다시 사라질 경우를 대비하여 아래에 게시 된 두 개의 위도 / 경도 지점 사이의 거리를 계산 하는 Java 함수입니다 .

    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지도는 12.915700, 77.632046, 11.665154, 78.145657에 대해 200Kms를 표시하며, 위 코드는 149.82Kms를 표시합니다. 여전히 잘못된 것이 있습니다.
Samy 2015

1
@Samy 위의 기능은 직선 거리를 제공합니다.
Rahul_Pawar

1
개발자가 자신의 변수 에 Units 레이블을 붙이는 나의 왕국 . 이중 DIST => 더블 distInMiles (또는 유사) (내가 upvoting있어,이 답변을 게시 한 사용자를 두드리는 ....... 아니라 코드의 원래 구현하고 있지 않다)
granadaCoder

14

참고 :이 솔루션은 짧은 거리에서만 작동합니다.

나는 응용 프로그램에 대해 dommer의 게시 된 공식을 사용하려고 시도했으며 장거리에서는 잘 작동했지만 내 데이터에서는 매우 짧은 거리를 모두 사용했으며 dommer의 게시물은 매우 열악했습니다. 나는 속도가 필요했고 더 복잡한 지리적 계산은 잘 작동했지만 너무 느 렸습니다. 따라서 속도가 필요한 경우 모든 계산이 짧습니다 (아마도 <100m 정도). 이 작은 근사치가 훌륭하게 작동한다는 것을 알았습니다. 세상이 평평하다고 가정하므로 장거리에 사용하지 마십시오. 주어진 위도에서 단일 위도와 경도의 거리를 근사화하고 피타고라스 거리를 미터 단위로 반환하는 방식으로 작동합니다.

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

이 SOF 기사를 우연히 발견 한 미래 독자.

당연히이 질문은 2010 년과 지금의 2019 년에 제기되었습니다.하지만 인터넷 검색 초기에 나타납니다. 원래 질문은 타사 라이브러리 사용을 할인하지 않습니다 (이 답변을 썼을 때).

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

다이빙하기 전에 "SloppyMath"에 대한 문서를 읽으십시오!

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


이것이 맞습니까? 이 jar 파일에는 ".util"이 없습니다. 방금 확인했습니다.
Adnan Ali

그렇기 때문에 항상 답변과 함께 버전을 게시합니다. 8.2.0을 받고 있는지 확인하십시오. 13 개의 찬성표는 또한 답변이 정확함을 시사합니다.
granadaCoder

5

다음은 다양한 구형 계산에 대한 자바 스크립트 예제가있는 페이지입니다. 페이지의 맨 처음에 필요한 정보를 얻을 수 있습니다.

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

다음은 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;

'd'는 거리를 유지합니다.


"a"가 부정적 일 수 있습니까?
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

많은 훌륭한 답변이 제공되었지만 성능상의 단점을 발견 했으므로 성능을 염두에 둔 버전을 제공하겠습니다. 모든 상수는 미리 계산되고 x, y 변수는 동일한 값을 두 번 계산하지 않도록 도입됩니다. 도움이되기를 바랍니다.

    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의 약간 업그레이드 된 답변 :

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

거리 함수는 동일하지만 2 개의 Location 개체를 사용 하는 작은 래퍼 함수를 ​​만들었습니다 . 덕분에 두 위치 모두 실제로 고도가있을 때만 거리 기능을 사용 합니다. 때로는 그렇지 않기 때문입니다. 그리고 이상한 결과를 초래할 수 있습니다 (위치가 고도를 모르는 경우 0이 반환됩니다). 이 경우 클래식 distanceTo 함수로 돌아갑니다 .


-1

이 위키 백과 문서 는 공식과 예제를 제공합니다. 텍스트는 독일어이지만 계산은 그 자체로 말합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.