近年のスマートフォン普及の勢いは目覚ましく、日本においてはほとんどすべての人がこれを持ち歩く社会となりました。
そのため、私が開発・改修を手掛けるシステムの中にも、端末が備えるGPSモジュールによって取得された利用者の位置情報を利用するものが多々出てくるようになっています。
位置情報の利用方法は様々ですが、その中で最も大きな割合を占めるのが、システムに登録された施設 (店舗やATM等) と利用者の間の距離を計算して近いものを提案するというもの。
単純な直線距離ではなく、道路や線路などに沿った実際の移動距離を求める場合もありますが、その場合も連続する線分 (折れ線) で近似された経路の長さを計算することになるので、結局は二点間の直線距離の計算に行き着きます。
2地点の座標 (λA, φA), (λB, φB) (λ は緯度、φ は経度) からこれらの間の距離を求める計算はそれほど難しいものではありません。
まず、地球を、原点 o を中心とする半径1の球体 と仮定します。
北極を (0, 0, 1)、ヌル島を (1, 0, 0) とすれば、A, B の座標はそれぞれ、
xA = cos λA cos φA
yA = cos λA sin φA
zA = sin λA
xB = cos λB cos φB
yB = cos λB sin φB
zB = sin λB
となります。
これらの位置ベクトル OA (xA, yA, zA) と OB (xB, yB, zB) が成す角の余弦値 cos χ は内積として
cos χ = OA ⋅ OB = xA xB + yA yB + zA zB
と計算されるので、χ そのものの値は逆余弦 cos-1 を用いて、
χ = cos-1( xA xB + yA yB + zA zB )
と求めることができます。
2点ABを結ぶ単位球面上の最短距離すなわち測地線の長さは、全周 2π に対する角度 χ の比 χ/2π でなので、これを地球の半径 R 倍だけ拡大してやれば、実際の二点間の距離 δ が得られます。
δ = 2πRχ/(2π) = Rχ
以上のプロセスを JavaScript で書き下したならば、以下のようになるでしょうか:
//地球半径 (単位: m)
const EARTH_RADIUS = 6378100;
//2点 (srcLat, srcLong), (dstLat, dstLong) 間の距離を計算
function calcDistance(srcLat, srcLong, dstLat, dstLong){
var srcX = Math.cos(srcLat)*Math.cos(srcLong);
var srcY = Math.cos(srcLat)*Math.sin(srcLong);
var srcZ = Math.sin(srcLat);
var dstX = Math.cos(dstLat)*Math.cos(dstLong);
var dstY = Math.cos(dstLat)*Math.sin(dstLong);
var dstZ = Math.sin(dstLat);
return EARTH_RADIUS*Math.acos(srcX*dstX + srcY*dstY + srcZ*dstZ);
}
ただし、関数 calcDistance の引数 srcLat, srcLong, dstLat, dstLong の単位は一般的に用いられる度ではなく、ラジアンであることに注意してください。