#!/usr/bin/perl -w
#
# GPSy拡張形式のトラックログを地図画像ビューア 2.0xで再生
# Nowral
# 01/10/27
#
# 初期化
use Time::Local;
$td = 10; #
$tdh = 30;
$tint = 600; # 時刻表示、何秒おきか
$cd = 0x10000; # depth / color
$pi = 4 * atan2(1,1); # 円周率
$rd = $pi / 180; # [ラジアン/度]
$btel = "tell application \"地図画像ビューア\"\n";
$etel = "end tell\n";
# 出力ファイル準備
$newargv = "track.as";
open(OUT, ">$newargv");
MacPerl::SetFileInfo('ToyS', 'TEXT', $newargv);
print OUT $btel;
$buff = "\tactivate\n";
MacPerl::DoAppleScript("$btel$buff$etel");
print OUT $buff;
# ログ読み込み
$nt = 0;
$nw = 0;
$n = 0;
$oldargv = "";
my($t1, $b1, $l1, $h1, $t2, $b2, $l2, $h2);
while (<>) {
@ed = split("\t");
next unless($ed[0] eq "T" ||
$ed[0] eq "W" || $ed[0] eq "Wx" || $ed[0] eq "wx");
unless(defined $dat) {
if($ed[10] eq "Tokyo") {
$a = 6377397.155; # 赤道半径 (Tokyo)
$f = 1 / 299.152813; # 扁平率 (Tokyo)
$dat = "Tokyo";
}
elsif($ed[10] eq "WGS 84" || $dat eq "<NO TRANSLATION>") {
$a = 6378137; # 赤道半径 (WGS 84)
$f = 1 / 298.257223; # 扁平率 (WGS 84)
$dat = "WGS-84";
}
else {
die "$dat Datum Not Supported";
}
$e2 = 2*$f - $f*$f; # 第1離心率
}
$b1 = &gdms2deg($ed[5]); # 緯度
$l1 = &gdms2deg($ed[6]); # 経度
$h1 = $ed[8] + 0; # 高さ <>楕円体高?
# トラック
if($ed[0] eq "T") {
$ed[4] =~ /(\d+)\/(\d+)\/(\d+)\s+(\d+):(\d+):(\d+)/ || die;
$t1 = timelocal($6,$5,$4,$2,$1-1,$3-1900);
$trn = "" if(defined $t2 && $t1-$t2>300
&& abs($b1-$b2)<1/3600 && abs($l1-$l2)<1/3600);
if($ARGV ne $oldargv || $ed[1] ne $trn) {
unless(defined $t2 && $t1-$t2<300) {
&prc_trk(\@date, \@lat, \@lon, \@alt, $n-1) if $n>2;
$oldargv = $ARGV;
$trn = $ed[1];
$n = 0;
undef $dat;
undef @date;
undef @lat;
undef @lon;
undef @alt;
}
}
push(@date, $t1);
push(@lat, $b1);
push(@lon, $l1);
push(@alt, $h1);
($t2, $b2, $l2, $h2) = ($t1, $b1, $l1, $h1);
++$n;
}
# ウェイポイント
elsif($ed[0] eq "W" || $ed[0] eq "Wx" || $ed[0] eq "wx") {
$clr = &penprop($nw);
$buff = <<END_SCRIPT4;
AddMemo "DEG $dat" MemoKind 1 ツ
Latitude $b1 Longitude $l1 ツ
MemoName "$ed[2]" Comment "" ツ
NameColor {$clr}
END_SCRIPT4
MacPerl::DoAppleScript("$btel$buff$etel");
print OUT $buff;
++$nw;
}
}
&prc_trk(\@date, \@lat, \@lon, \@alt, $n-1) if $n>2;
print OUT $etel;
close(OUT);
printf "# トラック本数 : %d\n", $nt;
printf "# ウェイポイント数: %d\n", $nw;
#MacPerl::Quit(2);
die "The Unhappy End";
sub prc_trk { # 一つながりのトラックを処理
my($tref, $bref, $lref, $href, $n) = @_;
my(@x, @y, @z, @h);
my(@ax, @ay, @az);
my(@sr, $sr, $dr);
my($t0, $t1, $t2, $t3, $u, $tlm);
my($vx1, $vy1, $vz1, $v1, $vmax, @v, $vlm);
my($ax1, $ay1, $az1, $ap, @ap);
my(@t) = @{$tref};
my($cmnt, $clr, @cmnt, $ic1, $ic2);
my($i, $buff, $nd, $rt);
($t0, $t3) = ($t[0], $t[$n]);
$st = $t3 - $t0;
# スプライン計算
foreach $i (0 .. $n) {
($x[$i], $y[$i], $z[$i])
= &llh2xyz(${$bref}[$i], ${$lref}[$i], ${$href}[$i], $a, $e2);
}
foreach $i (0 .. $n-1) { $h[$i] = $t[$i+1] - $t[$i]; }
@ax = &sp_gen(\@x, \@h, $n);
@ay = &sp_gen(\@y, \@h, $n);
@az = &sp_gen(\@z, \@h, $n);
# 積算距離計算
$sr = 0;
undef @sr;
push(@sr, $sr);
foreach $i (0 .. $n-1) {
$dr = &part_amt(1, $h[$i],
$x[$i], $x[$i+1], $ax[$i], $ax[$i+1],
$y[$i], $y[$i+1], $ay[$i], $ay[$i+1],
$z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$sr += $dr;
push(@sr, $sr);
}
# 停止位置検出
$i = 0;
$vmax = 0;
undef @v;
undef @ap;
for($t1=$t0; $t1<=$t3; ++$t1) {
for(; $t[$i+1]<$t1; ++$i) {}
$u = ($t1-$t[$i]) / $h[$i];
$vx1 = &sp_v($u, $h[$i], $x[$i], $x[$i+1], $ax[$i], $ax[$i+1]);
$vy1 = &sp_v($u, $h[$i], $y[$i], $y[$i+1], $ay[$i], $ay[$i+1]);
$vz1 = &sp_v($u, $h[$i], $z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$v1 = sqrt($vx1**2 + $vy1**2 + $vz1**2);
$vmax = $v1 if $vmax<$v1;
push(@v, $v1);
if($v1) {
$ax1 = &sp_a($u, $ax[$i], $ax[$i+1]);
$ay1 = &sp_a($u, $ay[$i], $ay[$i+1]);
$az1 = &sp_a($u, $az[$i], $az[$i+1]);
$ap = $ax1*$vx1 + $ay1*$vy1 + $az1*$vz1; # 加速度の進行方向成分
push(@ap, $ap/$v1);
}
else { push(@ap, 0); }
}
undef @cmnt;
$vlm = 0;
$t2 = -$tdh;
for($t1=$tdh; $t1<=$st-$tdh; ++$t1) {
$v1 = $v[$t1];
if($vlm<$v1) {
$vlm = $v1;
$tlm = $t1;
}
if($ap[$t1-1]<0 && $ap[$t1]>0 && $v1<0.5
&& $v[$t1-$tdh]+$v[$t1+$tdh]>8 && $t1-$t2>$tdh*2) {
$cmnt[int($t1/$td+0.5)] = "●";
$t2 = $t1;
$cmnt[int($tlm/$td+0.5)] = sprintf("<%.0f", $vlm*3.6) if $vlm>5;
$vlm = 0;
}
}
# トラック情報
my($min0, $hour0, $mday0, $mon0) = (localtime($t0))[1..4];
my($min3, $hour3, $mday3, $mon3) = (localtime($t3))[1..4];
printf "# 元データ数: %d\n", $n+1;
printf "# 開始時刻 : %d:%02d\n", $hour0, $min0;
printf "# 終了時刻 : %d:%02d\n", $hour3, $min3;
printf "# 所要時間 : %d。%d\'\n", int($st/3600), $st/60%60;
if($sr<10000) {
printf "# 総距離 : %.0f [m]\n", $sr;
}
else {
printf "# 総距離 : %.1f [km]\n", $sr/1000;
}
printf "# 平均速度 : %.1f [km/h]\n", $sr/$st*3.6;
# 新軌跡
$rt = time;
$clr = &penprop($mday0+$nt);
$cmnt = sprintf("%d/%d %02d:%02d-", $mon0, $mday0, $hour0, $min0)
. ($mday0==$mday3 ? "" : "$mday3 ") . sprintf("%02d:%02d", $hour3, $min3);
$buff = <<END_SCRIPT1;
beep 1
NewLine "DEG $dat" LineKind 1 ツ
LineName "$cmnt" LineColor {$clr} ツ
NameColor {$clr} CommentColor {$clr}
END_SCRIPT1
MacPerl::DoAppleScript("$btel$buff$etel");
print OUT $buff;
# 書き出しループ
$i = 0;
$ic2 = 0;
$nd = 0;
$t2 = $t0 + $tint;
for($t1=$t0; $t1<$t3+$td; $t1+=$td) {
$t1 = $t3 if $t1>$t3;
for(; $t[$i+1]<$t1; ++$i) {}
$u = ($t1-$t[$i]) / $h[$i];
$x1 = &sp_x($u, $h[$i], $x[$i], $x[$i+1], $ax[$i], $ax[$i+1]);
$y1 = &sp_x($u, $h[$i], $y[$i], $y[$i+1], $ay[$i], $ay[$i+1]);
$z1 = &sp_x($u, $h[$i], $z[$i], $z[$i+1], $az[$i], $az[$i+1]);
my($b1, $l1, $h1) = &xyz2llh($x1, $y1, $z1, $a, $e2);
# アイコン
# 0: アイコンを表示しない(デフォルト)
# 1: 矢印、 2: 歩く人、 3: 自転車、 ツ
# 4: 自動車(赤)、 5: 亀、 6: 自動車(青)
$ic1 = $v[$t1-$t0] * 3.6;
$ic1 = $ic1<2 ? 5 : $ic1<6 ? 2 : $ic1<25 ? 3 : $ic1<60 ? 6 : $ic1<120 ? 4 : 1;
$buff = $ic1==$ic2 ? "" : "\tSetIcon $ic1\n";
$ic2 = $ic1;
# コメント
$cmnt = defined $cmnt[int(($t1-$t0)/$td)] ? $cmnt[int(($t1-$t0)/$td)] : "";
if($t1>=$t2 || $t1==$t3) { # 時刻表示のタイミング?
$sr = $sr[$i] + &part_amt($u, $h[$i],
$x[$i], $x[$i+1], $ax[$i], $ax[$i+1],
$y[$i], $y[$i+1], $ay[$i], $ay[$i+1],
$z[$i], $z[$i+1], $az[$i], $az[$i+1]);
$cmnt .= " " if $cmnt;
$cmnt .= ($t1-$t0>=3600 ? (int(($t1-$t0)/3600))."。" : "")
. sprintf("%d\' %.1fk", ($t1-$t0)/60%60, $sr/1000);
$t2 += $tint;
}
if($t1==$t0 || $t1==$t3) {
$cmnt .= " " if $cmnt;
$cmnt .= sprintf("(%d:%02d)", (localtime($t1))[2,1]);
}
# ポイント追加
$buff .= <<END_SCRIPT2;
AddNode Latitude $b1 Longitude $l1 Comment "$cmnt"
END_SCRIPT2
MacPerl::DoAppleScript("$btel$buff$etel");
print OUT $buff;
$nd++;
}
# 軌跡終了
$buff = <<END_SCRIPT3;
CloseLine
beep 1
END_SCRIPT3
MacPerl::DoAppleScript("$btel$buff$etel");
print OUT $buff;
$rt = time - $rt;
printf "# 最高速度 : %.1f [km/h]\n", $vmax*3.6;
printf "# 新データ数: %d\n", $nd;
printf "# 所要時間 : %d\'%d\"\n", $rt/60%60, $rt%60;
print "\n";
++$nt;
}
sub penprop { # 番号 -> 色
my($id) = @_;
my($cb, $cr, @cs);
$id *= 65;
$cb = int(($id+60) / 120);
$cr = ($id/120-$cb) * $cd;
$cs[$cb%3] = $cd - 1;
($cs[($cb+1)%3], $cs[($cb+2)%3]) = $cr>0 ? ($cr, 0) : (0, -$cr);
return sprintf("%d, %d, %d", @cs);
}
sub gdms2deg { # 経緯度、GPSy形式 -> 度
my($d) = @_;
$d =~ /(-?)(\d*\.?\d*)。?(\d*\.?\d*)'?(\d*\.?\d*)"?/ || die;
return ($1 ? -1 : 1) * ($2 + $3/60 + $4/3600);
}
sub llh2xyz { # 楕円体座標 -> 直交座標
my($b, $l, $h, $a, $e2) = @_;
my($sb, $cb, $rn, $x, $y, $z);
$b *= $rd;
$l *= $rd;
$sb = sin($b);
$cb = cos($b);
$rn = $a / sqrt(1-$e2*$sb*$sb);
$x = ($rn+$h) * $cb * cos($l);
$y = ($rn+$h) * $cb * sin($l);
$z = ($rn*(1-$e2)+$h) * $sb;
($x, $y, $z);
}
sub xyz2llh { # 直交座標 -> 楕円体座標
my($x, $y, $z, $a, $e2) = @_;
my($bda, $p, $t, $st, $ct, $b, $l, $sb, $rn, $h);
$bda = sqrt(1-$e2); # b/a
$p = sqrt($x*$x+$y*$y);
$t = atan2($z, $p*$bda);
$st = sin($t);
$ct = cos($t);
$b = atan2($z+$e2*$a/$bda*$st*$st*$st, $p-$e2*$a*$ct*$ct*$ct);
$l = atan2($y, $x);
$sb = sin($b);
$rn = $a / sqrt(1-$e2*$sb*$sb);
$h = $p/cos($b) - $rn;
($b/$rd, $l/$rd, $h);
}
sub sp_gen { # 3次の自然スプライン決定
my($xref, $href, $n) = @_;
my(@x) = @$xref;
my(@h) = @$href;
my(@rho, @tau);
$rho[1] = 0;
$tau[1] = 0;
foreach $i (1 .. $n-1) {
my($di) = 6 * (($x[$i+1]-$x[$i])/$h[$i] - ($x[$i]-$x[$i-1])/$h[$i-1]);
my($fi) = $h[$i-1]*$rho[$i] + 2*$h[$i] + 2*$h[$i-1];
$rho[$i+1] = - $h[$i] / $fi;
$tau[$i+1] = ($di - $h[$i-1]*$tau[$i]) / $fi;
}
undef @x;
undef @h;
my(@a);
$a[$n] = 0;
for($i=$n; $i>0; --$i) { $a[$i-1] = $rho[$i]*$a[$i] + $tau[$i]; }
return @a;
}
sub sp_x { # スプライン関数値の計算
my($u, $hi, $xi, $xip, $ai, $aip) = @_;
my($uu) = 1 - $u;
my($hh6) = $hi * $hi / 6;
return $hh6*$ai*$uu*$uu*$uu + $hh6*$aip*$u*$u*$u
+ ($xi-$hh6*$ai)*$uu + ($xip-$hh6*$aip)*$u;
}
sub sp_v { # スプライン関数一階微分値の計算
my($u, $hi, $xi, $xip, $ai, $aip) = @_;
my($uu) = 1 - $u;
return - $ai*$hi/2*$uu*$uu + $aip*$hi/2*$u*$u
+ ($xip-$xi)/$hi - $hi/6*($aip-$ai);
}
sub sp_a { # スプライン関数二階微分値の計算
my($u, $ai, $aip) = @_;
return $ai*(1-$u) + $aip*$u;
}
sub dldt { # 速度の絶対値 <> 単位時間あたりに進む距離
my($u, $hi,
$xi, $xip, $axi, $axip,
$yi, $yip, $ayi, $ayip,
$zi, $zip, $azi, $azip) = @_;
my($vx, $vy, $vz);
$vx = &sp_v($u, $hi, $xi, $xip, $axi, $axip);
$vy = &sp_v($u, $hi, $yi, $yip, $ayi, $ayip);
$vz = &sp_v($u, $hi, $zi, $zip, $azi, $azip);
return sqrt($vx*$vx + $vy*$vy + $vz*$vz);
}
sub part_amt { # i区間におけるパラメタuまでの積算
my($u, $hi,
$xi, $xip, $axi, $axip,
$yi, $yip, $ayi, $ayip,
$zi, $zip, $azi, $azip) = @_;
my($sr, $m, $k);
$m = $u * $hi;
$sr = &dldt(0, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
for($k=1; $k<$m; ++$k) {
$sr += 2 * &dldt($k/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += 4 * &dldt($k/$hi-0.5, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
}
$k--;
$m -= $k;
$sr += ($m-1) * &dldt($k/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += 4 * $m * &dldt(($k+$m/2)/$hi, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
$sr += $m * &dldt($u, $hi, $xi, $xip, $axi, $axip, $yi, $yip, $ayi, $ayip, $zi, $zip, $azi, $azip);
return $sr/6;
}