1

緯度/経度の 4 つのポイントと方位を指定して境界ボックスを見つける必要があります (例の図を参照)。どの 2 点が方位によって並んでいるか (この例では 1 と 2) は常にわかっているので、バウンディング ボックスの長さは常にわかります。ただし、幅は任意で、ポイントは線に沿った任意の場所にあります (例では 3 と 4)。

ここに画像の説明を入力

私の最初の考えは、ポイント間の角度 (1 と 3、1 と 4、2 と 3、2 と 4) を計算し、一連の「コサインの法則」方程式を使用してコーナー ポイントを計算する必要があるということです。 . もっと簡単な方法はありますか?それはうまくいきますか?

4

1 に答える 1

2

周りを見回して、おそらくより適切なサイト (ここ) を尋ねても、Chris Veness (ここ) の何かに基づいて、2 つの点とその方位が与えられた交点を見つけるための解決策を見つけました。したがって、バウンディング ボックスの角を取得するには、上/下と左/右 (1 & 3、1 & 4、2 & 3、2 & 4) の各組み合わせを取得し、既知の方位を使用して交点を見つけ、それに応じて調整します. たとえば、画像の右下を見つけるには、ポイント 1 の方向に方位 + 90 を使用し、ポイント 3 の方向に方位 - 180 を使用して、ポイント 1 と 3 の交点を計算します。

アルゴリズムの功績を認めることはできませんし、それが幾何学的にどのように機能するかという点で実際に説明することさえできませんが、私のテストではうまくいきました。以下は、Chris が提供する JavaScript バージョンからの私の Java 翻訳です。

public static CoordD getIntersection(CoordD point1, double bearing1, CoordD point2, double bearning2) {
    double lat1 = rad(point1.latitude); double lon1 = rad(point1.longitude);
    double lat2 = rad(point2.latitude); double lon2 = rad(point2.longitude);
    double bearing13 = rad(bearing1); double bearing 23 = rad(bearing2);
    double dLat = lat2 - lat1; double dLon = lon2 - lon1;

    double dist12 = 2 * Math.asin( Math.sqrt( Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2) ) );
    if (dist12 == 0) return null;

    double bearingA = Math.acos( ( Math.sin(lat2) - Math.sin(lat1) * Math.cos(dist12) ) /
        ( Math.sin(dist12) * Math.cos(lat1) ) );
    double bearingB = Math.acos( ( Math.sin(lat1) - Math.sin(lat2) * Math.cos(dist12) ) /
        ( Math.sin(dist12) * Math.cos(lat2) ) );
    if (Double.isNaN(bearingA)) bearingA = 0;
    if (Double.isNaN(bearingB)) bearingB = 0;

    double bearing12, bearing21;
    if (Math.sin(dLon) > 0) {
        bearing12 = bearingA;
        bearing21 = 2 * Math.PI - bearingB;
    } else { 
        bearing12 = 2 * Math.PI - bearingA;
        bearing21 = bearingB;
    }

    double alpha1 = (bearing13 - bearing12 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 2-1-3
    double alpha2 = (bearing21 - bearing23 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 1-2-3

    if (Math.sin(alpha1) == 0 && Math.sin(alpha2) == 0) return null; // Infinite intersections
    if (Math.sin(alpha1) * Math.sin(alpha2) < 0) return null; // Ambiguous intersection

    // needed?
    // alpha1 = Math.abs(alpha1);
    // alpha2 = Math.abs(alpha2);

    double alpha3 = Math.acos( -Math.cos(alpha1) * Math.cos(alpha2) +
        Math.sin(alpha1) * Math.sin(alpha2) * Math.cos(dist12) );
    double dist13 = Math.atan2( Math.sin(dist12) * Math.sin(alpha1) * Math.sin(alpha2),
        Math.cos(alpha2) + Math.cos(alpha1) * Math.cos(alpha3) );

    double lat3 = Math.asin( Math.sin(lat1) * Math.cos(dist13) +
        Math.cos(lat1) * Math.sin(dist13) * Math.cos(bearing13) );

    double dLon13 = Math.atan2( Math.sin(bearing13) * Math.sin(dist13) * Math.cos(lat1),
        Math.cos(dist13) - Math.sin(lat1) * Math.sin(lat3) );
    double lon3 = lon1 + dLon3;
    lon3 = (lon3 + 3 * Math.PI) % ( 2* Math.PI) - Math.PI // normalize to +/-180

    return new CoordD(deg(lat3), deg(lon3));
}

rad()deg()は、ラジアンと度の間で変換する単なるヘルパー関数です。 CoordDは、緯度/経度のポイントを格納する 2 つの double のみを含むヘルパー クラスです。

于 2013-10-21T19:40:49.240 に答える