よく使うサブルーチン
2016年1月3日 (日) 12:57時点におけるimported>Webmasterによる版
個人的によく使うサブルーチンをまとめてみました
出典元
参考にした出典元です 中央値処理
サブルーチン
#!/usr/bin/perl
use strict;
use warnings;
#---------------------------------------------------------------------------------------------------------------------
#緯度経度からメッシュ番号を算出するサブルーチン
#パッケージ名を「lat_long_to_mesh」とする
#lat_long_to_mesh::mesh($Longitude, $Latitude, $MESH_CODE)と呼ばれることで
#経度/緯度/メッシュサイズをで入れると、指定されたメッシュ番号に変換して返す
#メッシュサイズ引数(1=1km/2=500m/3=250m/4=125m/5=100m)
package lat_long_to_mesh;
sub mesh {
my($Longitude_out, $Latitude_out, $MESH_CODE) = @_;
#print $Longitude_out,"-",$Latitude_out,"-",$MESH_CODE,"\n";
#-------------------------緯度経度→メッシュ番号算出----------------------------------------------
# 1st mesh(latitude)
#・緯度×60分÷40分=p 余りa p=第1次地域区画を示す数字の上2けた の計算
#
my $mesh_P = int($Latitude_out * 60 / 40);
my $mesh_a = ($Latitude_out * 60) - ($mesh_P * 40) ;
#print "一次メッシュ(P=$mesh_P a=$mesh_a)\n";
# 2nd mesh(latitude)
#・ a÷5分=q 余りb q=第2次地域区画を示す数字の上1けた の計算
my $mesh_Q = int($mesh_a / 5);
my $mesh_b = $mesh_a - ($mesh_Q * 5) ;
#print "二次メッシュ(Q=$mesh_Q b=$mesh_b)\n";
# 3tn mesh(latitude)
#・b×60秒÷30秒=r 余りx r=第3次地域区画を示す数字の上1けた の計算
my $mesh_R = int($mesh_b * 60 / 30);
my $mesh_x = ($mesh_b * 60) - ($mesh_R * 30) ;
#print "三次メッシュ(R=$mesh_R x=$mesh_x)\n";
# 4tn mesh(latitude)
#・x÷15秒=R2 余りx2 R2=第4次地域区画を示す数字の上1けた の計算
my $mesh_R2 = int($mesh_x / 15);
my $mesh_x2 = $mesh_x - ($mesh_R2 * 15) ;
#print "四次メッシュ(R2=$mesh_R2 x2=$mesh_x2)\n";
# 5th mesh(latitude)
#・x2÷7.5秒=R3 余りx3 R3=第5次地域区画を示す数字の上1けた の計算
my $mesh_R3 = int($mesh_x2 / 7.5);
my $mesh_x3 = $mesh_x2 - ($mesh_R3 * 7.5) ;
#print "五次メッシュ(R3=$mesh_R3 x3=$mesh_x3)\n";
# 6rh mesh(latitude)
#・ x2÷3.75秒=R3 余りx3 R3=第5次地域区画を示す数字の上1けた の計算
my $mesh_R4 = int($mesh_x3 / 3.75);
my $mesh_x4 = $mesh_x3 - ($mesh_R4 * 3.75) ;
#print "六次メッシュ(R4=$mesh_R4 x4=$mesh_x4)\n";
# 100m mesh(latitude)
# 緯度差3秒
#・x÷3秒=R5 余りx4 R4=100mメッシュを示す数字の上1けた の計算
my $mesh_R5 = int($mesh_x / 3);
my $mesh_x5 = $mesh_x - ($mesh_R2 * 3) ;
#print "100mメッシュ(R5=$mesh_R2 x5=$mesh_x2)\n";
# 1st mesh(longitude)
#・経度-100度=s 余りc s=第1次地域区画を示す数字の下2けた の計算
#
my $mesh_S = int($Longitude_out - 100);
my $mesh_c = $Longitude_out -100 - $mesh_S ;
#print "一次メッシュ(S=$mesh_S c=$mesh_c)\n";
# 2nd mesh(longitude)
#・c×60分÷7分30秒=t 余りd t=第2次地域区画を示す数字の下1けた の計算
#
my $mesh_T = int($mesh_c * 60 / 7.5);
my $mesh_d = ($mesh_c * 60) - ($mesh_T * 7.5) ;
#print "二次メッシュ(T=$mesh_T d=$mesh_d)\n";
# 3th mesh(longitude)
#・d×60秒÷45秒=u 余りy u=第3次地域区画を示す数字の下1けた の計算
#
my $mesh_U = int($mesh_d * 60 / 45);
my $mesh_y = ($mesh_d * 60) - ($mesh_U * 45) ;
#print "三次メッシュ(U=$mesh_U y=$mesh_y)\n";
# 4th mesh(longitude)
# 経度差は22.5秒
#・y÷22.5秒=u2 余りy2 u2=第4次地域区画を示す数字の下1けた の計算
#
my $mesh_u2 = int($mesh_y / 22.5);
my $mesh_y2 = $mesh_y - ($mesh_u2 * 22.5) ;
#print "四次メッシュ(u2=$mesh_u2 y2=$mesh_y2)\n";
# 5th mesh(longitude)
#・y2÷11.25秒=u3 余りy3 u3=第5次地域区画を示す数字の下1けた の計算
#
my $mesh_u3 = int($mesh_y2 / 11.25);
my $mesh_y3 = $mesh_y2 - ($mesh_u3 * 11.25) ;
#print "五次メッシュ(u3=$mesh_u3 y3=$mesh_y3)\n";
# 6th mesh(longitude)
#・y3÷5.625秒=u4 余りy4 u4=第6次地域区画を示す数字の下1けた の計算
#
my $mesh_u4 = int($mesh_y3 / 5.625);
my $mesh_y4 = $mesh_y3 - ($mesh_u4 * 5.625) ;
#print "六次メッシュ(u4=$mesh_u4 y4=$mesh_y4)\n";
# 100m mesh(longitude)
#・y÷4.5秒=u5 余りy5 u5=100mメッシュを示す数字の下1けた の計算
#経度差は4.5秒
my $mesh_u5 = int($mesh_y / 4.5);
my $mesh_y5 = $mesh_y - ($mesh_u2 * 4.5) ;
#print "100mメッシュ(u5=$mesh_u2 y5=$mesh_y2)\n";
#-------------組み立て-----------
my $mesh1 = $mesh_P * 100 + $mesh_S;
my $mesh2 = $mesh_Q * 10 + $mesh_T;
my $mesh3 = $mesh_R * 10 + $mesh_U;
my $mesh4 = oct('0b'.$mesh_R2.$mesh_u2) + 1;
my $mesh5 = oct('0b'.$mesh_R3.$mesh_u3) + 1;
my $mesh6 = oct('0b'.$mesh_R4.$mesh_u4) + 1;
my $mesh_code_out = 0;
if ($MESH_CODE == 1){$mesh_code_out = sprintf("%04d%02d%02d", $mesh1, $mesh2, $mesh3);} #1kmメッシュ計算
elsif ($MESH_CODE == 2){$mesh_code_out = sprintf("%04d%02d%02d%01d", $mesh1, $mesh2, $mesh3, $mesh4);}#500mメッシュ計算
elsif ($MESH_CODE == 3){$mesh_code_out = sprintf("%04d%02d%02d%01d%01d", $mesh1, $mesh2, $mesh3, $mesh4, $mesh5);}#250mメッシュ計算
elsif ($MESH_CODE == 4){$mesh_code_out = sprintf("%04d%02d%02d%01d%01d%01d", $mesh1, $mesh2, $mesh3, $mesh4, $mesh5, $mesh6);}#125mメッシュ計算
elsif ($MESH_CODE == 5){$mesh_code_out = sprintf("%04d%02d%02d%01d%01d", $mesh1, $mesh2, $mesh3, $mesh_R5, $mesh_u5);} #100mメッシュ計算
return $mesh_code_out;
}
#---------------------------------------------------------------------------------------------------------------------
#メッシュ番号から中心緯度経度を算出するプログラム
#出力は三次/四次/五次/六次まで
sub mesh2lat_long{
my($sample_data) = @_;
my $MESH_No = 0;#何次メッシュかを得る
#メッシュの文字列の長さを得る
my $MESH_Length = length($sample_data);
if($MESH_Length == 8){$MESH_No = 3}#三次メッシュ(1km)
elsif ($MESH_Length == 9){$MESH_No = 4}#四次メッシュ(500m)
elsif ($MESH_Length == 10){$MESH_No = 5}#五次メッシュ(250m)
elsif ($MESH_Length == 11){$MESH_No = 6}#六次メッシュ(125m)
#一次メッシュ算出
my $MESH_01_Lat = substr($sample_data,0,2) / 1.5; #単位(度)
my $MESH_01_Long = substr($sample_data,2,2) + 100; #単位(度)
#二次メッシュ算出
my $MESH_02_Lat = substr($sample_data,4,1) * 5; #単位(分)
my $MESH_02_Long = substr($sample_data,5,1) * 7.5; #単位(分)
#print $MESH_02_Long," ";
#三次メッシュ算出
my $MESH_03_Lat = substr($sample_data,6,1) * 30 + 15; #単位(秒)
my $MESH_03_Long = substr($sample_data,7,1) * 45 + 22.5;#単位(秒)
#四次メッシュ算出
#算出が四次より大きければ処理する
#編集初期化
my $MESH_04_Lat =0;
my $MESH_04_Long =0;
if ($MESH_No >= 4){
if(substr($sample_data,8,1) == 1)
{
$MESH_04_Lat = -7.5;
$MESH_04_Long = -11.25;
}
elsif(substr($sample_data,8,1) == 2)
{
$MESH_04_Lat = -7.5;
$MESH_04_Long = 11.25;
}
elsif(substr($sample_data,8,1) == 3)
{
$MESH_04_Lat = +7.5;
$MESH_04_Long = -11.25;
}
elsif(substr($sample_data,8,1) == 4)
{
$MESH_04_Lat = +7.5;
$MESH_04_Long = +11.25;
}
}
#五次メッシュ算出
#算出が五次より大きければ処理する
#編集初期化
my $MESH_05_Lat =0;
my $MESH_05_Long =0;
if ($MESH_No >= 5){
if(substr($sample_data,9,1) == 1)
{
$MESH_05_Lat = -7.5 / 2;
$MESH_05_Long = -11.25 / 2;
}
elsif(substr($sample_data,9,1) == 2)
{
$MESH_05_Lat = -7.5 / 2;
$MESH_05_Long = 11.25 / 2;
}
elsif(substr($sample_data,9,1) == 3)
{
$MESH_05_Lat = +7.5 / 2;
$MESH_05_Long = -11.25 / 2;
}
elsif(substr($sample_data,9,1) == 4)
{
$MESH_05_Lat = +7.5 / 2;
$MESH_05_Long = +11.25 / 2;
}
}
#六次メッシュ算出
#算出が六次より大きければ処理する
#編集初期化
my $MESH_06_Lat =0;
my $MESH_06_Long =0;
if ($MESH_No >= 6){
if(substr($sample_data,10,1) == 1)
{
$MESH_06_Lat = -7.5 / 4;
$MESH_06_Long = -11.25 / 4;
}
elsif(substr($sample_data,10,1) == 2)
{
$MESH_06_Lat = -7.5 / 4;
$MESH_06_Long = 11.25 / 4;
}
elsif(substr($sample_data,10,1) == 3)
{
$MESH_06_Lat = +7.5 / 4;
$MESH_06_Long = -11.25 / 4;
}
elsif(substr($sample_data,10,1) == 4)
{
$MESH_06_Lat = +7.5 / 4;
$MESH_06_Long = +11.25 / 4;
}
}
#--------------------------------------------------------------------------
#秒の積算
my $Lat_Sec = $MESH_03_Lat + $MESH_04_Lat + $MESH_05_Lat + $MESH_06_Lat;
my $Long_Sec = $MESH_03_Long + $MESH_04_Long + $MESH_05_Long + $MESH_06_Long;
#print "秒の算出:(MESH_03)$MESH_03_Lat(MESH_04)$MESH_04_Lat(MESH_05)$MESH_05_Lat(MESH_06)$MESH_06_Lat\n";
#print "秒の算出:(MESH_03)$MESH_03_Long(MESH_04)$MESH_04_Long(MESH_05)$MESH_05_Long(MESH_06)$MESH_06_Long\n";
#print "\n";
#この時点の時分秒
#print "Lat :$MESH_01_Lat(度)$MESH_02_Lat(分)$Lat_Sec(秒)\n";
#print "Long:$MESH_01_Long(度)$MESH_02_Long(分)$Long_Sec(秒)\n";
#秒が60秒を超えたら分に加算
$MESH_02_Lat = $MESH_02_Lat + int($Lat_Sec/60);
$Lat_Sec = $Lat_Sec-int($Lat_Sec/60)*60;
$MESH_02_Long = $MESH_02_Long + int($Long_Sec/60);
$Long_Sec = $Long_Sec-int($Long_Sec/60)*60;
#print "Lat :$MESH_01_Lat(度)$MESH_02_Lat(分)$Lat_Sec(秒)\n";
#print "Long:$MESH_01_Long(度)$MESH_02_Long(分)$Long_Sec(秒)\n";
#分が60分を超えたら度に加算
$MESH_01_Lat = $MESH_01_Lat + int($MESH_02_Lat/60);
$MESH_02_Lat = $MESH_02_Lat - int($MESH_02_Lat/60)*60;
$MESH_01_Long = $MESH_01_Long + int($MESH_02_Long/60);
$MESH_02_Long = $MESH_02_Long - int($MESH_02_Long/60)*60;
#print "Lat :$MESH_01_Lat(度)$MESH_02_Lat(分)$Lat_Sec(秒)\n";
#print "Long:$MESH_01_Long(度)$MESH_02_Long(分)$Long_Sec(秒)\n";
#緯度経度10進数計算
my $MESH_Lat = $MESH_01_Lat + ($MESH_02_Lat / 60) + ($Lat_Sec / 60 /60);
my $MESH_Long = $MESH_01_Long + ($MESH_02_Long / 60) + ($Long_Sec / 60 /60);
#答え
#print "Lat=",$MESH_Lat," Long=",$MESH_Long,"\n";
return ($MESH_Lat,$MESH_Long);
}
#---------------------------------------------------------------------------------------------------------------------
#モジュールがインストールしていなくても平均/中央/最大/最小を算出するためのサブルーチン
#---------------平均値算出----------------------
sub mean{
my $n=@_;
my $mean=0;
foreach my $i (@_)
{
$mean+=$i/$n;
}
return($mean);
}
#---------------最大値値算出----------------------
sub max{
my @nums = @_;
my $max_num;
for my $num (@nums) {
if (!defined $max_num) {
$max_num = $num;
}
else{
if ($num > $max_num) {
$max_num = $num;
}
}
}
return $max_num;
}
#---------------最小値算出----------------------
sub min{
my @nums = @_;
my $min_num;
for my $num (@nums) {
if (!defined $min_num){
$min_num = $num;
}
else {
if ($num < $min_num){
$min_num = $num;
}
}
}
return $min_num;
}
#---------------中央値値算出----------------------
sub median{
my @list=sort{$a<=>$b}@_; #昇順にソート
my $n=@_; #データの個数
if($n%2==0){ #データの個数が偶数の場合
my $x1=$n/2;
my $x2=$n/2+1;
my $median_g=($list[$x1-1]+$list[$x2-1])*0.5;
#print "median=$median_g \n";
return($median_g);
}else{ #データの個数が奇数の場合
my $x=$n/2;
my $median_k=$list[$x];
#print "median=$median_k \n";
return($median_k);
}
}
1;