【问题标题】:Distance between lat/long points using the haversine formula使用haversine公式的纬度/经度点之间的距离
【发布时间】:2010-11-30 13:21:33
【问题描述】:

我正在尝试查找两个经度和纬度点之间的距离。我正在尝试使用great circle distance。这是公式:

我不知道为什么,但我的程序不工作。这是我得到的结果:

Change Angle: 0.00016244370761414
Earth Radius: 6371

RESULTS: 
Correct  Distance: 24.883 km
Computed Distance: 1.0349288612097

来源:

$latStart = 44.638;
$longStart = -63.587;

$latFinish = 44.644;
$longFinish = -63.597;


# Convert Input to Radians
$latStart = deg2Rad($latStart);
$longStart = deg2Rad($longStart);

$latFinish = deg2Rad($latFinish);
$longFinish = deg2Rad($longFinish);

# Because the Earth is not perfectly spherical, no single value serves as its 
# natural radius. Distances from points on the surface to the center range from 
# 6,353 km to 6,384 km (≈3,947–3,968 mi). Several different ways of modeling the 
# Earth as a sphere each yield a convenient mean radius of 6371 km (≈3,959 mi).
# http://en.wikipedia.org/wiki/Earth_radius
$earthRadius = 6371;

# difference in Long/Lat
$latChange = $latFinish - $latStart;
$longChange = $longFinish - $longStart;



# haversine formula 
# numerically stable for small distances
# http://en.wikipedia.org/wiki/Great-circle_distance
$changeAngle = 2 * asin(
                sqrt(
                        pow(sin($latChange/2),2) +
                        cos($latStart) * cos($latFinish) * pow(sin($longChange/2),2)
                )
        );



echo "Change Angle: $changeAngle\n";
echo "Earth Radius: $earthRadius\n";

【问题讨论】:

    标签: geometry geography


    【解决方案1】:

    让我们使用平面近似进行粗略检查。纬度差为0.006°,经度差为0.01°,但乘以纬度的余弦得到0.0075°。应用毕达哥拉斯:

    >>> sqrt(0.006 ** 2 + 0.0075 ** 2)
    0.0096046863561492727
    

    大约是 0.000167 弧度,非常接近您的计算。 (更粗略的检查:一个度数大约是 69 英里,比 100 公里多一点,所以 0.01° 应该比 1 公里多一点。)

    所以我认为是你所谓的“正确距离”是错误的,而不是你的计算。

    【讨论】:

      【解决方案2】:

      您的方法大致基于毕达哥拉斯定理——我总是以艰难的方式完成它,例如(实际上,我预先计算了轴的值并将它们与数据一起存储在数据库中) :

      $startXAxis   = cos(deg2Rad($latStart)) * cos(deg2Rad($longStart));
      $startYAxis   = cos(deg2Rad($latStart)) * sin(deg2Rad($longStart));
      $startZAxis   = sin(deg2Rad($latStart));
      $finishXAxis   = cos(deg2Rad($latFinish)) * cos(deg2Rad($longFinish));
      $finishYAxis   = cos(deg2Rad($latFinish)) * sin(deg2Rad($longFinish));
      $finishZAxis   = sin(deg2Rad($latFinish));
      
      $changeAngle = acos($startXAxis * $finishXAxis + $startYAxis * $finishYAxis + $startZAxis * $finishZAxis);
      

      【讨论】:

        【解决方案3】:

        您的公式看起来与我的实现不同。但是我的在 .NET 中,但我已经对其进行了单元测试并且效果很好。

        这是一个稍微改写的版本:http://megocode3.wordpress.com/2008/02/05/haversine-formula-in-c/

        /// <summary>
        /// Implementation of the Haversine formula
        /// For calculating the distance between 2 points on a sphere
        /// http://en.wikipedia.org/wiki/Haversine_formula
        /// </summary>
        public class Haversine
        {
            /// <summary>
            /// Calculate the distance between 2 points in miles or kilometers
            /// http://megocode3.wordpress.com/2008/02/05/haversine-formula-in-c/
            /// 
            /// This assumes sea level
            /// </summary>
            public double Distance(LatLon pos1, LatLon pos2, DistanceType type)
            {
                const double RADIUS_OF_EARTH_IN_MILES = 3963.1676;
                const double RADIUS_OF_EARTH_IN_KILOMETERS = 6378.1;
        
                //radius of the earth
                double R = (type == DistanceType.Miles) ? RADIUS_OF_EARTH_IN_MILES : RADIUS_OF_EARTH_IN_KILOMETERS;
        
                //Deltas
                double dLat = ToRadian(pos2.Lat - pos1.Lat);
                double dLon = ToRadian(pos2.Lon - pos1.Lon);
        
                double a = Math.Sin(dLat/2)*Math.Sin(dLat/2) + Math.Cos(ToRadian(pos1.Lat))*Math.Cos(ToRadian(pos2.Lat)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
                double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
        
                double d = R*c;
                return d;
            }
        
            /// <summary>
            /// Convert to Radians.
            /// </summary>
            private double ToRadian(double val)
            {
                return (Math.PI / 180) * val;
            }
        }
        

        【讨论】:

        • 谢谢,这很有帮助。我用你的代码检查了我的。原来我输入错误的输入值之一。我发誓我已经检查了三次,但我想没有。
        猜你喜欢
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-11
        • 2012-10-13
        • 2012-01-26
        相关资源
        最近更新 更多