From ba70836c190d7ae5a72545f509137bc370790ecc Mon Sep 17 00:00:00 2001 From: Stefan `Sec` Zehl Date: Thu, 24 Nov 2016 23:43:54 +0100 Subject: [PATCH] Add mkkml - an IRA to KML converter --- mkkml | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100755 mkkml diff --git a/mkkml b/mkkml new file mode 100755 index 0000000..67b19d2 --- /dev/null +++ b/mkkml @@ -0,0 +1,335 @@ +#!/usr/bin/perl + +our $live; +use POSIX; +use strict; +use warnings; + +sub head{ +return < + +EOF +} + +sub style{ +return < + + 4.2 + + http://maps.google.com/mapfiles/kml/shapes/placemark_circle_highlight.png + + + + + + + + + normal + #hl2 + + + highlight + #default2 + + + + + + + normal + #default + + + highlight + #hl + + + +EOF +} + +sub foot{ +return < +EOF +} + +sub emit { + my ($tag,$content)=@_; + return "<$tag>".$content."\n"; +} + +sub argb{ + my ($r,$g,$b)=@_; + my $v=sprintf "%02x%02x%02x%02x",255,$r*255,$g*255,$b*255; + return $v; +} + +sub rainbow{ + my ($cur,$max)=@_; + my $h=$cur/$max*2/3; + my ($s,$v)=(1,1); + return argb($v,$v,$v) if $s==0; + my $i = int($h*6.0); + my $f = ($h*6.0) - $i; + my $p = $v*(1.0 - $s); + my $q = $v*(1.0 - $s*$f); + my $t = $v*(1.0 - $s*(1.0-$f)); + $i = $i%6; + return argb($v, $t, $p) if $i==0; + return argb($q, $v, $p) if $i==1; + return argb($p, $v, $t) if $i==2; + return argb($p, $q, $v) if $i==3; + return argb($t, $p, $v) if $i==4; + return argb($v, $p, $q) if $i==5; + die; +} + +sub quant{ + my $quant=$_[1]; + my $val=$_[0]; + if($val<0){ # int(-0.1) = 0, but should be -1 for this. + $val=(int($val/$quant)-1)*$quant; + }else{ + $val=(int($val/$quant))*$quant; + }; + return $val; +} + +# Collecting data + +sub add_pt{ + my $ref=shift; + my ($x,$y,$h,$val)=@_; + push @{$ref},[$x,$y,$h,$val]; +} + +# Emitting data + +sub do_heatmap{ + my $ref=shift; + my $name=shift; + my $deg=shift // 0.3; + + + my %heatcnt; + my %heatval; + my ($sx,$sy,$sc); + for my $p (@{$ref}){ + my ($x,$y,$h,$val)=@{$p}; + + # Sum for middle point + $sx+=$x;$sy+=$y;$sc++; + + # Quantize coordinates to $deg degree squares. + $x=quant($x,$deg); + $y=quant($y,$deg); + + # Create heatmap + $heatcnt{$x}{$y}++; + $heatval{$x}{$y}+=$val; + }; + + # Find maxima for scaling + my ($maxval,$maxcnt)=(0,0); + for my $x (keys %heatcnt){ + for my $y (keys %{$heatcnt{$x}}){ + $heatval{$x}{$y}=$heatval{$x}{$y}/$heatcnt{$x}{$y}; # AVERAGE + $maxval=$heatval{$x}{$y} if ( $heatval{$x}{$y} > $maxval); + $maxcnt=$heatcnt{$x}{$y} if ( $heatcnt{$x}{$y} > $maxcnt); + }; + }; + printf STDERR "$name maxval: %.3f\n",$maxval; + + print "\t"; + print emit("name" => $name) if defined $name; + + print "\t\n"; + print "\t\t",emit("name" => "heatmap"); + my $pd=$deg; + for my $x (keys %heatcnt){ + for my $y (keys %{$heatcnt{$x}}){ + my $val=$heatval{$x}{$y}; + my $cnt=$heatcnt{$x}{$y}; + +# my $color=rainbow($cnt,$maxcnt); + my $color=rainbow($val,$maxval); + + $cnt*=3*1000; + my $coord= sprintf join(" ",("%s,%s,%s")x4), + $x ,$y ,$cnt, + $x ,$y+$pd,$cnt, + $x+$pd,$y+$pd,$cnt, + $x+$pd,$y ,$cnt; +print < + #defaultStyles + + + 1 + 1 + absolute + + + $coord + + + + +EOM +; + } + } + print "\t\n"; + + print "\t\n"; + print "\t\t",emit( name => "Mid" ); + print "\t\t\n"; + print "\t\t\t"; + print $sx/$sc,",",$sy/$sc,",0"; + print "\n"; + print "\t\t\n"; + print "\t\n"; + print "\t\n"; +} + +sub do_tracks{ + my $ref=shift; + $|=1; +# print "",emit("name" => "Tracks"); + # Break track into pieces after 1000 seconds + for my $id (sort keys %{$ref}){ + my $track=$ref->{$id}; + my $idx=0; + my @tracks; + + while ($idx<$#{$track}){ + my $sidx=$idx; + while ($idx<$#{$track} && ($track->[$idx][3]-$track->[$sidx][3])<1000){ + $idx++; + }; + push @tracks,[@{$track}[$sidx..$idx-1]]; + }; + $ref->{$id}=[@tracks]; + } + for my $id (sort keys %{$ref}){ + print "\n"; + print emit( name => "T$id" ); + print emit( description => "Satellite $id track" ); + print "\n"; + print emit( altitudeMode => "absolute" ); + for my $st (@{$ref->{$id}}){ + print "\n"; + for my $p (@{$st}){ + my ($x,$y,$h,$t)=@{$p}; + print emit("when", strftime("%Y-%m-%dT%H:%M:%SZ",localtime($t))); + } + for my $p (@{$st}){ + my ($x,$y,$h,$t)=@{$p}; + print emit("gx:coord","$x $y $h"); + } + print "\n"; + }; + print "\n"; + print "\n"; + } +# print "\n"; +} + + +sub read_line{ + my ($data,$line)=@_; + if(/^IRA: (\S+) (\d+) \d+\s+(\d+)%\s+([0-9.]+).* sat:(\d+) beam:(\d+) (?:rps=\S+ )?pos=.([+-][0-9.]+)\/([+-][0-9.]+). alt=(-?\d+)/){ + my ($fn,$t,$conf,$str,$sat,$beam,$x,$y,$h)=($1,$2,$3,$4,$5,$6,$7,$8,$9); + # fn: filename, t: time, str: signal level + if ($fn=~/-(\d{10})-/){ # Reconstruct time + $t=$1+$t/1000; + }else{ + $t=$t/1000; + }; + my $dir; + if ( $h > 600 && $h < 900){ + $dir="up"; + }elsif ($h > -100 && $h < 100){ + $dir="down"; + }else{ + next; # ignore broken stuff + }; + $h*=1000; + $data->{$dir}=[] unless $data->{$dir}; # Vivify + add_pt($data->{$dir},$y,$x,$h,$str); + $data->{"track_$dir"}{$sat}=[] unless $data->{"track_$dir"}{$sat}; # Vivify + add_pt($data->{"track_$dir"}{$sat},$y,$x,$h,$t); + }else{ + print STDERR "Couldn't parse: $_\n"; + }; +} + +sub read_data{ + my $data=shift; + while (){ + chomp; + read_line($data,$_); + }; +} + +my $mode; +if ($ARGV[0] =~ /^(heatmap|tracks)/){ + $mode=shift; +}else{ + print STDERR "Usage:\n"; + print STDERR "$0 {heatmap|tracks}\n"; + exit(-1); +} + +my $data={}; +read_data($data); + +print head(),"\n",style(); + +if ($mode eq "tracks"){ + do_tracks($data->{track_up}); +}elsif($mode eq "heatmap"){ + my $deg = shift || 0.5; + do_heatmap($data->{down},"Down",$deg); + do_heatmap($data->{up}, "Up", $deg); +} + +print "\n",foot();