他の2つのポイントの中間にあるポイントを見つける方法は?


8

私はマップデータのOSMモバイルバイナリ形式の実装に取り​​組んでいます。ウェイに沿った各ポイントに16ビットのデルタを使用しているため、2つのポイント間に大きな距離がある場合、ウェイを表すことができません。

文書化された解決策は、ギャップを小さく保つために、新しいポイントをウェイに注入することです。

これが私のコードの関連セクションです:

// calculate the distance between this point and the previous point,
// multiplied by 1,000,000 so it can be represented as an integer.
int32_t realNodeLatDelta = ((point.latitude - lastPoint.latitude) * 1000000);
int32_t realNodeLonDelta = ((point.longitude - lastPoint.longitude) * 1000000);

// cast as a 16 bit int (reduces filesize by about half)
int16_t nodeLatDelta = realNodeLatDiff;
int16_t nodeLonDelta = realNodeLonDiff;

// check if the cast caused corruption
if (realNodeLatDelta != nodeLatDelta || realNodeLatDelta != nodeLatDelta) {
  // if this point is reached, we need to add new points in the way,
  // which can be represented in a 16 bit delta
}

途中で新しいポイントの位置を計算する方法がわかりませんか?私はそれが大きなサークルである必要があると思いますか?

この問題を引き起こすのに十分離れたポイントはまれですが、実際に発生する場合、それは通常、政治的境界などであり、かなり長くなる傾向があり、正確に表す必要があります。


OSM-devメーリングリスト(lists.openstreetmap.org/listinfo/dev)でこの質問をすることをお勧めします。これは、一般的なGISフォーラムには少々具体的すぎます。
Igor Brejc、2012年

1
確かに、他の2つのポイントの中間にあるポイントを見つけるための数学はあまり具体的ではありませんか?
Abhi Beckert、2012年

そうではありませんが、この問題に対処する方法は他にもある可能性があります。これはフォーマット固有のものです。
Igor Brejc、2012年

これに対処するための代替方法はありません。16ビット整数は、ある方法でポイントに許可されている唯一のフォーマットであり、(小数点以下6桁の精度で)16ビット整数は、2つのポイント間の約3.5kmの違いしか表現できません。唯一の選択肢は、その形式を使用しないことです(これは私の暫定的な解決策です)。でも、できれば標準的なものを使いたいです。
Abhi Beckert、2012年

1
私はあなたが一桁離れているかもしれないと思います:地球上で見つけることができる最長距離は約20,000 kmです。16ビットで、これは300mの精度に変換されます。
whuber

回答:


13

楕円体モデルで最高の精度が得られます。単純化のために、距離を自分でコーディングする必要がある場合は、それらを回避する必要があります。代償を払います。地球の平坦化が約1/300であることを考えると、純粋に球形のモデルを使用すると、非常に長いルートの場合、最大1/300の相対距離誤差が発生する可能性があります。これは探索する価値があります。

まず、球形の公式:(lat、lon)をデカルト座標に変換し、2つのデカルト点を平均化してから、平均を球座標に変換します。ここに擬似コードがあります:

function cartesian(f,l) { // f = latitude, l = longitude
    return (cos(f)*cos(l), cos(f)*sin(l), sin(f))
}
function spherical(x,y,z) {
    r = sqrt(x^2 + y^2)
    if (r == 0) {
        if (z > 0) return (90, 0) 
        elseif (z < 0) return (-90, 0)
        else return Undefined // (x,y,z) == (0,0,0)
    } else {
        return (atan2(r, z), atan2(x, y)) // atan2 must return *degrees*
    }
}
function midpoint(f0,l0, f1,l1) { 
    return spherical((cartesian(f0,l0) + cartesian(f1,l1))/2)
}

(の計算にmidpointは、ベクトルの合計とその合計のスカラー除算が含まれるため、実際には3つの合計と3つの除算が隠されています。)

これが球形ジオメトリの中点です。計算には、2つの余弦、2つの正弦、平方根、2つのアークタンジェント、およびいくつかの乗算と加算が必要です。かなり高速で簡単です。極の近くや+ -180子午線を越えても問題はありません。2つの点が正反対の場合、結果は未定義になります。

エラーを測定する1つの方法は、元のポイント間の距離と比較して、中点を経由して移動した距離の増加を計算することです。元の距離と比較して増加が小さい場合、不満はほとんどありません。WGS84楕円体の正確な楕円体距離を使用してこれらの誤差を計算しました。結果の典型的な例として、端点の1つが(lat、lon)=(45、0)に固定されている場合の相対エラーのプロットを次に示します。

相対エラー

等高線は対数(基数10)スケールです。-6等高線は、相対誤差が10 ^(-6)である点を示します。つまり、100万分の1(ppm)です。-5のコンター((-45、180)の近くにかろうじて見える、正反対のポイント)は10 ppmです。-7、-8などは、ppmの一部です。非常に正確です。

明らかに、ほぼ正反対の2つの点の中点を計算しようとしない限り、問題はありません。(計算は球に対して完全に正しいことを覚えておいてください。これらのエラーは球の平坦化が原因です。)

16ビットの精度が約16 ppm(10を底とする対数が-4.8に等しい)であることを考えると、2つの点が正反対に離れている場合に2点が1度以上離れている場合、中点を見つけるために球面公式を使用しても問題ありません。

より単純な線形公式はどうですか? これを調べるために、2つの端点間の距離を基準にして、線形の中間点(2つの緯度と2つの経度を平均することによって得られる)と球形の中間点との間の距離を比較してみましょう。次の図では、1つのエンドポイントを(45、180)に固定し、その周りの比較的小さな領域を調べています。

相対エラー2

これらのコンターのほとんど(10を底とする対数)は-2に近く、100分の1 (1%)のエラーです。南北方向についてはエラーはありませんが、他のすべての方向については、多くのアプリケーションでエラーが許容されません

線形近似が正常になるかどうかを確認するために、前のマップを10倍に拡大してみましょう。幅が1度(この緯度で50マイル)で、幅が0.5度(35マイル)になっています。大都市または小都市とその郊外の規模で。

これで、輪郭は-3〜-4程度になります。つまり、100〜1000分の1(0.01%〜0.1%)です。かなり粗雑で、よく見ると高解像度のコンピュータ画面ではほとんど目立ちません。

相対エラー3

振り返ってみると、球形の計算式はやや複雑ですが、簡単に実装できますが、近くの場所での単純な線形計算式よりも世界中で高い精度が得られます。(エラーを測定するために2つの異なる方法を使用したため、それらを直接比較することはできません。

要点:

- 線形式は、都市スケールで0.01%から0.1%の相対誤差で中点を誤配置します。広い領域では、位置のずれが著しく間違っている可能性があります(1%から最大数百%)。

- 球の公式は、球の地球モデルに対して完全に正しいものです。より正確な楕円体の公式と比較すると、ほぼ正反対の点を除いて、それはまだうまくいくはずです。


1
わあ、ありがとう!それはいくつかの本当に良い情報です。完璧な精度は必要ありません。個人のGPSを使用するためのiPhoneアプリであり、主に道路にのみ焦点を当てています。高速道路は数百キロにわたって完全に直線的ではないため、線形精度でも「十分」です。しかし、政治的境界線はしばしばまっすぐで長いものです(西オーストラリア州の右側は1,800kmです)。球形の公式はそのために完璧でなければなりません。私はあなたにあなたの答えに対する報奨金を与えることができればいいのに、あなたはそれに値する。
Abhi Beckert、2012年

8

あなたのソリューションは短い距離では機能しますが、それよりも長い距離では機能しません。理由を確認する最も簡単な方法は、次のマップ(ここから取得)を確認することです。

ここに画像の説明を入力してください

これは正距円筒図法の世界地図です。経度と緯度はX軸とY軸に単純に直線的に投影されます。あなたの数学は青い長方形で表すことができます。ただし、青い対角線は、地球の表面上の2点間の最短の「線」を表すものではありませ。必要なのは大円黒い曲線で表される)です。

C ++を使用していますが、Mike GavaghanのC#Geodesy Libraryをご覧になることをお勧めします。これはオープンソースであり、コードは高品質であり、大圏に沿って計算を行う方法を理解できるはずです。計算の背後にある数学に興味がある場合は、Vincentyの式を確認することもできます。


ありがとう!それがまさに私が探しているものです。Mike GavaghanのコードはCに移植するのが簡単に見えます(私は実際にはObjective-Cを使用しています)。私の線形計算がうまくいくと確信していましたが、何かが必要でした。
Abhi Beckert、2012年

-1

単純な線形数学はうまくいくようです:

double newLat = lastCoord.latitude + ((coord.latitude - lastCoord.latitude) / 2);
double newLon = lastCoord.longitude + ((coord.longitude - lastCoord.longitude) / 2);

すべてが十分に小さくなるまで、大きすぎるウェイの各セクションに半分ほど新しいポイントを再帰的に挿入しています。

より長い距離でより複雑な計算が必要かどうかはわかりませんが(誰かが私にこれを確認してもらえますか?)、この計算(約5km)ではうまく機能します。

ポイント間の長い直線の例

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.