23

場所の緯度と経度のセットがあります。

  • セット内のある場所から別の場所 までの距離を見つける方法は?
  • 式はありますか?
4

12 に答える 12

33

Haversine 式は、球状の地球を想定しています。しかし、地球の形はもっと複雑です。扁平回転楕円体モデルは、より良い結果をもたらします。

そのような精度が必要な場合は、Vincenty の逆公式を使用することをお勧めします。詳細については、 http://en.wikipedia.org/wiki/Vincenty's_formulaeを参照してください。これを使用すると、回転楕円体モデルで 0.5mm の精度を得ることができます。

地球の実際の形状は複雑すぎて公式で表現できないため、完全な公式はありません。さらに、地球の形状は気候変動によって変化し ( http://www.nasa.gov/centers/goddard/earthhandsun/earthshape.htmlを参照)、地球の自転によって時間とともに変化します。

また、上記の方法は高度を考慮しておらず、海面偏平楕円体を想定していることにも注意してください。

編集 2010 年 7 月 10 日: Vincenty の逆公式が宣言された精度に収束しないまれな状況があることがわかりました。より正確なGeographicLib ( http://sourceforge.net/projects/geographiclib/を参照) を使用することをお勧めします。

于 2009-09-14T16:17:55.253 に答える
9

ここに 1 つがあります: http://www.movable-type.co.uk/scripts/latlong.html

Haversine 式を使用する:

R = earth’s radius (mean radius = 6,371km)
Δlat = lat2− lat1
Δlong = long2− long1
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
c = 2.atan2(√a, √(1−a))
d = R.c 
于 2009-09-14T07:00:15.993 に答える
5

Haversine 式を適用して距離を求めます。2 つの座標間の距離を見つけるには、以下の C# コードを参照してください。さらに良いのは、特定の半径内にある店舗のリストを見つけたい場合はWHERE、SQL の句または C# の LINQ フィルターをそれに適用できます。

ここでの計算式はキロメートル単位です。関連する数値を変更する必要があり、マイルでも機能します。

例: 6371.392896 をマイルに変換します。

    DECLARE @radiusInKm AS FLOAT
    DECLARE @lat2Compare AS FLOAT
    DECLARE @long2Compare AS FLOAT
    SET @radiusInKm = 5.000
    SET @lat2Compare = insert_your_lat_to_compare_here
    SET @long2Compare = insert_you_long_to_compare_here

    SELECT * FROM insert_your_table_here WITH(NOLOCK)
    WHERE (6371.392896*2*ATN2(SQRT((sin((radians(GeoLatitude - @lat2Compare)) / 2) * sin((radians(GeoLatitude - @lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2)))
    , SQRT(1-((sin((radians(GeoLatitude - @lat2Compare)) / 2) * sin((radians(GeoLatitude - @lat2Compare)) / 2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2)))
    ))) <= @radiusInKm

C# で Haversine 式を実行する場合は、

    double resultDistance = 0.0;
    double avgRadiusOfEarth = 6371.392896; //Radius of the earth differ, I'm taking the average.

    //Haversine formula
    //distance = R * 2 * aTan2 ( square root of A, square root of 1 - A )
    //                   where A = sinus squared (difference in latitude / 2) + (cosine of latitude 1 * cosine of latitude 2 * sinus squared (difference in longitude / 2))
    //                   and R = the circumference of the earth

    double differenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare);
    double differenceInLong = DegreeToRadian(currentLongitude - longtitudeToCompare);
    double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude)) * Math.Cos(DegreeToRadian(latitudeToCompare)) * Math.Sin(differenceInLong / 2) * Math.Sin(differenceInLong / 2);
    double aFormula = (Math.Sin((differenceInLat) / 2) * Math.Sin((differenceInLat) / 2)) + (aInnerFormula);
    resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula), Math.Sqrt(1 - aFormula));

DegreesToRadian は私がカスタム作成した関数で、単純な 1 ライナーです。"Math.PI * angle / 180.0

私のブログエントリ - SQL Haversine

于 2010-06-11T07:36:50.817 に答える
4

何方をお探しですか

ハバーシン式

Haversine 式は、経度と緯度から球面上の 2 点間の大圏距離を与える、ナビゲーションで重要な方程式です。これは、球面の「三角形」の辺と角度を関連付ける球面三角法のより一般的な公式であるハーバーサインの法則の特殊なケースです。

于 2009-09-14T06:58:37.353 に答える
3

これを見てください..にはJavaScriptの例もあります。

距離を見つける

于 2009-09-14T06:59:06.510 に答える
2

大円距離公式を使用します。

于 2009-09-14T06:59:58.287 に答える
1

これは、指定された IP によって場所/近くの場所を長い/緯度で見つけるためのフィドルです。

http://jsfiddle.net/bassta/zrgd9qc3/2/

そして、これが直線で距離を計算するために使用する関数です。

function distance(lat1, lng1, lat2, lng2) {
        var radlat1 = Math.PI * lat1 / 180;
        var radlat2 = Math.PI * lat2 / 180;
        var radlon1 = Math.PI * lng1 / 180;
        var radlon2 = Math.PI * lng2 / 180;
        var theta = lng1 - lng2;
        var radtheta = Math.PI * theta / 180;
        var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
        dist = Math.acos(dist);
        dist = dist * 180 / Math.PI;
        dist = dist * 60 * 1.1515;

        //Get in in kilometers
        dist = dist * 1.609344;

        return dist;
    }

キロ単位で距離を返します

于 2015-03-31T14:36:37.427 に答える
0

このページでは、Android の Location クラスで位置の距離を計算する方法のコード全体と式を確認できます。

アンドロイド/場所/場所.java

EDIT : @Richard からのヒントによると、無効なリンクを避けるために、リンクされた関数のコードを回答に入れました。

private static void computeDistanceAndBearing(double lat1, double lon1,
    double lat2, double lon2, BearingDistanceCache results) {
    // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
    // using the "Inverse Formula" (section 4)
    int MAXITERS = 20;
    // 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 A = 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 = 0.0;
    double cos2SM = 0.0;
    double cosSigma = 0.0;
    double sinSigma = 0.0;
    double cosLambda = 0.0;
    double sinLambda = 0.0;
    double lambda = L; // initial guess
    for (int iter = 0; iter < MAXITERS; 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; // (14)
        sinSigma = Math.sqrt(sinSqSigma);
        cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
        sigma = Math.atan2(sinSigma, cosSigma); // (16)
        double sinAlpha = (sinSigma == 0) ? 0.0 :
            cosU1cosU2 * sinLambda / sinSigma; // (17)
        cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
        cos2SM = (cosSqAlpha == 0) ? 0.0 :
            cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
        double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
        A = 1 + (uSquared / 16384.0) * // (3)
            (4096.0 + uSquared *
             (-768 + uSquared * (320.0 - 175.0 * uSquared)));
        double B = (uSquared / 1024.0) * // (4)
            (256.0 + uSquared *
             (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
        double C = (f / 16.0) *
            cosSqAlpha *
            (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
        double cos2SMSq = cos2SM * cos2SM;
        deltaSigma = B * sinSigma * // (6)
            (cos2SM + (B / 4.0) *
             (cosSigma * (-1.0 + 2.0 * cos2SMSq) -
              (B / 6.0) * cos2SM *
              (-3.0 + 4.0 * sinSigma * sinSigma) *
              (-3.0 + 4.0 * cos2SMSq)));
        lambda = L +
            (1.0 - C) * f * sinAlpha *
            (sigma + C * sinSigma *
             (cos2SM + C * cosSigma *
              (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
        double delta = (lambda - lambdaOrig) / lambda;
        if (Math.abs(delta) < 1.0e-12) {
            break;
        }
    }
    float distance = (float) (b * A * (sigma - deltaSigma));
    results.mDistance = distance;
    float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
        cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
    initialBearing *= 180.0 / Math.PI;
    results.mInitialBearing = initialBearing;
    float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
            -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
    finalBearing *= 180.0 / Math.PI;
    results.mFinalBearing = finalBearing;
    results.mLat1 = lat1;
    results.mLat2 = lat2;
    results.mLon1 = lon1;
    results.mLon2 = lon2;
}
于 2015-07-03T07:25:31.963 に答える