Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 654 → Rev 655

/MissionCockpit/tags/V0.2.7/mkcockpit.pl
0,0 → 1,1528
#!/usr/bin/perl
#!/usr/bin/perl -d:ptkdb
 
###############################################################################
#
# mkcockpit.pl - MK Mission Cockpit - GUI
#
# Copyright (C) 2009 Rainer Walther (rainerwalther-mail@web.de)
#
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
#
# Es ist Ihnen gestattet:
# * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
# * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
#
# Zu den folgenden Bedingungen:
# * Namensnennung.
# Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
# * Keine kommerzielle Nutzung.
# Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
# * Weitergabe unter gleichen Bedingungen.
# Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
# verändern oder als Grundlage für einen anderen Inhalt verwenden,
# dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
# weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
#
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
#
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
# des Rechteinhabers dazu erhalten.
#
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
#
# Weitere Details zur Lizenzbestimmung gibt es hier:
# Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
# Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
#
###############################################################################
# 2009-02-20 0.0.1 rw created
# 2009-04-01 0.1.0 rw RC1
# 2009-04-16 0.1.1 rw Bugfix, ALT= average of airsensor and Sat
# 2009-05-14 0.2.0 rw Waypoint Player
# 2009-05-17 0.2.1 rw Cursor-Steuerung fuer WP-Player. Cmdline-Parameter "-geometry"
# 2009-07-18 0.2.2 rw DE/EN multinational
# Target-Balloon with Distance, Tolerance and Holdtime
# Fix footprint "Ausreiser"
# JPEG and PNG maps supported
# Player for KML Files
# 2009-07-26 0.2.3 rw System Messages Balloon
# 2009-07-31 0.2.4 rw ODO Kilometerzähler
# Enter WP-Number from Keyboard
# Random WP-Player (Waypoint and Map)
# Check Airfield Border
# Draw Calibration points on map
# 2009-08-08 0.2.5 rw KML Recorder
# Text to speech
# Subroutines moved to libmkcockpit.pl
# Timer moved to libmktimer.pl
# Start Scenarion configuration
# Battery capacity estimation
# Read map definition from maps/map.xml
# 2009-08-23 0.2.6 rw Tracking-Antenna Icon
# Show Fox only in Player-Pause mode
# POI heading control
# Display scale
# Measuring-tool on left mouse button
# Display Operation Radius Border
# Read map definition from KML file (GE import)
# Include of local *.pm changed
# Copy x/y/Lat/Lon to Clipboard when pressing left mouse button
# Calculate size of map image
# track.pl - Commandline parameter added for COM ports
# don't use local perl libs any more
# 2009-10-18 0.2.7 rw Mk-Simulator
# Start tracker at program start. Coldstart at MK-calibration
# COM Port >9; PortSetSkip config
# Reset Flight-Time and ODO when clicking on OSD-value
#
###############################################################################
 
$Version = "0.2.7 - 2009-10-18";
 
# change working directory to program path
my $Cwd = substr ($0, 0, rindex ($0, "mkcockpit.pl"));
chdir $Cwd;
 
# set path for local Perl libs
push @INC, $Cwd . "perl/lib";
 
use threads; # http://search.cpan.org/~jdhedden/threads-1.72/threads.pm
# http://perldoc.perl.org/threads.html
use threads::shared; # http://search.cpan.org/~jdhedden/threads-shared-1.28/shared.pm
use Thread::Queue; # http://search.cpan.org/dist/Thread-Queue-2.11/lib/Thread/Queue.pm
use Tk;
use Tk::Balloon;
use Tk::Dialog;
use Tk::Notebook;
use Tk::JPEG; # http://search.cpan.org/~srezic/Tk-804.028/JPEG/JPEG.pm
use Tk::PNG; # http://search.cpan.org/~srezic/Tk-804.028/PNG/PNG.pm
use Math::Trig;
use Time::HiRes qw(usleep); # http://search.cpan.org/~jhi/Time-HiRes-1.9719/HiRes.pm
use XML::Simple; # http://search.cpan.org/dist/XML-Simple-2.18/lib/XML/Simple.pm
use Clipboard; # http://search.cpan.org/~king/Clipboard-0.09/lib/Clipboard.pm
use Image::Size; # http://search.cpan.org/~rjray/Image-Size-3.2/lib/Image/Size.pm
 
 
# Version setting
share (%Version);
$Version{'mkcockpit.pl'} = $Version;
 
# Read configuration
$XmlConfigFile = "mkcockpit.xml";
$Cfg = XMLin($XmlConfigFile);
 
require "track.pl"; # Tracking antenna
require "mkcomm.pl"; # MK communication
require "logging.pl"; # CSV and GPX Logging
require "geserver.pl"; # Google Earth Server
require "$Cfg->{'map'}->{'MapDir'}/map.pl"; # Landkarte
require "libmap.pl"; # map subs
require "translate.pl"; # Übersetzungstable
require "tts.pl"; # Text to Speech
require "libmkcockpit.pl"; # Subroutines
require "libmksim.pl"; # MK Simulator
 
# Commandline parameter
my %CmdLine = @ARGV;
 
# Aktuell gültige Karte
my %Map = %{$Maps{'Current'}};
 
# optional map specific Cfg setup from map definition
foreach $Key (keys %Map)
{
# Cfg:Section:Keyword
if ( $Key =~ /^Cfg:(\S*):(\S*)/i )
{
$Section = $1;
$Keyword = $2;
$Cfg->{$Section}->{$Keyword} = $Map{$Key};
}
}
 
# Canvas size - get image size
my $ImgFile = "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}";
($MapSizeX, $MapSizeY, my $ImgError) = imgsize ($ImgFile);
if ( $MapSizeX eq "" )
{
print "$ImgFile: $ImgError\n";
# Try size information from map definition
$MapSizeX = $Map{'Size_X'};
$MapSizeY = $Map{'Size_Y'};
}
 
 
# Thread fuer Kommunikation mit MK starten
# Output: %MkOsd, %MkTarget, %MkNcDebug, %Mk
# Input: Thread-Queue: $MkSendQueue
$mk_thr = threads->create (\&MkCommLoop) -> detach();
 
# Start Logging Thread
$log_thr = threads->create (\&MkLogLoop) -> detach();
 
# Start GoogleEarth Thread
$ge_thr = threads->create (\&GeServer) -> detach();
 
# Start TTS Thread
$tts_thr = threads->create (\&TtsLoop) -> detach();
 
# Start Antenna tracker
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
{
$track_thr = threads->create (\&TrackAntennaGps)->detach();
}
 
#
# Player:
# Waypoint-List: @Waypoints
# KML-Target-List: @KmlTargets
#
 
# Player state machine
$PlayerMode = 'Stop'; # Play, Stop, Pause, Home ...
$PlayerWptKmlMode = 'WPT'; # WPT, KML
$PlayerRandomMode = 'STD'; # STD, RND, MAP
$PlayerRecordMode = ""; # "", REC
$WpPlayerIndex = 0;
$WpPlayerHoldtime = -1;
$KmlPlayerIndex = 0;
$PlayerPause_Lat = "";
$PlayerPause_Lon = "";
 
# Point Of Interest (POI)
my $Poi_x = $MapSizeX/2-100;
my $Poi_y = $MapSizeY/2 ;
($Poi_Lat, $Poi_Lon) = &MapXY2Gps($Poi_x + 24, $Poi_y + 48);
 
# POI from Map configuration
if ( $Map{'Poi_Lat'} ne "" and $Map{'Poi_Lon'} ne "" )
{
$Poi_Lat = $Map{'Poi_Lat'};
$Poi_Lon = $Map{'Poi_Lon'};
($Poi_x, $Poi_y) = &MapGps2XY($Poi_Lat, $Poi_Lon);
$Poi_x = $Poi_x - 24;
$Poi_y = $Poi_y - 48;
}
$Poi_Mode = 0; # POI Mode off
 
# Hauptfenster
$main = new MainWindow;
$main->title ("MK Mission Cockpit - Version $Version");
 
if ( $CmdLine{'-geometry'} ne "" )
{
$main->geometry( "$CmdLine{'-geometry'}" );
}
 
 
# pattern for dashed lines
my $stipple_bits = [];
foreach my $b (1..8)
{
push @$stipple_bits, pack ('b8', '1' x $b . '.' x (8 - $b));
$main->DefineBitmap("stipple$b" => 8, 1, $stipple_bits->[$b-1]);
}
 
#-----------------------------------------------------------------
# Menu
#-----------------------------------------------------------------
 
# Menu bar
my $menu_bar = $main->Menu;
$main->optionAdd("*tearOff", "false");
$main->configure ('-menu' => $menu_bar);
 
my $menu_file = $menu_bar->cascade('-label' => $Translate{'File'});
$menu_file->command('-label' => $Translate{'Preferences'},
'-command' => [\&Configure],
);
$menu_file->separator;
$menu_file->command('-label' => $Translate{'Exit'},
'-command' => [\&CbExit ],
);
 
my $menu_debug = $menu_bar->cascade(-label => $Translate{'Debug'});
$menu_debug->command('-label' => $Translate{'NcOsdDataset'},
'-command' => [\&DisplayHash, \%MkOsd, $Translate{'NcOsdDataset'}, "Display Refresh Heartbeat"],
);
$menu_debug->command('-label' => $Translate{'NcTargetDataset'},
'-command' => [\&DisplayHash, \%MkTarget, $Translate{'NcTargetDataset'}, "Display Refresh Heartbeat"],
);
$menu_debug->command('-label' => $Translate{'NcDebugDataset'},
'-command' => [\&DisplayHash, \%MkNcDebug, $Translate{'NcDebugDataset'}, "Display Refresh Heartbeat"],
);
$menu_debug->command('-label' => $Translate{'NcOther'},
'-command' => [\&DisplayHash, \%Mk, $Translate{'NcOther'}, "Display Refresh Heartbeat"],
);
$menu_debug->separator;
$menu_debug->command('-label' => $Translate{'TrackingDebugDataset'},
'-command' => [\&DisplayHash, \%MkTrack, $Translate{'TrackingDebugDataset'}, "Display Refresh Heartbeat"],
);
$menu_debug->separator;
$menu_debug->command('-label' => $Translate{'MkDebugSim'},
'-command' => \&MkSim,
);
#$menu_debug->command('-label' => $Translate{'MapDebugDataset'},
# '-command' => [\&DisplayHash, \%Map, $Translate{'MapDebugDataset'}, "Display"],
# );
 
my $menu_help = $menu_bar->cascade(-label => $Translate{'Help'});
$menu_help->command('-label' => 'Version',
'-command' => [\&DisplayHash, \%Version, $Translate{'Version'}, "Display"],
);
$menu_help->separator;
$menu_help->command('-label' => $Translate{'About'},
'-command' => sub
{
my $License = <<EOF;
Copyright (C) 2009 Rainer Walther (rainerwalther-mail\@web.de)
 
Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
 
See LICENSE.TXT
EOF
 
my $DlgAbout = $frame_map->Dialog('-title' => $Translate{'AboutMissionCockpit'},
'-text' => "$License",
'-buttons' => ['OK'],
'-bitmap' => 'info',
);
$DlgAbout->Show;
});
 
 
# Hauptfenster Statuszeile
$frame_status = $main->Frame( '-background' => 'lightgray',
) -> pack('-side' => 'bottom',
'-anchor' => 'w',
'-fill' => 'none',
'-expand' => 'y',
);
$status_line = $frame_status->Label ('-text' => $Translate{'StatusLine'},
) -> pack ('-side' => 'bottom',
);
 
#-----------------------------------------------------------------
# Frames
#-----------------------------------------------------------------
 
#
# Frame: Map
#
$frame_map = $main->Frame( '-background' => 'lightgray',
'-relief' => 'sunken',
'-borderwidth' => 5,
) -> pack('-side' => 'top',
'-fill' => 'x',
);
 
# Map Überschrift
$frame_map_top = $frame_map->Frame() -> pack( '-side' => 'top',
'-expand' => 'x',
'-anchor' => 'w',
);
 
$frame_map_top->Label ('-text' => "$Translate{'Map'}: $Map{'Name'} ($Map{'File'})",
'-background' => 'lightgray',
'-relief' => 'flat',
) -> pack( '-side' => 'left' );
 
# Map Statuszeile
$map_status = $frame_map->Frame( '-background' => 'lightgray',
) -> pack('-side' => 'bottom',
'-anchor' => 'w',
'-fill' => 'none',
'-expand' => 'y',
);
$map_status_line = $map_status->Label ( '-text' => $Translate{'StatusLine'},
'-background' => 'lightgray',
) -> pack ('-side' => 'bottom',);
 
#
# Map Canvas
#
 
$map_canvas = $frame_map->Canvas( '-width' => $MapSizeX,
'-height' => $MapSizeY,
'-cursor' => 'cross',
) -> pack();
 
 
# Images and Icons on canvas
my @Icons = (
# Image Tag File Pos_x Pos_y
'Map', 'Map', "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}", 0, 0,
'HeartbeatSmall', 'Heartbeat', "$Cfg->{'mkcockpit'}->{'IconHeartSmall'}", $MapSizeX/4, 10,
'HeartbeatLarge', 'Heartbeat', "$Cfg->{'mkcockpit'}->{'IconHeartLarge'}", $MapSizeX/4, -100,
'Satellite-Photo', 'Satellite', "$Cfg->{'mkcockpit'}->{'IconSatellite'}", $MapSizeX-300, -100,
'Antenna-Photo', 'Track-Antenna',"$Cfg->{'track'}->{'IconAntenna'}", 0, -50,
'POI-Photo', 'POI' ,"$Cfg->{'mkcockpit'}->{'IconPoi'}", $Poi_x, $Poi_y,
'Waypoint-Photo', 'Waypoint', "$Cfg->{'mkcockpit'}->{'IconWaypoint'}", 0, -150,
'Target-Photo', 'Target', "$Cfg->{'mkcockpit'}->{'IconTarget'}", 0, -100,
'Fox-Photo', 'Fox', "$Cfg->{'mkcockpit'}->{'IconFox'}", $MapSizeX/2-100, $MapSizeY/2,
'WpPlay-Foto', 'Wp-PlayPause', "$Cfg->{'waypoint'}->{'IconPlay'}", $MapSizeX/2+150, $MapSizeY-48,
'WpPause-Foto', 'Wp-PlayPause', "$Cfg->{'waypoint'}->{'IconPause'}", $MapSizeX/2+150, -100,
'WpStop-Foto', 'Wp-Stop', "$Cfg->{'waypoint'}->{'IconStop'}", $MapSizeX/2+200, $MapSizeY-48,
'WpNext-Foto', 'Wp-Next', "$Cfg->{'waypoint'}->{'IconNext'}", $MapSizeX/2+50, $MapSizeY-48,
'WpPrev-Foto', 'Wp-Prev', "$Cfg->{'waypoint'}->{'IconPrev'}", $MapSizeX/2, $MapSizeY-48,
'WpFirst-Foto', 'Wp-First', "$Cfg->{'waypoint'}->{'IconFirst'}", $MapSizeX/2-50, $MapSizeY-48,
'WpLast-Foto', 'Wp-Last', "$Cfg->{'waypoint'}->{'IconLast'}", $MapSizeX/2+100, $MapSizeY-48,
'WpHome-Foto', 'Wp-Home', "$Cfg->{'waypoint'}->{'IconHome'}", $MapSizeX/2-100, $MapSizeY-48,
'WpRecord-Foto', 'Wp-Record', "$Cfg->{'waypoint'}->{'IconRecord'}", $MapSizeX/2-150, $MapSizeY-48,
'WpRandomOff-Foto', 'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomOff'}", $MapSizeX/2-200, -100,
'WpRandomOn-Foto', 'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomOn'}", $MapSizeX/2-200, $MapSizeY-48,
'WpRandomMap-Foto', 'Wp-WptRandom', "$Cfg->{'waypoint'}->{'IconRandomMap'}", $MapSizeX/2-200, -100,
'WpWpt-Foto', 'Wp-WptKml', "$Cfg->{'waypoint'}->{'IconWpt'}", $MapSizeX/2-250, $MapSizeY-48,
'WpKml-Foto', 'Wp-WptKml', "$Cfg->{'waypoint'}->{'IconKml'}", $MapSizeX/2-250, -100 ,
);
my $i = 0;
for $Icon (0 .. $#Icons/5)
{
my $Image = $Icons[$i++];
my $Tag = $Icons[$i++];
my $File = $Icons[$i++];
my $Pos_x = $Icons[$i++];
my $Pos_y = $Icons[$i++];
 
$map_canvas->Photo( $Image,
'-file' => $File,
);
$map_canvas->createImage( $Pos_x, $Pos_y,
'-tags' => $Tag,
'-anchor' => 'nw',
'-image' => $Image,
);
}
 
 
# Calibration Points
$map_canvas->createLine ( $Map{'P1_x'}-8, $Map{'P1_y'},
$Map{'P1_x'}+8, $Map{'P1_y'},
$Map{'P1_x'}, $Map{'P1_y'},
$Map{'P1_x'}, $Map{'P1_y'}-8,
$Map{'P1_x'}, $Map{'P1_y'}+8,
'-tags' => 'Calibration',
'-arrow' => 'none',
'-fill' => 'red',
'-width' => 1,
);
$map_canvas->createLine ( $Map{'P2_x'}-8, $Map{'P2_y'},
$Map{'P2_x'}+8, $Map{'P2_y'},
$Map{'P2_x'}, $Map{'P2_y'},
$Map{'P2_x'}, $Map{'P2_y'}-8,
$Map{'P2_x'}, $Map{'P2_y'}+8,
'-tags' => 'Calibration',
'-arrow' => 'none',
'-fill' => 'red',
'-width' => 1,
);
 
# scale
my $x1 = $MapSizeX/2 +280;
my $x2 = $MapSizeX -30;
my $y1 = $MapSizeY - 20;
my $y2 = $MapSizeY - 15;
if ( $x2 - $x1 > 150 )
{
$x1 = $x2 - 150;
}
 
$map_canvas->createLine ( $x1, $y1,
$x1, $y2,
$x2, $y2,
$x2, $y1,
'-tags' => 'Scale',
'-arrow' => 'none',
'-fill' => 'red',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
'-width' => 1,
);
 
my ($Lat1, $Lon1) = &MapXY2Gps($x1, $y1);
my ($Lat2, $Lon2) = &MapXY2Gps($x2, $y2);
my ($Dist, $Bearing) = &MapGpsTo($Lat1, $Lon1, $Lat2, $Lon2 );
$Dist = sprintf ("%.2f m", $Dist);
$map_canvas->createText ( $x1 + ($x2 - $x1)/2 - 20, $y1 - ($y2 - $y1)/2,
'-tags' => 'Scale-Text',
'-text' => $Dist,
'-anchor' => 'w',
'-font' => '-*-Arial-Bold-R-Normal--*-120-*',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorScale'} || 'white',
);
 
# border polygon
$map_canvas->createPolygon( @Map{'Border'},
'-tags' => 'Map-Border',
'-fill' => '',
'-outline' => $Cfg->{'mkcockpit'}->{'ColorAirfield'}, '-width' => 2,
);
$map_canvas->raise('Map-Border', 'Map'); # Border above Map
 
 
# Balloon attached to Canvas
$map_balloon = $frame_map->Balloon('-statusbar' => $status_line, );
$map_balloon->attach($map_canvas,
'-balloonposition' => 'mouse',
'-state' => 'balloon',
'-msg' => { 'MK-Arrow' => $Translate{'Balloon-MK-Arrow'},
'MK-Home-Line' => $Translate{'Balloon-MK-Home-Line'},
'MK-Home-Dist' => $Translate{'Balloon-MK-Home-Dist'},
'MK-Target-Line' => $Translate{'Balloon-MK-Target-Line' },
'MK-Target-Dist' => $Translate{'Balloon-MK-Target-Dist'},
'MK-Speed' => $Translate{'Balloon-MK-Speed'},
'Map-Variometer' => $Translate{'Balloon-Map-Variometer' },
'Map-Variometer-Pointer' => $Translate{'Balloon-Map-Variometer-Pointer'},
'Map-Variometer-Skala' => $Translate{'Balloon-Map-Variometer-Pointer'},
'Fox' => $Translate{'Balloon-Fox'},
'Heartbeat' => $Translate{'Balloon-Heartbeat'},
'Satellite' => $Translate{'Balloon-Satellite'},
'Waypoint' => $Translate{'Balloon-Waypoint'},
'Map-Border' => $Translate{'Balloon-Map-Border'},
'Waypoint-Connector' => $Translate{'Balloon-Waypoint-Connector'},
'Wp-PlayPause' => $Translate{'Balloon-Wp-PlayPause'},
'Wp-Stop' => $Translate{'Balloon-Wp-Stop'},
'Wp-First' => $Translate{'Balloon-Wp-First'},
'Wp-Last' => $Translate{'Balloon-Wp-Last'},
'Wp-Next' => $Translate{'Balloon-Wp-Next'},
'Wp-Prev' => $Translate{'Balloon-Wp-Prev'},
'Wp-Home' => $Translate{'Balloon-Wp-Home'},
'Wp-WptKml' => $Translate{'Balloon-Wp-WptKml'},
'Wp-WptRandom' => $Translate{'Balloon-Wp-WptRandom'},
'Wp-Record' => $Translate{'Balloon-Wp-Record'},
'Track-Antenna' => $Translate{'Balloon-TrackAntenna'},
'POI' => $Translate{'Balloon-Poi'},
},
);
 
#
# Mouse button 1
#
 
# Button 1 Press
$map_canvas->CanvasBind("<Button-1>", sub
{
# print coords in status line
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my ($Lat, $Lon) = &MapXY2Gps($x, $y);
 
$map_status_line->configure ('-text' => "Lat: $Lat Lon: $Lon x: $x y: $y");
 
# save Coords and GPS-Pos for Button-Motion and Release
$Button1_x = $x;
$Button1_y = $y;
$Button1_Lat = $Lat;
$Button1_Lon = $Lon;
 
# copy Pixel-Coordinates to Clipboard
Clipboard->copy ("x=$x\r\n" . "y=$y\r\n" . "Lat=$Lat\r\n" . "Lon=$Lon\r\n");
});
 
# Button 1 Motion
$map_canvas->CanvasBind("<Button1-Motion>", sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
# delete old measuring line
$map_canvas->delete('Map-Measure');
 
my @Tags = $map_canvas->gettags($id);
if ( ( $Tags[0] eq "Map" or $Tags[0] eq "Map-Border") and
$x ne $Button1_x and $y ne $Button1_y )
{
# button moved on Map
 
# draw new measuring line
$map_canvas->createLine ( $Button1_x, $Button1_y, $x, $y,
'-tags' => 'Map-Measure',
'-arrow' => 'none',
'-fill' => 'white',
'-width' => 1,
);
 
# update status line
my ($Lat, $Lon) = &MapXY2Gps($x, $y);
my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
$Dist = sprintf ("%.2f m", $Dist);
$Bearing = sprintf ("%.2f degree", $Bearing);
 
$map_status_line->configure ('-text' => "Dist: $Dist Bearing: $Bearing");
}
});
 
# Button 1 Release
$map_canvas->CanvasBind("<Button1-ButtonRelease>", sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
# delete measuring line
$map_canvas->delete('Map-Measure');
 
my @Tags = $map_canvas->gettags($id);
if ( ( $Tags[0] eq "Map" or $Tags[0] eq "Map-Border") and
$x ne $Button1_x and $y ne $Button1_y )
{
# button released on Map
 
# update status line
my ($Lat, $Lon) = &MapXY2Gps($x, $y);
my ($Dist, $Bearing) = &MapGpsTo($Button1_Lat, $Button1_Lon, $Lat, $Lon);
$Dist = sprintf ("%.2f m", $Dist);
$Bearing = sprintf ("%.2f degree", $Bearing);
 
$map_status_line->configure ('-text' => "Dist: $Dist Bearing: $Bearing");
}
});
 
 
# Mouse button 1 for Fox
my $FoxOldx = 0;
my $FoxOldy = 0;
my $FoxTime = time;
&FoxHide(); # Show only in Player-Pause Mode
 
# Pick Fox
$map_canvas->bind('Fox' => '<Button-1>' => sub
{
# prepare to move Fox
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
$FoxOldx = $x;
$FoxOldy = $y;
$FoxTime = time;
});
 
# Move Fox
$map_canvas->bind('Fox' => '<Button1-Motion>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
$map_canvas->move($id => $x - $FoxOldx, $y - $FoxOldy);
$FoxOldx = $x;
$FoxOldy = $y;
if ( time > $FoxTime )
{
# wenn in Bewegung Koordinaten nur 1/s senden
my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
$x = $x0 + ($x1 - $x0)/2;
$y = $y1;
 
($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);
$FoxTime = time;
 
$map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat Lon: $PlayerPause_Lon x: $x y: $y");
}
});
 
# Release Fox
$map_canvas->bind('Fox' => '<Button1-ButtonRelease>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
$x = $x0 + ($x1 - $x0)/2;
$y = $y1;
 
($PlayerPause_Lat, $PlayerPause_Lon) = &MapXY2Gps($x, $y);
 
# Show user that Waypoints in MK are cleared
$WaypointsModified = 1;
&WpRedrawLines();
 
$map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $PlayerPause_Lat Lon: $PlayerPause_Lon x: $x y: $y");
});
 
# Pick Waypoint
my $WpOldx;
my $WpOldy;
$map_canvas->bind('Waypoint' => '<Button-1>' => sub
{
# prepare to move
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
$WpOldx = $x;
$WpOldy = $y;
});
# Move Waypoint
$map_canvas->bind('Waypoint' => '<Button1-Motion>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
# move icon and Wp-Number
my $WpIndex = &WpGetIndexFromId($id);
if ( $WpIndex >= 0 )
{
my $Tag = $Waypoints[$WpIndex]{'Tag'};
$map_canvas->move($Tag => $x - $WpOldx, $y - $WpOldy);
}
 
$WpOldx = $x;
$WpOldy = $y;
});
 
# Release Wp
$map_canvas->bind('Waypoint' => '<Button1-ButtonRelease>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
# take coords from lower/middle icon position
my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
$x = $x0 + ($x1 - $x0)/2;
$y = $y1;
 
# update Waypoint-Array
my $WpIndex = &WpGetIndexFromId($id);
if ( $WpIndex >= 0 )
{
# got it: set new coords
 
my ($Lat, $Lon) = &MapXY2Gps($x, $y);
my $Wp = $Waypoints[$WpIndex];
$Wp->{'MapX'} = $x;
$Wp->{'MapY'} = $y;
$Wp->{'Pos_Lat'} = $Lat;
$Wp->{'Pos_Lon'} = $Lon;
# redraw connector-lines
&WpRedrawLines();
 
# red connectors: Wp still have to be sent to MK
$map_canvas->itemconfigure('Waypoint-Connector',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorWpResend'},
);
$WaypointsModified = 1;
my $WpNum = $WpIndex + 1;
$map_status_line->configure ('-text' => "$Translate{'WpMoved'}: $WpNum -> Lat: $Lat Lon: $Lon x: $x y: $y");
}
});
 
# Mouse button 1 for POI
my $PoiOldx = 0;
my $PoiOldy = 0;
&PoiHide();
 
# Pick Poi
$map_canvas->bind('POI' => '<Button-1>' => sub
{
# prepare to move Icon
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
$PoiOldx = $x;
$PoiOldy = $y;
});
 
# Move POI
$map_canvas->bind('POI' => '<Button1-Motion>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
$map_canvas->move($id => $x - $PoiOldx, $y - $PoiOldy);
$PoiOldx = $x;
$PoiOldy = $y;
});
 
# Release POI
$map_canvas->bind('POI' => '<Button1-ButtonRelease>' => sub
{
my ($x, $y) = ($Tk::event->x, $Tk::event->y);
my $id = $map_canvas->find('withtag', 'current');
 
my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
$x = $x0 + ($x1 - $x0)/2;
$y = $y1;
 
($Poi_Lat, $Poi_Lon) = &MapXY2Gps($x, $y);
 
$map_status_line->configure ('-text' => "$Translate{'PoiMoved'}: -> Lat: $Poi_Lat Lon: $Poi_Lon x: $x y: $y");
});
 
 
# Reset Flight time
$map_canvas->bind('MK-OSD-Tim-Value' => '<Button-1>' => sub
{
$MkFlyingTime = 0;
});
 
# Reset ODO
$map_canvas->bind('MK-OSD-Odo-Value' => '<Button-1>' => sub
{
$OdoMeter = 0;
});
 
 
#
# Mouse button 3 context menu
#
my $map_menu = $map_canvas->Menu('-tearoff' => 0,
'-title' =>'None',
'-menuitems' =>
[
[Button => $Translate{'WpAddAndSend'}, -command => sub
{
# send Wp to MK
($Lat, $Lon) = &MapXY2Gps($Wp_x, $Wp_y);
&MkFlyTo ( '-lat' => $Lat,
'-lon' => $Lon,
'-mode' => "Waypoint"
);
 
# Add Wp to Waypoints list
&WpAdd ($MapCanvasX, $MapCanvasY);
 
# switch player to Wp mode and redraw waypoints
&PlayerWpt();
 
$map_status_line->configure ('-text' => "$Translate{'WpSavedAndSent'} -> Lat: $Lat Lon: $Lon");
}],
 
 
[Button => $Translate{'WpProperties'}, -command => sub
{
# find Wp-Hash for selected icon/tag
my $WpIndex = &WpGetIndexFromId($MapCanvasId);
if ( $WpIndex >= 0 )
{
my $Wp = $Waypoints[$WpIndex];
my $WpNum = $WpIndex + 1;
 
&DisplayHash ($Wp, "$Translate{'WpProperties'} $WpNum", "Edit Waypoint Refresh");
 
$map_status_line->configure ('-text' => "$Translate{'WpProperties'} $WpNum");
}
}],
[Button => $Translate{'WpResendAll'}, -command => sub
{
&WpSendAll();
$map_status_line->configure ('-text' => $Translate{'WpAllSent'});
}],
 
'', # Separator
[Button => $Translate{'WpLoadAndSend'}, -command => sub
{
my $WpFile = $main->getOpenFile('-defaultextension' => ".xml",
'-filetypes' =>
[['Waypoints', '.xml' ],
['All Files', '*', ],
],
'-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
'-title' => $Translate{'WpLoad'},
);
if ( -f $WpFile )
{
&WpLoadFile ($WpFile);
 
# send all Wp to MK
&WpSendAll();
 
# switch player to Wp mode and redraw waypoints
$PlayerRandomMode = 'STD';
&PlayerWpt();
$map_status_line->configure ('-text' => "$Translate{'WpLoadedAndSent'}: $WpFile");
}
}],
[Button => $Translate{'WpSave'}, -command => sub
{
my $WpFile = $main->getSaveFile('-defaultextension' => ".xml",
'-filetypes' =>
[['Waypoints', '.xml' ],
['All Files', '*', ],
],
'-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
'-title' => $Translate{'WpSave'},
);
 
&WpSaveFile ($WpFile);
$map_status_line->configure ('-text' => "$Translate{'WpSaved'}: $WpFile");
}],
'', # Separator
 
[Button => $Translate{'WpDelete'}, -command => sub
{
# find Wp-Hash for selected icon/tag
my $WpIndex = &WpGetIndexFromId($MapCanvasId);
if ( $WpIndex >= 0 )
{
&WpDelete ($WpIndex);
 
# redraw connector-lines
$WaypointsModified = 1;
&WpRedrawLines();
&WpRedrawIcons(); # wg. Wp-Nummern
 
my $WpNum = $WpIndex + 1;
$map_status_line->configure ('-text' => "$Translate{'WpDeleted'}: $WpNum");
}
}],
 
[Button => $Translate{'WpAllDeleteAndSend'}, -command => sub
{
undef @Waypoints;
$WpPlayerIndex = 0;
$WpPlayerHoldtime = -1;
 
# remove all Wp-Icons and Wp-Number on canvas
&WpHide();
 
&WpSendAll();
 
$map_status_line->configure ('-text' => "$Translate{'WpAllDeleted'}: $WpIndex");
}],
 
'', # Separator
 
[Button => $Translate{'KmlLoadAndPlay'}, -command => sub
{
$KmlFile = $main->getOpenFile('-defaultextension' => ".kml",
'-filetypes' =>
[['KML', '.kml' ],
['All Files', '*', ],
],
'-initialdir' => $Cfg->{'waypoint'}->{'KmlDir'},
'-title' => $Translate{'KmlLoad'},
);
if ( -f $KmlFile )
{
&KmlLoadFile($KmlFile);
 
# switch player to KML mode and redraw track
&PlayerKml();
 
$map_status_line->configure ('-text' => "$Translate{'KmlLoaded'}: $KmlFile" );
}
 
}],
 
'', # Separator
[Button => $Translate{'WpFlyImmediately'}, -command => sub
{
&MkFlyTo ( '-x' => $MapCanvasX,
'-y' => $MapCanvasY,
'-mode' => "Target"
);
 
# redraw connector-lines
$WaypointsModified = 1;
&WpRedrawLines();
 
$map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $Lat Lon: $Lon x: $MapCanvasX y: $MapCanvasY");
}],
]
);
$map_canvas->CanvasBind("<Button-3>" => [ sub
{
$map_canvas->focus;
my($w, $x, $y) = @_;
($MapCanvasX, $MapCanvasY) = ($Tk::event->x, $Tk::event->y);
$MapCanvasId = $map_canvas->find('withtag', 'current');
$map_menu->post($x, $y);
}, Ev('X'), Ev('Y') ] );
 
 
# Mouse bindings
$map_canvas->bind('Wp-PlayPause' => '<Button-1>' => \&CbPlayerPlayPause );
$map_canvas->bind('Wp-Next' => '<Button-1>' => \&CbPlayerNext );
$map_canvas->bind('Wp-Prev' => '<Button-1>' => \&CbPlayerPrev );
$map_canvas->bind('Wp-First' => '<Button-1>' => \&CbPlayerFirst );
$map_canvas->bind('Wp-Last' => '<Button-1>' => \&CbPlayerLast );
$map_canvas->bind('Wp-Home' => '<Button-1>' => \&CbPlayerHome );
$map_canvas->bind('Wp-Stop' => '<Button-1>' => \&CbPlayerStop );
$map_canvas->bind('Wp-WptKml' => '<Button-1>' => \&CbPlayerWptKml );
$map_canvas->bind('Wp-WptRandom' => '<Button-1>' => \&CbPlayerWptRandom );
$map_canvas->bind('Wp-Record' => '<Button-1>' => \&CbPlayerRecord );
 
 
# Focus Canvas, if any key pressed. Needed for the following key-bindings
$main->bind('<Any-Enter>' => sub { $map_canvas->Tk::focus });
 
# Disable default arrow-key bindings on canvas
$main->bind('Tk::Canvas',"<$_>",undef)for qw /Left Right Up Down/;
 
# keyboard bindings
$map_canvas->Tk::bind( '<Key-space>' , \&CbPlayerPlayPause );
$map_canvas->Tk::bind( '<Key-n>' , \&CbPlayerNext );
$map_canvas->Tk::bind( '<Key-p>' , \&CbPlayerPrev );
$map_canvas->Tk::bind( '<Key-f>' , \&CbPlayerFirst );
$map_canvas->Tk::bind( '<Key-l>' , \&CbPlayerLast );
$map_canvas->Tk::bind( '<Key-h>' , \&CbPlayerHome );
$map_canvas->Tk::bind( '<Key-s>' , \&CbPlayerStop );
$map_canvas->Tk::bind( '<Key-w>' , \&CbPlayerWptKml );
$map_canvas->Tk::bind( '<Key-k>' , \&CbPlayerWptKml );
$map_canvas->Tk::bind( '<Key-r>' , \&CbPlayerWptRandom );
$map_canvas->Tk::bind( '<Key-a>' , \&CbPlayerRecord );
$map_canvas->Tk::bind( '<Key-m>' , \&CbPlayerMute );
$map_canvas->Tk::bind( '<Key-v>' , \&CbPoi );
$map_canvas->Tk::bind( '<Key-0>' , [\&CbPlayerNum, "0"] );
$map_canvas->Tk::bind( '<Key-1>' , [\&CbPlayerNum, "1"] );
$map_canvas->Tk::bind( '<Key-2>' , [\&CbPlayerNum, "2"] );
$map_canvas->Tk::bind( '<Key-3>' , [\&CbPlayerNum, "3"] );
$map_canvas->Tk::bind( '<Key-4>' , [\&CbPlayerNum, "4"] );
$map_canvas->Tk::bind( '<Key-5>' , [\&CbPlayerNum, "5"] );
$map_canvas->Tk::bind( '<Key-6>' , [\&CbPlayerNum, "6"] );
$map_canvas->Tk::bind( '<Key-7>' , [\&CbPlayerNum, "7"] );
$map_canvas->Tk::bind( '<Key-8>' , [\&CbPlayerNum, "8"] );
$map_canvas->Tk::bind( '<Key-9>' , [\&CbPlayerNum, "9"] );
$map_canvas->Tk::bind( '<Key-Left>' , [\&CbPlayerMove, -1, 0] );
$map_canvas->Tk::bind( '<Key-Right>' , [\&CbPlayerMove, 1, 0] );
$map_canvas->Tk::bind( '<Key-Up>' , [\&CbPlayerMove, 0, 1] );
$map_canvas->Tk::bind( '<Key-Down>' , [\&CbPlayerMove, 0, -1] );
$map_canvas->Tk::bind( '<Key-Escape>', \&CbExit );
 
 
#
# dynamic objecs on canvas
#
 
# current MK position on canvas
$MkPos_x = $MapSizeX/2;
$MkPos_y = $MapSizeY/2;
 
# Line from MK to Home
$map_canvas->createLine ( $MapSizeX/2, $MapSizeY/2, $MapSizeX/2, $MapSizeY/2,
'-tags' => 'MK-Home-Line',
'-arrow' => 'none',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeLine'},
'-width' => 3,
);
# Text Entfernung positioniert an der Home-Linie
$map_canvas->createText ( $MapSizeX/2 + 8, $MapSizeY/2 - 8,
'-tags' => 'MK-Home-Dist',
'-text' => '0 m',
'-anchor' => 'w',
'-font' => '-*-Arial-Bold-R-Normal--*-200-*',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeDist'},
);
 
# Line from MK to Target, draw invisible out of sight
$map_canvas->createLine ( 0, -100, 0, -100,
'-tags' => 'MK-Target-Line',
'-arrow' => 'none',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetLine'},
'-width' => 3,
);
# Text Entfernung positioniert an der Target-Linie
$map_canvas->createText ( 0, -100,
'-tags' => 'MK-Target-Dist',
'-text' => '0 m',
'-anchor' => 'w',
'-font' => '-*-Arial-Bold-R-Normal--*-200-*',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetDist'},
);
 
# Line from MK to POI, draw invisible out of sight
$map_canvas->createLine ( 0, -200, 0, -200,
'-tags' => 'MK-POI-Line',
'-arrow' => 'none',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorPoiLine'},
'-stipple' => "stipple4",
'-width' => 1,
);
$map_canvas->lower('MK-POI-Line', 'Target');
 
# MK Geschwindigkeits-Vektor
$MapMkSpeedLen = 60; # Länge Speed-Zeiger
my $x0 = $MapSizeX/2;
my $y0 = $MapSizeY/2;
my $x1 = $MapSizeX/2;
my $y1 = $MapSizeY/2 - $MapMkSpeedLen;
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
'-tags' => 'MK-Speed',
'-arrow' => 'last',
'-arrowshape' => [10, 10, 3 ],
'-fill' => $Cfg->{'mkcockpit'}->{'ColorSpeedVector'},
'-width' => 4,
);
 
# MK als Pfeilspitze einer Linie darstellen
$MapMkLen = 25;
my $x0 = $MapSizeX/2;
my $y0 = $MapSizeY/2 + $MapMkLen/2;
my $x1 = $MapSizeX/2;
my $y1 = $MapSizeY/2 - $MapMkLen/2;
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
'-tags' => 'MK-Arrow',
'-arrow' => 'last',
'-arrowshape' => [25, 30, 10 ],
'-fill' => $Cfg->{'mkcockpit'}->{'ColorMkSatNo'},
'-width' => 1
);
# OSD Texte auf Karte anzeigen
my @Texts = (
# Tag Text Pos_x Pos_y Font
'MK-OSD-Tim-Label', "TIM", $MapSizeX/2 - 40, 20, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Tim-Value', "00:00", $MapSizeX/2, 20, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Tim-Left', "", $MapSizeX/2 + 90, 20, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Bat-Label', "BAT", $MapSizeX/2 - 40, 50, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Bat-Value', "0.0 V", $MapSizeX/2, 50, '-*-Arial-Bold-R-Normal--*-270-*',
# 'MK-OSD-Bat-Level', "", $MapSizeX/2 + 90, 50, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Spd-Label', "SPD", 10, 20, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Spd-Value', "0.0 km/h", 60, 20, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Alt-Label', "ALT", 10, 50, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Alt-Value', "0 m", 60, 50, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Odo-Label', "ODO", 10, 80, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Odo-Value', "0.000 km", 60, 80, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Sat-Label', "SAT", $MapSizeX - 230, 20, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Sat-Value', "0", $MapSizeX - 180, 20, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Wp-Label', "WPT", $MapSizeX - 230, 50, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Wp-Value', "0 / 0", $MapSizeX - 180, 50, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Mode-Label', "MOD", $MapSizeX - 230, 80, '-*-Arial-Bold-R-Normal--*-150-*',
'MK-OSD-Mode-Value', "", $MapSizeX - 180, 80, '-*-Arial-Bold-R-Normal--*-270-*',
'MK-OSD-Rec-Value', "", $MapSizeX - 180, 110, '-*-Arial-Bold-R-Normal--*-200-*',
);
my $i = 0;
for $Text (0 .. $#Texts/5)
{
my $Tag = $Texts[$i++];
my $Text = $Texts[$i++];
my $Pos_x = $Texts[$i++];
my $Pos_y = $Texts[$i++];
my $Font = $Texts[$i++];
 
$map_canvas->createText ( $Pos_x, $Pos_y,
'-tags' => $Tag,
'-text' => $Text,
'-font' => $Font,
'-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
'-anchor' => 'w',
);
 
}
 
 
# Variometer on canvas
my @Polygon;
for ( $y = -100; $y <= 100; $y += 10)
{
my $Len = 5;
if ( ($y % 50) == 0 )
{
$Len = 10;
$map_canvas->createText ( $Len+5, $MapSizeY/2 + $y,
'-tags' => 'Map-Variometer-Skala',
'-text' => sprintf ("%3d", -$y / 10),
'-anchor' => 'w',
'-font' => '-*-Arial-Normal-R-Normal--*-150-*',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
);
}
push @Polygon, ( 0, $MapSizeY/2 + $y);
push @Polygon, ($Len, $MapSizeY/2 + $y);
push @Polygon, ( 0, $MapSizeY/2 + $y);
}
 
$map_canvas->createLine(@Polygon,
'-tags' => 'Map-Variometer',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
'-width' => 2,
'-arrow' => 'none',
);
# Vario Pointer
$map_canvas->createPolygon( 5, $MapSizeY/2, 20, $MapSizeY/2+10, 20, $MapSizeY/2-10,
'-tags' => 'Map-Variometer-Pointer',
'-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometerPointer'},
'-outline' => 'black', '-width' => 1,
);
 
# Tracking Canvas
 
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
{
# Canvas size
$TrackSizeX = 125;
$TrackSizeY = 100;
$TrackOffY = $TrackSizeY - $MapSizeY + 20;
$TrackPtrLen = 50; # Länge Zeiger
 
# draw in map-canvas
$track_canvas = $map_canvas;
 
# Ziffernblatt
my $x0 = $TrackSizeX/2 - $TrackPtrLen;
my $y0 = $TrackSizeY + $TrackPtrLen - $TrackOffY;
my $x1 = $TrackSizeX/2 + $TrackPtrLen;
my $y1 = $TrackSizeY - $TrackPtrLen - $TrackOffY;
$track_canvas->createArc ( $x0, $y0, $x1, $y1,
'-extent' => '200',
'-start' => '-10',
'-style' => 'chord',
'-outline' => 'gray', '-width' => '1',
);
 
# Skala Ziffernblatt
for ($i=0; $i<=180; $i+=15)
{
my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 20) * cos( deg2rad $i );
my $y0 = $TrackSizeY - ($TrackPtrLen - 20) * sin( deg2rad $i ) - $TrackOffY;
my $x1 = $TrackSizeX/2 - ($TrackPtrLen - 28) * cos( deg2rad $i );
my $y1 = $TrackSizeY - ($TrackPtrLen - 28) * sin( deg2rad $i ) - $TrackOffY;
$track_canvas->createLine ( $x0, $y0, $x1, $y1,
'-fill' => 'white',
'-width' => 1,
);
}
 
# Skala Beschriftung Ziffernblatt
for ($i=0; $i<=180; $i+=45)
{
my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 12) * cos( deg2rad $i );
my $y0 = $TrackSizeY - ($TrackPtrLen - 12) * sin( deg2rad $i ) - $TrackOffY;
$track_canvas->createText ( $x0, $y0,
'-text' => $i - 90,
'-fill' => 'white',
);
}
 
# Ziffernblatt Beschriftung Einheit
my $x0 = $TrackSizeX/2;
my $y0 = $MapSizeY -6;
$track_canvas->createText ( $x0, $y0,
'-text' => "Antenne Winkel",
'-justify' => 'center',
'-fill' => 'white',
);
# Zeiger
my $x0 = $TrackSizeX/2;
my $y0 = $TrackSizeY - 0 - $TrackOffY;
my $x1 = $TrackSizeX/2;
my $y1 = $TrackSizeY - ($TrackPtrLen - 22) - $TrackOffY;
$track_ptr_id= $track_canvas->createLine ( $x0, $y0, $x1, $y1,
'-tags' => 'Track-Ptr',
'-arrow' => 'last',
'-arrowshape' => [20, 30, 5 ],
'-fill' => 'red',
'-width' => 8,
);
# Zeiger Center
my $Dia = 7;
my $x0 = $TrackSizeX/2 - $Dia;
my $y0 = $TrackSizeY + $Dia - $TrackOffY;
my $x1 = $TrackSizeX/2 + $Dia;
my $y1 = $TrackSizeY - $Dia - $TrackOffY;
$track_canvas->createArc ( $x0, $y0, $x1, $y1,
'-extent' => '359',
'-outline' => 'gray', '-width' => 1,
'-fill' => 'gray',
);
}
#
# Load Start Scenario
#
 
# Waypoint file
my $CfgVal = $Cfg->{'StartScenario'}->{'WpFile'};
if ( ! -f $CfgVal )
{
$CfgVal = $Cfg->{'waypoint'}->{'WpDir'} . "/" . $Cfg->{'StartScenario'}->{'WpFile'};
}
if ( -f $CfgVal )
{
&WpLoadFile($CfgVal);
 
# send all Wp to MK
&WpSendAll();
}
 
# KML file
my $CfgVal = $Cfg->{'StartScenario'}->{'KmlFile'};
if ( ! -f $CfgVal )
{
$CfgVal = $Cfg->{'waypoint'}->{'KmlDir'} . "/" . $Cfg->{'StartScenario'}->{'KmlFile'};
}
if ( -f $CfgVal )
{
&KmlLoadFile($CfgVal);
}
 
# PLayer Mode
my $CfgVal = $Cfg->{'StartScenario'}->{'PlayerMode'};
if ( $CfgVal =~ /Play/i ) { &PlayerPlay(); }
if ( $CfgVal =~ /Pause/i ) { &PlayerPause(); }
if ( $CfgVal =~ /Home/i ) { &PlayerHome(); }
if ( $CfgVal =~ /Stop/i ) { &PlayerStop(); }
 
# Player Random Mode
my $CfgVal = $Cfg->{'StartScenario'}->{'PlayerRandomMode'};
if ( $CfgVal eq "STD" ) { &PlayerRandomStd(); }
if ( $CfgVal eq "RND" ) { &PlayerRandomRnd(); }
if ( $CfgVal eq "MAP" ) { &PlayerRandomMap(); }
 
# PLayer Wpt/Kml Mode
my $CfgVal = $Cfg->{'StartScenario'}->{'PlayerWptKmlMode'};
if ( $CfgVal eq "WPT" ) { &PlayerWpt(); }
if ( $CfgVal eq "KML" ) { &PlayerKml(); }
 
# Audio TTS Mute
my $CfgVal = $Cfg->{'StartScenario'}->{'AudioMute'};
if ( $CfgVal =~ /y/i )
{
$TtsMute = 1;
}
 
 
#
# Timer
#
require "libmktimer.pl";
 
 
MainLoop(); # should never end
 
 
#
# GUI Call Back
#
 
# Player CallBack: Play/Pause button
sub CbPlayerPlayPause()
{
if ( ($PlayerMode eq "Pause") or ($PlayerMode eq "Stop") or ($PlayerMode eq "Home") )
{
&PlayerPlay();
}
else
{
&PlayerPause();
}
}
 
 
# Player CallBack: Next
sub CbPlayerNext()
{
if ( $PlayerMode ne 'Stop' )
{
if ( $PlayerWptKmlMode eq 'WPT' )
{
&WpTargetNext();
}
if ( $PlayerWptKmlMode eq 'KML' )
{
&KmlTargetNext();
}
}
}
 
 
# Player CallBack: Prev
sub CbPlayerPrev()
{
if ( $PlayerMode ne 'Stop' )
{
if ( $PlayerWptKmlMode eq 'WPT' )
{
&WpTargetPrev();
}
if ( $PlayerWptKmlMode eq 'KML' )
{
&KmlTargetPrev();
}
}
}
 
 
# Player CallBack: First
sub CbPlayerFirst()
{
if ( $PlayerMode ne 'Stop' )
{
if ( $PlayerWptKmlMode eq 'WPT' )
{
&WpTargetFirst();
}
if ( $PlayerWptKmlMode eq 'KML' )
{
&KmlTargetFirst();
}
}
}
 
# Player CallBack: Last
sub CbPlayerLast()
{
if ( $PlayerMode ne 'Stop' )
{
if ( $PlayerWptKmlMode eq 'WPT' )
{
&WpTargetLast();
}
if ( $PlayerWptKmlMode eq 'KML' )
{
&KmlTargetLast();
}
}
}
 
 
# Player CallBack: Home
sub CbPlayerHome()
{
if ( $PlayerMode ne 'Stop' )
{
&PlayerHome();
}
}
 
 
# Player CallBack: Stop
sub CbPlayerStop()
{
if ( $PlayerMode ne 'Stop' )
{
&PlayerStop();
}
}
 
 
# Player CallBack: Move MK in Pause-Mode
sub CbPlayerMove()
{
my ($Id, $DirX, $DirY) = @_;
 
if ( $PlayerMode eq 'Pause' and
$PlayerPause_Lat ne "" and $PlayerPause_Lon ne "" )
{
my $Dist = $Cfg->{'waypoint'}->{'PauseMoveDist'} || 1; # 1m default
 
my $BearingTop = &MapAngel() - 90.0;
my $BearingKey = rad2deg atan2($DirX, $DirY);
my $Bearing = $BearingTop + $BearingKey;
 
($PlayerPause_Lat, $PlayerPause_Lon) = &MapGpsAt($PlayerPause_Lat, $PlayerPause_Lon, $Dist, $Bearing)
}
}
 
 
# Player CallBack: Toggle WPT/KML button
sub CbPlayerWptKml()
{
 
if ( $PlayerWptKmlMode =~ /WPT/i )
{
&PlayerKml();
}
elsif ( $PlayerWptKmlMode =~ /KML/i )
{
&PlayerWpt();
}
}
 
 
# Player CallBack: Toggle Random modes. STD -> RND -> MAP
sub CbPlayerWptRandom()
{
if ( $PlayerRandomMode eq "STD" )
{
&PlayerRandomRnd();
}
elsif ( $PlayerRandomMode eq "RND" )
{
&PlayerRandomMap();
}
else
{
&PlayerRandomStd();
}
}
 
 
# Player CallBack: Togglle Record KML
sub CbPlayerRecord()
{
if ( $PlayerRecordMode =~ /REC/i )
{
&PlayerRecordOff();
}
elsif ( $PlayerRecordMode eq "" )
{
&PlayerRecordOn();
}
}
 
 
# Player CallBack: Number Keys
sub CbPlayerNum()
{
my ($Id, $Num) = @_;
 
$CbPlayerKey = "$CbPlayerKey" . "$Num";
}
 
 
# Player CallBack: mute TTS audio
sub CbPlayerMute()
{
if ( $TtsMute )
{
$TtsMute = 0;
}
else
{
$TtsMute = 1;
}
}
 
# Switch POI Mode
sub CbPoi()
{
if ( $PoiMode )
{
$PoiMode = 0;
&PoiHide();
}
else
{
$PoiMode = 1;
&PoiShow();
}
}
 
# CallBack: Exit Mission Cockpit
sub CbExit()
{
# stop antenna tracking
$TrackQueue->enqueue( "IDLE" );
 
# wait for tracker shutdown, with timeout
for ($i=0; $i < 5; $i++)
{
if ( $MkTrack{'State'} ne "Idle" )
{
sleep 1;
}
}
 
exit;
}
 
 
#
# subroutines moved to libmkcockpit.pl
# Timer moved to libmktimer.pl
#
 
 
__END__