【问题标题】:Calculate distance of two geo points in km c#以km c#计算两个地理点的距离
【发布时间】:2011-09-26 12:31:06
【问题描述】:

我想计算两个地理点的距离。这些点以经度和纬度给出。

坐标是:

点 1:36.578581,-118.291994

第 2 点:36.23998,-116.83171

这里是一个网站来比较结果:

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

这里是我从这个链接中使用的代码: Calculate distance between two points in google maps V3

    const double PIx = Math.PI;
    const double RADIO = 6378.16;

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(double lon1, double lat1, double lon2, double lat2)
    {
        double R = 6371; // km
        double dLat = Radians(lat2 - lat1);
        double dLon = Radians(lon2 - lon1);
        lat1 = Radians(lat1);
        lat2 = Radians(lat2);

        double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
        double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        double d = R * c;

        return d;
    }


Console.WriteLine(DistanceAlgorithm.DistanceBetweenPlaces(36.578581, -118.291994, 36.23998, -116.83171));

问题是我得到了两个不同的结果。

我的成绩:163,307 公里

网站结果:136公里

有什么建议吗???

托蒂

【问题讨论】:

  • 你做了一个有点狡猾的假设,即地球的赤道半径和极地半径是相同的。

标签: c# c#-4.0 geocode


【解决方案1】:

我认为您正在交换纬度和经度值。尝试更正这些或更改参数顺序。

【讨论】:

    【解决方案2】:

    我使用Wikipedia 中的公式并将其放入 lambda 函数中:

    Func<double, double, double, double, double> CalcDistance = (lat1, lon1, lat2, lon2) =>
            {
                Func<double, double> Radians = (angle) =>
                {
                    return angle * (180.0 / Math.PI);
                };
    
                const double radius = 6371;
    
                double delataSigma = Math.Acos(Math.Sin(Radians(lat1)) * Math.Sin(Radians(lat2)) +
                    Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * Math.Cos(Math.Abs(Radians(lon2) - Radians(lon1))));
    
                double distance = radius * delataSigma;
    
                return distance;
            };
    

    【讨论】:

      【解决方案3】:

      在我几年前发表的文章中(链接:http://www.codeproject.com/Articles/469500/Edumatter-School-Math-Calculators-and-Equation-Sol)我描述了 3 个有用的Functions 来计算 2 个地理点之间的距离(换句话说,地球上 2 个之间的大圆(正交)距离地理点),在准确性/性能方面有所不同:

      // Haversine formula to calculate great-circle distance between two points on Earth
      
          private const double _radiusEarthMiles = 3959;
          private const double _radiusEarthKM = 6371;
          private const double _m2km = 1.60934;
          private const double _toRad = Math.PI / 180;
      
          /// <summary>
          /// Haversine formula to calculate 
          /// great-circle (orthodromic) distance on Earth 
          /// High Accuracy, Medium speed
          /// </summary>
          /// <param name="Lat1">double: 1st point Latitude</param>
          /// <param name="Lon1">double: 1st point Longitude</param>
          /// <param name="Lat2">double: 2nd point Latitude</param>
          /// <param name="Lon2">double: 2nd point Longitude</param>
          /// <returns>double: distance in miles</returns>
          public static double DistanceMilesHaversine(double Lat1,
                                                      double Lon1,
                                                      double Lat2,
                                                      double Lon2)
          {
              try
              {
                  double _radLat1 = Lat1 * _toRad;
                  double _radLat2 = Lat2 * _toRad;
                  double _dLatHalf = (_radLat2 - _radLat1) / 2;
                  double _dLonHalf = Math.PI * (Lon2 - Lon1) / 360;
      
                  // intermediate result
                  double _a = Math.Sin(_dLatHalf);
                  _a *= _a;
      
                  // intermediate result
                  double _b = Math.Sin(_dLonHalf);
                  _b *= _b * Math.Cos(_radLat1) * Math.Cos(_radLat2);
      
                  // central angle, aka arc segment angular distance
                  double _centralAngle = 2 * Math.Atan2(Math.Sqrt(_a + _b), Math.Sqrt(1 - _a - _b));
      
                  // great-circle (orthodromic) distance on Earth between 2 points
                  return _radiusEarthMiles * _centralAngle;
              }
              catch { throw; }
          }
      
      // Spherical law of cosines formula to calculate great-circle distance between two points on Earth
      
             /// <summary>
              /// Spherical Law of Cosines formula to calculate 
              /// great-circle (orthodromic) distance on Earth;
              /// High Accuracy, Medium speed
              /// http://en.wikipedia.org/wiki/Spherical_law_of_cosines
              /// </summary>
              /// <param name="Lat1">double: 1st point Latitude</param>
              /// <param name="Lon1">double: 1st point Longitude</param>
              /// <param name="Lat2">double: 2nd point Latitude</param>
              /// <param name="Lon2">double: 2nd point Longitude</param>
              /// <returns>double: distance in miles</returns>
              public static double DistanceMilesSLC(  double Lat1, 
                                                      double Lon1, 
                                                      double Lat2, 
                                                      double Lon2)
              {
                  try
                  {
                      double _radLat1 = Lat1 * _toRad;
                      double _radLat2 = Lat2 * _toRad;
                      double _radLon1 = Lon1 * _toRad;
                      double _radLon2 = Lon2 * _toRad;
      
                      // central angle, aka arc segment angular distance
                      double _centralAngle = Math.Acos(Math.Sin(_radLat1) * Math.Sin(_radLat2) +
                              Math.Cos(_radLat1) * Math.Cos(_radLat2) * Math.Cos(_radLon2 - _radLon1));
      
                      // great-circle (orthodromic) distance on Earth between 2 points
                      return _radiusEarthMiles * _centralAngle;
                  }
                  catch { throw; }
              }
      
      // Great-circle distance calculation using Spherical Earth projection formula**
      
      /// <summary>
      /// Spherical Earth projection to a plane formula (using Pythagorean Theorem)
      /// to calculate great-circle (orthodromic) distance on Earth.
      /// http://en.wikipedia.org/wiki/Geographical_distance
      /// central angle = 
      /// Sqrt((_radLat2 - _radLat1)^2 + (Cos((_radLat1 + _radLat2)/2) * (Lon2 - Lon1))^2)
      /// Medium Accuracy, Fast,
      /// relative error less than 0.1% in search area smaller than 250 miles
      /// </summary>
      /// <param name="Lat1">double: 1st point Latitude</param>
      /// <param name="Lon1">double: 1st point Longitude</param>
      /// <param name="Lat2">double: 2nd point Latitude</param>
      /// <param name="Lon2">double: 2nd point Longitude</param>
      /// <returns>double: distance in miles</returns>
      public static double DistanceMilesSEP(double Lat1,
                                            double Lon1,
                                            double Lat2,
                                            double Lon2)
      {
          try
          {
              double _radLat1 = Lat1 * _toRad;
              double _radLat2 = Lat2 * _toRad;
              double _dLat = (_radLat2 - _radLat1);
              double _dLon = (Lon2 - Lon1) * _toRad;
      
              double _a = (_dLon) * Math.Cos((_radLat1 + _radLat2) / 2);
      
              // central angle, aka arc segment angular distance
              double _centralAngle = Math.Sqrt(_a * _a + _dLat * _dLat);
      
              // great-circle (orthodromic) distance on Earth between 2 points
              return _radiusEarthMiles * _centralAngle;
          }
          catch { throw; }
      }
      

      函数以英里为单位返回结果;以公里为单位的距离乘以 1.60934(请参阅private const double _m2km = 1.60934)。

      与样本相关:求point1(36.578581,-118.291994)和point2(36.23998,-116.83171)的距离,上述三个Function产生如下结果(km):

      136.00206654936932
      136.00206654937023
      136.00374497149613
      

      计算器(链接:http://www.movable-type.co.uk/scripts/latlong.html)给出的结果是:136.0

      希望这可能会有所帮助。最好的问候,

      【讨论】:

        【解决方案4】:

        我刚刚尝试在 GeoDataSource 上编写代码,并且效果非常好: http://www.geodatasource.com/developers/c-sharp

        【讨论】:

          【解决方案5】:

          由于您使用的是框架 4.0,我建议您使用 GeoCoordinate 类。

          // using System.Device.Location;
          
          GeoCoordinate c1 = new GeoCoordinate(36.578581, -118.291994);
          GeoCoordinate c2 = new GeoCoordinate(36.23998, -116.83171);
          
          double distanceInKm = c1.GetDistanceTo(c2) / 1000;
          // Your result is: 136,111419742602
          

          您必须添加对 System.Device.dll 的引用。

          【讨论】:

            【解决方案6】:

            您的公式几乎是正确的,但是您必须将参数换成经度和纬度

            Console.WriteLine(DistanceAlgorithm.DistanceBetweenPlaces(-118.291994, 36.578581, -116.83171, 36.23998)); // = 136 km
            

            我使用的是简化公式:

            // cos(d) = sin(φА)·sin(φB) + cos(φА)·cos(φB)·cos(λА − λB),
            //  where φА, φB are latitudes and λА, λB are longitudes
            // Distance = d * R
            public static double DistanceBetweenPlaces(double lon1, double lat1, double lon2, double lat2)
            {
                double R = 6371; // km
            
                double sLat1 = Math.Sin(Radians(lat1));
                double sLat2 = Math.Sin(Radians(lat2));
                double cLat1 = Math.Cos(Radians(lat1));
                double cLat2 = Math.Cos(Radians(lat2));
                double cLon = Math.Cos(Radians(lon1) - Radians(lon2));
            
                double cosD = sLat1*sLat2 + cLat1*cLat2*cLon;
            
                double d = Math.Acos(cosD);
            
                double dist = R * d;
            
                return dist;
            }
            

            测试:

            (赤道距离):经度 0、100;纬度 = 0,0; DistanceBetweenPlaces(0, 0, 100, 0) = 11119.5 公里

            (北极距离):经度 0、100;纬度 = 90,90; DistanceBetweenPlaces(0, 90, 100, 90) = 0 公里

            经度:-118.291994,-116.83171;纬度:36.578581、36.23998 = 135.6 公里

            经度:36.578581、36.23998;纬度:-118.291994,-116.83171 = 163.2 公里

            最好的问候

            附:在web site,您用于结果比较,对于每个点,第一个文本框是纬度,第二个是经度

            【讨论】:

            • 不,这只是一个检查球面上两个点之间距离的数学公式。 wgs​​84 需要更复杂的椭球计算
            【解决方案7】:

            试试这个...我以前用过这个是应用程序——它非常准确。请原谅我没有对最初发表这篇文章的聪明人给予应有的赞扬,我将它从 java 转换为 C#:

            namespace Sample.Geography
            {
                using System;
            
            public class GeodesicDistance
            {
                private static double DegsToRadians(double degrees)
                {
                    return (0.017453292519943295 * degrees);
                }
            
                public static double? GetDistance(double lat1, double lon1, double lat2, double lon2)
                {
                    long num = 0x615299L;
                    double num2 = 6356752.3142;
                    double num3 = 0.0033528106647474805;
                    double num4 = DegsToRadians(lon2 - lon1);
                    double a = Math.Atan((1 - num3) * Math.Tan(DegsToRadians(lat1)));
                    double num6 = Math.Atan((1 - num3) * Math.Tan(DegsToRadians(lat2)));
                    double num7 = Math.Sin(a);
                    double num8 = Math.Sin(num6);
                    double num9 = Math.Cos(a);
                    double num10 = Math.Cos(num6);
                    double num11 = num4;
                    double num12 = 6.2831853071795862;
                    int num13 = 20;
                    double y = 0;
                    double x = 0;
                    double num18 = 0;
                    double num20 = 0;
                    double num22 = 0;
                    while ((Math.Abs((double) (num11 - num12)) > 1E-12) && (--num13 > 0))
                    {
                        double num14 = Math.Sin(num11);
                        double num15 = Math.Cos(num11);
                        y = Math.Sqrt(((num10 * num14) * (num10 * num14)) + (((num9 * num8) - ((num7 * num10) * num15)) * ((num9 * num8) - ((num7 * num10) * num15))));
                        if (y == 0)
                        {
                            return 0;
                        }
                        x = (num7 * num8) + ((num9 * num10) * num15);
                        num18 = Math.Atan2(y, x);
                        double num19 = ((num9 * num10) * num14) / y;
                        num20 = 1 - (num19 * num19);
                        if (num20 == 0)
                        {
                            num22 = 0;
                        }
                        else
                        {
                            num22 = x - (((2 * num7) * num8) / num20);
                        }
                        double num21 = ((num3 / 16) * num20) * (4 + (num3 * (4 - (3 * num20))));
                        num12 = num11;
                        num11 = num4 + ((((1 - num21) * num3) * num19) * (num18 + ((num21 * y) * (num22 + ((num21 * x) * (-1 + ((2 * num22) * num22)))))));
                    }
                    if (num13 == 0)
                    {
                        return null;
                    }
                    double num23 = (num20 * ((num * num) - (num2 * num2))) / (num2 * num2);
                    double num24 = 1 + ((num23 / 16384) * (4096 + (num23 * (-768 + (num23 * (320 - (175 * num23)))))));
                    double num25 = (num23 / 1024) * (256 + (num23 * (-128 + (num23 * (74 - (47 * num23))))));
                    double num26 = (num25 * y) * (num22 + ((num25 / 4) * ((x * (-1 + ((2 * num22) * num22))) - ((((num25 / 6) * num22) * (-3 + ((4 * y) * y))) * (-3 + ((4 * num22) * num22))))));
                    return new double?((num2 * num24) * (num18 - num26));
                }
            }
            }
            

            【讨论】:

            • 哇!!已经很复杂的代码被绝对无意义的变量名弄得更加乱七八糟。我要告诉鲍伯叔叔!!! :o)
            • 我同意,num1 到 num22 不是很好的变量命名 :-) 但感谢您的帮助!
            • 有时最好使用数学代码,因为它会从某些生成器中掉出来,因为如果出现拼写错误,“修复变量名”会导致细微的错误。
            • @Morten 谁是UncleBob
            • @TheRealChx101 鲍勃叔叔是罗伯特·马丁,“清洁代码”的作者
            猜你喜欢
            • 2011-08-10
            • 1970-01-01
            • 1970-01-01
            • 2017-12-13
            • 2023-04-02
            • 2011-04-26
            • 1970-01-01
            • 1970-01-01
            • 2011-12-24
            相关资源
            最近更新 更多