| Top Page | プログラミング | メッシュコード |


メッシュコード変換プログラム for Perl

Updated on 2010-07-13

meshcode_to_latlong
メッシュコードを受けとり、緯度・経度を返す。 デフォルトではメッシュの中央の座標を返すが、オプション指定により、 北東、北西、南東、南西のコーナーの座標を得ることもできる。 メッシュコードは一次、二次、三次どれでも可。
latlong_to_meshcode
緯度・経度を受けとり、メッシュコードを返す。 デフォルトでは三次メッシュを返すが、オプション指定により、 二次、一次のコードを返すことも可。
dms_to_deg
度・分・秒の3つの引数を受けとり、度(小数点表示)に換算する。
deg_to_dms
度(小数点表示)を受けとり、度・分・秒を返す。

以下の内容のファイルへのリンク (MESH.pm)。 「リンク先を保存」等でダウンロードして使用。


#  MESH.pm
#
#  メッシュコード計算パッケージ (for Perl)
#
#      2010-07-12  TAKENAKA, Akio
#
#  use MESH; で、このファイルて定義した4つの関数を
#  読み込んでから使用する。
#
#  meshcode_to_latlong,  メッシュコードから緯度・経度へ
#  latlong_to_meshcode,  緯度・経度からメッシュコードへ。
#  dms_to_deg,           度・分・秒から度(小数点表示)へ。
#  deg_to_dms,           度(小数点表示)から度・分・秒へ。

package MESH;

use Exporter;

@ISA = qw(Exporter);

@EXPORT = qw(
meshcode_to_latlong
latlong_to_meshcode
dms_to_deg
deg_to_dms
);

use strict;

########################################
# メッシュコードを渡し、対応する緯度・経度を返す。
# 特に指定しなければメッシュの中央の座標を返す。
# メッシュコードは一次、ニ次、三次いずれも可。
#
# NW, NE, SW, SE を2つ目の引数として渡すと、それぞれ北西、北東、南西、南東の
# コーナーの座標を返す。
#
# 緯度・経度は度単位の小数。
# 
#  usage 
#  my $code_a = "55354251"; # 三次メッシュコード
#  my ($lat_c, $long_c)   = &MESH::meshcode_to_latlong($code_a);  # 中央の緯度・経度
#
#  my $code_b = "5535";     #  一次メッシュコード
#  my ($lat_ne, $long_ne) = &MESH::meshcode_to_latlong($code_b), 'NE');  # 北東端

sub meshcode_to_latlong
{
    my $code = shift @_;
    my ($code12, $code34, $code5, $code6, $code7, $code8);

    my ($lat_width, $long_width);  # ひとつのメッシュの幅

    if ($code =~ /^(\d\d)(\d\d)/) { # 一次メッシュ相当部分の取り出し
        $code12 = $1;
        $code34 = $2;
        $lat_width  = 2 / 3;
        $long_width = 1;
    }
    else {  # 最初に4つの数字が並んでいなければその場で終了
        die("MESH::mesh_to_latlong()  invalid meshcode $code");
    }

    if  ($code =~ /^\d{4}(\d)(\d)/) {  # 二次メッシュ相当部分の取り出し
        $code5 = $1;
        $code6 = $2;
        $lat_width  /= 8;
        $long_width /= 8;
        
    }
    if  ($code =~ /^\d{6}(\d)(\d)/) {  # 三次メッシュ相当部分の取り出し
        $code7 = $1;
        $code8 = $2;
        $lat_width  /= 10;
        $long_width /= 10;
    }

    my $loc = "C";  # 位置指定をしない場合、中央の座標を返す。
    if (@_) {       # 位置指定があれば取得。
        $loc = shift @_;
    }

    unless ($loc =~ /^C|(NE)|(NW)|(SE)|(SW)$/)  { # 不正が位置指定
        die("MESH::mesh_to_latlong()  invalid option $loc");
    }

    # 以下、南西コーナーの座標を求める。

    my $lat  = $code12 * 2 / 3;          #  一次メッシュ
    my $long = $code34 + 100;

    if ($code5 ne '' && $code6 ne '') {  # 二次メッシュ
        $lat  += ($code5 * 2 / 3) / 8;
        $long +=  $code6 / 8; 
    }
    if ($code7 ne '' && $code8 ne '') {  # 三次メッシュ
        $lat  += ($code7 * 2 / 3) / 8 / 10;
        $long +=  $code8 / 8 / 10; 
    }

    if ($loc =~ /C/) {   # 中央の座標
        $lat  += $lat_width  / 2;
        $long += $long_width / 2;
    }
    if ($loc =~ /N/) {   # 北端の座標
        $lat  += $lat_width;
    }
    if ($loc =~ /E/) {   # 東端の座標
        $long  += $long_width;
    }

    $lat  = sprintf("%.8f", $lat);  # 小数点以下8桁まで。
    $long = sprintf("%.8f", $long);

    return ($lat, $long);
}

##################
#  緯度・経度(度単位)を受けとり、これを含むメッシュのコードを返す
# 
#  3番めの引数として 1,2,3 を渡せば、一次メッシュ、二次メッシュ、
#  三次メッシュコードを計算する。指定がなければ三次メッシュ、
#
# Usage;
# my $code_3 = &MESH::latlong_to_meshcode(35.3, 138.5)      # 三次メッシュコード
# my $code_2 = &MESH::latlong_to_meshcode(35.3, 138.5, 2)   # 二次メッシュコード

sub latlong_to_meshcode
{
    my ($lat, $long, $order) = @_;

    unless ($order) {
        $order = 3;
    }

    unless ($order =~ /^[123]$/) {
        die ("ESJ::latlong_to_mesh()  invalid mesh order $order\n");
    }

#    print $lat, "\t", $long, "\t", $order, "\n";
    
    my ($code12, $code34, $code5, $code6, $code7, $code8);
    
    # Latitude 

    my $lat_in_min = $lat * 60;

    $code12 = int($lat_in_min / 40);
    my $lat_rest_in_min = $lat_in_min - $code12 * 40;
    
    $code5 = int($lat_rest_in_min / 5 ); # 二次メッシュの1区画は緯度5分。
    $lat_rest_in_min -= $code5 * 5;

    $code7 = int($lat_rest_in_min / (5/10));

    # Longitude 
    
    $code34 = int($long) - 100;
    my $long_rest_in_deg = $long - int($long);

    $code6 = int($long_rest_in_deg * 8);
    $long_rest_in_deg -= $code6 / 8;

    $code8 = int($long_rest_in_deg / (1/80) );

    my $code = $code12 . $code34;

    if ($order >= 2) {
        $code = sprintf("%s%01d%01d", $code, $code5, $code6);
    }
    if ($order >= 3) {
        $code = sprintf("%s%01d%01d", $code, $code7, $code8);
    }

    return $code;
}

##################
#  度、分、秒を受けとり、度の単位で小数点表示に変換して返す。
#
# Usage;
# my $lat = '138:25:02'; 
# my $deg = &MESH::dms_to_deg( split(/:/, $lat) );

sub dms_to_deg
{
    my ($deg, $min, $sec) = @_;

    my $in_deg = $deg + $min / 60 + $sec / 3600;
    $in_deg = sprintf("%.6f", $in_deg);  # 小数点以下6桁まで。

    return $in_deg;
}

##################
# 度の単位の小数点表示を受けとり、 度、分、秒に変換して返す。
#
# Usage;
# my $lat = 138.415; 
# my ($d, $m, $s) = &MESH::deg_to_dms(lat);
# pirnt join(':', $d, $m, $s);

sub deg_to_dms
{
    my $in_deg = shift @_;

    my $deg = int($in_deg);
    my $rest_in_deg = $in_deg - $deg;

    my $min = int( $rest_in_deg * 60 );
    my $rest_in_min = $rest_in_deg * 60 - $min;

    my $sec = $rest_in_min * 60;
    $sec = sprintf("%.2f", $sec);  # 小数点以下2桁まで。

    # もし繰り上がってしまっていたら、その分の調整、

    if ($sec >= 60) {  # 秒が60を越えたら
        $sec -= 60;
        $min += 1; 
    }
    if ($min == 60) {    # 分が60 を越えたら
       $min -= 60;
       $deg += 1; 
    }

    return ($deg, $min, $sec);
}

1;

| Top Page | プログラミング | メッシュコード |