緯度と経度で始点から終点までの距離を計算するクラスを作ってみました。

mixi日記に書いたネタですが、始点と終点のGPS情報から間の直線距離を求めるクラスを作ってみました。
とは言っても、
http://q.hatena.ne.jp/1105008401
に書いてあるVBAのソースをPHPに移植しただけなので、どういう理論で出来ているか、はよく判らんのですが。伊達に数学投げ出してないぜ。

とりあえず、池袋駅からサンシャインまでの距離は当たってるっぽいので、方位については君やあなたやみんなが検証してくれると非常に嬉しいです。

では、早速。

http://www.yaskey.cside.tv/mapserver/note/gps.html
も参考にしようと思ってます、はい。

<?php
// クラス初期化
$gps = new GPSDistance();

//池袋駅
// 緯度と経度は度分秒で指定
// 南緯・西経を現す時は、全て-で指定する必要がある。
$fromLongi = $gps->toLht(35, 43, 36,491); // 緯度
$fromLatti = $gps->toLht(139, 42, 51.509); // 経度

// サンシャイン
$toLongi = $gps->toLht(35, 43, 43,053); // 緯度
$toLatti = $gps->toLht(139, 43, 21.266); // 経度

// 算出
$result = array();
$result = $gps->getDistanceFromCordi($fromLongi, $fromLatti, $toLongi, $toLatti);
print_r($result);

class GPSDistance
{

	private $ER = 6378.14;
	private $PI = 3.14159265358979;
	private $sig = 0;

	function __construct() {
	}

	// LHT座標変換
	// $dig = 度
	// $min = 分
	// $sec = 秒
	function toLht($dig, $min, $sec = 0) {
		return (($dig + ($min / 60) + ($sec / 3600)) * 10000);
	}

	// 距離測定
	// $fromLongi 始点緯度
	// $fromLatti 始点経度
	// $toLongi 終点緯度
	// $toLatti 終点経度
	// 戻り値:配列 array(距離, 方角)
	function getDistanceFromCordi($fromLongi, $fromLatti, $toLongi, $toLatti) {

		if (($fromLongi == $toLongi) 
			&& ($fromLatti = $toLatti)) {
			return array(0, 0);
		}

		// ラジアン変換
		$fx = $this->_toRadian($fromLongi);
		$fy = $this->_toRadian($fromLatti);
		$tx = $this->_toRadian($toLongi);
		$ty = $this->_toRadian($toLatti);

		$result = array();

		// 距離計算
		$ram = $tx - $fx;

		$xx = (sin($fy) * sin($ty)) + (cos($fy) * cos($ty) * cos($ram));
		if ($xx == -1) {
			$sig = $this->PI;
		} else if ($xx == 1) {
			$sig = 0;
		} else {
			$sig = atan(($xx * -1) / sqrt(($xx * -1) * $xx + 1)) + ($this->PI / 2);
		}

		$distance = (($this->ER * $sig) * 1000);

		// 方位換算
		$ssig = sin($sig);
		if ($ssig == 0) {
			$direction = 0;
		} else {
			$yy = ((cos($ty) * sin($ram)) / $ssig);
			if (($yy * -1) + 1 < 0) {
				if (sin($ram) > 0) {
					$direction = 90;
				} else {
					$direction = 270;
				}
			} else if (sqrt((($yy * -1) * $yy) + 1) == 0) {
				if (sin($ram) > 0) {
					$direction = 90;
				} else {
					$direction = 270;
				}
			} else {
				$direction = atan($yy / sqrt((($yy * -1) * $yy) + 1));
				if (((cos($fy) * sin($tx)) - 
					(sin($fy) * cos($tx) * cos($ram))) < 0) {
					$direction = $this->PI - $direction;
				}
				$direction = (($direction * 180) / $this->PI);
				if ($direction < 0) {
					$direction = $direction + 360;
				}
			}
		}

		return array($distance, $direction);

	}

	private function _toRadian($target) {
		return (($target * $this->PI) / 1800000);
	}
}
?>