纠正我计算两点之间的大圆距离的算法

时间:2015-04-21 14:26:45

标签: java algorithm

我使用以下算法计算两点之间的距离,但它产生了不合理的结果。我哪里错了?

private static double distFrom(double latA, double lngA, double latB, double lngB) {
    double pk = 180/3.14169;

    double a1 = latA / pk;
    double a2 = lngA / pk;
    double b1 = latB / pk;
    double b2 = lngB / pk;

    double t1 = Math.cos(a1)*Math.cos(a2)*Math.cos(b1)*Math.cos(b2);
    double t2 = Math.cos(a1)*Math.sin(a2)*Math.cos(b1)*Math.sin(b2);
    double t3 = Math.sin(a1)*Math.sin(b1);
    double tt = Math.acos(t1 + t2 + t3);

    return 3959*tt;
}

3 个答案:

答案 0 :(得分:7)

使用Math.PI替换3.14169会有所改善,因为PI的第一个数字是3.141 5 9

此外,还有很多算法。尝试http://www.geodatasource.com/developers/java,它会给你一个英里,公里和海里的答案。

答案 1 :(得分:1)

更好地使用标准字母 - 经度为L,纬度为B.您使用的http://en.wikipedia.org/wiki/Great-circle_distance方法的公式很奇怪。根据维基,它将是:

    double B1 = latA / pk;
    double B2 = latB / pk;
    double dL = (lngA-lngB) / pk;

    double t1 = Math.cos(B1)*Math.cos(B2)*Math.cos(dL);
    double t2 = Math.sin(B1)*Math.sin(B2);

    double tt = Math.acos(t1 + t2);

减少计算 - >减少舍入错误。

但请注意,这个基于acos的公式在数学上是正确的,但不是计算上的 - 它在短距离内具有低浮点精度!在提到的page上,有更好的计算公式,基于asin用于短距离和基于atan的通用算法。选择其中一个。

答案 2 :(得分:0)

这是 http://en.wikipedia.org/wiki/Great-circle_distance 的 atan 版本(“文森蒂公式的特殊情况”)的实现,它“对所有距离都准确”:

/**
 * Mean earth radius in Kilometers (KM) as defined in WGS84
 */
public static final double EARTH_RADIUS_KM = 6371.0087714;

/**
 * Mean earth radius in US Miles, converted from Kilometers
 */
public static final double EARTH_RADIUS_MI = EARTH_RADIUS_KM * 0.621371192;

/**
 * Mean earth radius in Nautical Miles, converted from Kilometers
 */
public static final double EARTH_RADIUS_NM = EARTH_RADIUS_KM * 0.539956803;

/**
 * Calculates the distance between two points on a sphere using a "special
 * case of the Vincenty formula" for accuracy. This uses more trigonometric
 * calls than other formulas, but is more accurate for all distances.
 * <p/>
 * 
 * For more details, see <a href=
 * "https://en.wikipedia.org/wiki/Great-circle_distance">https://en.wikipedia.org/wiki/Great-circle_distance</a>.
 * 
 * @param startLat
 *          The starting point's latitude
 * @param startLon
 *          The starting point's longitude
 * @param endLat
 *          The ending point's latitude
 * @param endLon
 *          The ending point's longitude
 * @param radius
 *          The radius of the spherical earth to be used
 * 
 * @return The distance between the points for the given radius
 */
public static double greatCircleDistance( double startLat, double startLon, double endLat, double endLon, double radius )
{
    // convert to radians
    double lonDelta = Math.toRadians( startLon - endLon );
    double lat1 = Math.toRadians( startLat );
    double lat2 = Math.toRadians( endLat );

    // compute repeatedly used values
    double cos1 = Math.cos( lat1 );
    double sin1 = Math.sin( lat1 );
    double cos2 = Math.cos( lat2 );
    double sin2 = Math.sin( lat2 );
    double cosDelta = Math.cos( lonDelta );

    double top1 = cos2 * Math.sin( lonDelta );
    top1 *= top1; // squared

    double top2 = (cos1 * sin2) - (sin1 * cos2 * cosDelta);
    top2 *= top2; // squared

    double top = Math.sqrt( top1 + top2 );
    double bottom = (sin1 * sin2) + (cos1 * cos2 * cosDelta);

    double rad = Math.atan( top / bottom );

    return radius * rad;
}

为地球半径选择不同的值可设置所需的单位。这适用于任何半径的任何球体,因此只要您知道起点和终点的纬度/经度,就可以使用 3389.5 公里的半径计算火星上的距离。