第53回 座標にもっとも近い線分上の点を内積で求める|gihyo.jp … 技術評論社
点$P(x_P, y_P)$と、線分$AB$($A(x_A, y_A), B(x_B, y_B)$)の距離を求める。
なので、まずはその判定が必要になる。
ベクトルの内積を使う。$\vec{AP}$と$\vec{AB}$のなす角を$\theta(0^\circ<\theta<180^\circ)$として、
$$ \vec{AP}\cdot\vec{AB}=|\vec{AP}||\vec{AB}|\cos{\theta} $$
また、PからAB(の延長線上)におろした垂線の足をCとすると、以下の式も成立する。
$$(AC)=|\vec{AP}|\cos{\theta}$$
ここで(AC)は、$\vec{AB}$ 方向に沿った線分ACの距離だが、負になり得る値である。(そのため$|\vec{AC}|$とは表記していない)
負の時というのは、$|\vec{AP}|>=0$より$\cos{\theta}<0$、つまり$\theta>90^\circ$なので、CはAを挟んでBと逆方向にあるということである。逆に正なら同じ側にある。
2式を合わせ、さらに正規化し、パラメータtを得る。
$$ (AC) = \frac{\vec{AP}\cdot\vec{AB}}{|\vec{AB}|} \\ t = \frac{(AC)}{|\vec{AB}|} = \frac{\vec{AP}\cdot\vec{AB}}{|\vec{AB}|^2} $$
前置きはここまで。
緯度経度で示された2点A,Bを結ぶ線と、点Pとの地球表面上の距離を求めたい時。
線分ABの結び方は、複数考えられる。今回考慮するABは、厳密には等角航路だが、地球全体からすると非常に短いため(せいぜい1km)、どれを選んでも誤差は無視できるとする。
国土交通省では地図を精確に表せるよう、ガウス・クリューゲル図法 - Wikipediaを用いた平面直角座標系を定義している。
これを利用して平面に落とし込み、平面上で上記の計算を行うと点と線分の距離が求まる。
平面直角座標系での系をわざと間違えてみると、誤差が発生することがわかる。誤差の割合は精度によらずだいたい一定。とはいえ、実用上は高が知れている。
精度(度) | 誤差(%) | 誤差 |
---|---|---|
1 | 0.5% | 140km中700m程度 |
0.1 | 0.4% | 14km中55m程度 |
0.01 | 0.4% | 1400m中5m程度 |
0.001 | 0.4% | 140m中0.5m程度 |
取りうる緯度経度の範囲が広い時、どこであろうと系を気にすることなく一定の精度で距離を計測したい。緯度経度から系を割り出すことはできても、処理内容が北海道の線分と沖縄の点を比較する可能性があるとき、誤差は避けられない。
これは検索してもあまり資料が出てこない。実用上は平面直角座標で何も問題ないし、お役所のお墨付きもあるし、メリットの方が大きいからかもしれない。ただ、理論上は地球を楕円球としてみれば、3次元空間のまま一定の公式で導出できそうなものである。
3次元の地心直交座標系に変換してから3次元ベクトルで同じように内外判定を行ってみた。
3次元上のベクトル$\vec{AB}$と、楕円球表面をなぞった$\stackrel{\frown}{AB}$は異なるため、平面直角座標系と比較して誤差が出る。誤差はABやPが互いに離れているほど大きくなるが、近い場合はほぼ等しくなる。
精度(度) | 誤差(%) | 誤差 |
---|---|---|
1 | 1%弱 | 140km中1000m程度 |
0.1 | 0.1% | 14km中10m程度 |
0.01 | 0.02% | 1400m中0.2m程度 |
0.001 | 0.01% | 140m中1cm程度 |
平面直角座標と比較して、データ量は2次元→3次元で単純に1.5倍になるが、内外判定の計算量はあまり変わらない。ただ、最終的な距離計算にHubenyを用いるため、その点では遅くなる。より精確になるともいえる。
速度は、ランダムに100万回pythonで計算させると、以下の通り。確かに平面と比較すると遅いが、どちらも十分に速いため大きな問題にはならなさそう。
平面直交座標 | 15s |
地心直交座標 | 23s |
pythonではpyprojを使うと楽ちんですね