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

Posted

技术标签:

【中文标题】使用纬度经度计算两点之间的距离?【英文标题】:Calculating distance between two points, using latitude longitude? 【发布时间】:2011-04-11 07:09:06 【问题描述】:

这是我的尝试,这只是我的代码的 sn-p:

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)

【问题讨论】:

【参考方案1】:

上面 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);

【讨论】:

为什么不用 Math.toRadians() 而不是 deg2rad()?它真的是自给自足的。 @Bala - 我的错,它在我电脑上代码的评论中,但这里没有。距离以米为单位。 @ÁronNemmondommegavezetéknevem 我已经更新了使用您非常好的建议的方法。 这里有一些cmets:***.com/questions/28510115/… a 可能是否定的【参考方案2】:

这是一个Java function that calculates the distance between two lat/long points,贴在下面,以防它再次消失。

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

【讨论】:

谷歌地图显示 12.915700、77.632046、11.665154、78.145657 为 200 公里,如上面的代码所示为 149.82 公里。还是有问题。 @Samy 上面的函数给你直线距离。 开发人员用单位标记他们的变量的王国。 double dist => double distInMiles(或类似的)(我不是在敲发布此答案的人,而是在投票......而是代码的原始实现者) 这种方法适用于小距离,我认为它可能比***.com/a/20410612/1537394 更好,因为它使用sin/cos/acos,这是合乎逻辑的,因为地球是一种球体。点赞。 对于输入 30.4570925、74.1676477、30.4570925、74.1676477,此函数将返回 NaN 而不是 0.0,因为 Math.acos() 函数不接受大于 1 的值。【参考方案3】:

偶然发现这篇 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”我刚刚检查过。 这就是为什么我总是发布带有答案的版本。确保您获得的是 8.2.0。 13 票也表明答案是准确的。 我认为如果你可以用代码中的 28 行替换它,那么添加依赖项是一种不好的做法,除非你从该依赖项中使用更多 我需要在 android Studio 中将这些 java 脚本转换为 java - 有什么建议或解决步骤吗?感谢您的帮助【参考方案4】:

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

我尝试将 dommer 发布的公式用于应用程序,发现它在长距离上表现良好,但在我的数据中,我使用的都是非常短的距离,而 dommer 的帖子表现很差。我需要速度,更复杂的地理计算效果很好,但太慢了。因此,如果您需要速度并且您所做的所有计算都很短(可能

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;
    

【讨论】:

如果这比这里接受的答案更适用于短距离,有人可以添加详细信息:***.com/a/16794680/1537394?【参考方案5】:

这是一个页面,其中包含用于各种球面计算的 javascript 示例。页面上的第一个应该可以满足您的需求。

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”可以是负数吗?【参考方案6】:

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

【讨论】:

【参考方案7】:
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);
        


    

【讨论】:

【参考方案8】:

来自@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 个 Location 对象。多亏了这一点,如果两个位置实际上都有高度,我只使用 distance 函数,因为有时它们没有。它可能会导致奇怪的结果(如果位置不知道它的高度 0 将被返回)。在这种情况下,我会使用经典的 distanceTo 函数。

【讨论】:

【参考方案9】:

此***article 提供了公式和示例。文本是德文的,但计算不言自明。

【讨论】:

以上是关于使用纬度经度计算两点之间的距离?的主要内容,如果未能解决你的问题,请参考以下文章

计算R中具有纬度,经度和海拔高度的两点之间的距离[关闭]

JavaScript 用纬度和经度坐标计算两点之间的距离

使用纬度和经度iphone地图上两点之间的距离方程

两个经纬度算距离公式 方法是啥

经纬度之间距离怎么算?

怎么知道经纬度算距离,