使用半正弦公式计算距离无效

问题描述 投票:0回答:1

免责声明 这是一项家庭任务。请不要认真对待这个问题或思考这个问题超过2秒。这根本不值得。对不起。

我正在尝试计算路线的大致距离。在 getPoints 方法中,我从数据库请求所有路线点并将它们写入数组。这部分工作良好并且符合预期。在这里你可以看到代码片段:

public ArrayList<Double> getPoints() {
    ArrayList<Double> location = new ArrayList<>();
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery("select latitude,longitude from " + Table_Name_Location, null);
    if (cursor.getCount() > 0) {
        while (cursor.moveToNext()) {
            Double latitude = cursor.getDouble(cursor.getColumnIndex("Lat"));
            Double longitude = cursor.getDouble(cursor.getColumnIndex("Longi"));
            location.add(latitude);
            location.add(longitude);
        }
    }
    cursor.close();
    return location;
}

private double distance(double lat1, double lon1, double lat2, double lon2) {
    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;
    return (dist);
}

private double deg2rad(double deg) {
    return (deg * Math.PI / 180.0);
}

private double rad2deg(double rad) {
    return (rad * 180.0 / Math.PI);
}

但是,当计算距离本身时,问题就出现了。由于某种原因,半正矢公式计算距离不正确。我发现问题出在距离方法的某个地方,但我自己无法识别。我比较了半正矢公式的实现,但没有发现与原始公式有任何差异。

java sqlite haversine
1个回答
0
投票

Android SDK 包含一个 Location 类,用于计算 Haversine 公式

这是源代码。

该方法的标题为 “distanceBetween”,并使用 private “computeDistanceAndBearing” 方法。
并且,计算值是距离(以米为单位)、初始方位和最终方位。

这是移植版本。
我删除了 BearingDistanceCache 参数,并将其调整为返回 double 数组

double[] computeDistanceAndBearing(double lat1, double lon1, double lat2, double lon2) {
    // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
    // using the "Inverse Formula" (section 4)

    // Convert lat/long to radians
    lat1 *= Math.PI / 180.0;
    lat2 *= Math.PI / 180.0;
    lon1 *= Math.PI / 180.0;
    lon2 *= Math.PI / 180.0;

    double a = 6378137.0; // WGS84 major axis
    double b = 6356752.3142; // WGS84 semi-major axis
    double f = (a - b) / a;
    double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);

    double l = lon2 - lon1;
    double aA = 0.0;
    double u1 = Math.atan((1.0 - f) * Math.tan(lat1));
    double u2 = Math.atan((1.0 - f) * Math.tan(lat2));

    double cosU1 = Math.cos(u1);
    double cosU2 = Math.cos(u2);
    double sinU1 = Math.sin(u1);
    double sinU2 = Math.sin(u2);
    double cosU1cosU2 = cosU1 * cosU2;
    double sinU1sinU2 = sinU1 * sinU2;

    double sigma = 0.0;
    double deltaSigma = 0.0;
    double cosSqAlpha;
    double cos2SM;
    double cosSigma;
    double sinSigma;
    double cosLambda = 0.0;
    double sinLambda = 0.0;

    double lambda = l; // initial guess
    for (int iter = 0; iter < 20; iter++) {
        double lambdaOrig = lambda;
        cosLambda = Math.cos(lambda);
        sinLambda = Math.sin(lambda);
        double t1 = cosU2 * sinLambda;
        double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
        double sinSqSigma = t1 * t1 + t2 * t2;
        sinSigma = Math.sqrt(sinSqSigma);
        cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda;
        sigma = Math.atan2(sinSigma, cosSigma);
        double sinAlpha = (sinSigma == 0) ? 0.0 :
            cosU1cosU2 * sinLambda / sinSigma;
        cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
        cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha;

        double uSquared = cosSqAlpha * aSqMinusBSqOverBSq;
        aA = 1 + (uSquared / 16384.0) * (4096.0 + uSquared * (-768 + uSquared * (320.0
            - 175.0 * uSquared)));
        double bB = (uSquared / 1024.0) * (256.0 + uSquared * (-128.0 + uSquared * (74.0
            - 47.0 * uSquared)));
        double cC = (f / 16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha));
        double cos2SMSq = cos2SM * cos2SM;
        deltaSigma = bB * sinSigma * (cos2SM + (bB / 4.0) * (cosSigma * (-1.0 + 2.0 * cos2SMSq)
            - (bB / 6.0) * cos2SM * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0
            + 4.0 * cos2SMSq)));

        lambda = l + (1.0 - cC) * f * sinAlpha * (sigma + cC * sinSigma * (cos2SM
            + cC * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM)));

        double delta = (lambda - lambdaOrig) / lambda;
        if (Math.abs(delta) < 1.0e-12) {
            break;
        }
    }

    float mDistance, mInitialBearing, mFinalBearing;
    mDistance = (float) (b * aA * (sigma - deltaSigma));
    float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
        cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
    initialBearing = (float) (initialBearing * (180.0 / Math.PI));
    mInitialBearing = initialBearing;
    float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
        -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
    finalBearing = (float) (finalBearing * (180.0 / Math.PI));
    mFinalBearing = finalBearing;

    return new double[] { mDistance, mInitialBearing, mFinalBearing };
}

并且,这是一个示例用法。
根据一些消息来源,从纽约市洛杉矶的距离约为3,934公里。

double[] nyc = { 40.712778, -74.006111 };
double[] la = { 34.05, -118.25 };
double[] x = computeDistanceAndBearing(nyc[0], nyc[1], la[0], la[1]);

输出

[3945043.75, -86.26732635498047, -114.04286193847656]
© www.soinside.com 2019 - 2024. All rights reserved.