概要
最近では企業が多くの API を公開しており、それらを利用して簡単にアプリケーションを作成できるようになりました。
その中には、店舗情報を扱う API も数多く存在します。
店舗情報を扱う API の多くは、店舗の位置情報を表すため緯度経度を利用しています。
位置情報を利用したアプリケーションを作成する場合、緯度経度から 2 点間の距離を求めたいと思うことがあるかもしれません。
例えば、店舗情報 API と組み合わせて、『現在地周辺の半径 ○○ m 以内のレストランを近い順に表示したい』と思った場合、これに該当します。
今回、緯度経度から 2 点間の距離を算出するプログラムを作成する機会があったので、その時のことをまとめました。
計算式
地球は球体なので、地球上の 2 点間の距離を算出するには、大円距離を求める必要があります。
大円距離の計算式はいくつかあるようですが、全ての距離に対して用いることのできる Vincenty 法を利用することとします。
プログラムを作成
Vincenty 法に当てはめていきます。
def distance(lat1, lng1, lat2, lng2)
# ラジアン単位に変換
x1 = lat1.to_f * Math::PI / 180
y1 = lng1.to_f * Math::PI / 180
x2 = lat2.to_f * Math::PI / 180
y2 = lng2.to_f * Math::PI / 180
# 地球の半径 (km)
radius = 6378.137
# 差の絶対値
diff_y = (y1 - y2).abs
calc1 = Math.cos(x2) * Math.sin(diff_y)
calc2 = Math.cos(x1) * Math.sin(x2) - Math.sin(x1) * Math.cos(x2) * Math.cos(diff_y)
# 分子
numerator = Math.sqrt(calc1 ** 2 + calc2 ** 2)
# 分母
denominator = Math.sin(x1) * Math.sin(x2) + Math.cos(x1) * Math.cos(x2) * Math.cos(diff_y)
# 弧度
degree = Math.atan2(numerator, denominator)
# 大円距離 (km)
degree * radius
end
abs は数値の絶対値を取得するメソッドです。
絶対値を取得する - 数値(Numeric)クラス - Ruby入門
数値計算用のメソッドはこちらを参考にしてください。
算出結果の確認
先ほどのプログラムで新宿駅と渋谷駅の距離を求めます。
# 新宿駅
lat1 = 35.689407
lng1 = 139.700306
# 渋谷駅
lat2 = 35.658034
lng2 = 139.701636
distance = distance(lat1, lng1, lat2, lng2)
# 小数点 6 桁で四捨五入
puts "#{distance.round(6)} km"
プログラムを実行します。
$ ruby distance.rb
3.494497 km
下記サイトで 2 点間の緯度経度を入力した結果と同じになりました。
まとめ
緯度経度から 2 点間の距離を算出する場合、大円距離を求める必要があります。
プログラムは Vincenty 法の公式に当てはめれば実装できます。
最後に
Ruby on Rails には位置情報を扱う gem がいくつか用意されています。
今回、作成した 2 点間距離を求めるプログラムも機能として盛り込まれています。
他にも多くの機能が用意されているようなので gem を使ってみるのも有りだと思います。
自分のアプリケーションにあった方法を採用してください。