2地点の緯度経度から距離を求める(global化 2/2)

前回(my-hobby : 2地点の緯度経度から距離を求める(global化 1/2))の続きです。
前回の内容を踏まえて、問題点を解決する方法を考えました。
具体的に言うと以下の様な方法です。
1.A地点の座標がx軸の中心となるように、地図を移動させる。y軸は任意。
2.B地点についてはA地点の緯度経度から相対的な位置関係を計算して、B地点とのx軸、y軸の経差、緯差を求める。
3.x軸、y軸の距離差を使用して、2地点の距離を計算する。

この方法だとA地点を経度の基点として、地図を左右に移動できるので、前回の様な問題を解決する事が出来ます。

上記の方法で計算式を書くと以下の様な感じです。(vb.netで記述しています)
[vbnet]
Dim longitude1 As Double ‘A地点の経度
Dim latitude1 As Double ‘B地点の緯度
Dim longitude2 As Double ‘A地点の経度
Dim latitude2 As Double ‘B地点の緯度

Dim latitude1Abs As Double ‘A地点の緯度の絶対値
Dim latitude2Abs As Double ‘B地点の緯度の絶対値
Dim CosIdoWK As Double ‘基準となる緯度(角度)

Dim xWK As Double ‘経度差
Dim yWK As Double ‘緯度差
Dim distance As Double ‘2地点の距離

distance = 0

‘基準となる緯度(角度)を取得
latitude1Abs = Abs(latitude1)
latitude2Abs = Abs(latitude2)
If latitude1Abs <= latitude2Abs Then
If latitude1Abs = 0 Then
CosIdoWK = latitude2Abs
Else
CosIdoWK = latitude1Abs
End If
Else
CosIdoWK = latitude2Abs
End If

‘A地点、B地点の経差、緯差を求める。
‘差の絶対値を取る事で、緯度経度に-(マイナス)が入っても、それぞれの差を求める事が出来る
x = Abs(longitude2 – longitude1)
y = Abs(latitude2 – latitude1)

‘経差を補正
‘※原点に対して180度を超過している(地球を半周以上している)場合は、反対周りの距離に変換する
If x > 180 Then
x = 360 – Abs(x)
End If

‘座標上から2地点の距離を求める
If CosIdoWK = 0 Then ‘赤道上の距離の場合
distance = x * 111
Else
xKm = x * Cos(Math.PI / 180 * CosIdoWK) * 111
yKm = y * 111
distance = (xKm ^ 2 + yKm ^ 2) ^ (1 / 2)
End If
[/vbnet]
※上記計算式は、2地点の距離が2極点を通過する場合は、超レアケースでかつ計算式が複雑になる為考慮していません。

上記計算式の場合、過去の記事(my-hobby : GoogleAPI~2つの住所から距離を求める~)でも紹介していますが、この計算式には根本的な欠陥があって、そもそも地球の円い表面を、平らな表面と仮定して計算している為、2地点の緯度差、経度差が大きくなればなるほど、その誤差は大きくなる可能性があります。
具体的には、以下の様な例と考えられます。

上記の様な例を元に、今回採用した方法で距離を計算するとA地点とB地点の距離は約17303Kmとなります。
しかし、A地点からB地点の移動は単純に地球を半周している為、40000Km÷2=20000Kmとなるのが正しい答えのはずです。
※計算結果と実際の距離には、約2700Kmもの誤差が発生しています。

要は、国を跨るような距離の計算は誤差が出過ぎるという事です。
正確に測ろうとすると、非常に難しい計算式になります。
今回の計算式は、国をまたぐような2点間の距離の計算は考慮しませんが、同じ国の中で2地点の距離の計算には最適だと思います。
(参考にしてみてください!)

2地点の緯度経度から距離を求める(global化 1/2)

以前の記事でmy-hobby : GoogleAPI~2つの住所から距離を求める~を紹介しましたが、
こちらの内容はあくまで日本国内に限った場合の方法でした。
先日メンバーのもじゃもじゃさんから、iPhoneのGPS機能を使ったアプリを作っているので、記事で掲載した内容を使いたいという話がありました。
自分の記事の内容を実際に使ってもらえるのはうれしい事なのですが、今の機能(日本国内限定)で使ってもらうのはちょっと失礼なので、思い切って全世界どこででも使えるようにしようと思います!

そもそも、なぜ日本国内限定にしているかと言うと、以前の記事で紹介した計算式は東経0~180度、北緯0~90度までの範囲でしか計算できない為、日本国内限定としていました。
※GoogleMAPS APIが返す座標(緯度経度)は以下の様な値となっています。
東経0~180度:0~180
西経0~180度:0~-180
北緯0~90度:0~90
南緯0~90度:0~-90
世界地図で表すと、以下の様な感じです。
【図1】

地図から緯度経度を調べるにて、各地点のGoogleMAPS APIが返す座標(緯度経度)の結果を確認できます

東経0~180度、北緯0~90度以外は座標が-(マイナス)を返すので、差を使った計算が出来ないという理由がありました。
緯度・経度の差より距離を求めているので、マイナスを返す場合、単純に差を求めると、結果が意図したものと異なる場合があります。
※前回までの計算式

IdoWK = Abs(txt_Ido.Text – txt_Ido2.Text) * 111
KeidoWK = Abs(txt_Keido.Text – txt_Keido2.Text) * Cos(Math.PI / 180 * CosIdoWK) * 111
KyoriWK = (IdoWK ^ 2 + KeidoWK ^ 2) ^ (1 / 2)

今回は上記内容を考慮してどの経度、緯度でも計算可能な式に変更したいと思います。
GoogleMAPS APIが返す座標の場合、緯度差、経度差を計算する際に-(マイナス)が邪魔になるので、これをどの位置でも0以上になるように原点(0,0)の位置を移動させます。
移動させた結果は以下の様な感じです。
【図2】

※x(経度)を180、y(緯度)を90足した(補正した)状態としました。

これでヨシ!と思いきや、この方法には大きな落とし穴がありました。

以下の図3の左のケースの様な場合に、上記の方法で2地点の距離を求めようとすると、最適な結果が得られなくなります。
【図3】

図2で示した座標で計算を行なうと、図3の左側の図の様な結果が2地点の距離になりますが、実は右側の図の方が距離が近いのです。
2地点の距離を求めると言っても、遠い距離を返してしまっては意味がありません。
地球の様に円い3次元の物体の表面を移動する場合には、単純に2地点を直線で結んだだけでは、最短距離を求める事が出来ないと言う事です。

かといって、3次元の世界で新たに計算式を作るのも面倒なので、2次元の世界で前回作った計算式を応用して最短距離を求める方法を考えたいと思います。
この問題の解決する為、少ない知恵を絞って考えた方法を次回紹介します。