Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用经纬度计算两点之间的距离?_Java_Math_Latitude Longitude - Fatal编程技术网

Java 使用经纬度计算两点之间的距离?

Java 使用经纬度计算两点之间的距离?,java,math,latitude-longitude,Java,Math,Latitude Longitude,下面是我的尝试,这只是我的代码片段: 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))

下面是我的尝试,这只是我的代码片段:

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)
这是一个,贴在下面,以防万一它再次消失

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

下面是一个页面,其中包含各种球形计算的javascript示例。页面上的第一个应该会给你你所需要的

下面是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”表示距离。

本维基百科提供了公式和示例。文本是德语,但计算本身就说明了问题

上面Dommer给出的Java代码给出了稍微不正确的结果,但是如果您正在处理GPS跟踪,那么这些小错误就会累加起来。这里是Haversine方法在Java中的一个实现,它还考虑了两点之间的高度差

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

注意:此解决方案仅适用于短距离

我试着在一个应用程序中使用dommer的post公式,发现它在长距离应用中效果很好,但在我的数据中,我使用的都是很短的距离,而dommer的post做得很差。我需要速度,更复杂的地理计算工作得很好,但太慢了。因此,在需要速度的情况下,所有的计算都很短(可能小于100米左右)。我发现这个小小的近似值非常有效。它假设世界是平的,所以不要长距离使用它,它的工作原理是近似给定纬度的单个纬度和经度的距离,并返回毕达哥拉斯距离(以米为单位)

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(lng1);
     return Math.sqrt(a*a+b*b);
    }

    private static double distPerLng(double lng){
      return 0.0003121092*Math.pow(lng, 4)
             +0.0101182384*Math.pow(lng, 3)
                 -17.2385140059*lng*lng
             +5.5485277537*lng+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;
    }
}

偶然发现这篇SOF文章的未来读者

显然,这个问题是在2010年提出的,现在是2019年。 但它出现在互联网搜索的早期。最初的问题并没有忽略第三方库的使用(当我写这个答案时)


org.apache.lucene

在开始之前,请阅读有关“SloppyMath”的文档


提供了很多很好的答案,但是我发现了一些性能缺陷,所以让我提供一个考虑性能的版本。每个常数都经过预先计算,并引入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) {
        double x = lt1 * d2r;
        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;
    }

来自@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);
}

distance函数是相同的,但我创建了一个小包装函数,它接受2个位置对象。由于这一点,我只在两个位置都有海拔高度时才使用距离功能,因为有时它们没有。它可能会导致奇怪的结果(如果位置不知道它的海拔高度,将返回0)。在本例中,我回到经典的距离到函数。

为什么不使用Math.toRadians()而不是deg2rad()?它真的是自我包容的。@Bala-我的错,它在我电脑上的代码注释中,但在这里丢失了。以米为单位的距离。@ronNemmondommegavezetéknevem我已经更新了该方法,以使用您非常好的建议。这里有一些评论:与变量名
a
c
有什么特别的关联吗?这些是带有传统标签的直角三角形的边吗?
a
b
c
?“a”可能是负数吗?谷歌地图显示12.915700、77.632046、11.665154、78.145657的距离为200公里,上面的代码显示为149.82公里。有些地方仍然不正确。@Samy上面的函数给出了直线距离。我的王国是让开发人员用单位标记变量。double dist=>double distin miles(或类似的)(我不是在敲发布此答案的人,我是在投票……而是代码的原始实现者)此方法在小距离下工作正常,我认为它可能比使用sin/cos/acos更好,因为地球是一种球体。向上投票。你确定这是对的吗?这个jar文件没有“.util”我只是检查了一下。这就是为什么我总是发布带有答案的版本。确保您获得了8.2.0。13次投票也表明答案是准确的。我认为,如果您可以在代码中用28行替换依赖项,则向某个内容添加依赖项是一种不好的做法,除非您使用的依赖项更多。有人可以添加详细信息,如果这比此处接受的答案在短距离内更有效:?
<dependency>
  <groupId>org.apache.lucene</groupId>
  <artifactId>lucene-spatial</artifactId>
  <version>8.2.0</version>
</dependency>
    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) {
        double x = lt1 * d2r;
        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;
    }
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);
}