今回は、日本語の住所から緯度経度を求めるプログラムの発展形として、2地点間の直線距離を求めるプログラムを作ってみることにする。
サンプル・プログラム
0001: <?php
0002: /** distance.php
0003: * 2地点間の直線距離を求める(MapFanを利用)
0004: *
0005: * @copyright (c)studio pahoo
0006: * @author パパぱふぅ
0007: * @version 1.0 2007/04/18
0008: */
0009: mb_internal_encoding("EUC-JP");
0010:
0011: /**
0012: * HTTP通信を行う
0013: * @param string $url "http://" から始まるURL
0014: * @param string $method GET,POST,HEAD (省略時はGET)
0015: * @param string $headers その他の任意のヘッダ (省略時は"")
0016: * @param array $post POST変数を格納した連想配列("変数名"=>"値") (省略時はNULL)
0017: * @param string $cookie Cookie(利用するときは常に$method="POST") (省略時は"")
0018: * @return string 取得したコンテンツ/FALSE 取得エラー
0019: */
0020: function http($url, $method="GET", $headers="", $post=NULL, $cookie="") {
0021: if ($cookie != "") $method = "POST";
0022: $URL = parse_url($url);
0023:
0024: $URL["query"] = isset($URL["query"]) ? $URL["query"] : ""; //クエリ
0025: $URL["port"] = isset($URL["port"]) ? $URL["port"] : 80; //ポート番号
0026:
0027: //リクエストライン
0028: $request = $method . " " . $URL["path"] . $URL["query"] . " HTTP/1.1\r\n";
0029:
0030: //リクエストヘッダ
0031: $request .= "Host: " . $URL["host"] . "\r\n";
0032: $request .= "User-Agent: PHP/" . phpversion() . "\r\n";
0033:
0034: //Basic認証用のヘッダ
0035: if (isset($URL["user"]) && isset($URL["pass"])) {
0036: $request .= "Authorization: Basic " . base64_encode($URL["user"] . ":" . $URL["pass"]) . "\r\n";
0037: }
0038:
0039: //追加ヘッダ
0040: $request .= $headers;
0041:
0042: //POSTの時
0043: if (strtoupper($method) == "POST") {
0044: while (list($name, $value) = each($post)) {
0045: $POST[] = $name . "=" . urlencode($value);
0046: }
0047: $postdata = implode("&", $POST);
0048: $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
0049: $request .= "Content-Length: " . strlen($postdata) . "\r\n";
0050: if ($cookie != "") $request .= "Cookie: $cookie\r\n";
0051: $request .= "\r\n";
0052: $request .= $postdata;
0053: } else {
0054: $request .= "\r\n";
0055: }
0056:
0057: //接続
0058: $fp = fsockopen($URL["host"], $URL["port"]);
0059: //エラー処理
0060: if (!$fp) return FALSE;
0061:
0062: //リクエスト送信
0063: fputs($fp, $request);
0064:
0065: //応答データ受信
0066: $response = "";
0067: while (!feof($fp)) $response .= fgets($fp);
0068:
0069: fclose($fp);
0070:
0071: return $response;
0072: }
0073:
0074: /**
0075: * 住所から緯度経度を求める(MapFan利用)
0076: * @param string $address 住所(EUC-JP)
0077: * @return string 緯度経度/NULL エラー
0078: */
0079: function address2geo($address) {
0080: $url = "http://www.mapfan.com/keywordsrch.cgi"; //mapfan
0081: $method = "POST";
0082: $post["SRCHKIND"] = "SRCH_ADR";
0083: $post["PARAM"] = $address;
0084:
0085: $result = http($url, $method, "", $post);
0086: preg_match("/(Location: http)(.*)/", $result, $arr);
0087: if (isset($arr[2]) == FALSE) return NULL;
0088:
0089: $url = "http" . $arr[2];
0090: $result = file_get_contents($url);
0091:
0092: //緯度経度
0093: preg_match("/var MAP = \"([A-Z|0-9|\.]*)\"/", $result, $arr);
0094:
0095: return isset($arr[1]) ? $arr[1] : NULL;
0096: }
0097:
0098: /**
0099: * 2地点間の直線距離を求める(Hubenyの簡易式による;日本測地系!)
0100: * @param string $a A地点の緯度経度(日本語またはExxx.xx.xxNxx.xx.xx表記)
0101: * @param string $b B地点の緯度経度(日本語またはExxx.xx.xxNxx.xx.xx表記)
0102: * @return double 直線距離(メートル)
0103: */
0104: function calc_distance($a, $b) {
0105: //A地点の経度・緯度を小数に
0106: preg_match("/E(\d+)\.(\d+)\.(\d+)\.(\d+)N(\d+)\.(\d+)\.(\d+)\.(\d+)/", $a, $regs);
0107: $a_long = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;
0108: $a_lati = $regs[5] + $regs[6] / 60 + $regs[7] / 3600 + $regs[8] / 36000;
0109:
0110: //B地点の経度・緯度を小数に
0111: preg_match("/E(\d+)\.(\d+)\.(\d+)\.(\d+)N(\d+)\.(\d+)\.(\d+)\.(\d+)/", $b, $regs);
0112: $b_long = $regs[1] + $regs[2] / 60 + $regs[3] / 3600 + $regs[4] / 36000;
0113: $b_lati = $regs[5] + $regs[6] / 60 + $regs[7] / 3600 + $regs[8] / 36000;
0114:
0115: //ラジアンに変換
0116: $a_long = deg2rad($a_long);
0117: $a_lati = deg2rad($a_lati);
0118: $b_long = deg2rad($b_long);
0119: $b_lati = deg2rad($b_lati);
0120:
0121: $latave = ($a_lati + $b_lati) / 2;
0122: $latidiff = $a_lati - $b_lati;
0123: $longdiff = $a_long - $b_long;
0124:
0125: //子午線曲率半径
0126: $meridian = 6334834 / sqrt(pow(1 - 0.006674 * sin($latave) * sin($latave), 3));
0127: //卯酉線曲率半径
0128: $primevertical = 6377397 / sqrt(1 - 0.006674 * sin($latave) * sin($latave));
0129:
0130: //Hubenyの簡易式
0131: $x = $meridian * $latidiff;
0132: $y = $primevertical * cos($latave) * $longdiff;
0133:
0134: return sqrt($x * $x + $y * $y);
0135: }
0136:
0137: // メイン・プログラム =======================================================
0138: // パラメータのリセット
0139: if (isset($_POST['reset'])) {
0140: $addressA = '';
0141: $addressB = '';
0142: $distance = '';
0143:
0144: // 距離計算
0145: } else if (isset($_POST['exec'])) {
0146: $addressA = htmlspecialchars($_POST['addressA']);
0147: $addressB = htmlspecialchars($_POST['addressB']);
0148:
0149: //入力は経度・緯度表記も可能に
0150: $geoA = (preg_match("/E(\d+)\.(\d+)\.(\d+)\.(\d+)N(\d+)\.(\d+)\.(\d+)\.(\d+)/", $addressA) == 0) ? address2geo($addressA) : $addressA;
0151: $geoB = (preg_match("/E(\d+)\.(\d+)\.(\d+)\.(\d+)N(\d+)\.(\d+)\.(\d+)\.(\d+)/", $addressB) == 0) ? address2geo($addressB) : $addressB;
0152:
0153: if ($geoA == NULL) {
0154: $distance = "A地点の住所が正しくありません";
0155: } else if ($geoB == NULL) {
0156: $distance = "B地点の住所が正しくありません";
0157: } else {
0158: $dd = calc_distance($geoA, $geoB) / 1000;
0159: $distance = sprintf("%8.2f キロメートル", $dd);
0160: }
0161:
0162: // パラメータ入力
0163: } else {
0164: $addressA = isset($_POST['addressA']) ? $_POST['addressA'] : "";
0165: $addressB = isset($_POST['addressB']) ? $_POST['addressB'] : "";
0166: $distance = isset($_POST['distance']) ? $_POST['distance'] : "";
0167: }
0168:
0169:
0170: // 表示処理 ==================================================================
0171: echo <<< EOF
0172: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
0173: "http://www.w3.org/TR/html4/loose.dtd">
0174: <html lang="ja">
0175: <head>
0176: <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" />
0177: <title>2地点間の直線距離を求める</title>
0178: <meta name="ROBOTS" content="NOINDEX,NOFOLLOW" />
0179: </head>
0180: <body>
0181: <h1>■2地点間の直線距離を求める</h1>
0182: <form name="myForm" method="post" enctype="multipart/form-data" action="$myself">
0183: <table border="0" cellspacing="10">
0184: <tr>
0185: <td>A地点</td>
0186: <td><input type="text" name="addressA" size="80" value="$addressA" /></td>
0187: </tr>
0188: <tr>
0189: <td>B地点</td>
0190: <td><input type="text" name="addressB" size="80" value="$addressB" /></td>
0191: </tr>
0192: <tr>
0193: <td>A〜B間の直線距離</td>
0194: <td>$distance</td>
0195: </tr>
0196: <tr>
0197: <td> </td>
0198: <td>
0199: <input type="submit" name="exec" value="計算" />
0200: <input type="submit" name="reset" value="リセット" />
0201: </td>
0202: </tr>
0203: <tr>
0204: <td colspan="2">
0205: <hr />
0206: <b>【使い方】</b>
0207: <ol>
0208: <li>[<b>A地点</b>],[<b>B地点</b>] に住所(都道府県名から番地・号まで)または緯度経度を入力してください。
0209: <br />ただし、住所に漢数字は使えません。
0210: <br />緯度経度は E139.45.56.9N35.41.0.7 (東経 139度45分56.9秒、北緯 35度41分0.7秒)のように入力してください。</li>
0211: <li>[<b>計算</b>] ボタンを押してください。</li>
0212: <li>2地点間の直線距離(キロメートル)が [<b>A〜B間の直線距離</b>] に表示されます。</li>
0213: <li>[<b>リセット</b>] ボタンを押すと、表示がクリアされます。</li>
0214: </ol>
0215: </td>
0216: </tr>
0217: </table>
0218: </form>
0219: </body>
0220: </html>
0221: EOF;
0222: ?>
| 2007年04月20日更新 | ||
| <<前へ | <目次> | 次へ>> |
| 戻る | 【関連ページ】 | |