Geometry 使用哈弗森公式计算横向/纵向点之间的距离

Geometry 使用哈弗森公式计算横向/纵向点之间的距离,geometry,geography,Geometry,Geography,我想找出两个经纬度点之间的距离。我正在试着用这个。这是公式: 我不知道为什么,但我的程序不起作用。这就是我得到的结果: Change Angle: 0.00016244370761414 Earth Radius: 6371 RESULTS: Correct Distance: 24.883 km Computed Distance: 1.0349288612097 资料来源: $latStart = 44.638; $longStart = -63.587; $latFinish

我想找出两个经纬度点之间的距离。我正在试着用这个。这是公式:

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

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

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

>>> sqrt(0.006 ** 2 + 0.0075 ** 2)
0.0096046863561492727
大约是0.000167弧度,非常接近你的计算。(更详细的信封背面检查:度约为69英里,比100公里多一点,因此0.01°应该比1公里多一点。)


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

你的方法松散地基于毕达哥拉斯定理——我总是以艰难的方式来实现,例如(实际上,我预先计算轴的值,并将其与数据一起存储在数据库中):


您的公式与我的实现不同。然而,我的是在.NET中,但我已经对它进行了单元测试,效果很好

这是一个稍微改写的版本:

//
///哈弗森公式的实施
///用于计算球体上两点之间的距离
/// http://en.wikipedia.org/wiki/Haversine_formula
/// 
公共级哈弗森
{
/// 
///以英里或公里为单位计算两点之间的距离
/// http://megocode3.wordpress.com/2008/02/05/haversine-formula-in-c/
/// 
///这是假设海平面
/// 
公共双距离(LatLon pos1、LatLon pos2、距离类型)
{
以英里为单位的地球常数双半径=3963.1676;
以公里为单位的地球常数双半径=6378.1;
//地球半径
双R=(类型==距离类型.Miles)?地球的半径(以英里为单位):地球的半径(以公里为单位);
//三角洲
双dLat=托拉迪安(位置2.Lat-位置1.Lat);
双dLon=ToRadian(pos2.Lon-pos1.Lon);
双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));
双d=R*c;
返回d;
}
/// 
///转换成弧度。
/// 
私人双托拉迪安(双瓦尔)
{
返回值(Math.PI/180)*val;
}
}

谢谢,这非常有帮助。我用你的密码检查了我的。结果是我输入了一个错误的值。我发誓我让tripple检查过,但我想没有。
$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);
/// <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;
    }
}