Skip to content

Commit

Permalink
Add mkkml - an IRA to KML converter
Browse files Browse the repository at this point in the history
  • Loading branch information
Sec42 committed Nov 24, 2016
1 parent 30c766a commit ba70836
Showing 1 changed file with 335 additions and 0 deletions.
335 changes: 335 additions & 0 deletions mkkml
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
#!/usr/bin/perl

our $live;
use POSIX;
use strict;
use warnings;

sub head{
return <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
EOF
}

sub style{
return <<EOF
<Style id="hl2">
<IconStyle>
<scale>4.2</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle_highlight.png</href>
</Icon>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Style id="default2">
<IconStyle>
<scale>4.2</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>
</Icon>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<StyleMap id="default1">
<Pair>
<key>normal</key>
<styleUrl>#hl2</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#default2</styleUrl>
</Pair>
</StyleMap>
<Style id="hl">
<IconStyle>
<scale>1.2</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle_highlight.png</href>
</Icon>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Style id="default">
<IconStyle>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>
</Icon>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<StyleMap id="default0">
<Pair>
<key>normal</key>
<styleUrl>#default</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#hl</styleUrl>
</Pair>
</StyleMap>
<Style id="defaultStyles">
<PolyStyle>
<outline>0</outline>
</PolyStyle>
</Style>
EOF
}

sub foot{
return <<EOF
</kml>
EOF
}

sub emit {
my ($tag,$content)=@_;
return "<$tag>".$content."</$tag>\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<Folder>";
print emit("name" => $name) if defined $name;

print "\t<Folder>\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 <<EOM
<Placemark>
<styleUrl>#defaultStyles</styleUrl>
<Style>
<PolyStyle>
<color>$color</color>
</PolyStyle>
</Style>
<Polygon>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates>$coord</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
EOM
;
}
}
print "\t</Folder>\n";

print "\t<Placemark>\n";
print "\t\t",emit( name => "Mid" );
print "\t\t<Point>\n";
print "\t\t\t<coordinates>";
print $sx/$sc,",",$sy/$sc,",0";
print "</coordinates>\n";
print "\t\t</Point>\n";
print "\t</Placemark>\n";
print "\t</Folder>\n";
}

sub do_tracks{
my $ref=shift;
$|=1;
# print "<Folder>",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 "<Placemark>\n";
print emit( name => "T$id" );
print emit( description => "Satellite $id track" );
print "<gx:MultiTrack>\n";
print emit( altitudeMode => "absolute" );
for my $st (@{$ref->{$id}}){
print "<gx:Track>\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 "</gx:Track>\n";
};
print "</gx:MultiTrack>\n";
print "</Placemark>\n";
}
# print "</Folder>\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 (<STDIN>){
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(),"<Folder>\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 "</Folder>\n",foot();

0 comments on commit ba70836

Please sign in to comment.