#!/usr/bin/perl -w
#
# この座標の水深は?
# Nowral
# 00/4/5
#
# 内部の経緯度は全て秒単位
$0 =~ /^(.*):(.*)$/;
$cwd = $1;
&UTM::utminit();

# japan1km.filled.grdデータ諸元 > グローバル変数
$hds = 0x043C;
$npix = 2080;
$nlin = 2573;
$lat0 =  46 * 3600;
$lon0 = 122 * 3600;
$lat2 =  24 * 3600;
$lon2 = 148 * 3600;
$dlat = 30; # 0.00833333333333333 * 3600;
$dlon = 45; # 0.0125 * 3600;

$lat2 = $lat0 - $nlin*$dlat;
$lon2 = $lon0 + $npix*$dlon;
$hlat = $dlat / 2;
$hlon = $dlon / 2;

# 経緯度入力
MacPerl::Ask("緯度? (北緯:入力例  43/38/27.9)", "43/38/27.9") =~ m/(\d+)[^\d](\d+)[^\d](\d+\.?\d*)/ || die;
$b = $1*3600 + $2*60 + $3;
MacPerl::Ask("経度? (東経:入力例  144/23/40.8)", "144/23/40.8") =~ m/(\d+)[^\d](\d+)[^\d](\d+\.?\d*)/ || die;
$l = $1*3600 + $2*60 + $3;
die unless($b<$lat0-$hlat && $b>$lat2+$hlat && $l>$lon0+$hlon && $l<$lon2-$hlon);

undef @ofss;
undef @hofs;
undef @hs;

# 近接三点を選択 < ロジック甘い?
$i = 0;
$ofs1 = &ll2ofs($b, $l);
push(@ofss, $ofs1);
$ofsd = &ll2ofs($b, $l-$hlon); # 左
push(@ofss, $ofsd) unless($ofsd == $ofs1);
$ofsd = &ll2ofs($b-$hlat, $l); # 下
push(@ofss, $ofsd) unless($ofsd == $ofs1);
$ofsd = &ll2ofs($b, $l+$hlon); # 右
push(@ofss, $ofsd) unless($ofsd == $ofs1);
$ofsd = &ll2ofs($b+$hlat, $l); # 上
push(@ofss, $ofsd) unless($ofsd == $ofs1);

die unless($#ofss == $i+2);
@hs[$i .. $i+2] = ("-", "-", "-");
$hofs{$ofss[$i]} .= " $i";
$i++;
$hofs{$ofss[$i]} .= " $i";
$i++;
$hofs{$ofss[$i]} .= " $i";
$i++;
#print join("\n", @ofss), "\n";

# 水深読み込み <まとめて
open(IN, "$cwd:japan1km.filled.grd") || die;
foreach $ofs (sort keys %hofs) {
#  print "$ofs : $hofs{$ofs}\n";
  seek(IN, $ofs, 0);
  read(IN, $_, 4);
  $h = unpack("f", $_);
  foreach $i (split(" ", $hofs{$ofs})) { $hs[$i] = $h; }
}
close(IN);
#print join("\n", @hs), "\n";

# 平面で補間
$i = 0;
$zn = ($l/3600+180) / 6 % 60 + 1; # ゾーン < 西境界含む
($x, $y) = &UTM::sec2utm($b, $l, $zn);
($h1, $h2, $h3) = @hs[$i .. $i+2];
($x1, $y1) = &UTM::sec2utm(&ofs2cll($ofss[$i]), $zn);
$i++;
($x2, $y2) = &UTM::sec2utm(&ofs2cll($ofss[$i]), $zn);
$i++;
($x3, $y3) = &UTM::sec2utm(&ofs2cll($ofss[$i]), $zn);
$i++;

$d = $x1*$y2*$h3 + $x2*$y3*$h1 + $x3*$y1*$h2 - $x1*$y3*$h2 - $x2*$y1*$h3 - $x3*$y2*$h1;
$u = $y2*$h3 + $y3*$h1 + $y1*$h2 - $y3*$h2 - $y1*$h3 - $y2*$h1;
$v = $x1*$h3 + $x2*$h1 + $x3*$h2 - $x1*$h2 - $x2*$h3 - $x3*$h1;
$w = $x1*$y2 + $x2*$y3 + $x3*$y1 - $x1*$y3 - $x2*$y1 - $x3*$y2;
$h = ($d - $u*$x - $v*$y) / $w;

# 結果出力
print "緯度:", &sec2dms($b), "\n";
print "経度:", &sec2dms($l), "\n";
printf("水深: %.02f [m]\n", $h);
MacPerl::Ask("水深 [m]", sprintf("%.02f", $h));

#MacPerl::Quit(2);
die "The Unhappy End";



sub ll2ofs { # 経緯度 -> 先頭からのオフセット
  my($b, $l) =@_;
  my($x, $y);
  $x = int(($l - $lon0)/$dlon);
  $y = int(($lat0 - $b)/$dlat);
  return ($y*$npix + $x)*4 + $hds;
}

sub ofs2cll { # 先頭からのオフセット -> メッシュ中心の経緯度
  my($ofs) =@_;
  my($b, $l);
  my($x, $y);
  $ofs = ($ofs - $hds) / 4;
  $x = $ofs % $npix;
  $y = ($ofs - $x) / $npix;
  $b = $lat0 - $y * $dlat;
  $l = $lon0 + $x * $dlon;
  return ($b - $hlat, $l + $hlon);
}

sub sec2dms { # 秒から度分秒への変換、精度指定あり
  my($s) = @_;
  my($dfe) = 3; # 小数点以下必要な桁数
  my($df) = 10 ** $dfe;
  my($m, $d, $sf);
  $sf = int($s*$df + 0.5);
  $s  = $sf / $df % 60;
  $m  = $sf / $df / 60 % 60;
  $d  = int($sf / $df / 3600);
  $sf %= $df;
#  ($d, $m, $s, $sf);
  sprintf("%d。%02d\'%02d\.%0$dfe\d\"", $d, $m, $s, $sf);
}

package UTM; # グローバル変数隔離のため
# $pi, $rd, $a, $f, $e2, $ed2, $cad, $cbd, $ccd, $cdd, $ced

sub utminit { # グローバル変数準備
#定数
  $pi  = 4 * atan2(1, 1); # 円周率
  $rd  = $pi / 180;       # radian / degree

# 日本測地系
  $a   = 6377397.155;    # 赤道半径 (Tokyo)
  $f   = 1 / 299.152813; # 扁平率 (Tokyo)
  $e2  = 2*$f - $f*$f;   # 第1離心率
  $ed2 = $e2 / (1-$e2);  # 第2離心率

# 子午線弧長計算式係数
  my($e4, $e6, $e8);
  $e4 = $e2 * $e2;
  $e6 = $e4 * $e2;
  $e8 = $e6 * $e2;

  $cad = $a * (1-$e2) * ( 1 + 3/4*$e2 + 45/64*$e4 + 175/256*$e6 + 11025/16384*$e8 );
  $cbd = $a * (1-$e2) * (     3/4*$e2 + 15/16*$e4 + 525/512*$e6 +   2205/2048*$e8 );
  $ccd = $a * (1-$e2) * (               15/64*$e4 + 105/256*$e6 +   2205/4096*$e8 );
  $cdd = $a * (1-$e2) * (                            35/512*$e6 +    315/2048*$e8 );
  $ced = $a * (1-$e2) * (                                           315/16384*$e8 );

  return 1;
}

sub sec2utm { # 経緯度 -> UTM座標
  my($b, $l, $zn) =@_;
  my($x, $y) = &ll2xy($b/3600*$rd, ($l/3600-$zn*6+183)*$rd);
  return ($x * 0.9996, $y * 0.9996 + 500000);
}

sub ll2xy { # Gauss-Klueger
  my($b, $dl) = @_;
  my($dl2, $dl4, $sb, $cb, $cb3, $cb5, $tb2, $tb4, $eta2, $rn, $x, $y);

  $dl2 = $dl * $dl;
  $dl4 = $dl2 * $dl2;
  
  $sb = sin($b);
  $cb = cos($b);
  $cb3 = $cb * $cb * $cb;
  $cb5 = $cb3 * $cb * $cb;
  $tb2 = $sb * $sb / $cb / $cb;
  $tb4 = $tb2 * $tb2;
  
  $eta2 = $ed2 * $cb * $cb;
  $rn = $a / (1-$f) / sqrt(1+$eta2); # 卯酉線曲率半径
  
  $x = $cad*$b - $cbd/2*sin(2*$b) + $ccd/4*sin(4*$b)
    - $cdd/6*sin(6*$b) + $ced/8*sin(8*$b); # 赤道から緯度Bまでの子午線弧長
  $x += $rn/2*$sb*$cb*$dl2;
  $x += $rn/24*$sb*$cb3*(5-$tb2+9*$eta2+4*$eta2*$eta2)*$dl4;
  $x += $rn/720*$sb*$cb5*(61-58*$tb2+$tb4)*$dl4*$dl2;

  $y = $rn*$cb*$dl;
  $y += $rn/6*$cb3*(1-$tb2+$eta2)*$dl*$dl2;
  $y += $rn/120*$cb5*(5-18*$tb2+$tb4)*$dl*$dl4;

  return ($x, $y);
}