PHPで経緯度から沖縄標準メッシュー番号に変換する関数

案件で住所からメッシュー番号の変換が必要になって、いろいろ調べた結果をここでメモしておきます。
  • メッシュー番号はなに?

地域メッシュwikipediaより)

  • まず、住所から経緯度に変換する

Google Maps APIを利用します。
Google Maps APIで住所から経緯度の変換はジオコーディングを使います。

ジオコーディングは実はjsからだけではなく、HTTP リクエスト経由からの利用も可能となっています。Google様!最高!

利用方法はここのページに情報が載ってます。

自分は一番シンプルのCSV形式で利用します。このように

/**
    * 住所の文字列から経緯度を取得
    *
    * @param <type> $address
    * @return <type> 変換が成功した場合 35.8569991,139.6488487 のような経緯度結果文字列を返す
    */
    function address2latlng($address=null) {
        if(!$address) return null;
        $address = urlencode($address);
        $rs = file_get_contents("http://maps.google.com/maps/geo?q=$address&output=csv&sensor=false&key=".あなたのきー;
        if($rs) {
            list($status,,$lat,$lng) = explode(",", $rs);
            if($status == 200) {
                return "$lat,$lng";
            }else {
                return null;
            }
        }else {
            return null;
        }
    }
  • そして、経緯度から沖縄標準メッシュー番号に変換する

このサイトのJSファイルを参考にPHP用の変換スクリプトを作りました。
沖縄標準メッシュ番号 表示サービスVer1.3

/**
 * $lat 経度
 * $lng 緯度
 *
 * 経度緯度から沖縄標準メッシュコードに変換する
 * 標準メッシュコード例: 29 45 B-3 f-7
 * 参考:
 * http://www.okikosai.or.jp/kenkyusho/any_data/mc/mc.html
 */
function mc_get($lat,$lng) {
    /* 緯度経度を基に標準メッシュ番号を算出 */
    /* Level1用配列 */
    $M1 = array();
    $M1[0] = Array("33","00","00","00","00","00");
    $M1[1] = Array("31","32","00","00","00","00");
    $M1[2] = Array("29","30","00","00","00","00");
    $M1[3] = Array("26","27","28","00","00","00");
    $M1[4] = Array("22","23","24","25","00","00");
    $M1[5] = Array("18","19","20","21","00","00");
    $M1[6] = Array("00","14","15","16","17","00");
    $M1[7] = Array("00","9","10","11","12","13");
    $M1[8] = Array("00","4","5","6","7","8");
    $M1[9] = Array("00","00","00","00","2","3");
    $M1[10] = Array("00","00","00","00","98","99");

    /* Level2用配列 */
    $M2 = Array();
    $M2[0] = Array("91","92","93","94","95","96","97","98","99","100");
    $M2[1] = Array("81","82","83","84","85","86","87","88","89","90");
    $M2[2] = Array("71","72","73","74","75","76","77","78","79","80");
    $M2[3] = Array("61","62","63","64","65","66","67","68","69","70");
    $M2[4] = Array("51","52","53","54","55","56","57","58","59","60");
    $M2[5] = Array("41","42","43","44","45","46","47","48","49","50");
    $M2[6] = Array("31","32","33","34","35","36","37","38","39","40");
    $M2[7] = Array("21","22","23","24","25","26","27","28","29","30");
    $M2[8] = Array("11","12","13","14","15","16","17","18","19","20");
    $M2[9] = Array("1","2","3","4","5","6","7","8","9","10");

    /* Level3用配列 */
    $M3 = Array();
    $M3[0] = Array("A-5","B-5","C-5","D-5","E-5");
    $M3[1] = Array("A-4","B-4","C-4","D-4","E-4");
    $M3[2] = Array("A-3","B-3","C-3","D-3","E-3");
    $M3[3] = Array("A-2","B-2","C-2","D-2","E-2");
    $M3[4] = Array("A-1","B-1","C-1","D-1","E-1");

    /* Level4用配列 */
    $M4 = Array();
    $M4[0] = Array("a-10","b-10","c-10","d-10","e-10","f-10","g-10","h-10","i-10","j-10");
    $M4[1] = Array("a-9","b-9","c-9","d-9","e-9","f-9","g-9","h-9","i-9","j-9");
    $M4[2] = Array("a-8","b-8","c-8","d-8","e-8","f-8","g-8","h-8","i-8","j-8");
    $M4[3] = Array("a-7","b-7","c-7","d-7","e-7","f-7","g-7","h-7","i-7","j-7");
    $M4[4] = Array("a-6","b-6","c-6","d-6","e-6","f-6","g-6","h-6","i-6","j-6");
    $M4[5] = Array("a-5","b-5","c-5","d-5","e-5","f-5","g-5","h-5","i-5","j-5");
    $M4[6] = Array("a-4","b-4","c-4","d-4","e-4","f-4","g-4","h-4","i-4","j-4");
    $M4[7] = Array("a-3","b-3","c-3","d-3","e-3","f-3","g-3","h-3","i-3","j-3");
    $M4[8] = Array("a-2","b-2","c-2","d-2","e-2","f-2","g-2","h-2","i-2","j-2");
    $M4[9] = Array("a-1","b-1","c-1","d-1","e-1","f-1","g-1","h-1","i-1","j-1");


    /* 算出結果格納用配列 */
    $MC = Array();

    /* 沖縄標準メッシュ基準点 */
    $lat_sp = 93600;
    $lng_sp = 459450;

    /* 座標値を秒単位へ変換 */
    $lat_ss = $lat * 3600;
    $lng_ss = $lng * 3600;

    /* Level1算出 */
    $lat_diff = ($lat_ss - $lat_sp);
    $lng_diff = ($lng_ss - $lng_sp);
    $lat_no = ceil($lat_diff / 300) - 1;
    $lng_no = ceil($lng_diff / 450) - 1;
    $MC[0] = $M1[$lat_no][$lng_no];


    /* Level1_No = 1 の場合の補正 $lngを半分左にシフト*/
    if (($MC[0] == "98") || ($MC[0] == "99")){
     if (($lng < 128.1875) || ($lng > 128.3125 )){
      $MC[0] = 0;
     }else{
      $lng_diff = $lng_diff - 225;
      $MC[0] = "1";
     }
    }
    /* 沖縄標準メッシュエリア外判定 */
    if (($MC[0] === 0) || !($MC[0])){
     return "";
    }

    /* Level2算出 */
    $lat_diff2 = $lat_diff - floor($lat_diff / 300) * 300;
    $lng_diff2 = $lng_diff - floor($lng_diff / 450) * 450;
    $lat_no = ceil($lat_diff2 / 30) - 1;
    $lng_no = ceil($lng_diff2 / 45) - 1;
    $MC[1] = $M2[$lat_no][$lng_no];

    /* Level3算出 */
    $lat_diff3 = $lat_diff2 - floor($lat_diff2 / 30) * 30;
    $lng_diff3 = $lng_diff2 - floor($lng_diff2 / 45) * 45;
    $lat_no = ceil($lat_diff3 / 6) - 1;
    $lng_no = ceil($lng_diff3 / 9) - 1;
    $MC[2] = $M3[$lat_no][$lng_no];

    /* Level4算出 */
    $lat_diff4 = $lat_diff3 - floor($lat_diff3 / 6) * 6;
    $lng_diff4 = $lng_diff3 - floor($lng_diff3 / 9) * 9;
    $lat_no = ceil($lat_diff4 / 0.6) - 1;
    $lng_no = ceil($lng_diff4 / 0.9) - 1;
    $MC[3] = $M4[$lat_no][$lng_no];

    return implode(" ", $MC);

}

  • 最後

ここまできたら、もう言うまでもないですね^^