今回は携帯で使えるWebマッピングについて書きます。
長くなりそうなので、前編後編に分けます。ご了承下さい。
Webマッピングに関連するものを作ることになったので色々調べてみました。
やりたいことは、ある地点Aから半径500m以内にある、
あらかじめDBに登録しているB達をひっぱってくるというもの。
調べた結果、自分の環境(PHP+PostgreSQL)での作り方として、
一番シンプルで高性能にまとまるのが、
PostGISをDBにインストールして、DBの中で処理を終わらせるやり方。
次にいいかもしれないと思ったのが、
PostgreSQLの標準の幾何型を使うやり方。
上記を使わずPHPだけで計算するやり方。
今回選んだのは、実際に計算してはじき出すやり方です。
上2つのやり方はネット上に結構ありましたし、
説明もいらないくらい簡単みたいなのです。
ですので、この方法でやることにしました。
では、まず考えないといけないのが、
ある地点Aから半径500m以内に登録されているものをどうひっぱるか。
あらかじめDBには緯度経度をそれぞれ登録しておきます。
ex.(DBのテーブル名:map 緯度カラム名:lat 経度カラム名:lon 人物名カラム:name)
postgres=> CREATE TABLE map( postgres(> lat DECIMAL, postgres(> lon DECIMAL, postgres(> name TEXT); CREATE TABLE
テーブルを作ったら。値をインサートしていきます。
比べられる距離が500m以内なので、当然500m以内の値を含ませてください。
postgres=> INSERT INTO map(lat,lon,name)VALUES('34.677723','135.502796','hogetaro'); INSERT 0 1 postgres=> INSERT INTO map(lat,lon,name)VALUES('34.673612','135.500650','hogeko'); INSERT 0 1 postgres=> INSERT INTO map(lat,lon,name)VALUES('34.683405','135.500307','hogejiro'); INSERT 0 1 postgres=> INSERT INTO map(lat,lon,name)VALUES('34.683705','135.512044','hogemi'); INSERT 0 1 postgres=> INSERT INTO map(lat,lon,name)VALUES('34.672817','135.506530','hogezaburo'); INSERT 0 1
こちら側で計算して出すので、POINT型にしなくてもいいです。DECIMAL型とかで。
この登録してる緯度経度と地点Aの緯度経度の2点間の距離を求めて、
あとはDBでその距離から絞れば範囲内のものがとって来れます。
はじめはずっと、なんとかいきなり範囲内のものをとってくるやり方を考えてましたが、
計算して出す場合は、わけた方が断然楽でした。
では次にこの2点間の距離を求める計算式を紹介します。
ヒュベニの距離計算式というみたいです。
地球を回転楕円体で捉えて、計算するみたいで平面でとってくるよりも、
若干精度は良いみたいです。DBの機能を活用しないやり方であれば、
この方法が一番良いかなと思いました。コチラを参考にしました。
PHPだけで動かすならこちらで紹介されているロジックで十分事足ります。
DBにあるデータと絡める場合は多少手を加える必要があります。
ひとつずつ順を追って見ていきましょう。
この計算式の大前提は、度分秒の緯度経度を小数の度に直すこと。
例.こういう度表記のものに変換します→135.502818
すでに度表記のものは変換しなくていいです。
度表記じゃないものの変換の仕方は、
まず取ってきた緯度経度を度分秒で分けます。
$startlat = 度 + 分/60 + 秒/3600;
これだけです、点が一個のやつになりました。
次に、上でできたやつをラジアンというものに変換します。
このラジアンになっていないと計算できませんので、注意。
そしてこの$latstartと後述の$lonstartが、比べるもとになる緯度経度を入れる箱です。
この2つの緯度経度を基準に考えるので、取ってきた値はここに入れます。
$latstart = $startlat * M_PI/180;
これでラジアンへの変換は完了です。
あとは残りの経度も同じようにラジアンに変換してしまいましょう。
$startlon = 度 + 分/60 + 秒/3600; $lonstart = $startlon * M_PI/180;
次に注意をしなければいけないのが、
この計算は最後はDBの中に入っていくので、
あらかじめDBに入っている緯度経度はDBの中でラジアンに直さないといけないということです。
それに伴って、DBに入れる段階で緯度経度を度表記にしておくと楽です。
今回はそのDBにはあらかじめ度表記ではいっていますので、説明は割愛します。
あとDBには最終的に式として放り込みますが、
現段階では見やすくするため文字列にするための“”はつけないでおきます。
DBの中でラジアンに変換する方法は、下の式を見てください。
$latend = lat * PI()/180;
PHPではM_PIだったのがDBの中では、
PI()に変わっていることに注意して下さい。
経度も同じです。
$lonend = lon * PI()/180;
この操作を終えたら次は、2点間の平均緯度を計算します。
$average = ($latstart + $latend)/2;
そして2点間の緯度差を計算。
$lat = $latstart - $latend;
次に、同じように2点間の経度差を計算します。
$lon = $lonstart - $lonend;
その次は今まで求めてきた値から子午線曲率半径を計算します。
$rrr = 1 - 0.006674 * (sin($average) * sin($average)); $mmm = 6334834 / sqrt($rrr * $rrr * $rrr);
そして卯酉線曲率半径も求めます。
$vvv = 6377397 / sqrt($rrr);
最後に、ヒュベニの距離計算式を使います。
$z1 = $mmm * $lat; $z2 = $vvv * Cos($average) * $lon; $distance = sqrt($z1 * $z1 + $z2 * $z2);
PHPで普通に緯度経度を埋め込んで結果を表示させると、
この$distanceの中に距離を計算した数値がfloatで入っています。
仮に、始点緯度34.675954、始点経度135.501741、終点緯度34.687357、終点経度135.525885とした場合、
float(2548.3581842627)
と返ってきます。単位はメートルです。
ちなみこれを書いてるところから、大阪城までの距離です。
大体そんなもんですかね。
後編ではこの式をDBに入れるように成型します。