路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説
2017/05/17
路線・駅検索を簡易的に行うため緯度経度からの距離計算を行う
緯度経度に基づく 2点間の距離の計算方法の考え方
2点の緯度と経度が分かれば、2点間の距離は計算できる
当たり前のことではあるわけですが、いざこれを利用しようと思うと結構大変です。
なぜなら、地球は球体なので、緯度によって東西方向(経度方向)の距離が変わってしまうからです。
さらに、実際の地球は完全な球体ではなく、赤道付近の方が広がっている楕円形であるためにさらに計算式が難解になっていきます。
そのため、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
地点1か、2を選択して、Googleの地図をクリックすると、緯度経度が入力されます。緯度経度を直接入力しても OKです。
2地点の緯度経度を入力した状態で、「距離計算を実行」をクリックすると、2地点間の距離のほか、「地点 1」における 1°の距離や、2点間の緯度差、経度差などどのような計算をしているのかが分かるような計算の途中の値も表示するようにしています。
この計算式は、先にも書きましたが、あくまでも簡易計算によって距離を求めていますので、数㎞程度なら誤差はほぼありませんが、距離が長くなれば長くなるほど誤差が出てくるものと思います。
2点間の直線距離計算ツールの計算の仕組み
2点間の直線距離計算には三角関数を使う
2点間の直線距離を計算するツールの仕組みの基本は、三角関数です。
上記にあるように、斜辺「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
ですが、緯度が変わるとその経度における半径が変わってきますので、その経度における半径を計算する必要があるのです。
ここで三角関数が必要になります。
辺「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で記述すると下記の様になります。
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に限ったことではないですが。
GoogleAdwords
GoogleAdwords
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
PHPのソースで見慣れない記号が出てきた・アロー演算子(->)、ダブルアロー演算子(=>)
PHPのプログラムソースには見慣れない記号が出てきます。その意味や調べ方です。
-
-
ECCUBEの新規追加ページがInternal Server Error・Not Foundに
ECCUBEで新規追加したページがInternal Server Errorに!原因はファイルのパーミッションの場合が多くその対処方法とプログラムの修正ポイントを解説。Not Foundも解説。
-
-
リダイレクトループが原因で「ERR_TOO_MANY_REDIRECTS」「このページを表示できません」が出たときの対策12事例+α
リダイレクトループ、自動転送設定ループの原因の解説とその対応方法を含め事例 12例を挙げて説明。
-
-
Smartyの Syntax Errorの原因はスペースかも
Smartyのなかなか原因がつかめない Syntax Errorの原因はスペースかもしれません。
-
-
JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()
JSONとは「JavaScript Object Notation」の略でテキストベースのデータフォーマット。JSONの値をPHPで配列に変換するWebツールの紹介とその処理「json_encode()」「json_decode()」関数の解説。
-
-
ECCUBEの問い合わせフォームに任意の値を引数として渡す方法
ECCUBEのお問い合わせフォームに値を固有の情報を送りそれに基づいて処理をする方法を解説。ボタンの設置、受け取り側のテンプレート、プログラムのサンプルソースを提供。
-
-
PHPで1ヵ月前、先月、今月1日、来月末の日付などの算出はDateTimeImmutableを使う
PHPには日時をオブジェクトとして生成する関数「DateTimeImmutable」「DateTime」が用意されている。これを利用して1ヶ月後、月初日、月末日、5日後などを指定して日付を取得できる。
-
-
SEO対策用タイトル、ディスクリプションの文字数カウントツール
SEO対策に使える文字数カウントツールで文字数の条件の説明も行っています。
-
-
ECCUBEのポイント設定、ポイント付与率を一括で変更する方法解説
ECCUBEの商品個別に設定してあるポイントを一括で変更する方法を解説。ECCUBEには商品個別のポイントを一括して変更する機能がありません。SQLを作成して一括置換!
-
-
ob_start、ob_get_contents関数でPHPの標準出力をバッファリング・変数に代入
標準出力をバッファリングし変数に代入することができるob_start()関数の解説。include()の処理をバッファリングすることで自由な場所に処理を記述することが可能。