计算两个坐标经纬度之间的距离(5种方式)

Posted 筱白爱学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算两个坐标经纬度之间的距离(5种方式)相关的知识,希望对你有一定的参考价值。

目录

概述

方式一

方式二

方式三

方式四

1.POM引入第三方依赖:

2.代码:

3.执行操作:

4.执行结果:

建议


概述

计算两个坐标之间的距离,话不多说,搞起来!!!!   拿去用吧,不谢....

方式一

反余弦计算方式

/**
     * 地球半径,单位m
     */
    private static final double EARTH_RADIUS = 6378137;

    /**
     * 根据经纬度,计算两点间的距离
     *
     * @param longitude1 第一个点的经度
     * @param latitude1  第一个点的纬度
     * @param longitude2 第二个点的经度
     * @param latitude2  第二个点的纬度
     * @return 返回距离,单位m
     */
    public static double getDistance1(double longitude1, double latitude1, double longitude2, double latitude2) 
        // 纬度
        double lat1 = Math.toRadians(latitude1);
        double lat2 = Math.toRadians(latitude2);
        // 经度
        double lng1 = Math.toRadians(longitude1);
        double lng2 = Math.toRadians(longitude2);
        // 纬度之差
        double a = lat1 - lat2;
        // 经度之差
        double b = lng1 - lng2;
        // 计算两点距离的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧长乘地球半径, 返回单位: 米
        s =  s * EARTH_RADIUS;
        return s;
    

方式二

基于googleMap中的算法得到两经纬度之间的距离,计算精度与谷歌地图的距离精度差不多。

/**
     * 默认地球半径,赤道半径(单位m)
     */
    private static double EARTH_RADIUS1 = 6371000;

    /**
     * 转化为弧度(rad)
     */
    private static double rad(double d)
    
        return d * Math.PI / 180.0;
    
    /**
     * @param lon1 第一点的精度
     * @param lat1 第一点的纬度
     * @param lon2 第二点的精度
     * @param lat2 第二点的纬度
     * @return 返回的距离,单位m
     * */
    public static double getDistance2(double lon1,double lat1,double lon2, double lat2) 
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lon1) - rad(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS1;
        s = Math.round(s * 10000) / 10000;
        return s;
    

方式三

反余弦计算方式

private static final double EARTH_RADIUS11 = 6371000; // 平均半径,单位:m;不是赤道半径。赤道为6378左右
    public static double getDistance3(Double lat1,Double lng1,Double lat2,Double lng2) 
        // 经纬度(角度)转弧度。弧度用作参数,以调用Math.cos和Math.sin
        double radiansAX = Math.toRadians(lng1); // A经弧度
        double radiansAY = Math.toRadians(lat1); // A纬弧度
        double radiansBX = Math.toRadians(lng2); // B经弧度
        double radiansBY = Math.toRadians(lat2); // B纬弧度

        // 公式中“cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2”的部分,得到∠AOB的cos值
        double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
                + Math.sin(radiansAY) * Math.sin(radiansBY);
//        System.out.println("cos = " + cos); // 值域[-1,1]
        double acos = Math.acos(cos); // 反余弦值
//        System.out.println("acos = " + acos); // 值域[0,π]
//        System.out.println("∠AOB = " + Math.toDegrees(acos)); // 球心角 值域[0,180]
        return EARTH_RADIUS11 * acos; // 最终结果
    

方式四

利用第三方jar包计算

1.POM引入第三方依赖:

<!--用于计算两点之间的距离-->
        <dependency>
            <groupId>org.gavaghan</groupId>
            <artifactId>geodesy</artifactId>
            <version>1.1.3</version>
        </dependency>

2.代码:

/**
     * 计算两个经纬度之间的距离
     * @param gpsFrom 第一个经纬度
     * @param gpsTo 第二个经纬度
     * @param ellipsoid 计算方式
     * @return 返回的距离,单位m
     */
    public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid)
    
        //创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);

        return geoCurve.getEllipsoidalDistance();
    

3.执行操作:

public static void main(String[] args) 
        double lon1 = 39.111111;
        double lat1 = 116.111111;
        double lon2 = 39.222222;
        double lat2 = 116.222222;

        GlobalCoordinates source = new GlobalCoordinates(lon1, lat1);
        GlobalCoordinates target = new GlobalCoordinates(lon2, lat2);

        double meter1 = getDistanceMeter(source, target, Ellipsoid.Sphere);
        double meter2 = getDistanceMeter(source, target, Ellipsoid.WGS84);

        System.out.println("Sphere坐标系计算结果:"+meter1 + "米");
        System.out.println("WGS84坐标系计算结果:"+meter2 + "米");
    

4.执行结果:

Sphere坐标系计算结果:15633.361234640292米
WGS84坐标系计算结果:15632.349374386973米

建议

我通过这几个方式测试,根据结果反馈,感觉方式四中Sphere坐标系计算结果相对来说偏差小一点.

期待大家的三连击,你们的支持是我的动力。加油,猿友们!!

计算两个纬度和经度坐标之间的距离

【中文标题】计算两个纬度和经度坐标之间的距离【英文标题】:Calculating Distance between two Latitude and Longitude GeoCoordinates 【发布时间】:2011-09-16 00:31:29 【问题描述】:

我正在计算两个地理坐标之间的距离。我正在针对 3-4 个其他应用程序测试我的应用程序。当我计算距离时,我的计算平均距离为 3.3 英里,而其他应用程序则为 3.5 英里。这对我尝试执行的计算有很大的不同。有没有好的类库来计算距离?我在 C# 中是这样计算的:

public static double Calculate(double sLatitude,double sLongitude, double eLatitude, 
                               double eLongitude)

    var radiansOverDegrees = (Math.PI / 180.0);

    var sLatitudeRadians = sLatitude * radiansOverDegrees;
    var sLongitudeRadians = sLongitude * radiansOverDegrees;
    var eLatitudeRadians = eLatitude * radiansOverDegrees;
    var eLongitudeRadians = eLongitude * radiansOverDegrees;

    var dLongitude = eLongitudeRadians - sLongitudeRadians;
    var dLatitude = eLatitudeRadians - sLatitudeRadians;

    var result1 = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) + 
                  Math.Cos(sLatitudeRadians) * Math.Cos(eLatitudeRadians) * 
                  Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);

    // Using 3956 as the number of miles around the earth
    var result2 = 3956.0 * 2.0 * 
                  Math.Atan2(Math.Sqrt(result1), Math.Sqrt(1.0 - result1));

    return result2;

我可能做错了什么?我应该先以公里计算,然后再转换为英里吗?

【问题讨论】:

地球平均半径 = 6,371km = 3958.76 英里 ***.com/questions/27928/… 不应该在 gis.stackexchange.com 上 它可能有,但我的问题更多地涉及在 Windows Phone 上计算它,这有点不同。公式是一样的,但是像 DistanceTo 方法这样的新方法调用不一定可用。 建议您存储 pi/180 这样您就不必不断重复计算。 【参考方案1】:

在这里,对于那些仍然不满意的人(比如我),来自 .NET-Frameworks GeoCoordinate 类的原始代码被重构为一个独立的方法:

public double GetDistance(double longitude, double latitude, double otherLongitude, double otherLatitude)

    var d1 = latitude * (Math.PI / 180.0);
    var num1 = longitude * (Math.PI / 180.0);
    var d2 = otherLatitude * (Math.PI / 180.0);
    var num2 = otherLongitude * (Math.PI / 180.0) - num1;
    var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);
    
    return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));

【讨论】:

美丽的答案,我想指出,由此产生的距离以米为单位。如official documentation所述 谢谢!我正在寻找 GeoCoordinate 类中使用的实际地球半径。 小优化,或者为了便于阅读,可以预先计算 pi/180 double oneDegree = Math.PI / 180.0; ? @brakeroo 感谢您的回复。我想保留原样,因为这是原始的 .NET 代码。当然,任何人都可以随意遵循您的建议。 工作就像一个魅力,最简单的答案;)【参考方案2】:

当 CPU/数学计算能力有限时:

有时(例如在我的工作中)计算能力不足(例如,没有浮点处理器,使用小型微控制器),某些三角函数可能会占用过多的 CPU 时间(例如 3000 多个时钟周期),所以当我只需要一个近似值时,特别是如果 CPU 不能长时间占用,我用它来最小化 CPU 开销:

/**------------------------------------------------------------------------
 * \brief  Great Circle distance approximation in km over short distances.
 *
 * Can be off by as much as 10%.
 *
 * approx_distance_in_mi = sqrt(x * x + y * y)
 *
 * where x = 69.1 * (lat2 - lat1)
 * and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3)
 *//*----------------------------------------------------------------------*/
double    ApproximateDisatanceBetweenTwoLatLonsInKm(
                  double lat1, double lon1,
                  double lat2, double lon2
                  ) 
    double  ldRadians, ldCosR, x, y;

    ldRadians = (lat1 / 57.3) * 0.017453292519943295769236907684886;
    ldCosR = cos(ldRadians);
    x = 69.1 * (lat2 - lat1);
    y = 69.1 * (lon2 - lon1) * ldCosR;

    return sqrt(x * x + y * y) * 1.609344;  /* Converts mi to km. */

归功于https://github.com/kristianmandrup/geo_vectors/blob/master/Distance%20calc%20notes.txt。

【讨论】:

【参考方案3】:

基于 Elliot Wood 的函数,如果有人对 C 函数感兴趣,这个函数正在工作......

#define SIM_Degree_to_Radian(x) ((float)x * 0.017453292F)
#define SIM_PI_VALUE                         (3.14159265359)

float GPS_Distance(float lat1, float lon1, float lat2, float lon2)

   float theta;
   float dist;

   theta = lon1 - lon2;

   lat1 = SIM_Degree_to_Radian(lat1);
   lat2 = SIM_Degree_to_Radian(lat2);
   theta = SIM_Degree_to_Radian(theta);

   dist = (sin(lat1) * sin(lat2)) + (cos(lat1) * cos(lat2) * cos(theta));
   dist = acos(dist);

//   dist = dist * 180.0 / SIM_PI_VALUE;
//   dist = dist * 60.0 * 1.1515;
//   /* Convert to km */
//   dist = dist * 1.609344;

   dist *= 6370.693486F;

   return (dist);

您可以将其更改为 double。它返回以公里为单位的值。

【讨论】:

【参考方案4】:

这是一个老问题,但在性能和优化方面,答案并不让我满意。

这是我优化的 C# 变体(距离以公里为单位,没有变量和冗余计算,非常接近 Haversine Formular https://en.wikipedia.org/wiki/Haversine_formula 的数学表达式)。

灵感来自: https://rosettacode.org/wiki/Haversine_formula#C.23

public static class Haversine

    public static double Calculate(double lat1, double lon1, double lat2, double lon2)
    
        double rad(double angle) => angle * 0.017453292519943295769236907684886127d; // = angle * Math.Pi / 180.0d
        double havf(double diff) => Math.Pow(Math.Sin(rad(diff) / 2d), 2); // = sin²(diff / 2)
        return 12745.6 * Math.Asin(Math.Sqrt(havf(lat2 - lat1) + Math.Cos(rad(lat1)) * Math.Cos(rad(lat2)) * havf(lon2 - lon1))); // earth radius 6.372,8‬km x 2 = 12745.6
    

【讨论】:

【参考方案5】:

这些平台有这个库GeoCoordinate:

单声道 .NET 4.5 .NET 核心 Windows Phone 8.x 通用 Windows 平台 Xamarin iOS Xamarin Android

通过 NuGet 完成安装:

PM> 安装包地理坐标

用法

GeoCoordinate pin1 = new GeoCoordinate(lat, lng);
GeoCoordinate pin2 = new GeoCoordinate(lat, lng);

double distanceBetween = pin1.GetDistanceTo(pin2);

两个坐标之间的距离,以为单位。

【讨论】:

【参考方案6】:

你可以使用这个功能:

来源:https://www.geodatasource.com/developers/c-sharp

private double distance(double lat1, double lon1, double lat2, double lon2, char unit) 
  if ((lat1 == lat2) && (lon1 == lon2)) 
    return 0;
  
  else 
    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 / Math.PI * 180.0);


Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "M"));
Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "K"));
Console.WriteLine(distance(32.9697, -96.80322, 29.46786, -98.53506, "N"));

【讨论】:

完美运行!谢谢!【参考方案7】:

对于那些使用 Xamarin 并且无法访问 GeoCoordinate 类的用户,您可以改用 Android Location 类:

public static double GetDistanceBetweenCoordinates (double lat1, double lng1, double lat2, double lng2) 
            var coords1 = new Location ("");
            coords1.Latitude = lat1;
            coords1.Longitude = lng1;
            var coords2 = new Location ("");
            coords2.Latitude = lat2;
            coords2.Longitude = lng2;
            return coords1.DistanceTo (coords2);
        

【讨论】:

【参考方案8】:

你可以使用System.device.Location:

System.device.Location.GeoCoordinate gc = new System.device.Location.GeoCoordinate()
Latitude = yourLatitudePt1,
Longitude = yourLongitudePt1
;

System.device.Location.GeoCoordinate gc2 = new System.device.Location.GeoCoordinate()
Latitude = yourLatitudePt2,
Longitude = yourLongitudePt2
;

Double distance = gc2.getDistanceTo(gc);

祝你好运

【讨论】:

【参考方案9】:

GetDistance 是最好的解决方案,但在很多情况下我们不能使用这种方法(例如 Universal App)

伪代码算法的计算距离到坐标:

public static double DistanceTo(double lat1, double lon1, double lat2, double lon2, char unit = 'K')

    double rlat1 = Math.PI*lat1/180;
    double rlat2 = Math.PI*lat2/180;
    double theta = lon1 - lon2;
    double rtheta = Math.PI*theta/180;
    double dist =
        Math.Sin(rlat1)*Math.Sin(rlat2) + Math.Cos(rlat1)*
        Math.Cos(rlat2)*Math.Cos(rtheta);
    dist = Math.Acos(dist);
    dist = dist*180/Math.PI;
    dist = dist*60*1.1515;

    switch (unit)
    
        case 'K': //Kilometers -> default
            return dist*1.609344;
        case 'N': //Nautical Miles 
            return dist*0.8684;
        case 'M': //Miles
            return dist;
    

    return dist;

真实世界的 C# 实现,它使用 扩展方法

用法:

var distance = new Coordinates(48.672309, 15.695585)
                .DistanceTo(
                    new Coordinates(48.237867, 16.389477),
                    UnitOfLength.Kilometers
                );

实施:

public class Coordinates

    public double Latitude  get; private set; 
    public double Longitude  get; private set; 

    public Coordinates(double latitude, double longitude)
    
        Latitude = latitude;
        Longitude = longitude;
    

public static class CoordinatesDistanceExtensions

    public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates)
    
        return DistanceTo(baseCoordinates, targetCoordinates, UnitOfLength.Kilometers);
    

    public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates, UnitOfLength unitOfLength)
    
        var baseRad = Math.PI * baseCoordinates.Latitude / 180;
        var targetRad = Math.PI * targetCoordinates.Latitude/ 180;
        var theta = baseCoordinates.Longitude - targetCoordinates.Longitude;
        var thetaRad = Math.PI * theta / 180;

        double dist =
            Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) *
            Math.Cos(targetRad) * Math.Cos(thetaRad);
        dist = Math.Acos(dist);

        dist = dist * 180 / Math.PI;
        dist = dist * 60 * 1.1515;

        return unitOfLength.ConvertFromMiles(dist);
    


public class UnitOfLength

    public static UnitOfLength Kilometers = new UnitOfLength(1.609344);
    public static UnitOfLength NauticalMiles = new UnitOfLength(0.8684);
    public static UnitOfLength Miles = new UnitOfLength(1);

    private readonly double _fromMilesFactor;

    private UnitOfLength(double fromMilesFactor)
    
        _fromMilesFactor = fromMilesFactor;
    

    public double ConvertFromMiles(double input)
    
        return input*_fromMilesFactor;
    
 

【讨论】:

你能提供用于这个微积分的公式或者一些关于什么线的cmets吗?我必须更改什么才能直接以公里而不是英里为单位获得结果距离而无需转换? 感谢您提供好的解决方案,我现在可以在我的桌面应用程序中使用它。 在我无法使用 GeoCoordinate 的 UWP 应用中表现出色。 计算结果为 95%。下面的函数是 100% 准确的:***.com/a/51839058/3736063【参考方案10】:

GeoCoordinate 类(.NET Framework 4 及更高版本)已经有 GetDistanceTo 方法。

var sCoord = new GeoCoordinate(sLatitude, sLongitude);
var eCoord = new GeoCoordinate(eLatitude, eLongitude);

return sCoord.GetDistanceTo(eCoord);

距离以米为单位。

您需要引用 System.Device。

【讨论】:

Nigel,您确定 DistanceTo 方法可以在手机上使用吗?我以为它使用了 WP7 的 2.0 版 GeoCoordinate。 我确实检查了这一点,并且设备的地理坐标有一个 GetDistanceTo 方法,这是您引用的方法(但不是您上面引用的方法)。没什么大不了。我将对此进行测试,看看内置的计算是否更好。谢谢奈杰尔! 我可能会问一个错误的问题,但结果的单位是什么?是英里还是公里。我在任何地方都找不到它。 @SaeedNamati - 根据msdn.microsoft.com/en-us/library/… 的说法,它也在寻找这个 - 它以米为单位。 是的,GeoCoordinate.GetDistanceTo() 返回以米为单位的值。对我来说,在美国,如果小于 1610,我将其转换为英尺(米 * 3.28084),否则我转换为英里(米 * 0.000621371)。对于我的目的来说,准确性已经绰绰有余了。【参考方案11】:

正在计算经纬度点之间的距离...

        double Lat1 = Convert.ToDouble(latitude);
        double Long1 = Convert.ToDouble(longitude);

        double Lat2 = 30.678;
        double Long2 = 45.786;
        double circumference = 40000.0; // Earth's circumference at the equator in km
        double distance = 0.0;
        double latitude1Rad = DegreesToRadians(Lat1);
        double latititude2Rad = DegreesToRadians(Lat2);
        double longitude1Rad = DegreesToRadians(Long1);
        double longitude2Rad = DegreesToRadians(Long2);
        double logitudeDiff = Math.Abs(longitude1Rad - longitude2Rad);
        if (logitudeDiff > Math.PI)
        
            logitudeDiff = 2.0 * Math.PI - logitudeDiff;
        
        double angleCalculation =
            Math.Acos(
              Math.Sin(latititude2Rad) * Math.Sin(latitude1Rad) +
              Math.Cos(latititude2Rad) * Math.Cos(latitude1Rad) * Math.Cos(logitudeDiff));
        distance = circumference * angleCalculation / (2.0 * Math.PI);
        return distance;

【讨论】:

【参考方案12】:

试试这个:

    public double getDistance(GeoCoordinate p1, GeoCoordinate p2)
    
        double d = p1.Latitude * 0.017453292519943295;
        double num3 = p1.Longitude * 0.017453292519943295;
        double num4 = p2.Latitude * 0.017453292519943295;
        double num5 = p2.Longitude * 0.017453292519943295;
        double num6 = num5 - num3;
        double num7 = num4 - d;
        double num8 = Math.Pow(Math.Sin(num7 / 2.0), 2.0) + ((Math.Cos(d) * Math.Cos(num4)) * Math.Pow(Math.Sin(num6 / 2.0), 2.0));
        double num9 = 2.0 * Math.Atan2(Math.Sqrt(num8), Math.Sqrt(1.0 - num8));
        return (6376500.0 * num9);
    

【讨论】:

【参考方案13】:

这里是 JavaScript 版本的男生和女生

function distanceTo(lat1, lon1, lat2, lon2, unit) 
      var rlat1 = Math.PI * lat1/180
      var rlat2 = Math.PI * lat2/180
      var rlon1 = Math.PI * lon1/180
      var rlon2 = Math.PI * lon2/180
      var theta = lon1-lon2
      var rtheta = Math.PI * theta/180
      var dist = Math.sin(rlat1) * Math.sin(rlat2) + Math.cos(rlat1) * Math.cos(rlat2) * Math.cos(rtheta);
      dist = Math.acos(dist)
      dist = dist * 180/Math.PI
      dist = dist * 60 * 1.1515
      if (unit=="K")  dist = dist * 1.609344 
      if (unit=="N")  dist = dist * 0.8684 
      return dist

【讨论】:

你需要 rlon1 和 `rlon2´ 做什么?

以上是关于计算两个坐标经纬度之间的距离(5种方式)的主要内容,如果未能解决你的问题,请参考以下文章

LBS高德地图百度地图的经纬度科普|MySQL和编程语言是如何计算两个坐标之间的距离?

java两点间距离公式

计算两个纬度和经度坐标之间的距离

计算两个纬度坐标之间的距离/方位

计算两个经纬度之间的距离

根据两点的经纬度坐标计算两个坐标点之间的直线距离