携帯と絡めると面白いWEBマッピング(後編)

By fukumoto - 08/11/05 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

前回に引き続き、緯度経度を持つ地点Aから、
DB内の距離指定範囲内のB地点をとってきます。
今回は実際に、前回作った式でDB内に放り込むことになるわけですが、
DBに放り込むに当たって、まず文字列にしないといけません。
それは結構簡単です。””をつけるだけです。
ではやってみましょう。
ex.(DBのテーブル名:map 緯度カラム名:lat 経度カラム名:lon 人物名カラム:name)
 
始点緯度経度に関しては、
前回書いたように、PHPの中で計算しますので、
文字列にしてはいけません、文字列にすると、
 

'SQLSTATE[42703]: Undefined column: 7 ERROR: column "m_pi" does not exist'

  
こんなエラーがでます。先にPHPで計算させておきます。
始点緯度経度の2つだけ、そのままにしましょう。
 

 //始点緯度をラジアンに変換
 $latstart = $startlat * M_PI/180;

 //始点経度をラジアンに変換
 $lonstart = $startlon * M_PI/180;

 //終点緯度をラジアンに変換
 $latend   = "lat * PI()/180";

 //終点経度をラジアンに変換
 $lonend   = "lon * PI()/180";

 //始点と終点の平均緯度を計算
 $average  = "({$latstart} + {$latend})/2"; 

 //緯度差を計算
 $lat = "{$latstart} - {$latend}";

 //経度差を計算
 $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})";

 

$distanceの中身はこんな感じです。
 

sqrt(6334834 / sqrt(1 - 0.006674 * (sin((0.60523890755482 + lat * PI()/180)/2) * 
sin((0.60523890755482 + lat * PI()/180)/2)) * 1 - 0.006674 * (sin((0.60523890755482 + lat * 
PI()/180)/2) * sin((0.60523890755482 + lat * PI()/180)/2)) * 1 - 0.006674 * (sin((0.60523890755482
 + lat * PI()/180)/2) * sin((0.60523890755482 + lat * PI()/180)/2))) * 0.60523890755482 - lat * 
PI()/180 * 6334834 / sqrt(1 - 0.006674 * (sin((0.60523890755482 + lat * PI()/180)/2) * 
sin((0.60523890755482 + lat * PI()/180)/2)) * 1 - 0.006674 * (sin((0.60523890755482 + lat * 
PI()/180)/2) * sin((0.60523890755482 + lat * PI()/180)/2)) * 1 - 0.006674 * (sin((0.60523890755482 
+ lat * PI()/180)/2) * sin((0.60523890755482 + lat * PI()/180)/2))) * 0.60523890755482 - lat * 
PI()/180 + 6377397 / sqrt(1 - 0.006674 * (sin((0.60523890755482 + lat * PI()/180)/2) * 
sin((0.60523890755482 + lat * PI()/180)/2))) * Cos((0.60523890755482 + lat * PI()/180)/2) * 
2.3649690108337 - lon * PI()/180 * 6377397 / sqrt(1 - 0.006674 * (sin((0.60523890755482 + lat * 
PI()/180)/2) * sin((0.60523890755482 + lat * PI()/180)/2))) * Cos((0.60523890755482 + lat * 
PI()/180)/2) * 2.3649690108337 - lon * PI()/180)

 
あとはこの$distanceを放り込むだけです。
 

 $sql  = " SELECT name "
        . " FROM map "
        . " WHERE "
        . "    500 > " . $distance . " ";

 
このSQLを放り込めばDBに登録されてる500m以内にいる人達が出てきます。
応用でもないですけど、500を1000にしたり100にしたりすれば、
範囲を広めたり狭めたりできます。
ただ、上記の$distanceのままDBに渡すと、PHPでは上手くいきましたが、
DBに入れる時はエラーがでました。
 

 'SQLSTATE[2201F]: Invalid argument for power function: 7 ERROR: cannot take square root of a negative number'

 
数値がマイナスやからダメってことで出ているようです。
緯度経度なので+も-も関係ないのですが、DBには関係があるようで、
下記の計算式にPostgeSQLのABS関数をつけて絶対値にしてあげます。
それで解決しました。
 

 //緯度差を計算
 $lat = "ABS({$latstart} - {$latend})";
 
 //経度差を計算
 $lon = "ABS({$lonstart} - {$lonend})";

 
var_dump()で返ってきた結果を見てみると、
 

 array(2) { [0]=>  array(1) { ["name"]=>  string(8) "hogetaro" } [1]=>  array(1) { ["name"]=>  string(6) "hogeko" } } 

 
と出ていますね、ここから500m以内にいるのはこのホゲ太郎とホゲ子の2人だけってことです。
これで一連の流れは終了です。

ちなみに基になる緯度経度を取ってきて、
$startlat,$startlonに入れる方法は様々です。
例えば、旅行に行く前に予め行きたいところの緯度経度を登録しておいて、
旅行先でGPSで緯度経度取ってきてそれをDBに入れると、
現在いる場所から行きたい場所までの距離を自分で求めることもできますし、
常に緯度経度情報を更新するようにしておくと、
登録している人同士の位置と距離がわかるものが作れますね。
そんな色々な利用方法を考えると楽しいですし、
携帯とWEBマッピング絡めると面白いものが作れると思いました。