位置情報取得

位置情報を扱うライブラリはこちらを使いました。
docomoのiエリアデータを利用して土地名も返してくれます。
http://labs.unoh.net/2008/08/phpgeomobilejp_converter.html
これをvendors/Geomobilejp/につっこむ。

2点間の緯度経度から直線距離を求める

こちらを参考。
http://www.pahoo.org/e-soul/webtech/php02/php02-21-01.shtm
上記のライブラリのデータをそのまま突っ込めるように、ちょっとだけ修正。
計算部分はそのままです。


で、これらをCakePHPのコンポーネントで使いたかったのでまとめました。

App/controllers/components/geo.php

<?php
App::import('Vendor','Geomobilejp_Mobile', array('file' => 'Geomobilejp'.DS.'Mobile.php'));
App::import('Vendor','Geomobilejp_Converter', array('file' => 'Geomobilejp'.DS.'Converter.php'));
App::import('Vendor','Geomobilejp_IArea', array('file' => 'Geomobilejp'.DS.'IArea.php'));

class GeoComponent extends Object {

  private $mobile;
  private $area;

  public function __construct() {
    $this->mobile = new Geomobilejp_Mobile;
    $conv = new Geomobilejp_Converter(
                                      $this->mobile->getLatitude(),
                                      $this->mobile->getLongitude(),
                                      $this->mobile->getDatum()
                                      );

    $iarea = new Geomobilejp_IArea;
    $this->area = $iarea->seekArea($conv);
  }

  public function getAreaData() {
    return array('code' => $this->area->getIAreaCode(),
                 'name' => $this->area->getName(),
                 'lat' => $this->mobile->getLatitude(),
                 'lon' => $this->mobile->getLongitude(),
                 );
  }

  public function calc_distance($lonA,$latA,$lonB,$latB) {
    //A地点の経度・緯度を小数に
    preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/", $lonA, $regs);
    $a_long = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;
    preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/", $latA, $regs);
    $a_lati = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;

    //B地点の経度・緯度を小数に
    preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/", $lonB, $regs);
    $b_long = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;
    preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/", $latB, $regs);
    $b_lati = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;

    //ラジアンに変換
    $a_long = deg2rad($a_long);
    $a_lati = deg2rad($a_lati);
    $b_long = deg2rad($b_long);
    $b_lati = deg2rad($b_lati);

    $latave = ($a_lati + $b_lati) / 2;
    $latidiff = $a_lati - $b_lati;
    $longdiff = $a_long - $b_long;

    //子午線曲率半径
    $meridian = 6334834 / sqrt(pow(1 - 0.006674 * sin($latave) * sin($latave), 3));//日本測地系
    //  $meridian = 6335439 / sqrt(pow(1 - 0.006694 * sin($latave) * sin($latave), 3));//世界測地系

    //卯酉線曲率半径
    $primevertical = 6377397 / sqrt(1 - 0.006674 * sin($latave) * sin($latave));//日本測地系
    //  $primevertical = 6378137 / sqrt(1 - 0.006694 * sin($latave) * sin($latave));//世界測地系

    //Hubenyの簡易式
    $x = $meridian * $latidiff;
    $y = $primevertical * cos($latave) * $longdiff;
    return sqrt($x * $x + $y * $y);
  }
}

geoコンポーネントのgetAreaDataはアプリにあわせて欲しいデータ返す。
位置情報が送られてくるcontrollerで使う。

App/controllers/foo_controller.php

<?php
class FooController extends Controller {
  var $name = 'Foo';
  var $components = array('Geo');

  function index () {
    $data = $this->Geo->getAreaData();
    $lonA = 'XXX.XX.XX.XX'; //経度
    $latA = 'XX.XX.XX.XXX'; //緯度

    //距離を計算したい2点間の経度・緯度を入れる
    $calc = $this->Geo->calc_distance($lonA, $latA, $data['lon'], $data['lat']);
  }
}
実践で使って変更する必要がありそう。。

今回まったく位置情報関連の知識がなかったので以下を参考にしました。

GPS携帯 位置情報 基礎知識
http://www.yaskey.cside.tv/mapserver/note/gps.html

携帯GPSの基礎知識たち
http://d.hatena.ne.jp/cloned/20080424

PHPで携帯位置情報を扱うライブラリ「Geomobilejp_Converter」を作りました
http://labs.unoh.net/2008/08/phpgeomobilejp_converter.html

DoCoMoのCSSとXHTMLまとめ
http://blog.ville.jp/2008/06/04/99

[Mobile] 3キャリア(+Willcom)位置情報取得方法まとめ(ドコモ編)
http://d.hatena.ne.jp/hororiholy/20080324/p1

位置情報を取得してみる
http://labs.unoh.net/2010/02/post_139.html

PHPで2地点間の直線距離を求める
http://www.pahoo.org/e-soul/webtech/php02/php02-21-01.shtm