2点の緯度・経度間の距離を求める方法として、「ヒュベニ(hubeny)の公式」というものがあります。
ネットで見ていくと色々でてくるんですが、公式を書いてあるサイトを見つけたので忘れないようにメモ。
ヒュベニの公式|カシミール3D
D=sqrt((M*dP)*(M*dP)+(N*cos(P)*dR)*(N*cos(P)*dR))
D: 2点間の距離(m)
P: 2点の平均緯度
dP: 2点の緯度差
dR: 2点の経度差
M: 子午線曲率半径
N: 卯酉線曲率半径
M=6334834/sqrt((1-0.006674*sin(P)*sin(P))^3)
N=6377397/sqrt(1-0.006674*sin(P)*sin(P))
ただし、こちらの計算式は日本測地系用です。
GoogleMapsは世界測地系を使用していますので、そこから取得した緯度経度を使って計算すると、結果がずれる可能性があります(準拠している楕円体が違う為)。
この公式を使う場合、計算式中で使われる数値を世界測地系に対応させる必要があります。
ご注意ください。
ちなみに、日本測地系ではベッセル楕円体を使用し、世界測地系ではGRS80楕円体を使用します。
■楕円体の定義
・ベッセル楕円体(日本測地系で使用)
赤道半径(m) 6378137m
極半径(m) 6356752m
扁平率(1/f) 1/298.257222101
離心率(e^2) 0.00669438
・GRS80楕円体(世界測地系で使用)
赤道半径(m) 6377397.155m
極半径(m) 6356078m
扁平率(1/f) 1/299.152813
離心率(e^2) 0.00667478
この公式をつかって、PHPで緯度経度から距離を求める関数を作成してみました。
第1~第4引数に開始点と終点の緯度経度(小数表現)を、第5引数をTRUEにすると世界測地系、FALSEにすると日本測地系で計算します。
※コードの動作確認はしていますが、数値などはネット上の情報を参考にしただけですので、正確なものかどうかは不明です。ご了承ください。
★子午線曲率半径で使われる数値(日本測地系なら6334834.0)の算出方法がわかりません。
ご存知の方いらしたらご教授くださると嬉しいです。m(_ _)m
// 緯度経度から2点間の距離を求める
function distance( $lat1, $lon1, $lat2, $lon2, $mode=true ) {
// 緯度経度をラジアンに変換
$radLat1 = $lat1 * M_PI / 180.0; // 緯度1
$radLon1 = $lon1 * M_PI / 180.0; // 経度1
$radLat2 = $lat2 * M_PI / 180.0; // 緯度2
$radLon2 = $lon2 * M_PI / 180.0; // 経度2
// 平均緯度
$radLatAve = ($radLat1 + $radLat2) / 2.0;
// 緯度差
$radLatDiff = $radLat1 - $radLat2;
// 経度差算
$radLonDiff = $radLon1 - $radLon2;
$sinLat = sin($radLatAve);
if( $mode) {
// $mode引数がtrueなら世界測地系で計算(デフォルト)
$temp = 1.0 - 0.00669438 * ($sinLat*$sinLat);
$meridianRad = 6335439.0 / sqrt($temp*$temp*$temp); // 子午線曲率半径
$dvrad = 6378137.0 / sqrt($temp); // 卯酉線曲率半径
} else {
// $mode引数がfalseなら日本測地系で計算
$temp = 1.0 - 0.00667478 * ($sinLat*$sinLat);
$meridianRad = 6334834.0 / sqrt($temp*$temp*$temp); // 子午線曲率半径
$dvrad = 6377397.155 / sqrt($temp); // 卯酉線曲率半径
}
$t1 = $meridianRad * $radLatDiff;
$t2 = $dvrad * Cos($radLatAve) * $radLonDiff;
$dist = sqrt(($t1*$t1) + ($t2*$t2));
return $dist;
}
参考にしたページ:
GPSデータから距離を算出する(ヒュベニの距離計算式)|クネアシ
ヒュベニの式|徒然なるままに
緯度・経度から距離を計算|soni cmode