エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説

      2017/05/17

路線・駅検索を簡易的に行うため緯度経度からの距離計算を行う

 

緯度経度に基づく 2点間の距離の計算方法の考え方

 
2点の緯度と経度が分かれば、2点間の距離は計算できる
 
当たり前のことではあるわけですが、いざこれを利用しようと思うと結構大変です。
 
なぜなら、地球は球体なので、緯度によって東西方向(経度方向)の距離が変わってしまうからです。
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
さらに、実際の地球は完全な球体ではなく、赤道付近の方が広がっている楕円形であるためにさらに計算式が難解になっていきます。
 
そのため、2点間の距離を正確に計算するには、下記のような式に基づいて計算をする必要があるわけです。
 
 緯度経度を用いた 2点間の測地線長、方位角を求める計算
 http://vldb.gsi.go.jp/sokuchi/surveycalc/surveycalc/algorithm/bl2st/bl2st.htm
 
 国土交通省・国土地理院の測量計算サイトより
 http://vldb.gsi.go.jp/sokuchi/surveycalc/main.html
 
 
飛行機や船、車などのナビゲーションシステムなど、2点間の距離を求めるのには上記のような「ヒュベニの公式」と言う式を利用するようです。
 
ですが、私が日々の業務で必要になる距離計算は、求人サイトや不動産検索サイトなどで、「駅からの距離を計算する」という感じです。
そのため、せいぜい数 ㎞程度の距離計算ができれば足りますので、そんな大げさな計算式は必要ないワケです。
 
しかも、日本国内向けのサイトでの計算ですので、緯度 30°~45°程度で計算ができればいいわけですので、簡易的な計算方法でも大きな誤差にはならないのだろう、と考えました。
そして、考えてそれに基づいて距離を計算するツールを作成しました。
 
 

2点間の直線距離計算ツール(地点1の緯度に基づき簡易計算)

 
2点間の直線距離計算ツール(地点1の緯度に基づき簡易計算)
 https://s-giken.info/distance/distance.php
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
地点1か、2を選択して、Googleの地図をクリックすると、緯度経度が入力されます。緯度経度を直接入力しても OKです。
 
2地点の緯度経度を入力した状態で、「距離計算を実行」をクリックすると、2地点間の距離のほか、「地点 1」における 1°の距離や、2点間の緯度差、経度差などどのような計算をしているのかが分かるような計算の途中の値も表示するようにしています。
 
 
この計算式は、先にも書きましたが、あくまでも簡易計算によって距離を求めていますので、数㎞程度なら誤差はほぼありませんが、距離が長くなれば長くなるほど誤差が出てくるものと思います。
 
 

2点間の直線距離計算ツールの計算の仕組み

 

2点間の直線距離計算には三角関数を使う

 
2点間の直線距離を計算するツールの仕組みの基本は、三角関数です。
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
上記にあるように、斜辺「c」の長さを求めるには、辺「a」「b」の長さが分かれば計算できます。
 
つまり、点Bが駅で、点Aが目的地。
それぞれの緯度経度が分かれば、その緯度経度の差分を計算することで、辺「a」「b」の距離が分かりますので、算出が可能、ということです。
 
 
ただ、これが簡単ではない理由もあり、緯度経度の引き算から求められる値は「角度」である点と、角度に対する距離が低緯度と高緯度とでは大きく違ってくる、ということなんです。
 
なので、辺「a」の角度に対する距離を計算するには、改めて三角関数を用いて該当する緯度における距離を計算する必要があるわけです。
 
 

2点間の直線距離計算の実際の流れ

 

緯度 1°における距離の計算

 
では、改めて最初から。
 
先に紹介した「2点間の直線距離計算ツール」では、地球の大きさを以下のように設定しています。
 極半径 :6356.752km
 赤道半径:6378.137km
 
続いて、緯度、経度の 1°の距離を計算しています。
 
まず、緯度方向。
緯度 1°の距離は、計算は簡単です。
1°の距離は、円周の 360°分の 1ですので下記の式になります。
 
 【極半径】 × 2 × π ÷ 360
 
【極半径】に上記の「6356.752km」を代入すると、「110.9km」となります。
地球は自転していますので、時点の力で赤道の方に広がっている楕円形になっていますが、ここでは真円として計算しています。
 
「π」は「パイ」と読みまして、円周率のことです。近似値は 3.14ですね。
 
 

経度 1°における距離の計算

 
続けて、経度方向。
赤道上の場合は、赤道上の半径が分かっていますので、緯度の時と同じく計算をすることは簡単で、下記の式になります。
 【赤道半径】 × 2 × π ÷ 360
 
ですが、緯度が変わるとその経度における半径が変わってきますので、その経度における半径を計算する必要があるのです。
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
ここで三角関数が必要になります。
 
辺「c」が地球の直径【赤道半径】で、角度「B」が緯度になります。
この時、辺「a」が【地点の緯度における半径】になるわけですが、辺「c」と角度「B」から辺「a」の長さを求めるときには「cos(コサイン)」を使うと算出できます。
 
そのため、下記の式で【地点の緯度における半径】が計算できます。
 
 cos( 【地点の緯度】 ÷ 180 × π ) × 【赤道半径】
 
 
そして、この【地点の緯度における半径】を基にすれば、これまでの計算式と同じように下記の式で 1°の距離を計算することができます。
 
 【地点の緯度における半径】 × 2 × π ÷ 360
 
 
具体的に、【赤道半径】に「6378.137km」を代入し、東京都がある北緯 35°で計算すると、「91.2km」となります。
 
 
この「2点間の直線距離計算ツール」では、「地点1」の緯度に基づいて経度 1°の距離を計算しています。
 
 

緯度経度から 2点間の距離を計算

 
指定した 2点の緯度経度から、2点間の緯度経度の差を計算します。
 
 地点1 - 地点2
 
2点間の差を計算する方法は、単純な引き算です。
ただ、ここで算出されるのは角度(°)ですので、その角度を先に計算した緯度、経度 1°当たりの距離をかけて 2点間の距離を算出します。
 
 緯度 1°当たりの距離 × 2点間の緯度差
 経度 1°当たりの距離 × 2点間の経度差
 
これで、2点間の距離が分かりましたので、最初の三角関数での計算を用いて計算を行います。
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
 
上記の計算式を PHPで記述すると下記の様になります。
sqrt ( pow ( 【緯度の距離差】, 2 ) + pow ( 【経度の距離差】, 2 ) )
 
 
この計算によって、
 新宿駅 緯度:35.69044038082377、経度:139.70049619674683
 渋谷駅 緯度:35.658227839738835、経度:139.70165491104126
の 2点間の距離は「3,575.40m」と計算できます。
 
 

今回の記事を書くにあたって調べた緯度・経度などの情報

 
今回の記事を書くにあたって、計算式の理解や検証をするために利用した緯度・経度に関連する情報も掲載しておきます。
単なるメモ書きですので掲載する必要がない情報ではありますが、掲載しておけば検索にヒットする場合もあるかなぁ、そんな下心もありつつ掲載することにしました。
 
 

札幌駅、東京駅、鹿児島駅の緯度と経度

 
今回の処理を作成するにあたって、検算に利用した場所の緯度経度は以下の通りとなります。
 
札幌駅  緯度:43.068661 経度:141.350755
東京駅  緯度:35.681298 経度:139.766247
鹿児島駅 緯度:31.583785 経度:130.541245
 
 

緯度の違いでの 1分の距離の違い

 
地球は球形ですので、緯度が高くなる(極に近くなる)と、経度の 1分(60分の 1°)の距離が短くなるわけですが、それが具体的にどれくらいなのか、それを調べたものになります。
 
緯度(北緯・南緯) 1分で下記の差があります。
 北緯60度で1.857km
 北緯30度で1.847km 差:0.01㎞(10m)
 
経度(西経・東経) 1分で下記の差があります。
 北緯60度で0.930km
 北緯44度で1.333km(北海道)差:0.183㎞ 13.8%誤差
 北緯35度で1.517km(東京)
 北緯31度で1.583km(鹿児島)差:0.067㎞ 04.2%誤差
 北緯30度で1.608km
 
つまり、東京を起点に距離計算を行うと、東西方向には、北海道で 13.8%の誤差が発生し、鹿児島で 4.2%の誤差が発生するということになります。
 
鹿児島の 4.2%はまだ許容範囲と言えなくもないですが、北海道の 13.8%はとても誤差といえるレベルではないですね。
 
 

緯度・latitudeと経度・longitudeの略し方

 
緯度と経度を表す英単語は、「latitude」と「longitude」です。
 
プログラムを記述する際も略さず「latitude」「longitude」と記述すればいいのですが、さすがに長い単語なので、略したいと思うのです。
 
緯度の「latitude」は「lat」と略し方がぱっとわかるわけですが、経度の「longitude」は略しにくいのです。
そのため略し方としては、「lng」「lon」の 2つがあるようなのですが、私は Googleが「lng」を使っているということで「lng」を選びました。
 
それを検証した方もあるようで、下記のブログは面白かったですね。
 Longitude の略し方。lng 派と lon 派の終わらない争い
 http://qiita.com/amay077/items/47caea53329f0e632c87
 
 

路線・駅検索のための緯度経度から距離を計算する処理のまとめ

 
この記事は 3本で 1セットの内容です。
まず最初の記事であるこの記事で、「2地点の緯度経度から距離を計算する方法を考察」し、2つ目の記事で、その 2点間の距離を計算する方法を基にして、「路線・駅検索の仕組みを考察」しました。
そして、3本目の記事で、その「路線・駅検索の仕組みを WordPressに実装する方法を考察」する、という流れです。
 
凡人なので、これだけのステップを踏まないとたどり着けない、ということではありますが、ブログの記事としては 3本の記事を作ることができました(笑)。
 路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説
 路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索
 「WordPressで駅検索を実装」(鋭意執筆中)
 
 
3本目の記事は、現在鋭意作成中です。
なぜ、WordPressに組み込むことを目指すのか、と言いますと、「月極駐車場検索エース」というサイトを作りましたが、ここには都道府県検索はありますが、路線・駅検索がありません。
そのため、「月極駐車場検索エース」に路線・駅検索を組み込むことを目指して思考を始めましたので、最終目標は WordPressへの組み込みなわけです。
 
 

Google Mapsの無償版 APIを利用する際の注意点

 
Googleが、2016年06月22日(アメリカ時間)に Google Mapsの無償版 APIの規約を大幅に変更しました。
それに伴い、2016年10月12日以降は Google Mapsの無償版 APIを利用している場合は、地図が表示されなくなる場合がありますので注意が必要です。
 
表示されなくなる条件の具体例は以下のようなものがあります。
・APIキーを登録していない場合
・1日 25,000回以上の APIへのアクセスがある場合
・古いバージョンの APIを利用している場合
 
詳細内容は下記の記事などを参考にしてみてください。
 http://klutche.org/archives/1779/
 https://www.zenrin-datacom.net/business/gmapsapi/policy_update.html
 
 
もう一つ、我々のような開発者が気を付けなくてはいけないポイントは、これまで多くの方が提供してくれていたサンプルソースの中には、今回の規約改定を受ける前のソースコードが多々ありますので、正常に動作しなくなったものが増えたであろうと推測できます。
 
Google Mapsのサンプルソースを利用して構築した地図が正しく表示されない場合は、その記事が書かれた時期を確認してみるのも有効になるでしょう。
 
記事が書かれた時期を確認する必要があるのは、Google Mapsの APIに限ったことではないですが。

 - PHP・Smarty・ECCUBE

GoogleAdwords

GoogleAdwords

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

リダイレクトループが原因で「ERR_TOO_MANY_REDIRECTS」「このページを表示できません」が出たときの対策12事例+α

リダイレクトループ、自動転送設定ループの原因の解説とその対応方法を含め事例 12例を挙げて説明。

ECCUBE mtb_constants initパラメータ設定の項目を追加する方法

ECCUBEのパラメータ設定で設定できる項目を追加する方法を説明します。

配列の値をテキスト表示する際に「、」でつなげるときの処理方法の一例
配列の値をテキスト表示する際に「、」でつなげるときの処理方法の一例

配列の値を「、」でつないで出力する際、単純にforeachで繰り返し処理をすると「イヌ、サル、キジ、」となるが文字列最後の「、」を出力しない方法を3つ解説している。

ob_start、ob_get_contents関数でPHPの標準出力をバッファリング・変数に代入

標準出力をバッファリングし変数に代入することができるob_start()関数の解説。include()の処理をバッファリングすることで自由な場所に処理を記述することが可能。

ファイル変更だけ!ECCUBEの本番から開発環境をコピーする手順を解説

ECCUBEを本番から開発環境をコピーする際の手順を解説。PGMメンテに必要な開発環境を構築する手順を解説。ECCUBEの仕組みは簡単なので作業は5分ほど。

PHPで正規表現の検証には preg_match_allが便利

PHPで正規表現の検証には preg_match_allが便利です。その便利さの使い方の解説です。

ECCUBEのポイント設定、ポイント付与率を一括で変更する方法解説

ECCUBEの商品個別に設定してあるポイントを一括で変更する方法を解説。ECCUBEには商品個別のポイントを一括して変更する機能がありません。SQLを作成して一括置換!

ECCUBEの商品一覧ページのSEO対策!rel=”next” rel=”prev”を設定

Googleは関連あるページはその旨明示するよう求めています。ECCUBEの商品一覧ページでその求めに応じるための「rel=”next”」「rel=”prev”」について解説します。

連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説
連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説

PHPの配列・連想配列のキーと値をまとめてhtmlspecialchars()関数でサニタイズ(無害化、無毒化)を行う関数を作成。連想配列のキーはarray_map()関数でのサニタイズは無理。

Smartyのテンプレート内の処理で計算、加工をする方法

Smartyのテンプレート上で変数を計算する、加工する方法を解説します。