kopia lustrzana https://github.com/dl2alf/AirScout
9478 wiersze
442 KiB
C#
9478 wiersze
442 KiB
C#
|
|
// AirScout Aircraft Scatter Prediction
|
|
// Copyright (C) DL2ALF
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Forms.VisualStyles;
|
|
using GMap.NET;
|
|
using GMap.NET.MapProviders;
|
|
using GMap.NET.WindowsForms;
|
|
using GMap.NET.WindowsForms.Markers;
|
|
using GMap.NET.WindowsForms.ToolTips;
|
|
using System.IO;
|
|
using System.IO.Ports;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using Zeptomoby.OrbitTools;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Reflection;
|
|
using System.Configuration;
|
|
using WinTest;
|
|
using System.Diagnostics;
|
|
using AquaControls;
|
|
using NDde;
|
|
using NDde.Server;
|
|
using NDde.Client;
|
|
using ScoutBase;
|
|
using ScoutBase.Core;
|
|
using ScoutBase.Database;
|
|
using ScoutBase.Elevation;
|
|
using ScoutBase.Stations;
|
|
using ScoutBase.Propagation;
|
|
using ScoutBase.Maps;
|
|
using ScoutBase.CAT;
|
|
using SerializableGenerics;
|
|
using Ionic.Zip;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using SQLiteDatabase;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
using System.Security.Cryptography;
|
|
using System.ComponentModel.Composition;
|
|
using System.ComponentModel.Composition.Hosting;
|
|
using OxyPlot;
|
|
using OxyPlot.WindowsForms;
|
|
using OxyPlot.Series;
|
|
using OxyPlot.Axes;
|
|
using System.Data.SQLite;
|
|
using DeviceId;
|
|
using AirScout.Properties;
|
|
using AirScout.Core;
|
|
using AirScout.Aircrafts;
|
|
using AirScout.PlaneFeeds;
|
|
using AirScout.AircraftPositions;
|
|
using AirScout.Signals;
|
|
using AirScout.PlaneFeeds.Plugin.MEFContract;
|
|
using AirScout.CAT;
|
|
using System.Security.RightsManagement;
|
|
using System.Web;
|
|
|
|
namespace AirScout
|
|
{
|
|
|
|
|
|
public partial class MapDlg : Form
|
|
{
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Application Directory")]
|
|
public string AppDirectory
|
|
{
|
|
get
|
|
{
|
|
return Application.StartupPath.TrimEnd(Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Local Application Data Directory")]
|
|
public string AppDataDirectory
|
|
{
|
|
get
|
|
{
|
|
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Application.CompanyName, Application.ProductName).TrimEnd(Path.DirectorySeparatorChar);
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Logfile Directory")]
|
|
public string LogDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string logdir = Properties.Settings.Default.Log_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
logdir = logdir.Replace('\\', Path.DirectorySeparatorChar);
|
|
logdir = logdir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(logdir))
|
|
logdir = "Log";
|
|
// replace variables, if any
|
|
logdir = VC.ReplaceAllVars(logdir);
|
|
// remove directory separator chars at begin and end
|
|
logdir = logdir.TrimStart(Path.DirectorySeparatorChar);
|
|
logdir = logdir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!logdir.Contains(Path.VolumeSeparatorChar))
|
|
logdir = Path.Combine(AppDataDirectory, logdir);
|
|
return logdir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Tempfile Directory")]
|
|
public string TmpDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string tmpdir = Properties.Settings.Default.Tmp_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
tmpdir = tmpdir.Replace('\\', Path.DirectorySeparatorChar);
|
|
tmpdir = tmpdir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(tmpdir))
|
|
tmpdir = "Tmp";
|
|
// replace variables, if any
|
|
tmpdir = VC.ReplaceAllVars(tmpdir);
|
|
// remove directory separator chars at begin and end
|
|
tmpdir = tmpdir.TrimStart(Path.DirectorySeparatorChar);
|
|
tmpdir = tmpdir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!tmpdir.Contains(Path.VolumeSeparatorChar))
|
|
tmpdir = Path.Combine(AppDataDirectory, tmpdir);
|
|
return tmpdir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Database Directory")]
|
|
public string DatabaseDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string databasedir = Properties.Settings.Default.Database_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
databasedir = databasedir.Replace('\\', Path.DirectorySeparatorChar);
|
|
databasedir = databasedir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(databasedir))
|
|
databasedir = "Database";
|
|
// replace variables, if any
|
|
databasedir = VC.ReplaceAllVars(databasedir);
|
|
// remove directory separator chars at begin and end
|
|
databasedir = databasedir.TrimStart(Path.DirectorySeparatorChar);
|
|
databasedir = databasedir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!databasedir.Contains(Path.VolumeSeparatorChar))
|
|
databasedir = Path.Combine(AppDataDirectory, databasedir);
|
|
return databasedir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Icon Directory")]
|
|
public string IconDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string icondir = Properties.Settings.Default.Icon_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
icondir = icondir.Replace('\\', Path.DirectorySeparatorChar);
|
|
icondir = icondir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(icondir))
|
|
icondir = "Icon";
|
|
// replace variables, if any
|
|
icondir = VC.ReplaceAllVars(icondir);
|
|
// remove directory separator chars at begin and end
|
|
icondir = icondir.TrimStart(Path.DirectorySeparatorChar);
|
|
icondir = icondir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!icondir.Contains(Path.VolumeSeparatorChar))
|
|
icondir = Path.Combine(AppDataDirectory, icondir);
|
|
return icondir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Elevation Directory")]
|
|
public string ElevationDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string elevationdir = Properties.Settings.Default.Elevation_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
elevationdir = elevationdir.Replace('\\', Path.DirectorySeparatorChar);
|
|
elevationdir = elevationdir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(elevationdir))
|
|
elevationdir = "elevation";
|
|
// replace variables, if any
|
|
elevationdir = VC.ReplaceAllVars(elevationdir);
|
|
// remove directory separator chars at begin and end
|
|
elevationdir = elevationdir.TrimStart(Path.DirectorySeparatorChar);
|
|
elevationdir = elevationdir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!elevationdir.Contains(Path.VolumeSeparatorChar))
|
|
elevationdir = Path.Combine(AppDataDirectory, elevationdir);
|
|
return elevationdir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Plugin Directory")]
|
|
public string PluginDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string plugindir = Properties.Settings.Default.Plugin_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
plugindir = plugindir.Replace('\\', Path.DirectorySeparatorChar);
|
|
plugindir = plugindir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(plugindir))
|
|
plugindir = "plugin";
|
|
// replace variables, if any
|
|
plugindir = VC.ReplaceAllVars(plugindir);
|
|
// remove directory separator chars at begin and end
|
|
plugindir = plugindir.TrimStart(Path.DirectorySeparatorChar);
|
|
plugindir = plugindir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!plugindir.Contains(Path.VolumeSeparatorChar))
|
|
plugindir = Path.Combine(AppDataDirectory, plugindir);
|
|
return plugindir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Rig Directory")]
|
|
public string RigDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string rigdir = Properties.Settings.Default.Rig_Directory;
|
|
// replace Windows/Linux directory spearator chars
|
|
rigdir = rigdir.Replace('\\', Path.DirectorySeparatorChar);
|
|
rigdir = rigdir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(rigdir))
|
|
rigdir = "rig";
|
|
// replace variables, if any
|
|
rigdir = VC.ReplaceAllVars(rigdir);
|
|
// remove directory separator chars at begin and end
|
|
rigdir = rigdir.TrimStart(Path.DirectorySeparatorChar);
|
|
rigdir = rigdir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!rigdir.Contains(Path.VolumeSeparatorChar))
|
|
rigdir = Path.Combine(AppDataDirectory, rigdir);
|
|
return rigdir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Plane Positions Directory")]
|
|
public string PlanePositionsDirectory
|
|
{
|
|
get
|
|
{
|
|
// get Property
|
|
string posdir = Properties.Settings.Default.Planes_PositionsDirectory;
|
|
// replace Windows/Linux directory spearator chars
|
|
posdir = posdir.Replace('\\', Path.DirectorySeparatorChar);
|
|
posdir = posdir.Replace('/', Path.DirectorySeparatorChar);
|
|
// set to default value if empty
|
|
if (String.IsNullOrEmpty(posdir))
|
|
posdir = "PlanePositions";
|
|
// replace variables, if any
|
|
posdir = VC.ReplaceAllVars(posdir);
|
|
// remove directory separator chars at begin and end
|
|
posdir = posdir.TrimStart(Path.DirectorySeparatorChar);
|
|
posdir = posdir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!posdir.Contains(Path.VolumeSeparatorChar))
|
|
posdir = Path.Combine(AppDataDirectory, TmpDirectory, posdir);
|
|
return posdir;
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("Directories")]
|
|
[DescriptionAttribute("Web Server Directory")]
|
|
public string WebserverDirectory
|
|
{
|
|
get
|
|
{
|
|
if (Debugger.IsAttached)
|
|
{
|
|
// use source code directory when in debug mode
|
|
string dir = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName, "wwwroot");
|
|
return dir;
|
|
}
|
|
else
|
|
return Path.Combine(Application.StartupPath, "wwwroot");
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("General")]
|
|
[DescriptionAttribute("Main Splitter Distance")]
|
|
private int MainSplitterDistance
|
|
{
|
|
get
|
|
{
|
|
return sc_Main.SplitterDistance;
|
|
}
|
|
set
|
|
{
|
|
// check bounds
|
|
if ((value > 0) && (value < this.Width))
|
|
sc_Main.SplitterDistance = value;
|
|
else
|
|
sc_Main.SplitterDistance = this.Width - gb_Map_Info_DefaultWidth;
|
|
Console.WriteLine("Setting MainSplitterDistance: " + this.Width + "--->" + sc_Main.SplitterDistance);
|
|
}
|
|
}
|
|
|
|
[CategoryAttribute("General")]
|
|
[DescriptionAttribute("Map Splitter Distance")]
|
|
private int MapSplitterDistance
|
|
{
|
|
get
|
|
{
|
|
return sc_Map.SplitterDistance;
|
|
}
|
|
set
|
|
{
|
|
// check bounds
|
|
if ((value > 0) && (value < this.Height))
|
|
sc_Map.SplitterDistance = value;
|
|
else
|
|
sc_Map.SplitterDistance = this.Height - tc_Main_DefaultHeight;
|
|
Console.WriteLine("Setting MapSplitterDistance: " + this.Height + "--->" + sc_Map.SplitterDistance);
|
|
}
|
|
}
|
|
|
|
[ImportMany(AllowRecomposition = true)] // This is a signal to the MEF framework to load all matching exported assemblies.
|
|
public List<Lazy<IPlaneFeedPlugin>> LazyPlaneFeedPlugins = new List<Lazy<IPlaneFeedPlugin>>();
|
|
public List<IPlaneFeedPlugin> PlaneFeedPlugins = new List<IPlaneFeedPlugin>();
|
|
|
|
// Default colors
|
|
private readonly new Color DefaultBackColor = SystemColors.Control;
|
|
private readonly new Color DefaultForeColor = Color.Black;
|
|
|
|
// Log
|
|
public static LogWriter Log;
|
|
|
|
public VarConverter VC = new VarConverter();
|
|
|
|
private int cntdn = 0;
|
|
|
|
DateTime CurrentTime = DateTime.UtcNow;
|
|
|
|
// FlightRadar
|
|
PlaneInfoCache Planes = new PlaneInfoCache();
|
|
SortedList<string, PlaneInfo> ActivePlanes = new SortedList<string, PlaneInfo>();
|
|
private DateTime History_OldestEntry = DateTime.MinValue;
|
|
private DateTime History_YoungestEntry = DateTime.MinValue;
|
|
private List<string> SelectedPlanes = new List<string>();
|
|
|
|
// Path
|
|
public List<ElevationPathDesignator> ElevationPaths = new List<ElevationPathDesignator>();
|
|
public List<PropagationPathDesignator> PropagationPaths = new List<PropagationPathDesignator>();
|
|
|
|
// Map
|
|
// Overlays
|
|
GMapOverlay gmo_Routes = new GMapOverlay("Routes");
|
|
GMapOverlay gmo_PropagationPaths = new GMapOverlay("PropagationPaths");
|
|
GMapOverlay gmo_Objects = new GMapOverlay("Objects");
|
|
GMapOverlay gmo_Planes = new GMapOverlay("Planes");
|
|
GMapOverlay gmo_Airports = new GMapOverlay("Airports");
|
|
GMapOverlay gmo_Callsigns = new GMapOverlay("Callsigns");
|
|
GMapOverlay gmo_NearestPaths = new GMapOverlay("PropagationPaths");
|
|
GMapOverlay gmo_NearestPlanes = new GMapOverlay("Planes");
|
|
GMapOverlay gmo_Locators = new GMapOverlay("Locators");
|
|
GMapOverlay gmo_Distances = new GMapOverlay("Distances");
|
|
GMapOverlay gmo_CallsignDetails = new GMapOverlay("CallsignDetails");
|
|
|
|
// Routes
|
|
GMapRoute gmr_FullPath;
|
|
GMapRoute gmr_VisiblePpath;
|
|
GMapRoute gmr_NearestFull;
|
|
GMapRoute gmr_NearestVisible;
|
|
|
|
// Markers
|
|
GMapMarker gmm_MyLoc;
|
|
GMapMarker gmm_DXLoc;
|
|
GMapMarker gmm_CurrentMarker;
|
|
|
|
// Bitmap indices
|
|
private int bmindex_darkorange;
|
|
private int bmindex_lightgreen;
|
|
private int bmindex_red;
|
|
private int bmindex_gray;
|
|
private int bmindex_magenta;
|
|
|
|
// Tooltip font
|
|
public Font ToolTipFont;
|
|
|
|
// dragging
|
|
bool isDraggingMarker = false;
|
|
bool isDraggingMap = false;
|
|
|
|
// Default width of right info box (get on startup as set in Designer)
|
|
int gb_Map_Info_DefaultWidth = 0;
|
|
|
|
// Default height of bottom tab control (get on startup as set in Designer)
|
|
int tc_Main_DefaultHeight = 0;
|
|
|
|
int gb_Map_Info_MaximizedHeight = 0;
|
|
int gb_Map_Zoom_MaximizedHeight = 0;
|
|
int gb_Map_Filter_MaximizedHeigth = 0;
|
|
int gb_Map_Alarms_MaximizedHeight = 0;
|
|
int gb_Map_Info_MinimizedHeight = 0;
|
|
int gb_Map_Zoom_MinimizedHeight = 0;
|
|
int gb_Map_Filter_MinimizedHeigth = 0;
|
|
int gb_Map_Alarms_MinimizedHeight = 0;
|
|
|
|
// Plane feeds
|
|
public PlaneFeed bw_PlaneFeed1;
|
|
public PlaneFeed bw_PlaneFeed2;
|
|
public PlaneFeed bw_PlaneFeed3;
|
|
|
|
// Startup
|
|
private bool FirstRun = true;
|
|
private bool CleanRun = false;
|
|
|
|
private Splash SplashDlg;
|
|
|
|
// Background workers
|
|
public ElevationDatabaseUpdater bw_GLOBEUpdater = new ElevationDatabaseUpdater();
|
|
public ElevationDatabaseUpdater bw_SRTM3Updater = new ElevationDatabaseUpdater();
|
|
public ElevationDatabaseUpdater bw_SRTM1Updater = new ElevationDatabaseUpdater();
|
|
public ElevationDatabaseUpdater bw_ASTER3Updater = new ElevationDatabaseUpdater();
|
|
public ElevationDatabaseUpdater bw_ASTER1Updater = new ElevationDatabaseUpdater();
|
|
|
|
public StationDatabaseUpdater bw_StationDatabaseUpdater = new StationDatabaseUpdater();
|
|
public AircraftDatabaseUpdater bw_AircraftDatabaseUpdater = new AircraftDatabaseUpdater();
|
|
|
|
public AircraftPositionDatabaseMaintainer bw_AircraftDatabaseMaintainer = new AircraftPositionDatabaseMaintainer();
|
|
|
|
public PathCalculator bw_GLOBEPathCalculator = new PathCalculator(ELEVATIONMODEL.GLOBE);
|
|
public PathCalculator bw_SRTM3PathCalculator = new PathCalculator(ELEVATIONMODEL.SRTM3);
|
|
public PathCalculator bw_SRTM1PathCalculator = new PathCalculator(ELEVATIONMODEL.SRTM1);
|
|
public PathCalculator bw_ASTER3PathCalculator = new PathCalculator(ELEVATIONMODEL.ASTER3);
|
|
public PathCalculator bw_ASTER1PathCalculator = new PathCalculator(ELEVATIONMODEL.ASTER1);
|
|
|
|
public CATUpdater bw_CATUpdater = new CATUpdater();
|
|
public CATWorker bw_CAT = new CATWorker();
|
|
|
|
public MapPreloader bw_MapPreloader = new MapPreloader();
|
|
|
|
// Operating modes
|
|
AIRSCOUTPATHMODE PathMode = AIRSCOUTPATHMODE.NONE;
|
|
AIRSCOUTLIFEMODE LifeMode = AIRSCOUTLIFEMODE.NONE;
|
|
AIRSCOUTPLAYMODE PlayMode = AIRSCOUTPLAYMODE.NONE;
|
|
|
|
private int Time_Offline_Interval = 0;
|
|
|
|
// Charting
|
|
|
|
// path chart
|
|
PlotModel pm_Path = new PlotModel();
|
|
PlotView pv_Path = new PlotView();
|
|
LinearAxis Path_X = new LinearAxis();
|
|
LinearAxis Path_Y = new LinearAxis();
|
|
AreaSeries Path_Elevation = new AreaSeries();
|
|
LineSeries Min_H1 = new LineSeries();
|
|
LineSeries Min_H2 = new LineSeries();
|
|
LineSeries Max_H = new LineSeries();
|
|
AreaSeries Min_H = new AreaSeries();
|
|
LineSeries Planes_Hi = new LineSeries();
|
|
LineSeries Planes_Lo = new LineSeries();
|
|
|
|
// elevation chart
|
|
PlotModel pm_Elevation = new PlotModel();
|
|
PlotView pv_Elevation = new PlotView();
|
|
LinearAxis Elevation_X = new LinearAxis();
|
|
LinearAxis Elevation_Y = new LinearAxis();
|
|
AreaSeries Elevation = new AreaSeries();
|
|
LineSeries LOS = new LineSeries();
|
|
|
|
// spectrum chart
|
|
PlotModel pm_Spectrum = new PlotModel();
|
|
PlotView pv_Spectrum = new PlotView();
|
|
LinearAxis Spectrum_X = new LinearAxis();
|
|
LinearAxis Spectrum_Y = new LinearAxis();
|
|
LineSeries Spectrum = new LineSeries();
|
|
AreaSeries SpectrumRecord = new AreaSeries();
|
|
int SpectrumPointsCount = 0;
|
|
int SpectrumMaxPoints = 600;
|
|
|
|
// Webbrowser
|
|
private System.Windows.Forms.WebBrowser wb_News = null;
|
|
|
|
CultureInfo LocalCulture;
|
|
|
|
// Watchlist control
|
|
private bool WatchlistUpdating = false;
|
|
private bool WatchlistAllCheckedChanging = false;
|
|
bool WatchlistAllChecked = false;
|
|
CheckBoxState WatchlistAllCheckedState = CheckBoxState.UncheckedNormal;
|
|
System.Drawing.Point WatchlistOldMousePos = new System.Drawing.Point(0, 0);
|
|
|
|
// Analysis
|
|
private List<DateTime> AllLastUpdated = new List<DateTime>();
|
|
private List<AircraftPositionDesignator> AllPositions = new List<AircraftPositionDesignator>();
|
|
private long AircraftPositionsCount = 0;
|
|
|
|
// Nearest plane
|
|
private PlaneInfo NearestPlane = null;
|
|
|
|
// Airports
|
|
private List<AirportDesignator> Airports = new List<AirportDesignator>();
|
|
|
|
// Session key
|
|
public string SessionKey = "";
|
|
|
|
// CAT
|
|
public IRig ConnectedRig = null;
|
|
public RIGSTATUS RigStatus = RIGSTATUS.NONE;
|
|
|
|
|
|
// Tracking & rotator control
|
|
AIRSCOUTTRACKMODE TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
TRACKSTATUS TrackStatus = TRACKSTATUS.NONE;
|
|
ROTSTATUS RotStatus = ROTSTATUS.NONE;
|
|
TrackValues TrackValues = null;
|
|
|
|
// Gauges display
|
|
public Color GaugesColor = Color.Black;
|
|
public Font TrackDisplayFont = new Font("Courier New", 16, FontStyle.Bold);
|
|
|
|
// Location grid updating
|
|
public bool UpdateLocationGrid = false;
|
|
|
|
#region Startup & Initialization
|
|
|
|
public MapDlg()
|
|
{
|
|
// save current local LocalCulture
|
|
LocalCulture = Application.CurrentCulture;
|
|
|
|
// force culture invariant language for GUI
|
|
Application.CurrentCulture = CultureInfo.InvariantCulture;
|
|
|
|
// set security protocol to TLS1.2 globally
|
|
// this will work even on .NET 4.0 for most operating systems > Windows XP
|
|
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; //TLS 1.2
|
|
|
|
InitializeComponent();
|
|
|
|
// Running on Windows or Linux/Mono?
|
|
if (SupportFunctions.IsMono)
|
|
{
|
|
Console.WriteLine("Checking system: Running on Linux/Mono.");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Checking system: Running on Windows.");
|
|
}
|
|
// do basic initialization
|
|
this.Text = "AirScout - Aircraft Scatter Prediction V" + Application.ProductVersion + " (c) 2013-2020 DL2ALF";
|
|
|
|
// create a new renderer wich is clipping the status text on overflow
|
|
ss_Main.Renderer = new ClippingToolStripRenderer();
|
|
|
|
// initialize settings
|
|
InitializeSettings();
|
|
|
|
// initialize charting
|
|
InitializeCharts();
|
|
|
|
// Initilialize Webbrowser
|
|
InitializeWebbrowser();
|
|
|
|
// check for command line args
|
|
string[] args = Environment.GetCommandLineArgs();
|
|
if ((args != null) && (args.Count() > 1))
|
|
{
|
|
// try to clean installation & database
|
|
if ((args[1].ToUpper() == "/CLEAN") ||
|
|
(args[1].ToUpper() == "-CLEAN"))
|
|
{
|
|
CleanupDlg Dlg = new CleanupDlg(this);
|
|
DialogResult result = Dlg.ShowDialog();
|
|
// exit immediately if user closes the form without pressing a button
|
|
if (result == DialogResult.Abort)
|
|
System.Environment.Exit(-1);
|
|
if (result == DialogResult.OK)
|
|
{
|
|
// re-initialize settings as they can be lost during clean-up
|
|
InitializeSettings();
|
|
// set a clean run flag
|
|
CleanRun = true;
|
|
}
|
|
}
|
|
}
|
|
// set elevation database update event handler
|
|
bw_GLOBEUpdater.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationDatabaseUpdater_ProgressChanged);
|
|
bw_SRTM3Updater.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationDatabaseUpdater_ProgressChanged);
|
|
bw_SRTM1Updater.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationDatabaseUpdater_ProgressChanged);
|
|
bw_ASTER3Updater.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationDatabaseUpdater_ProgressChanged);
|
|
bw_ASTER1Updater.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationDatabaseUpdater_ProgressChanged);
|
|
|
|
// set station database updater event handler
|
|
bw_StationDatabaseUpdater.ProgressChanged += new ProgressChangedEventHandler(bw_StationDatabaseUpdater_ProgressChanged);
|
|
bw_StationDatabaseUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_StationDatabaseUpdater_RunWorkerCompleted);
|
|
|
|
// set aircraft database updater event handler
|
|
bw_AircraftDatabaseUpdater.ProgressChanged += new ProgressChangedEventHandler(bw_AircraftDatabaseUpdater_ProgressChanged);
|
|
bw_AircraftDatabaseUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_AircraftDatabaseUpdater_RunWorkerCompleted);
|
|
|
|
// set aircraft database maintainer event handler
|
|
bw_AircraftDatabaseMaintainer.ProgressChanged += new ProgressChangedEventHandler(bw_AircraftDatabaseMaintainer_ProgressChanged);
|
|
bw_AircraftDatabaseMaintainer.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_AircraftDatabaseMaintainer_RunWorkerCompleted);
|
|
|
|
// set elevation path calculator event handler
|
|
bw_GLOBEPathCalculator.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationPathCalculator_ProgressChanged);
|
|
bw_SRTM3PathCalculator.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationPathCalculator_ProgressChanged);
|
|
bw_SRTM1PathCalculator.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationPathCalculator_ProgressChanged);
|
|
bw_ASTER3PathCalculator.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationPathCalculator_ProgressChanged);
|
|
bw_ASTER1PathCalculator.ProgressChanged += new ProgressChangedEventHandler(bw_ElevationPathCalculator_ProgressChanged);
|
|
|
|
// set map preloader event handler
|
|
bw_MapPreloader.ProgressChanged += new ProgressChangedEventHandler(bw_MapPreloader_ProgressChanged);
|
|
|
|
// CAT updater event handler
|
|
bw_CATUpdater.ProgressChanged += bw_CATUpdater_ProgressChanged;
|
|
|
|
// CAT interface event handler
|
|
bw_CAT.ProgressChanged += new ProgressChangedEventHandler(bw_CAT_ProgressChanged);
|
|
|
|
// save FirstRun property before trying to upgrade user settings
|
|
FirstRun = Properties.Settings.Default.FirstRun;
|
|
}
|
|
|
|
string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
|
|
{
|
|
// Check arguments.
|
|
if (cipherText == null || cipherText.Length <= 0)
|
|
throw new ArgumentNullException("cipherText");
|
|
if (key == null || key.Length <= 0)
|
|
throw new ArgumentNullException("key");
|
|
if (iv == null || iv.Length <= 0)
|
|
throw new ArgumentNullException("iv");
|
|
|
|
// Declare the RijndaelManaged object
|
|
// used to decrypt the data.
|
|
RijndaelManaged aesAlg = null;
|
|
|
|
// Declare the string used to hold
|
|
// the decrypted text.
|
|
string plaintext;
|
|
|
|
// Create a RijndaelManaged object
|
|
// with the specified key and IV.
|
|
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
|
|
|
|
// Create a decrytor to perform the stream transform.
|
|
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
|
// Create the streams used for decryption.
|
|
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
|
|
{
|
|
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
|
{
|
|
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
|
|
{
|
|
// Read the decrypted bytes from the decrypting stream
|
|
// and place them in a string.
|
|
plaintext = srDecrypt.ReadToEnd();
|
|
srDecrypt.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
return plaintext;
|
|
}
|
|
|
|
private string OpenSSLDecrypt(string encrypted, string passphrase)
|
|
{
|
|
//get the key bytes (not sure if UTF8 or ASCII should be used here doesn't matter if no extended chars in passphrase)
|
|
var key = Encoding.UTF8.GetBytes(passphrase);
|
|
|
|
//pad key out to 32 bytes (256bits) if its too short
|
|
if (key.Length < 32)
|
|
{
|
|
var paddedkey = new byte[32];
|
|
Buffer.BlockCopy(key, 0, paddedkey, 0, key.Length);
|
|
key = paddedkey;
|
|
}
|
|
|
|
//setup an empty iv
|
|
var iv = new byte[16];
|
|
|
|
//get the encrypted data and decrypt
|
|
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
|
|
return DecryptStringFromBytesAes(encryptedBytes, key, iv);
|
|
}
|
|
|
|
public void InitializeSession()
|
|
{
|
|
// register this AirScout instance
|
|
try
|
|
{
|
|
WebClient client;
|
|
string result;
|
|
Log.WriteMessage("Registering AirScout: Creating Instance ID");
|
|
// check AirScout instance id and generate new if not set
|
|
if (String.IsNullOrEmpty(Properties.Settings.Default.AirScout_Instance_ID))
|
|
{
|
|
Properties.Settings.Default.AirScout_Instance_ID = Guid.NewGuid().ToString();
|
|
}
|
|
Log.WriteMessage("Registering AirScout: Creating Device ID");
|
|
// create an unique device id
|
|
DeviceIdBuilder devid = new DeviceIdBuilder();
|
|
Log.WriteMessage("Registering AirScout: Creating Device ID [MachineName]:" + devid.AddMachineName().ToString());
|
|
// not supported on Mono
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
Log.WriteMessage("Registering AirScout: Creating Device ID [MACAddress]:" + devid.AddMacAddress().ToString());
|
|
Log.WriteMessage("Registering AirScout: Creating Device ID [Processor]:" + devid.AddProcessorId().ToString());
|
|
Log.WriteMessage("Registering AirScout: Creating Device ID [Motherboard]:" + devid.AddMotherboardSerialNumber().ToString());
|
|
}
|
|
// store in settings if not set so far
|
|
if (String.IsNullOrEmpty(Properties.Settings.Default.AirScout_Device_ID) || (devid.ToString() != Properties.Settings.Default.AirScout_Device_ID))
|
|
{
|
|
// not set or not the same, assuming AirScout is running on a new machine --> create a new instance id
|
|
Properties.Settings.Default.AirScout_Instance_ID = Guid.NewGuid().ToString();
|
|
}
|
|
// store device id in settings
|
|
Properties.Settings.Default.AirScout_Device_ID = devid.ToString();
|
|
Log.WriteMessage("Registering AirScout: Getting Session Key");
|
|
// get new session key
|
|
client = new WebClient();
|
|
string id = Properties.Settings.Default.AirScout_Instance_ID;
|
|
result = client.DownloadString(Properties.Settings.Default.AirScout_Register_URL +
|
|
"?id=" + Properties.Settings.Default.AirScout_Instance_ID +
|
|
"&mycall=" + Properties.Settings.Default.MyCall +
|
|
"&mylat=" + Properties.Settings.Default.MyLat.ToString() +
|
|
"&mylon=" + Properties.Settings.Default.MyLon.ToString() +
|
|
"&myversion=" + Application.ProductVersion);
|
|
if (!result.ToLower().Contains("error"))
|
|
{
|
|
SessionKey = Encryption.OpenSSLDecrypt(result, Properties.Settings.Default.AirScout_Instance_ID);
|
|
}
|
|
else
|
|
{
|
|
Log.WriteMessage("Error while registering AirScout: " + result);
|
|
MessageBox.Show(result + "\n\nSome functionality might be limited.", "Error while registering AirScout");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage("Error while registering AirScout: " + ex.ToString());
|
|
MessageBox.Show(ex.Message + "\n\nSome functionality might be limited.", "Error while registering AirScout");
|
|
}
|
|
Log.WriteMessage("Registering AirScout successful.");
|
|
}
|
|
|
|
public void CheckDirectories()
|
|
{
|
|
// check if directories exist
|
|
if (!Directory.Exists(TmpDirectory))
|
|
Directory.CreateDirectory(TmpDirectory);
|
|
if (!Directory.Exists(LogDirectory))
|
|
Directory.CreateDirectory(LogDirectory);
|
|
if (!Directory.Exists(IconDirectory))
|
|
Directory.CreateDirectory(IconDirectory);
|
|
if (!Directory.Exists(DatabaseDirectory))
|
|
Directory.CreateDirectory(DatabaseDirectory);
|
|
if (!Directory.Exists(ElevationDirectory))
|
|
Directory.CreateDirectory(ElevationDirectory);
|
|
if (!Directory.Exists(PluginDirectory))
|
|
Directory.CreateDirectory(PluginDirectory);
|
|
if (!Directory.Exists(RigDirectory))
|
|
Directory.CreateDirectory(RigDirectory);
|
|
if (!Directory.Exists(PlanePositionsDirectory))
|
|
Directory.CreateDirectory(PlanePositionsDirectory);
|
|
|
|
// cleanup plane positions directory
|
|
string[] files = Directory.GetFiles(PlanePositionsDirectory, "*.*", SearchOption.TopDirectoryOnly);
|
|
foreach (string file in files)
|
|
{
|
|
try
|
|
{
|
|
File.Delete(file);
|
|
}
|
|
catch
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CopyPluginWithPDB(string src, string dst)
|
|
{
|
|
try
|
|
{
|
|
// copy plugin itself
|
|
if (File.Exists(src))
|
|
File.Copy(src, dst, true);
|
|
// copy symbol file for debug, if any
|
|
src = src.Replace(".dll", ".pdb");
|
|
dst = dst.Replace(".dll", ".pdb");
|
|
if (File.Exists(src))
|
|
File.Copy(src, dst, true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
public void CopyPlugins(string srcdir, string dstdir, string filespec)
|
|
{
|
|
// move the planefeed plugins from program directory to the plugins directory but only if they not exist
|
|
// otherwise do version check
|
|
string[] srcplugins = Directory.GetFiles(srcdir, filespec);
|
|
foreach (string srcplugin in srcplugins)
|
|
{
|
|
try
|
|
{
|
|
string filename = Path.GetFileName(srcplugin);
|
|
string srcversion = FileVersionInfo.GetVersionInfo(srcplugin).FileVersion;
|
|
DateTime srctime = File.GetLastWriteTimeUtc(srcplugin);
|
|
// calculate destination file name
|
|
string dstplugin = dstdir + Path.DirectorySeparatorChar + filename;
|
|
if (!File.Exists(dstplugin))
|
|
{
|
|
// copy file if not exists
|
|
CopyPluginWithPDB(srcplugin, dstplugin);
|
|
Log.WriteMessage("Plugin Manager: Copied plugin " + filename + "[" + srcversion + "].");
|
|
}
|
|
else
|
|
{
|
|
// do version check
|
|
string dstversion = FileVersionInfo.GetVersionInfo(dstplugin).FileVersion;
|
|
DateTime dsttime = File.GetLastWriteTimeUtc(dstplugin);
|
|
if (srcversion.CompareTo(dstversion) > 0)
|
|
{
|
|
// overwrite dstfile if newer version
|
|
CopyPluginWithPDB(srcplugin, dstplugin);
|
|
Log.WriteMessage("Plugin Manager: Replaced plugin " + filename + "[" + dstversion + "] with newer version [" + srcversion + "].");
|
|
}
|
|
else if (srcversion.CompareTo(dstversion) == 0)
|
|
{
|
|
if (srctime > dsttime)
|
|
{
|
|
// overwrite dstfile if same version but newer
|
|
CopyPluginWithPDB(srcplugin, dstplugin);
|
|
Log.WriteMessage("Plugin Manager: Replaced plugin " + filename + "[" + dsttime.ToString("yyyy-MM-dd HH:mm:ss") + "] with newer file [" + srctime.ToString("yyyy-MM-dd HH:mm:ss") + "].");
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadPlugins()
|
|
{
|
|
// chek for planefeed plugins
|
|
Log.WriteMessage("Loading plugins...");
|
|
// get major&minor version
|
|
string mainversion = Assembly.GetExecutingAssembly().GetName().Version.ToString().Split('.')[0] + "." + Assembly.GetExecutingAssembly().GetName().Version.ToString().Split('.')[1];
|
|
string filespec = "AirScout.PlaneFeeds.Plugin.*.dll";
|
|
|
|
// first copy plugins from application directory to plugin directory if they not exist or newer
|
|
CopyPlugins(Path.Combine(AppDirectory,"Plugin"), PluginDirectory, filespec);
|
|
|
|
// check for new plugins on the web resource
|
|
try
|
|
{
|
|
// clear temporary files
|
|
try
|
|
{
|
|
SupportFunctions.DeleteFilesFromDirectory(TmpDirectory, new string[] { "*.tmp", "*.PendingOverwrite" });
|
|
SupportFunctions.DeleteFilesFromDirectory(TmpDirectory, filespec);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
// calculate url
|
|
string url = Properties.Settings.Default.Plugins_Update_URL + "/" + mainversion + "/" + "planefeeds.zip";
|
|
string filename = Path.Combine(TmpDirectory, "planefeeds.zip");
|
|
// get zip file
|
|
AutoDecompressionWebClient cl = new AutoDecompressionWebClient();
|
|
DOWNLOADFILESTATUS status = cl.DownloadFileIfNewer(url, filename, true, true);
|
|
if (((status & DOWNLOADFILESTATUS.ERROR) > 0) && ((status & DOWNLOADFILESTATUS.NOTFOUND) > 0))
|
|
{
|
|
Log.WriteMessage("PluginManager: checking plugins --> nothing found on web or error while downloading.");
|
|
}
|
|
else if (((status & DOWNLOADFILESTATUS.NEWER) > 0) || ((status & DOWNLOADFILESTATUS.NOTNEWER) > 0))
|
|
{
|
|
// update files with web resource if newer
|
|
// copy plugins from application directory to plugin directory
|
|
CopyPlugins(TmpDirectory, PluginDirectory, filespec);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
|
|
// load available plugins, we need a robust algorithm here!
|
|
// error while composing a single plugin or error during call to plugin constructor must not affect loading of other plugins!
|
|
// furthermore: DirectoryCatalog does not work on Linux when plugins are placed in other directory than program's main directory
|
|
// solution -->
|
|
// try to compose each single plugin first and collect "clean" plugins in a container for error-free composing with Lazy<T>
|
|
// after that, try to call each plugin's constructor and collect "clean" plugins in a separate list for further use
|
|
try
|
|
{
|
|
List<AssemblyCatalog> catalog = new List<AssemblyCatalog>();
|
|
CompositionContainer tmpcontainer = null;
|
|
foreach (string plfile in Directory.GetFiles(PluginDirectory, filespec, SearchOption.AllDirectories))
|
|
{
|
|
try
|
|
{
|
|
// try to import a single plugin
|
|
var tmpcatalog = new AssemblyCatalog(System.Reflection.Assembly.UnsafeLoadFrom(plfile));
|
|
tmpcontainer = new CompositionContainer(tmpcatalog);
|
|
tmpcontainer.ComposeParts(this);
|
|
// add to main catalog only when composition was OK
|
|
tmpcontainer.Dispose();
|
|
catalog.Add(tmpcatalog);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex.GetType() == typeof(ReflectionTypeLoadException))
|
|
{
|
|
foreach (Exception le in ((ReflectionTypeLoadException)ex).LoaderExceptions)
|
|
{
|
|
Log.WriteMessage("Error while loading plugin[" + plfile + "]: " + le.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.WriteMessage("Error while loading plugin[" + plfile + "]: " + ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
// catalog should cointain only "clean" plugins so composing all parts should be possible without errors
|
|
var container = new CompositionContainer(new AggregateCatalog(catalog));
|
|
container.ComposeParts(this);
|
|
foreach (Lazy<IPlaneFeedPlugin> lazyplugin in LazyPlaneFeedPlugins)
|
|
{
|
|
try
|
|
{
|
|
// try to call plaugin constructor and add the value to Planefeeds list
|
|
// 2022_04_24 check plugin version against program version: do not load older plugins
|
|
var plugin = lazyplugin.Value;
|
|
if (plugin != null)
|
|
{
|
|
if (plugin.Version.StartsWith(mainversion))
|
|
{
|
|
PlaneFeedPlugins.Add(plugin);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage("Error while loading plugin: " + ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
Log.WriteMessage("Loading plugins successful.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the default value of a property
|
|
/// </summary>
|
|
/// <param name="propertyname">The property name.</param>
|
|
/// <returns>The property value.</returns>
|
|
public static dynamic GetPropertyDefaultValue(string propertyname)
|
|
{
|
|
SettingsProperty prop = Properties.Settings.Default.Properties[propertyname];
|
|
if (prop == null)
|
|
return null;
|
|
|
|
object def = prop.DefaultValue;
|
|
if (def == null)
|
|
return null;
|
|
|
|
Type t = Properties.Settings.Default.Properties[propertyname].PropertyType;
|
|
if (t == null)
|
|
return null;
|
|
|
|
try
|
|
{
|
|
TypeConverter tc = TypeDescriptor.GetConverter(t);
|
|
object value = tc.ConvertFromString(null, CultureInfo.InvariantCulture, (string)def);
|
|
|
|
return value;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
return null;
|
|
/*
|
|
string p = prop.DefaultValue.ToString();
|
|
Type t = Properties.Settings.Default.Properties[propertyname].PropertyType;
|
|
return Convert.ChangeType(p, t);
|
|
*/
|
|
|
|
}
|
|
|
|
private string QualifyDatabaseDirectory(string databasedir)
|
|
{
|
|
// replace Windows/Linux directory spearator chars
|
|
databasedir = databasedir.Replace('\\', Path.DirectorySeparatorChar);
|
|
databasedir = databasedir.Replace('/', Path.DirectorySeparatorChar);
|
|
// replace variables, if any
|
|
databasedir = VC.ReplaceAllVars(databasedir);
|
|
// remove directory separator chars at begin and end
|
|
databasedir = databasedir.TrimStart(Path.DirectorySeparatorChar);
|
|
databasedir = databasedir.TrimEnd(Path.DirectorySeparatorChar);
|
|
// fully qualify path
|
|
if (!databasedir.Contains(Path.VolumeSeparatorChar))
|
|
databasedir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), databasedir);
|
|
return databasedir;
|
|
}
|
|
|
|
private void InitializeSettings()
|
|
{
|
|
|
|
// Load user settings
|
|
LoadUserSettings();
|
|
|
|
// check for invalid settings
|
|
// check if band is BNONE --> set to 1.2G
|
|
if (Properties.Settings.Default.Band == BAND.BNONE)
|
|
Properties.Settings.Default.Band = BAND.B1_2G;
|
|
// chekc if band settings are NULL --> set to default
|
|
if (Properties.Settings.Default.Path_Band_Settings == null)
|
|
Properties.Settings.Default.Path_Band_Settings = new BandSettings(true);
|
|
// check if watchlist in null --> create new
|
|
if (Properties.Settings.Default.Watchlist == null)
|
|
Properties.Settings.Default.Watchlist = new Watchlist();
|
|
string location = StationData.Database.GetDBLocation();
|
|
// check calls
|
|
if (String.IsNullOrEmpty(Properties.Settings.Default.MyCall))
|
|
Properties.Settings.Default.MyCall = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyCall));
|
|
if (String.IsNullOrEmpty(Properties.Settings.Default.DXCall))
|
|
Properties.Settings.Default.DXCall = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXCall));
|
|
// check lat/lon
|
|
if (!GeographicalPoint.Check(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon))
|
|
{
|
|
Properties.Settings.Default.MyLat = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyLat));
|
|
Properties.Settings.Default.MyLon = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyLon));
|
|
UpdateLocation(Properties.Settings.Default.MyCall, Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, GEOSOURCE.FROMUSER);
|
|
}
|
|
if (!GeographicalPoint.Check(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon))
|
|
{
|
|
Properties.Settings.Default.DXLat = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXLat));
|
|
Properties.Settings.Default.DXLon = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXLon));
|
|
UpdateLocation(Properties.Settings.Default.DXCall, Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, GEOSOURCE.FROMUSER);
|
|
}
|
|
// set current elevation model
|
|
SetElevationModel();
|
|
// set antenna height to 10m be default
|
|
Properties.Settings.Default.MyHeight = 10;
|
|
Properties.Settings.Default.DXHeight = 10;
|
|
|
|
// check database directory settings
|
|
Properties.Settings.Default.AircraftDatabase_Directory = QualifyDatabaseDirectory(Properties.Settings.Default.AircraftDatabase_Directory);
|
|
Properties.Settings.Default.StationsDatabase_Directory = QualifyDatabaseDirectory(Properties.Settings.Default.StationsDatabase_Directory);
|
|
Properties.Settings.Default.ElevationDatabase_Directory = QualifyDatabaseDirectory(Properties.Settings.Default.StationsDatabase_Directory);
|
|
Properties.Settings.Default.PropagationDatabase_Directory = QualifyDatabaseDirectory(Properties.Settings.Default.PropagationDatabase_Directory);
|
|
}
|
|
|
|
private void DumpSettingsToLog(string name, SettingsPropertyValueCollection settings)
|
|
{
|
|
foreach (SettingsPropertyValue p in settings)
|
|
{
|
|
try
|
|
{
|
|
if ((p != null) && (p.Name != null))
|
|
{
|
|
string value = p.PropertyValue != null ? p.PropertyValue.ToString() : "[null]";
|
|
string default_value = GetPropertyDefaultValue(p.Name) != null ? "[Default = " + GetPropertyDefaultValue(p.Name) + "]" : "[Default = null]";
|
|
Log.WriteMessage(name + "." + p.Name + " = " + value + default_value);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Error while checking property + " + p.Name + ": " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void CheckSettings()
|
|
{
|
|
Log.WriteMessage("Checking properties...");
|
|
// check for empty MyCalls list
|
|
if (Properties.Settings.Default.MyCalls == null)
|
|
{
|
|
Properties.Settings.Default.MyCalls = new List<string>();
|
|
Properties.Settings.Default.MyCalls.Add("DL2ALF");
|
|
}
|
|
if (Properties.Settings.Default.MyCalls.Count == 0)
|
|
Properties.Settings.Default.MyCalls.Add("DL2ALF");
|
|
// checking window size & location
|
|
Rectangle bounds = Screen.FromControl(this).Bounds;
|
|
if ((Properties.Settings.Default.General_WindowLocation.X < bounds.Left) ||
|
|
(Properties.Settings.Default.General_WindowLocation.Y < bounds.Top) ||
|
|
(Properties.Settings.Default.General_WindowLocation.X > bounds.Right) ||
|
|
(Properties.Settings.Default.General_WindowLocation.Y > bounds.Bottom))
|
|
{
|
|
Properties.Settings.Default.General_WindowLocation = new System.Drawing.Point(bounds.Left, bounds.Top);
|
|
}
|
|
if ((Properties.Settings.Default.General_WindowSize.Width > bounds.Width) ||
|
|
(Properties.Settings.Default.General_WindowSize.Height > bounds.Height))
|
|
{
|
|
Properties.Settings.Default.General_WindowSize = new System.Drawing.Size(bounds.Width, bounds.Height);
|
|
}
|
|
// list all properties in log
|
|
foreach (SettingsPropertyValue p in Properties.Settings.Default.PropertyValues)
|
|
{
|
|
if ((p != null) && (p.Name != null))
|
|
{
|
|
string value = p.PropertyValue != null ? p.PropertyValue.ToString() : "[null]";
|
|
Log.WriteMessage("Checking property " + p.Name + " = " + value);
|
|
}
|
|
}
|
|
/*
|
|
// check URLs for trailing separator
|
|
if (!Properties.Settings.Default.Elevation_GLOBE_URL.EndsWith("/"))
|
|
Properties.Settings.Default.Elevation_GLOBE_URL = Properties.Settings.Default.Elevation_GLOBE_URL + "/";
|
|
if (!Properties.Settings.Default.Elevation_SRTM3_URL.EndsWith("/"))
|
|
Properties.Settings.Default.Elevation_SRTM3_URL = Properties.Settings.Default.Elevation_SRTM3_URL + "/";
|
|
if (!Properties.Settings.Default.Elevation_SRTM1_URL.EndsWith("/"))
|
|
Properties.Settings.Default.Elevation_SRTM1_URL = Properties.Settings.Default.Elevation_SRTM1_URL + "/";
|
|
if (!Properties.Settings.Default.StationDatabase_Update_URL.EndsWith("/"))
|
|
Properties.Settings.Default.StationDatabase_Update_URL = Properties.Settings.Default.StationDatabase_Update_URL + "/";
|
|
*/
|
|
// check for last saved stations not in database and revert to at least DL2ALF and GB3MHZ if necessary
|
|
// first check for saved stations
|
|
string mycall = Properties.Settings.Default.MyCall;
|
|
double mylat = Properties.Settings.Default.MyLat;
|
|
double mylon = Properties.Settings.Default.MyLon;
|
|
string myloc = MaidenheadLocator.LocFromLatLon(mylat, mylon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, 3);
|
|
LocationDesignator ld = StationData.Database.LocationFind(mycall, myloc);
|
|
if (ld == null)
|
|
{
|
|
mycall = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyCall));
|
|
mylat = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyLat));
|
|
mylon = GetPropertyDefaultValue(nameof(Properties.Settings.Default.MyLon));
|
|
myloc = MaidenheadLocator.LocFromLatLon(mylat, mylon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, 3);
|
|
UpdateLocation(mycall, mylat, mylon, GEOSOURCE.FROMUSER);
|
|
Properties.Settings.Default.MyCall = mycall;
|
|
Properties.Settings.Default.MyLat = mylat;
|
|
Properties.Settings.Default.MyLon = mylon;
|
|
}
|
|
string dxcall = Properties.Settings.Default.DXCall;
|
|
double dxlat = Properties.Settings.Default.DXLat;
|
|
double dxlon = Properties.Settings.Default.DXLon;
|
|
string dxloc = MaidenheadLocator.LocFromLatLon(dxlat, dxlon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, 3);
|
|
ld = StationData.Database.LocationFind(dxcall, dxloc);
|
|
if (ld == null)
|
|
{
|
|
dxcall = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXCall));
|
|
dxlat = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXLat));
|
|
dxlon = GetPropertyDefaultValue(nameof(Properties.Settings.Default.DXLon));
|
|
dxloc = MaidenheadLocator.LocFromLatLon(dxlat, dxlon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, 3);
|
|
UpdateLocation(dxcall, dxlat, dxlon, GEOSOURCE.FROMUSER);
|
|
Properties.Settings.Default.DXCall = dxcall;
|
|
Properties.Settings.Default.DXLat = dxlat;
|
|
Properties.Settings.Default.DXLon = dxlon;
|
|
}
|
|
Log.WriteMessage("Checking properties finished...");
|
|
}
|
|
|
|
private void CheckInternet()
|
|
{
|
|
// check internet connectivity
|
|
try
|
|
{
|
|
using (var client = new WebClient())
|
|
{
|
|
string url = Properties.Settings.Default.Connectivity_URL;
|
|
using (var stream = client.OpenRead(url))
|
|
{
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
MessageBox.Show("Could not find an internet connection.\nThis is required on first run.\nAirScout will close.", "Internet connectivity");
|
|
this.Close();
|
|
}
|
|
}
|
|
|
|
private void InitializeLogfile()
|
|
{
|
|
// set directories and formats for logfile
|
|
ScoutBase.Core.Properties.Settings.Default.LogWriter_Directory = LogDirectory;
|
|
ScoutBase.Core.Properties.Settings.Default.LogWriter_FileFormat = "AirScout_{0:yyyy_MM_dd}.log";
|
|
ScoutBase.Core.Properties.Settings.Default.LogWriter_MessageFormat = "{0:u} {1}";
|
|
// gets an instance of a LogWriter
|
|
Log = LogWriter.Instance;
|
|
Log.WriteMessage("-------------------------------------------------------------------------------------");
|
|
Log.WriteMessage(Application.ProductName + " is starting up.", 0, false);
|
|
Log.WriteMessage("-------------------------------------------------------------------------------------");
|
|
Log.WriteMessage("Operating system : " + Environment.OSVersion.Platform);
|
|
Log.WriteMessage("OS Major version : " + Environment.OSVersion.Version.Major);
|
|
Log.WriteMessage("OS Minor version : " + Environment.OSVersion.Version.Minor);
|
|
Log.WriteMessage("Application directory : " + AppDirectory);
|
|
Log.WriteMessage("Application data directory: " + AppDataDirectory);
|
|
Log.WriteMessage("Log directory : " + LogDirectory);
|
|
Log.WriteMessage("Temp directory : " + TmpDirectory);
|
|
Log.WriteMessage("Database directory : " + DatabaseDirectory);
|
|
Log.WriteMessage("Elevation directory : " + ElevationDirectory);
|
|
Log.WriteMessage("Plugin directory : " + PluginDirectory);
|
|
Log.WriteMessage("Rig directory : " + RigDirectory);
|
|
Log.WriteMessage("Application settings file : " + AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
|
|
Log.WriteMessage("User settings file : " + GetUserSettingsPath());
|
|
Log.WriteMessage("Disk space available : " + SupportFunctions.GetDriveAvailableFreeSpace(Path.GetPathRoot(AppDataDirectory)) / 1024 / 1024 + " MB");
|
|
Log.WriteMessage("-------------------------------------------------------------------------------------");
|
|
}
|
|
|
|
private void InitializeDatabase()
|
|
{
|
|
Log.WriteMessage("Started.");
|
|
SetElevationModel();
|
|
// reset database status
|
|
Properties.Settings.Default.Elevation_GLOBE_DatabaseStatus = DATABASESTATUS.UNDEFINED;
|
|
Properties.Settings.Default.Elevation_SRTM3_DatabaseStatus = DATABASESTATUS.UNDEFINED;
|
|
Properties.Settings.Default.Elevation_SRTM1_DatabaseStatus = DATABASESTATUS.UNDEFINED;
|
|
Properties.Settings.Default.Elevation_ASTER3_DatabaseStatus = DATABASESTATUS.UNDEFINED;
|
|
Properties.Settings.Default.Elevation_ASTER1_DatabaseStatus = DATABASESTATUS.UNDEFINED;
|
|
// set nearfield suppression
|
|
PropagationData.Database.NearFieldSuppression = Properties.Settings.Default.Path_NearFieldSuppression;
|
|
// get all database directories and store it in settings
|
|
Properties.Settings.Default.AircraftDatabase_Directory = AircraftData.Database.DefaultDatabaseDirectory();
|
|
Properties.Settings.Default.StationsDatabase_Directory = StationData.Database.DefaultDatabaseDirectory();
|
|
Properties.Settings.Default.ElevationDatabase_Directory = ElevationData.Database.DefaultDatabaseDirectory();
|
|
Properties.Settings.Default.PropagationDatabase_Directory = PropagationData.Database.DefaultDatabaseDirectory();
|
|
Properties.Settings.Default.Rig_Directory = RigData.Database.DefaultDatabaseDirectory();
|
|
MapData.Database.DefaultDatabaseDirectory();
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void CreateDistances()
|
|
{
|
|
gmo_Distances.Clear();
|
|
for (int dist = 100; dist <= 1000; dist += 100)
|
|
{
|
|
GMapRoute circle = new GMapRoute("Distance: " + dist.ToString());
|
|
circle.Stroke = new Pen(Color.DarkGray, 1);
|
|
for (int i = 0; i <= 360; i++)
|
|
{
|
|
LatLon.GPoint p = LatLon.DestinationPoint(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, i, dist);
|
|
circle.Points.Add(new PointLatLng(p.Lat, p.Lon));
|
|
|
|
}
|
|
gmo_Distances.Routes.Add(circle);
|
|
}
|
|
|
|
}
|
|
|
|
private void InitializeMaps()
|
|
{
|
|
// setting User Agent to fix Open Street Map issue 2016-09-20
|
|
GMap.NET.MapProviders.GMapProvider.UserAgent = "AirScout";
|
|
// clearing referrer URL issue 2019-12-14
|
|
gm_Main.MapProvider.RefererUrl = "";
|
|
// set initial settings for main map
|
|
gm_Main.MapProvider = GMapProviders.Find(Properties.Settings.Default.Map_Provider);
|
|
gm_Main.IgnoreMarkerOnMouseWheel = true;
|
|
gm_Main.MinZoom = 0;
|
|
gm_Main.MaxZoom = 20;
|
|
gm_Main.Zoom = 6;
|
|
gm_Main.DragButton = System.Windows.Forms.MouseButtons.Left;
|
|
gm_Main.CanDragMap = true;
|
|
gm_Main.ScalePen = new Pen(Color.Black, 3);
|
|
gm_Main.MapScaleInfoEnabled = true;
|
|
|
|
// clear all overlays
|
|
gm_Main.Overlays.Clear();
|
|
gmo_Airports.Clear();
|
|
gmo_Callsigns.Clear();
|
|
gmo_Locators.Clear();
|
|
gmo_Objects.Clear();
|
|
gmo_Planes.Clear();
|
|
gmo_PropagationPaths.Clear();
|
|
gmo_Routes.Clear();
|
|
gmo_Locators.Clear();
|
|
gmo_Distances.Clear();
|
|
|
|
// add all overlays
|
|
gm_Main.Overlays.Add(gmo_Locators);
|
|
gm_Main.Overlays.Add(gmo_Distances);
|
|
gm_Main.Overlays.Add(gmo_Airports);
|
|
gm_Main.Overlays.Add(gmo_PropagationPaths);
|
|
gm_Main.Overlays.Add(gmo_Objects);
|
|
gm_Main.Overlays.Add(gmo_Routes);
|
|
gm_Main.Overlays.Add(gmo_Planes);
|
|
gm_Main.Overlays.Add(gmo_Callsigns);
|
|
gm_Main.Overlays.Add(gmo_CallsignDetails);
|
|
|
|
gm_Main.Opacity = (double)Properties.Settings.Default.Map_Opacity;
|
|
|
|
// create locators, if enabled
|
|
if (Properties.Settings.Default.Map_ShowLocators)
|
|
InitializeLocators();
|
|
|
|
// setting User Agent to fix Open Street Map issue 2016-09-20
|
|
GMap.NET.MapProviders.GMapProvider.UserAgent = "AirScout";
|
|
// clearing referrer URL issue 2019-12-14
|
|
gm_Nearest.MapProvider.RefererUrl = "";
|
|
// set initial settings for main map
|
|
gm_Nearest.MapProvider = GMapProviders.Find(Properties.Settings.Default.Map_Provider);
|
|
gm_Main.MapProvider.RefererUrl = "";
|
|
gm_Nearest.IgnoreMarkerOnMouseWheel = true;
|
|
gm_Nearest.MinZoom = 0;
|
|
gm_Nearest.MaxZoom = 20;
|
|
gm_Nearest.Zoom = 6;
|
|
gm_Nearest.DragButton = System.Windows.Forms.MouseButtons.Left;
|
|
gm_Nearest.CanDragMap = true;
|
|
gm_Nearest.ScalePen = new Pen(Color.Black, 3);
|
|
gm_Nearest.MapScaleInfoEnabled = true;
|
|
|
|
// clear all overlays
|
|
gm_Nearest.Overlays.Clear();
|
|
gmo_NearestPaths.Clear();
|
|
gmo_NearestPlanes.Clear();
|
|
|
|
// add all overlays
|
|
gm_Nearest.Overlays.Add(gmo_NearestPaths);
|
|
gm_Nearest.Overlays.Add(gmo_NearestPlanes);
|
|
gm_Nearest.Position = new PointLatLng(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
gm_Nearest.ShowCenter = false;
|
|
|
|
// setting User Agent to fix Open Street Map issue 2016-09-20
|
|
GMap.NET.MapProviders.GMapProvider.UserAgent = "AirScout";
|
|
// clearing referrer URL issue 2019-12-14
|
|
gm_Cache.MapProvider.RefererUrl = "";
|
|
// set initial settings for main map
|
|
gm_Cache.MapProvider = GMapProviders.Find(Properties.Settings.Default.Map_Provider);
|
|
|
|
}
|
|
|
|
private void CreateLocators(double steplat, double steplon, Pen pen)
|
|
{
|
|
// get visible map bounds first
|
|
double minlat = (int)(gm_Main.ViewArea.Bottom / steplat) * steplat - steplat;
|
|
double maxlat = gm_Main.ViewArea.Top;
|
|
double minlon = (int)(gm_Main.ViewArea.Left / steplon) * steplon - steplon;
|
|
double maxlon = gm_Main.ViewArea.Right;
|
|
|
|
Console.WriteLine("ViewArea = " + minlat.ToString("F2") + "," + minlon.ToString("F2") + " <> " + maxlat.ToString("F2") + "," + maxlon.ToString("F2"));
|
|
|
|
for (double lon = minlon; lon < maxlon; lon += steplon)
|
|
{
|
|
for (double lat = minlat; lat < maxlat; lat += steplat)
|
|
{
|
|
// create name
|
|
string loc = "";
|
|
if (steplat >= 10.0)
|
|
{
|
|
loc = MaidenheadLocator.LocFromLatLon(lat + steplat / 2, lon + steplon / 2, false, 1);
|
|
}
|
|
else if (steplat >= 1.0)
|
|
{
|
|
loc = MaidenheadLocator.LocFromLatLon(lat + steplat / 2, lon + steplon / 2, false, 2);
|
|
}
|
|
else if (steplat >= 1.0 / 24.0)
|
|
{
|
|
loc = MaidenheadLocator.LocFromLatLon(lat + steplat / 2, lon + steplon / 2, false, 3);
|
|
}
|
|
else if (steplat >= 1.0 / 24.0 / 10.0)
|
|
{
|
|
loc = MaidenheadLocator.LocFromLatLon(lat + steplat / 2, lon + steplon / 2, false, 4);
|
|
}
|
|
else if (steplat >= 1.0 / 24.0 / 10.0 / 24.0)
|
|
{
|
|
loc = MaidenheadLocator.LocFromLatLon(lat + steplat / 2, lon + steplon / 2, false, 5);
|
|
}
|
|
|
|
// create polygon
|
|
List<PointLatLng> l = new List<PointLatLng>();
|
|
l.Add(new PointLatLng(lat, lon));
|
|
l.Add(new PointLatLng(lat, lon + steplon));
|
|
l.Add(new PointLatLng(lat + steplat, lon + steplon));
|
|
l.Add(new PointLatLng(lat + steplat, lon));
|
|
GMapLocatorPolygon p = new GMapLocatorPolygon(l, loc);
|
|
p.Stroke = pen;
|
|
p.Fill = Brushes.Transparent;
|
|
p.Tag = loc;
|
|
gmo_Locators.Polygons.Add(p);
|
|
}
|
|
}
|
|
|
|
}
|
|
private void InitializeLocators()
|
|
{
|
|
// NASTY!! still throws execption sometimes
|
|
// when restoring cursor
|
|
try
|
|
{
|
|
// clear locator overlay anyway
|
|
gmo_Locators.Clear();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do all most nothing
|
|
}
|
|
|
|
// return if not activated
|
|
if (!Properties.Settings.Default.Map_ShowLocators)
|
|
return;
|
|
|
|
// create great circles, if enabled
|
|
if (Properties.Settings.Default.Map_ShowLocators)
|
|
{
|
|
try
|
|
{
|
|
gmo_Locators.IsVisibile = true;
|
|
// declutter: calculate an approbiate stepwidth according to the zoom level
|
|
double bigsteplat = 0;
|
|
double bigsteplon = 0;
|
|
double smallsteplat = 0;
|
|
double smallsteplon = 0;
|
|
Pen bigpen = new Pen(Brushes.Transparent);
|
|
Pen smallpen = new Pen(Brushes.Transparent);
|
|
switch (gm_Main.Zoom)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
bigsteplat = 10.0;
|
|
bigsteplon = 20.0;
|
|
bigpen = new Pen(Color.DarkGray, 1);
|
|
smallsteplat = 0;
|
|
smallsteplon = 0;
|
|
smallpen = new Pen(Brushes.Transparent);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
bigsteplat = 1.0;
|
|
bigsteplon = 2.0;
|
|
bigpen = new Pen(Color.DarkGray, 1);
|
|
smallsteplat = 0;
|
|
smallsteplon = 0;
|
|
smallpen = new Pen(Brushes.Transparent);
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
bigsteplat = 1.0;
|
|
bigsteplon = 2.0;
|
|
bigpen = new Pen(Color.DarkGray, 2);
|
|
smallsteplat = 1.0 / 24.0;
|
|
smallsteplon = 2.0 / 24.0;
|
|
smallpen = new Pen(Color.DarkGray, 1);
|
|
break;
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
bigsteplat = 1.0 / 24.0;
|
|
bigsteplon = 2.0 / 24.0;
|
|
bigpen = new Pen(Color.DarkGray, 2);
|
|
smallsteplat = 1.0 / 24.0 / 10.0;
|
|
smallsteplon = 2.0 / 24.0 / 10.0;
|
|
smallpen = new Pen(Color.DarkGray, 1);
|
|
break;
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
bigsteplat = 1.0 / 24.0 / 10.0;
|
|
bigsteplon = 2.0 / 24.0 / 10.0;
|
|
bigpen = new Pen(Color.DarkGray, 2);
|
|
smallsteplat = 1.0 / 24.0 / 10.0 / 24.0;
|
|
smallsteplon = 2.0 / 24.0 / 10.0 / 24.0;
|
|
smallpen = new Pen(Color.DarkGray, 1);
|
|
break;
|
|
}
|
|
|
|
if ((bigsteplon > 0) && (bigsteplat > 0))
|
|
{
|
|
CreateLocators(bigsteplat, bigsteplon, bigpen);
|
|
}
|
|
if ((smallsteplon > 0) && (smallsteplat > 0))
|
|
{
|
|
CreateLocators(smallsteplat, smallsteplon, smallpen);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void Splash(string text)
|
|
{
|
|
Splash(text, Color.White);
|
|
}
|
|
|
|
private void Splash(string text, Color color)
|
|
{
|
|
// show message in splash window
|
|
if (SplashDlg != null)
|
|
{
|
|
SplashDlg.Status(text, color);
|
|
}
|
|
}
|
|
|
|
private void MapDlg_Load(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// Show splash screen
|
|
SplashDlg = new Splash();
|
|
SplashDlg.Show();
|
|
// bring window to front
|
|
SplashDlg.BringToFront();
|
|
// wait for splash window is fully visible
|
|
while (SplashDlg.Opacity < 1)
|
|
{
|
|
Application.DoEvents();
|
|
}
|
|
// show AirScout main window
|
|
this.BringToFront();
|
|
// Check directories, complete it and create, if not exist
|
|
Splash("Checking directories...");
|
|
CheckDirectories();
|
|
// start a log, specify format of logfile and entries
|
|
Splash("Initializing logfile...");
|
|
InitializeLogfile();
|
|
// Check properties
|
|
Splash("Checking settings...");
|
|
CheckSettings();
|
|
// check, copy and load plugins
|
|
Splash("Loading plugins...");
|
|
LoadPlugins();
|
|
// Initialize database
|
|
Splash("Initializing database...");
|
|
InitializeDatabase();
|
|
// initialize icons
|
|
Splash("Creating icons...");
|
|
InitializeIcons();
|
|
ToolTipFont = CreateFontFromString(Properties.Settings.Default.Map_ToolTipFont);
|
|
Splash("Loading Map...");
|
|
|
|
cntdn = Properties.Settings.Default.Planes_Update;
|
|
btn_Map_PlayPause.Select();
|
|
|
|
// intially fill dialog box elements and set band
|
|
string[] bands = Bands.GetStringValuesExceptNoneAndAll();
|
|
foreach (string b in bands)
|
|
cb_Band.Items.Add(b);
|
|
BAND band = Properties.Settings.Default.Band;
|
|
cb_Band.SelectedItem = Bands.GetStringValue(band);
|
|
string[] cats = PlaneCategories.GetStringValues();
|
|
foreach (string cat in cats)
|
|
cb_Planes_Filter_Min_Cat.Items.Add(cat);
|
|
// initialize gauge controls
|
|
ag_Azimuth.fromAngle = -90;
|
|
ag_Azimuth.toAngle = 270;
|
|
|
|
ag_Elevation.fromAngle = 180;
|
|
ag_Elevation.toAngle = 270;
|
|
|
|
// install additional mouse events
|
|
gb_Map_Info.MouseClick += new MouseEventHandler(this.gb_Map_Info_MouseClick);
|
|
gb_Map_Zoom.MouseClick += new MouseEventHandler(this.gb_Map_Zoom_MouseClick);
|
|
gb_Map_Filter.MouseClick += new MouseEventHandler(this.gb_Map_Filter_MouseClick);
|
|
gb_Map_Alarms.MouseClick += new MouseEventHandler(this.gb_Map_Alarms_MouseClick);
|
|
|
|
if (PlaneFeedPlugins != null)
|
|
{
|
|
foreach (IPlaneFeedPlugin plugin in PlaneFeedPlugins)
|
|
{
|
|
if (Properties.Settings.Default.Planes_PlaneFeed1 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed1 = new PlaneFeed();
|
|
bw_PlaneFeed1.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed2 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed2 = new PlaneFeed();
|
|
bw_PlaneFeed2.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed3 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed3 = new PlaneFeed();
|
|
bw_PlaneFeed3.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update image list sizes
|
|
il_Planes_L.ImageSize = new System.Drawing.Size(Properties.Settings.Default.Planes_IconSize_L, Properties.Settings.Default.Planes_IconSize_L);
|
|
il_Planes_M.ImageSize = new System.Drawing.Size(Properties.Settings.Default.Planes_IconSize_M, Properties.Settings.Default.Planes_IconSize_M);
|
|
il_Planes_H.ImageSize = new System.Drawing.Size(Properties.Settings.Default.Planes_IconSize_H, Properties.Settings.Default.Planes_IconSize_H);
|
|
il_Planes_S.ImageSize = new System.Drawing.Size(Properties.Settings.Default.Planes_IconSize_S, Properties.Settings.Default.Planes_IconSize_S);
|
|
|
|
// try to upgrade user settings from prevoius version on first run
|
|
try
|
|
{
|
|
if (FirstRun)
|
|
{
|
|
Log.WriteMessage("Preparing for first run.");
|
|
|
|
// Reload settings
|
|
LoadUserSettings();
|
|
|
|
// try to ugrade settings when not started with /CLEAN option
|
|
if (!CleanRun)
|
|
{
|
|
Log.WriteMessage("Upgrading settings.");
|
|
Properties.Settings.Default.Upgrade();
|
|
// handle skip to version 1.3.3.1
|
|
if (String.IsNullOrEmpty(Properties.Settings.Default.Version) || (String.Compare(Properties.Settings.Default.Version, "1.3.3.0") < 0))
|
|
{
|
|
/*
|
|
// reset elevation data url to new default values
|
|
Properties.Settings.Default.Elevation_GLOBE_URL = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_GLOBE_URL));
|
|
Properties.Settings.Default.Elevation_SRTM3_URL = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_SRTM3_URL));
|
|
Properties.Settings.Default.Elevation_SRTM1_URL = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_SRTM1_URL));
|
|
// reset elevation data path to default values
|
|
Properties.Settings.Default.Elevation_GLOBE_DataPath = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_GLOBE_DataPath));
|
|
Properties.Settings.Default.Elevation_SRTM3_DataPath = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_SRTM3_DataPath));
|
|
Properties.Settings.Default.Elevation_SRTM1_DataPath = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Elevation_SRTM1_DataPath));
|
|
// reset stations data url to its default value
|
|
Properties.Settings.Default.StationDatabase_Update_URL = GetPropertyDefaultValue(nameof(Properties.Settings.Default.StationDatabase_Update_URL));
|
|
*/
|
|
|
|
// reset Sync with KST option
|
|
Properties.Settings.Default.Watchlist_SyncWithKST = GetPropertyDefaultValue(nameof(Properties.Settings.Default.Watchlist_SyncWithKST));
|
|
|
|
Properties.Settings.Default.Version = Application.ProductVersion;
|
|
|
|
SaveUserSettings();
|
|
}
|
|
AirScout.PlaneFeeds.Properties.Settings.Default.Upgrade();
|
|
}
|
|
|
|
CheckDirectories();
|
|
CheckSettings();
|
|
// reset topmost state
|
|
if (SplashDlg != null)
|
|
SplashDlg.TopMost = false;
|
|
/*
|
|
// run database updater once for basic information
|
|
bw_DatabaseUpdater.RunWorkerAsync(UPDATERSTARTOPTIONS.FIRSTRUN);
|
|
// wait till finished
|
|
while (bw_DatabaseUpdater.IsBusy)
|
|
Application.DoEvents();
|
|
*/
|
|
if (SplashDlg != null)
|
|
SplashDlg.Close();
|
|
// must have internet connection on FirstRun
|
|
CheckInternet();
|
|
// show FirstRunWizard
|
|
try
|
|
{
|
|
FirstRunWizard Dlg = new FirstRunWizard(this);
|
|
if (Dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
Log.WriteMessage("Aborting FirstRunWizard.");
|
|
// flush the log and exit immediately
|
|
Log.FlushLog();
|
|
System.Environment.Exit(-1);
|
|
}
|
|
else
|
|
{
|
|
// reset FirstRun property
|
|
Properties.Settings.Default.FirstRun = false;
|
|
Properties.Settings.Default.FirstRun = Properties.Settings.Default.FirstRun;
|
|
|
|
// set privacy statements (for legacy)
|
|
Properties.Settings.Default.First_Agree = true;
|
|
Properties.Settings.Default.First_Disagree = false;
|
|
Properties.Settings.Default.First_Privacy = false;
|
|
|
|
// save settings
|
|
SaveUserSettings();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
// flush the log and exit immediately
|
|
Log.FlushLog();
|
|
System.Environment.Exit(-1);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
// get initial widths and heigths
|
|
gb_Map_Info_DefaultWidth = gb_Map_Info.Width;
|
|
tc_Main_DefaultHeight = tc_Main.Height;
|
|
|
|
// refresh the Layout
|
|
OnSizeChanged(null);
|
|
|
|
// get initial height of boxes
|
|
gb_Map_Info_MinimizedHeight = gb_Map_Info.Height - gb_Map_Info.DisplayRectangle.Height;
|
|
gb_Map_Zoom_MinimizedHeight = gb_Map_Zoom.Height - gb_Map_Zoom.DisplayRectangle.Height;
|
|
gb_Map_Filter_MinimizedHeigth = gb_Map_Filter.Height - gb_Map_Filter.DisplayRectangle.Height;
|
|
gb_Map_Alarms_MinimizedHeight = gb_Map_Alarms.Height - gb_Map_Alarms.DisplayRectangle.Height;
|
|
gb_Map_Info_MaximizedHeight = gb_Map_Info.Height;
|
|
gb_Map_Zoom_MaximizedHeight = gb_Map_Zoom.Height;
|
|
gb_Map_Filter_MaximizedHeigth = gb_Map_Filter.Height;
|
|
gb_Map_Alarms_MaximizedHeight = gb_Map_Alarms.Height;
|
|
|
|
// check directories and settings for missing values
|
|
CheckDirectories();
|
|
CheckSettings();
|
|
|
|
if (PlaneFeedPlugins != null)
|
|
{
|
|
foreach (IPlaneFeedPlugin plugin in PlaneFeedPlugins)
|
|
{
|
|
if (Properties.Settings.Default.Planes_PlaneFeed1 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed1 = new PlaneFeed();
|
|
bw_PlaneFeed1.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed2 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed2 = new PlaneFeed();
|
|
bw_PlaneFeed2.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed3 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed3 = new PlaneFeed();
|
|
bw_PlaneFeed3.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
// register this instance of AirScout and get a session key
|
|
InitializeSession();
|
|
|
|
// start permanent background workers
|
|
StartAllBackgroundWorkers();
|
|
|
|
// start main timer
|
|
ti_Progress.Start();
|
|
|
|
FirstRun = false;
|
|
|
|
// check if a vaild feed is on
|
|
if ((bw_PlaneFeed1 == null) && (bw_PlaneFeed2 == null) && (bw_PlaneFeed3 == null))
|
|
MessageBox.Show("Plane Feeds are disabled. \n\nYou can use the software anyway, but you will never see a plane on the map. \nIn order to get valid plane positions do the following:\n\n1. Go to the \"Options/Plane\" tab and activate at least one plane feed\n2. Go to the \"Options/General\" tab and adjust \"Planes Positions Range\" to a suitable area around your location", "Plane Feeds Disabled");
|
|
|
|
// invalidate tracking values
|
|
TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
|
|
// set online mode by default
|
|
Properties.Settings.Default.Time_Mode_Online = true;
|
|
|
|
// install OnIdle event handler
|
|
// must be here at first!
|
|
Application.Idle += new EventHandler(OnIdle);
|
|
// move map to MyLoc
|
|
if (!double.IsNaN(Properties.Settings.Default.MyLat) && !double.IsNaN(Properties.Settings.Default.MyLon))
|
|
gm_Main.Position = new PointLatLng(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
// update status
|
|
UpdateStatus();
|
|
//initialize maps
|
|
InitializeMaps();
|
|
// show airports on map
|
|
UpdateAirports();
|
|
// show watchlist on map
|
|
UpdateWatchlistInMap();
|
|
// set special event handlers on locator combo boxes
|
|
// set callsign history and locs
|
|
cb_MyCall_TextChanged(this, null);
|
|
// set MyLoc and DXLoc combobox properties
|
|
cb_MyLoc.DisplayMember = nameof(LocatorDropDownItem.Locator);
|
|
cb_MyLoc.ValueMember = nameof(LocatorDropDownItem.GeoLocation);
|
|
cb_MyLoc.Precision = (int)Properties.Settings.Default.Locator_MaxLength / 2;
|
|
cb_MyLoc.SmallLettersForSubsquares = Properties.Settings.Default.Locator_SmallLettersForSubsquares;
|
|
cb_MyLoc.AutoLength = Properties.Settings.Default.Locator_AutoLength;
|
|
cb_DXLoc.DisplayMember = nameof(LocatorDropDownItem.Locator);
|
|
cb_DXLoc.ValueMember = nameof(LocatorDropDownItem.GeoLocation);
|
|
cb_DXLoc.Precision = (int)Properties.Settings.Default.Locator_MaxLength / 2;
|
|
cb_DXLoc.SmallLettersForSubsquares = Properties.Settings.Default.Locator_SmallLettersForSubsquares;
|
|
cb_DXLoc.AutoLength = Properties.Settings.Default.Locator_AutoLength;
|
|
// populate watchlist
|
|
RefreshWatchlistView();
|
|
// Linux/Mon Hacks for layout
|
|
if (SupportFunctions.IsMono)
|
|
{
|
|
// cycle control tab view to ensure that all elements are drawn
|
|
tc_Control.SelectedTab = tp_Control_Options;
|
|
tc_Control.SelectedTab = tp_Control_Multi;
|
|
tc_Control.SelectedTab = tp_Control_Single;
|
|
|
|
btn_Map_PlayPause.Image = null;
|
|
btn_Map_PlayPause.Text = "Play";
|
|
btn_Map_PlayPause.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
|
btn_Map_PlayPause.Font = new Font(btn_Map_PlayPause.Font, FontStyle.Bold);
|
|
}
|
|
// set players bounds
|
|
sb_Analysis_Play.Minimum = 0;
|
|
sb_Analysis_Play.Maximum = int.MaxValue;
|
|
// set path mode to single
|
|
PathMode = AIRSCOUTPATHMODE.SINGLE;
|
|
// set life mode to life
|
|
LifeMode = AIRSCOUTLIFEMODE.LIFE;
|
|
// set play mode to pause
|
|
PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
|
|
// maintain background calculations thread wait
|
|
Properties.Settings.Default.Background_Calculations_ThreadWait = 0;
|
|
Log.WriteMessage("Finished.");
|
|
// start timer to finish startup
|
|
ti_Startup.Start();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// close the application in case of any exception
|
|
if (Log != null)
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
else
|
|
Console.WriteLine("Fatal Error: " + ex.ToString());
|
|
// close the splash window
|
|
if (SplashDlg != null)
|
|
SplashDlg.Close();
|
|
MessageBox.Show("An error occured during startup: " + ex.ToString() + "\n\nPress >OK< to close the application.", "AirScout", MessageBoxButtons.OK);
|
|
this.Close();
|
|
}
|
|
// restore window size, state and location
|
|
try
|
|
{
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
this.Size = Properties.Settings.Default.General_WindowSize;
|
|
this.Location = Properties.Settings.Default.General_WindowLocation;
|
|
this.WindowState = Properties.Settings.Default.General_WindowState;
|
|
}
|
|
else
|
|
{
|
|
// ignore window settings under Linux/Mono
|
|
// start always maximized
|
|
this.WindowState = FormWindowState.Maximized;
|
|
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if failed
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
// reset splitter positions to its default value in settings
|
|
Properties.Settings.Default.MainSplitter_Distance = -1;
|
|
Properties.Settings.Default.MapSplitter_Distance = -1;
|
|
}
|
|
|
|
// dump all properties to log
|
|
Log.WriteMessage("============================= Application Settings ==================================");
|
|
DumpSettingsToLog("Properties.Settings.Default", Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("AirScout.PlaneFeeds.Properties.Settings.Default", AirScout.PlaneFeeds.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("ScoutBase.Elevation.Properties.Settings.Default", ScoutBase.Elevation.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("ScoutBase.Stations.Properties.Settings.Default", ScoutBase.Stations.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("ScoutBase.Propagation.Properties.Settings.Default", ScoutBase.Propagation.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("ScoutBase.CAT.Properties.Settings.Default", ScoutBase.CAT.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("AirScout.Aircrafts.Properties.Settings.Default", AirScout.Aircrafts.Properties.Settings.Default.PropertyValues);
|
|
DumpSettingsToLog("AirScout.CAT.Properties.Settings.Default", AirScout.CAT.Properties.Settings.Default.PropertyValues);
|
|
Log.WriteMessage("=====================================================================================");
|
|
|
|
// set Pause Mode
|
|
// Pause();
|
|
|
|
}
|
|
|
|
private void FinishStartup()
|
|
{
|
|
// finish startup
|
|
// close splash window
|
|
// set window layout
|
|
if (SplashDlg != null)
|
|
SplashDlg.Close();
|
|
// restore splitter positions
|
|
try
|
|
{
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
MapSplitterDistance = Properties.Settings.Default.MapSplitter_Distance;
|
|
MainSplitterDistance = Properties.Settings.Default.MainSplitter_Distance;
|
|
}
|
|
else
|
|
{
|
|
// ignore window settings under Linux/Mono and always use default values
|
|
MapSplitterDistance = -1;
|
|
MainSplitterDistance = -1;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if failed
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
// make main window visible
|
|
this.Visible = true;
|
|
// set focus to map
|
|
this.btn_Map_Save.Focus();
|
|
// Linux/Mono compatibility
|
|
// simulate splitter click
|
|
this.sc_Map_SplitterMoved(this, null);
|
|
this.sc_Main_SplitterMoved(this, null);
|
|
}
|
|
|
|
// creates plane feed work event arguments from settings
|
|
private PlaneFeedWorkEventArgs CreatePlaneFeedWorkEventArgs(string feedname)
|
|
{
|
|
PlaneFeedWorkEventArgs feedargs = new PlaneFeedWorkEventArgs();
|
|
feedargs.Feed = null;
|
|
foreach (IPlaneFeedPlugin plugin in PlaneFeedPlugins)
|
|
{
|
|
if (plugin.Name == feedname)
|
|
feedargs.Feed = plugin;
|
|
}
|
|
feedargs.AppDirectory = AppDirectory;
|
|
feedargs.AppDataDirectory = AppDataDirectory;
|
|
feedargs.LogDirectory = LogDirectory;
|
|
feedargs.TmpDirectory = TmpDirectory;
|
|
feedargs.DatabaseDirectory = DatabaseDirectory;
|
|
feedargs.PlanePositionsDirectory = PlanePositionsDirectory;
|
|
feedargs.MaxLat = Properties.Settings.Default.MaxLat;
|
|
feedargs.MinLon = Properties.Settings.Default.MinLon;
|
|
feedargs.MinLat = Properties.Settings.Default.MinLat;
|
|
feedargs.MaxLon = Properties.Settings.Default.MaxLon;
|
|
feedargs.MinAlt = Properties.Settings.Default.Planes_MinAlt;
|
|
feedargs.MaxAlt = Properties.Settings.Default.Planes_MaxAlt;
|
|
feedargs.MyLat = Properties.Settings.Default.MyLat;
|
|
feedargs.MyLon = Properties.Settings.Default.MyLon;
|
|
feedargs.DXLat = Properties.Settings.Default.DXLat;
|
|
feedargs.DXLon = Properties.Settings.Default.DXLon;
|
|
feedargs.KeepHistory = Properties.Settings.Default.Planes_KeepHistory;
|
|
feedargs.Interval = Properties.Settings.Default.Planes_Interval;
|
|
feedargs.ExtendedPlausibilityCheck_Enable = Properties.Settings.Default.Planes_ExtendedPlausibilityCheck_Enabled;
|
|
feedargs.ExtendedPlausiblityCheck_MaxErrorDist = Properties.Settings.Default.Planes_ExtendedPlausibilityCheck_MaxErrorDist;
|
|
feedargs.LogErrors = Properties.Settings.Default.Planes_LogErrors;
|
|
feedargs.InstanceID = Properties.Settings.Default.AirScout_Instance_ID;
|
|
feedargs.SessionKey = SessionKey;
|
|
feedargs.GetKeyURL = Properties.Settings.Default.AirScout_GetKey_URL;
|
|
feedargs.LogPlanePositions = Properties.Settings.Default.Planes_TracePositions;
|
|
return feedargs;
|
|
}
|
|
|
|
private void StartAllBackgroundWorkers()
|
|
{
|
|
// start all background workers
|
|
// check if the thread is not NULL and not activated
|
|
Say("Starting background threads...");
|
|
if ((bw_AirportMapper != null) && !bw_AirportMapper.IsBusy)
|
|
bw_AirportMapper.RunWorkerAsync();
|
|
if ((bw_JSONWriter != null) && !bw_JSONWriter.IsBusy)
|
|
bw_JSONWriter.RunWorkerAsync();
|
|
if ((bw_NewsFeed != null) && !bw_NewsFeed.IsBusy)
|
|
bw_NewsFeed.RunWorkerAsync();
|
|
if ((bw_AircraftDatabaseMaintainer != null) && (!bw_AircraftDatabaseMaintainer.IsBusy))
|
|
{
|
|
AircraftPositionDatabaseMaintainerStartOptions startoptions = new AircraftPositionDatabaseMaintainerStartOptions();
|
|
startoptions.Name = "Aircrafts";
|
|
startoptions.Database_MaxCount = (long)Properties.Settings.Default.AircraftDatabase_MaxCount;
|
|
startoptions.Database_MaxSize = (double)Properties.Settings.Default.AircraftDatabase_MaxSize;
|
|
startoptions.Database_MaxDaysLifetime = (int)Properties.Settings.Default.AircraftDatabase_MaxDaysLifetime;
|
|
bw_AircraftDatabaseMaintainer.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Background_Update_OnStartup)
|
|
{
|
|
if ((bw_StationDatabaseUpdater != null) && !bw_StationDatabaseUpdater.IsBusy)
|
|
{
|
|
StationDatabaseUpdaterStartOptions startoptions = new StationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "Stations";
|
|
startoptions.RestrictToAreaOfInterest = Properties.Settings.Default.Location_RestrictToAreaOfInterest;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.InstanceID = Properties.Settings.Default.AirScout_Instance_ID;
|
|
startoptions.SessionKey = SessionKey;
|
|
startoptions.GetKeyURL = Properties.Settings.Default.AirScout_GetKey_URL;
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
bw_StationDatabaseUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if ((bw_AircraftDatabaseUpdater != null) && !bw_AircraftDatabaseUpdater.IsBusy)
|
|
{
|
|
AircraftDatabaseUpdaterStartOptions startoptions = new AircraftDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "Aircrafts";
|
|
startoptions.InstanceID = Properties.Settings.Default.AirScout_Instance_ID;
|
|
startoptions.SessionKey = SessionKey;
|
|
startoptions.GetKeyURL = Properties.Settings.Default.AirScout_GetKey_URL;
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
bw_AircraftDatabaseUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (bw_GLOBEUpdater != null) && !bw_GLOBEUpdater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "GLOBE";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
startoptions.Model = ELEVATIONMODEL.GLOBE;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_GLOBE_EnableCache;
|
|
bw_GLOBEUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (bw_SRTM3Updater != null) && !bw_SRTM3Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "SRTM3";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
startoptions.Model = ELEVATIONMODEL.SRTM3;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_SRTM3_EnableCache;
|
|
bw_SRTM3Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (bw_SRTM1Updater != null) && !bw_SRTM1Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "SRTM1";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
startoptions.Model = ELEVATIONMODEL.SRTM1;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_SRTM1_EnableCache;
|
|
bw_SRTM1Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (bw_ASTER3Updater != null) && !bw_ASTER3Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "ASTER3";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
startoptions.Model = ELEVATIONMODEL.ASTER3;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_ASTER3_EnableCache;
|
|
bw_ASTER3Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (bw_ASTER1Updater != null) && !bw_ASTER1Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "ASTER1";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE;
|
|
startoptions.Model = ELEVATIONMODEL.ASTER1;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_ASTER1_EnableCache;
|
|
bw_ASTER1Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (bw_GLOBEPathCalculator != null) && !bw_GLOBEPathCalculator.IsBusy)
|
|
bw_GLOBEPathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (bw_SRTM3PathCalculator != null) && !bw_SRTM3PathCalculator.IsBusy)
|
|
bw_SRTM3PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (bw_SRTM1PathCalculator != null) && !bw_SRTM1PathCalculator.IsBusy)
|
|
bw_SRTM1PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (bw_ASTER3PathCalculator != null) && !bw_ASTER3PathCalculator.IsBusy)
|
|
bw_ASTER3PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (bw_ASTER1PathCalculator != null) && !bw_ASTER1PathCalculator.IsBusy)
|
|
bw_ASTER1PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
if (Properties.Settings.Default.Map_Preloader_Enabled && (bw_MapPreloader != null) && !bw_MapPreloader.IsBusy)
|
|
bw_MapPreloader.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNONCE);
|
|
}
|
|
else if (Properties.Settings.Default.Background_Update_Periodically)
|
|
{
|
|
if ((bw_StationDatabaseUpdater != null) && !bw_StationDatabaseUpdater.IsBusy)
|
|
{
|
|
StationDatabaseUpdaterStartOptions startoptions = new StationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "Stations";
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.RestrictToAreaOfInterest = Properties.Settings.Default.Location_RestrictToAreaOfInterest;
|
|
startoptions.InstanceID = Properties.Settings.Default.AirScout_Instance_ID;
|
|
startoptions.SessionKey = SessionKey;
|
|
startoptions.GetKeyURL = Properties.Settings.Default.AirScout_GetKey_URL;
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
bw_StationDatabaseUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if ((bw_AircraftDatabaseUpdater != null) && !bw_AircraftDatabaseUpdater.IsBusy)
|
|
{
|
|
AircraftDatabaseUpdaterStartOptions startoptions = new AircraftDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "Aircrafts";
|
|
startoptions.InstanceID = Properties.Settings.Default.AirScout_Instance_ID;
|
|
startoptions.SessionKey = SessionKey;
|
|
startoptions.GetKeyURL = Properties.Settings.Default.AirScout_GetKey_URL;
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
bw_AircraftDatabaseUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (bw_GLOBEUpdater != null) && !bw_GLOBEUpdater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "GLOBE";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
startoptions.Model = ELEVATIONMODEL.GLOBE;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_GLOBE_EnableCache;
|
|
bw_GLOBEUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (bw_SRTM3Updater != null) && !bw_SRTM3Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "SRTM3";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
startoptions.Model = ELEVATIONMODEL.SRTM3;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_SRTM3_EnableCache;
|
|
bw_SRTM3Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (bw_SRTM1Updater != null) && !bw_SRTM1Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "SRTM1";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
startoptions.Model = ELEVATIONMODEL.SRTM1;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_SRTM1_EnableCache;
|
|
bw_SRTM1Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (bw_ASTER3Updater != null) && !bw_ASTER3Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "ASTER3";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
startoptions.Model = ELEVATIONMODEL.ASTER3;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_ASTER3_EnableCache;
|
|
bw_ASTER3Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (bw_ASTER1Updater != null) && !bw_ASTER1Updater.IsBusy)
|
|
{
|
|
ElevationDatabaseUpdaterStartOptions startoptions = new ElevationDatabaseUpdaterStartOptions();
|
|
startoptions.Name = "ASTER1";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
startoptions.Model = ELEVATIONMODEL.ASTER1;
|
|
startoptions.MinLat = Properties.Settings.Default.MinLat;
|
|
startoptions.MinLon = Properties.Settings.Default.MinLon;
|
|
startoptions.MaxLat = Properties.Settings.Default.MaxLat;
|
|
startoptions.MaxLon = Properties.Settings.Default.MaxLon;
|
|
startoptions.FileCacheEnabled = Properties.Settings.Default.Elevation_ASTER1_EnableCache;
|
|
bw_ASTER1Updater.RunWorkerAsync(startoptions);
|
|
}
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (bw_GLOBEPathCalculator != null) && !bw_GLOBEPathCalculator.IsBusy)
|
|
bw_GLOBEPathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (bw_SRTM3PathCalculator != null) && !bw_SRTM3PathCalculator.IsBusy)
|
|
bw_SRTM3PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (bw_SRTM1PathCalculator != null) && !bw_SRTM1PathCalculator.IsBusy)
|
|
bw_SRTM1PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (bw_ASTER3PathCalculator != null) && !bw_ASTER3PathCalculator.IsBusy)
|
|
bw_ASTER3PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (bw_ASTER1PathCalculator != null) && !bw_ASTER1PathCalculator.IsBusy)
|
|
bw_ASTER1PathCalculator.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
if (Properties.Settings.Default.Map_Preloader_Enabled && (bw_MapPreloader != null) && !bw_MapPreloader.IsBusy)
|
|
bw_MapPreloader.RunWorkerAsync(BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY);
|
|
}
|
|
|
|
if ((bw_PlaneFeed1 != null) && (!bw_PlaneFeed1.IsBusy))
|
|
bw_PlaneFeed1.RunWorkerAsync(CreatePlaneFeedWorkEventArgs(Properties.Settings.Default.Planes_PlaneFeed1));
|
|
if ((bw_PlaneFeed2 != null) && (!bw_PlaneFeed2.IsBusy))
|
|
bw_PlaneFeed2.RunWorkerAsync(CreatePlaneFeedWorkEventArgs(Properties.Settings.Default.Planes_PlaneFeed2));
|
|
if ((bw_PlaneFeed3 != null) && (!bw_PlaneFeed3.IsBusy))
|
|
bw_PlaneFeed3.RunWorkerAsync(CreatePlaneFeedWorkEventArgs(Properties.Settings.Default.Planes_PlaneFeed3));
|
|
|
|
if (Properties.Settings.Default.Server_Activate)
|
|
{
|
|
if ((bw_WinTestReceive != null) && (!bw_WinTestReceive.IsBusy))
|
|
bw_WinTestReceive.RunWorkerAsync();
|
|
WebserverStartArgs args = new WebserverStartArgs();
|
|
args.TmpDirectory = TmpDirectory;
|
|
args.WebserverDirectory = WebserverDirectory;
|
|
if ((bw_Webserver != null) && (!bw_Webserver.IsBusy))
|
|
bw_Webserver.RunWorkerAsync(args);
|
|
}
|
|
|
|
if (Properties.Settings.Default.SpecLab_Enabled)
|
|
{
|
|
if ((bw_SpecLab_Receive != null) && (!bw_SpecLab_Receive.IsBusy))
|
|
bw_SpecLab_Receive.RunWorkerAsync();
|
|
}
|
|
|
|
if (Properties.Settings.Default.Track_Activate)
|
|
{
|
|
if ((bw_Track != null) && (!bw_Track.IsBusy))
|
|
bw_Track.RunWorkerAsync();
|
|
}
|
|
|
|
if (AirScout.CAT.Properties.Settings.Default.CAT_Activate)
|
|
{
|
|
CATUpdaterStartOptions startoptions = new CATUpdaterStartOptions();
|
|
startoptions.Name = "CAT Updater";
|
|
startoptions.Options = BACKGROUNDUPDATERSTARTOPTIONS.RUNPERIODICALLY;
|
|
if ((bw_CATUpdater != null) && (!bw_CATUpdater.IsBusy))
|
|
bw_CATUpdater.RunWorkerAsync(startoptions);
|
|
}
|
|
|
|
if (AirScout.CAT.Properties.Settings.Default.CAT_Activate)
|
|
{
|
|
CATWorkerStartOptions startoptions = new CATWorkerStartOptions();
|
|
startoptions.Name = "CAT Interface";
|
|
startoptions.RigType = AirScout.CAT.Properties.Settings.Default.CAT_RigType;
|
|
startoptions.PortName = AirScout.CAT.Properties.Settings.Default.CAT_PortName;
|
|
startoptions.Baudrate = AirScout.CAT.Properties.Settings.Default.CAT_Baudrate;
|
|
startoptions.DataBits = AirScout.CAT.Properties.Settings.Default.CAT_DataBits;
|
|
startoptions.Parity = AirScout.CAT.Properties.Settings.Default.CAT_Parity;
|
|
startoptions.StopBits = AirScout.CAT.Properties.Settings.Default.CAT_StopBits;
|
|
startoptions.RTS = AirScout.CAT.Properties.Settings.Default.CAT_RTS;
|
|
startoptions.DTR = AirScout.CAT.Properties.Settings.Default.CAT_DTR;
|
|
startoptions.Poll = AirScout.CAT.Properties.Settings.Default.CAT_Poll;
|
|
startoptions.Timeout = AirScout.CAT.Properties.Settings.Default.CAT_Timeout;
|
|
if ((bw_CAT != null) && (!bw_CAT.IsBusy))
|
|
bw_CAT.RunWorkerAsync(startoptions);
|
|
}
|
|
Say("Background threads started.");
|
|
}
|
|
|
|
private void StopBackgroundworker(BackgroundWorker worker, string name, int count, int total)
|
|
{
|
|
if (worker == null)
|
|
return;
|
|
if (!worker.IsBusy)
|
|
return;
|
|
worker.CancelAsync();
|
|
// waiting for background threads to finish
|
|
int timeout = 10000; // timeout in ms
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
Say("Stopping background thread " + count.ToString() + " of " + total.ToString() + " [" + name + "]...");
|
|
while ((worker != null) && worker.IsBusy)
|
|
{
|
|
Application.DoEvents();
|
|
}
|
|
st.Stop();
|
|
Log.WriteMessage("Stopping " + name + ", " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
|
|
private void StopAllBackgroundWorkers()
|
|
{
|
|
Say("Stopping background threads...");
|
|
// cancel permanent background workers, wait for finish
|
|
int bcount = 18;
|
|
int i = 1;
|
|
// cancel all threads
|
|
StopBackgroundworker(bw_WinTestReceive, nameof(bw_WinTestReceive), i, bcount); i++;
|
|
StopBackgroundworker(bw_SpecLab_Receive, nameof(bw_SpecLab_Receive), i, bcount); i++;
|
|
StopBackgroundworker(bw_Track, nameof(bw_Track), i, bcount); i++;
|
|
StopBackgroundworker(bw_JSONWriter, nameof(bw_JSONWriter), i, bcount); i++;
|
|
StopBackgroundworker(bw_NewsFeed, nameof(bw_NewsFeed), i, bcount); i++;
|
|
StopBackgroundworker(bw_PlaneFeed1, nameof(bw_PlaneFeed1), i, bcount); i++;
|
|
StopBackgroundworker(bw_PlaneFeed2, nameof(bw_PlaneFeed2), i, bcount); i++;
|
|
StopBackgroundworker(bw_PlaneFeed3, nameof(bw_PlaneFeed3), i, bcount); i++;
|
|
StopBackgroundworker(bw_GLOBEPathCalculator, nameof(bw_GLOBEPathCalculator), i, bcount); i++;
|
|
StopBackgroundworker(bw_SRTM3PathCalculator, nameof(bw_SRTM3PathCalculator), i, bcount); i++;
|
|
StopBackgroundworker(bw_SRTM1PathCalculator, nameof(bw_SRTM1PathCalculator), i, bcount); i++;
|
|
StopBackgroundworker(bw_ASTER3PathCalculator, nameof(bw_ASTER3PathCalculator), i, bcount); i++;
|
|
StopBackgroundworker(bw_ASTER1PathCalculator, nameof(bw_ASTER1PathCalculator), i, bcount); i++;
|
|
StopBackgroundworker(bw_AircraftDatabaseUpdater, nameof(bw_AircraftDatabaseUpdater), i, bcount); i++;
|
|
StopBackgroundworker(bw_StationDatabaseUpdater, nameof(bw_StationDatabaseUpdater), i, bcount); i++;
|
|
StopBackgroundworker(bw_MapPreloader, nameof(bw_MapPreloader), i, bcount); i++;
|
|
StopBackgroundworker(bw_CATUpdater, nameof(bw_CATUpdater), i, bcount); i++;
|
|
StopBackgroundworker(bw_CAT, nameof(bw_CAT), i, bcount); i++;
|
|
Say("Background threads stopped.");
|
|
}
|
|
|
|
private void CancelAllBackgroundWorkers()
|
|
{
|
|
// cancel all background workers, don't wait for finish
|
|
if (bw_AirportMapper != null)
|
|
bw_AirportMapper.CancelAsync();
|
|
if (bw_PlaneFeed1 != null)
|
|
bw_PlaneFeed1.CancelAsync();
|
|
if (bw_PlaneFeed2 != null)
|
|
bw_PlaneFeed2.CancelAsync();
|
|
if (bw_PlaneFeed3 != null)
|
|
bw_PlaneFeed3.CancelAsync();
|
|
if (bw_WinTestReceive != null)
|
|
bw_WinTestReceive.CancelAsync();
|
|
if (bw_SpecLab_Receive != null)
|
|
bw_SpecLab_Receive.CancelAsync();
|
|
if (bw_Track != null)
|
|
bw_Track.CancelAsync();
|
|
if (bw_JSONWriter != null)
|
|
bw_JSONWriter.CancelAsync();
|
|
if (bw_Webserver != null)
|
|
bw_Webserver.CancelAsync();
|
|
if (bw_NewsFeed != null)
|
|
bw_NewsFeed.CancelAsync();
|
|
if (bw_HistoryDownloader != null)
|
|
bw_HistoryDownloader.CancelAsync();
|
|
if (bw_StationDatabaseUpdater != null)
|
|
bw_StationDatabaseUpdater.CancelAsync();
|
|
if (bw_AircraftDatabaseMaintainer != null)
|
|
bw_AircraftDatabaseMaintainer.CancelAsync();
|
|
if (bw_AircraftDatabaseUpdater != null)
|
|
bw_AircraftDatabaseUpdater.CancelAsync();
|
|
if (bw_GLOBEPathCalculator != null)
|
|
bw_GLOBEUpdater.CancelAsync();
|
|
if (bw_SRTM3Updater != null)
|
|
bw_SRTM3Updater.CancelAsync();
|
|
if (bw_SRTM1Updater != null)
|
|
bw_SRTM1Updater.CancelAsync();
|
|
if (bw_ASTER3Updater != null)
|
|
bw_ASTER3Updater.CancelAsync();
|
|
if (bw_ASTER1Updater != null)
|
|
bw_ASTER1Updater.CancelAsync();
|
|
if (bw_GLOBEPathCalculator != null)
|
|
bw_GLOBEPathCalculator.CancelAsync();
|
|
if (bw_SRTM3PathCalculator != null)
|
|
bw_SRTM3PathCalculator.CancelAsync();
|
|
if (bw_SRTM1PathCalculator != null)
|
|
bw_SRTM1PathCalculator.CancelAsync();
|
|
if (bw_ASTER3PathCalculator != null)
|
|
bw_ASTER3PathCalculator.CancelAsync();
|
|
if (bw_ASTER1PathCalculator != null)
|
|
bw_ASTER1PathCalculator.CancelAsync();
|
|
if (bw_CATUpdater != null)
|
|
bw_CATUpdater.CancelAsync();
|
|
if (bw_CAT != null)
|
|
bw_CAT.CancelAsync();
|
|
}
|
|
|
|
private Bitmap CreatePlaneIcon(Color color)
|
|
{
|
|
// get the basic icon
|
|
Bitmap bm = new Bitmap(AppDirectory + Path.DirectorySeparatorChar + Properties.Settings.Default.Planes_IconFileName);
|
|
// read the content and change color of each pixel
|
|
for (int j = 0; j < bm.Width; j++)
|
|
{
|
|
for (int k = 0; k < bm.Height; k++)
|
|
{
|
|
// get the color of each pixel
|
|
Color c = bm.GetPixel(j, k);
|
|
// check if not transparent
|
|
if (c.A > 0)
|
|
{
|
|
// change color
|
|
bm.SetPixel(j, k, Color.FromArgb(c.A, color.R, color.G, color.B));
|
|
}
|
|
}
|
|
}
|
|
return bm;
|
|
}
|
|
|
|
public static Color ColorFromHSV(double hue, double saturation, double value)
|
|
{
|
|
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
|
|
double f = hue / 60 - Math.Floor(hue / 60);
|
|
|
|
value = value * 255;
|
|
int v = Convert.ToInt32(value);
|
|
int p = Convert.ToInt32(value * (1 - saturation));
|
|
int q = Convert.ToInt32(value * (1 - f * saturation));
|
|
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
|
|
|
|
if (hi == 0)
|
|
return Color.FromArgb(255, v, t, p);
|
|
else if (hi == 1)
|
|
return Color.FromArgb(255, q, v, p);
|
|
else if (hi == 2)
|
|
return Color.FromArgb(255, p, v, t);
|
|
else if (hi == 3)
|
|
return Color.FromArgb(255, p, q, v);
|
|
else if (hi == 4)
|
|
return Color.FromArgb(255, t, p, v);
|
|
else
|
|
return Color.FromArgb(255, v, p, q);
|
|
}
|
|
|
|
public Color GetColor(double power)
|
|
{
|
|
double H = power * 0.3; // Hue (note 0.4 = Green, see huge chart below)
|
|
double S = 0.95; // Saturation
|
|
double B = 0.95; // Brightness
|
|
|
|
return ColorFromHSV((float)H * 360, (float)S, (float)B);
|
|
}
|
|
|
|
private Bitmap CreateAirportIcon(int alpha)
|
|
{
|
|
// get the basic icon
|
|
Bitmap bm = new Bitmap(AppDirectory + Path.DirectorySeparatorChar + Properties.Settings.Default.Airports_IconFileName);
|
|
// read the content and change opacity of each pixel
|
|
for (int j = 0; j < bm.Width; j++)
|
|
{
|
|
for (int k = 0; k < bm.Height; k++)
|
|
{
|
|
// get the color of each pixel
|
|
Color c = bm.GetPixel(j, k);
|
|
// check if not transparent
|
|
if (c.A > 0)
|
|
{
|
|
// change color
|
|
bm.SetPixel(j, k, Color.FromArgb(alpha, c.R, c.G, c.B));
|
|
}
|
|
}
|
|
}
|
|
return bm;
|
|
}
|
|
|
|
private void InitializeIcons()
|
|
{
|
|
// create extra icons regular size
|
|
Log.WriteMessage("Started.");
|
|
try
|
|
{
|
|
// now generate 0% - 100% colored planes
|
|
for (int i = 0; i <= 100; i++)
|
|
{
|
|
Bitmap bm = CreatePlaneIcon(GetColor(1.0f - (float)i / 100.0f));
|
|
il_Planes_L.Images.Add(bm);
|
|
il_Planes_M.Images.Add(bm);
|
|
il_Planes_H.Images.Add(bm);
|
|
il_Planes_S.Images.Add(bm);
|
|
}
|
|
il_Planes_L.Images.Add(CreatePlaneIcon(Color.Gray));
|
|
il_Planes_M.Images.Add(CreatePlaneIcon(Color.Gray));
|
|
il_Planes_H.Images.Add(CreatePlaneIcon(Color.Gray));
|
|
il_Planes_S.Images.Add(CreatePlaneIcon(Color.Gray));
|
|
bmindex_gray = il_Planes_M.Images.Count - 1;
|
|
il_Planes_L.Images.Add(CreatePlaneIcon(Color.LightGreen));
|
|
il_Planes_M.Images.Add(CreatePlaneIcon(Color.LightGreen));
|
|
il_Planes_H.Images.Add(CreatePlaneIcon(Color.LightGreen));
|
|
il_Planes_S.Images.Add(CreatePlaneIcon(Color.LightGreen));
|
|
bmindex_lightgreen = il_Planes_M.Images.Count - 1;
|
|
il_Planes_L.Images.Add(CreatePlaneIcon(Color.DarkOrange));
|
|
il_Planes_M.Images.Add(CreatePlaneIcon(Color.DarkOrange));
|
|
il_Planes_H.Images.Add(CreatePlaneIcon(Color.DarkOrange));
|
|
il_Planes_S.Images.Add(CreatePlaneIcon(Color.DarkOrange));
|
|
bmindex_darkorange = il_Planes_M.Images.Count - 1;
|
|
il_Planes_L.Images.Add(CreatePlaneIcon(Color.Red));
|
|
il_Planes_M.Images.Add(CreatePlaneIcon(Color.Red));
|
|
il_Planes_H.Images.Add(CreatePlaneIcon(Color.Red));
|
|
il_Planes_S.Images.Add(CreatePlaneIcon(Color.Red));
|
|
bmindex_red = il_Planes_M.Images.Count - 1;
|
|
il_Planes_L.Images.Add(CreatePlaneIcon(Color.Magenta));
|
|
il_Planes_M.Images.Add(CreatePlaneIcon(Color.Magenta));
|
|
il_Planes_H.Images.Add(CreatePlaneIcon(Color.Magenta));
|
|
il_Planes_S.Images.Add(CreatePlaneIcon(Color.Magenta));
|
|
bmindex_magenta = il_Planes_M.Images.Count - 1;
|
|
il_Airports.Images.Add(CreateAirportIcon(255));
|
|
|
|
// save icons to Icons directory
|
|
il_Planes_L.Images[bmindex_gray].Save(
|
|
Path.Combine(IconDirectory, "plane_l_gray.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_M.Images[bmindex_gray].Save(
|
|
Path.Combine(IconDirectory, "plane_m_gray.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_H.Images[bmindex_gray].Save(
|
|
Path.Combine(IconDirectory, "plane_h_gray.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_S.Images[bmindex_gray].Save(
|
|
Path.Combine(IconDirectory, "plane_s_gray.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
|
|
il_Planes_L.Images[bmindex_darkorange].Save(
|
|
Path.Combine(IconDirectory, "plane_l_darkorange.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_M.Images[bmindex_darkorange].Save(
|
|
Path.Combine(IconDirectory, "plane_m_darkorange.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_H.Images[bmindex_darkorange].Save(
|
|
Path.Combine(IconDirectory, "plane_h_darkorange.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_S.Images[bmindex_darkorange].Save(
|
|
Path.Combine(IconDirectory, "plane_s_darkorange.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
|
|
il_Planes_L.Images[bmindex_red].Save(
|
|
Path.Combine(IconDirectory, "plane_l_red.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_M.Images[bmindex_red].Save(
|
|
Path.Combine(IconDirectory, "plane_m_red.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_H.Images[bmindex_red].Save(
|
|
Path.Combine(IconDirectory, "plane_h_red.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_S.Images[bmindex_red].Save(
|
|
Path.Combine(IconDirectory, "plane_s_red.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
|
|
il_Planes_L.Images[bmindex_magenta].Save(
|
|
Path.Combine(IconDirectory, "plane_l_magenta.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_M.Images[bmindex_magenta].Save(
|
|
Path.Combine(IconDirectory, "plane_m_magenta.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_H.Images[bmindex_magenta].Save(
|
|
Path.Combine(IconDirectory, "plane_h_magenta.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
il_Planes_S.Images[bmindex_magenta].Save(
|
|
Path.Combine(IconDirectory, "plane_s_magenta.png"),
|
|
System.Drawing.Imaging.ImageFormat.Png);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void InitializeCharts()
|
|
{
|
|
// propagation path chart
|
|
pm_Path.Title = String.Empty;
|
|
pm_Path.DefaultFontSize = (double)Properties.Settings.Default.Charts_FontSize;
|
|
pm_Path.IsLegendVisible = false;
|
|
pv_Path.BackColor = Color.White;
|
|
pv_Path.Model = pm_Path;
|
|
// add axes
|
|
pm_Path.Axes.Clear();
|
|
// add X-axis
|
|
Path_X.IsZoomEnabled = false;
|
|
Path_X.Maximum = 1000;
|
|
Path_X.Minimum = 0;
|
|
Path_X.MajorGridlineStyle = LineStyle.Solid;
|
|
Path_X.MinorGridlineStyle = LineStyle.Dot;
|
|
Path_X.Position = AxisPosition.Bottom;
|
|
this.pm_Path.Axes.Add(Path_X);
|
|
// add Y-axis
|
|
Path_Y.IsZoomEnabled = false;
|
|
Path_Y.Maximum = 20000;
|
|
Path_Y.Minimum = 0;
|
|
Path_Y.MajorGridlineStyle = LineStyle.Solid;
|
|
Path_Y.MinorGridlineStyle = LineStyle.Dot;
|
|
Path_Y.Position = AxisPosition.Left;
|
|
this.pm_Path.Axes.Add(Path_Y);
|
|
// add series
|
|
pm_Path.Series.Clear();
|
|
Path_Elevation.Title = "Elevation";
|
|
Min_H1.Title = "Min_H1";
|
|
Min_H1.StrokeThickness = 2;
|
|
Min_H1.LineStyle = LineStyle.Solid;
|
|
Min_H1.Color = OxyColors.Red;
|
|
Min_H2.Title = "Min_H2";
|
|
Min_H2.StrokeThickness = 2;
|
|
Min_H2.LineStyle = LineStyle.Solid;
|
|
Min_H2.Color = OxyColors.Gold;
|
|
Max_H.Title = "Max_H";
|
|
Max_H.StrokeThickness = 2;
|
|
Max_H.LineStyle = LineStyle.Dot;
|
|
Max_H.Color = OxyColors.DarkBlue;
|
|
Min_H.Title = "Min_H";
|
|
Min_H.StrokeThickness = 0;
|
|
Min_H.LineStyle = LineStyle.Solid;
|
|
Min_H.Color = OxyColors.Magenta.ChangeSaturation(0.4);
|
|
Planes_Hi.Title = "Planes_Hi";
|
|
Planes_Hi.Color = OxyColors.Transparent;
|
|
Planes_Hi.MarkerType = MarkerType.Square;
|
|
Planes_Hi.MarkerFill = OxyColors.Magenta;
|
|
Planes_Lo.Title = "Planes_Lo";
|
|
Planes_Lo.Color = OxyColors.Transparent;
|
|
Planes_Lo.MarkerType = MarkerType.Square;
|
|
Planes_Lo.MarkerFill = OxyColors.Gray;
|
|
pm_Path.Series.Add(Path_Elevation);
|
|
pm_Path.Series.Add(Min_H1);
|
|
pm_Path.Series.Add(Min_H2);
|
|
pm_Path.Series.Add(Max_H);
|
|
pm_Path.Series.Add(Min_H);
|
|
pm_Path.Series.Add(Planes_Hi);
|
|
pm_Path.Series.Add(Planes_Lo);
|
|
// add legend
|
|
pm_Path.LegendTitle = "";
|
|
pm_Path.LegendPosition = LegendPosition.TopRight;
|
|
pm_Path.LegendBackground = OxyColors.White;
|
|
pm_Path.LegendBorder = OxyColors.Black;
|
|
pm_Path.LegendBorderThickness = 1;
|
|
// add control
|
|
this.tp_Elevation.Controls.Add(pv_Path);
|
|
pv_Path.Paint += new PaintEventHandler(pv_Path_Paint);
|
|
|
|
// zoomed elevation chart
|
|
pm_Elevation.Title = String.Empty;
|
|
pm_Elevation.DefaultFontSize = (double)Properties.Settings.Default.Charts_FontSize;
|
|
pm_Elevation.IsLegendVisible = false;
|
|
pv_Elevation.BackColor = Color.White;
|
|
pv_Elevation.Model = pm_Elevation;
|
|
// add series
|
|
pm_Elevation.Series.Clear();
|
|
Elevation.Title = "Elevation";
|
|
LOS.Title = "LOS";
|
|
LOS.StrokeThickness = 2;
|
|
LOS.Color = OxyColors.Black;
|
|
pm_Elevation.Series.Add(Elevation);
|
|
pm_Elevation.Series.Add(LOS);
|
|
// create axes
|
|
pm_Elevation.Axes.Clear();
|
|
// add X-axis
|
|
Elevation_X.IsZoomEnabled = false;
|
|
Elevation_X.Maximum = 1000;
|
|
Elevation_X.Minimum = 0;
|
|
Elevation_X.MajorGridlineStyle = LineStyle.Solid;
|
|
Elevation_X.MinorGridlineStyle = LineStyle.Dot;
|
|
Elevation_X.Position = AxisPosition.Bottom;
|
|
this.pm_Elevation.Axes.Add(Elevation_X);
|
|
// add Y-axis
|
|
Elevation_Y.IsZoomEnabled = false;
|
|
// auto size maximum
|
|
// Elevation_Y.Maximum = maxelv,
|
|
Elevation_Y.Minimum = 0;
|
|
Elevation_Y.MajorGridlineStyle = LineStyle.Solid;
|
|
Elevation_Y.MinorGridlineStyle = LineStyle.Dot;
|
|
Elevation_Y.Position = AxisPosition.Left;
|
|
this.pm_Elevation.Axes.Add(Elevation_Y);
|
|
// add legend
|
|
pm_Elevation.LegendTitle = "";
|
|
pm_Elevation.LegendPosition = LegendPosition.TopRight;
|
|
pm_Elevation.LegendBackground = OxyColors.White;
|
|
pm_Elevation.LegendBorder = OxyColors.Black;
|
|
pm_Elevation.LegendBorderThickness = 1;
|
|
// add control
|
|
this.tp_Elevation.Controls.Add(pv_Elevation);
|
|
|
|
// spectrum chart
|
|
pm_Spectrum.Title = String.Empty;
|
|
pm_Spectrum.DefaultFontSize = (double)Properties.Settings.Default.Charts_FontSize;
|
|
pv_Spectrum.BackColor = Color.White;
|
|
pv_Spectrum.Model = pm_Spectrum;
|
|
// add Spectrum series
|
|
pm_Spectrum.Series.Clear();
|
|
// create axes
|
|
pm_Spectrum.Axes.Clear();
|
|
// add X-axis
|
|
Spectrum_X.IsZoomEnabled = false;
|
|
Spectrum_X.Maximum = SpectrumMaxPoints;
|
|
Spectrum_X.Minimum = 0;
|
|
Spectrum_X.MajorGridlineStyle = LineStyle.Solid;
|
|
Spectrum_X.MinorGridlineStyle = LineStyle.Dot;
|
|
Spectrum_X.Position = AxisPosition.Bottom;
|
|
this.pm_Spectrum.Axes.Add(Spectrum_X);
|
|
// add Y-axis
|
|
Spectrum_Y.IsZoomEnabled = false;
|
|
Spectrum_Y.Maximum = 0;
|
|
Spectrum_Y.Minimum = -120;
|
|
Spectrum_Y.MajorGridlineStyle = LineStyle.Solid;
|
|
Spectrum_Y.MinorGridlineStyle = LineStyle.Dot;
|
|
Spectrum_Y.Position = AxisPosition.Left;
|
|
this.pm_Spectrum.Axes.Add(Spectrum_Y);
|
|
// add series
|
|
SpectrumRecord.Color = OxyColors.Magenta;
|
|
pm_Spectrum.Series.Add(SpectrumRecord);
|
|
Spectrum.InterpolationAlgorithm = OxyPlot.InterpolationAlgorithms.CanonicalSpline;
|
|
Spectrum.StrokeThickness = 3;
|
|
Spectrum.Color = OxyColors.Goldenrod;
|
|
pm_Spectrum.Series.Add(Spectrum);
|
|
// add control
|
|
this.pv_Spectrum.Dock = DockStyle.Fill;
|
|
this.gb_Spectrum.Controls.Add(pv_Spectrum);
|
|
return;
|
|
|
|
}
|
|
|
|
private void InitializeWebbrowser()
|
|
{
|
|
// do not initialize webbrowser --> not working on all Linux systems
|
|
if (SupportFunctions.IsMono)
|
|
return;
|
|
// iniitialize webbrowser on Windows
|
|
this.wb_News = new System.Windows.Forms.WebBrowser();
|
|
//
|
|
// wb_News
|
|
//
|
|
this.wb_News.DataBindings.Add(new System.Windows.Forms.Binding("Url", global::AirScout.Properties.Settings.Default, "News_URL", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
|
|
this.wb_News.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
this.wb_News.Location = new System.Drawing.Point(0, 0);
|
|
this.wb_News.MinimumSize = new System.Drawing.Size(20, 20);
|
|
this.wb_News.Name = "wb_News";
|
|
this.wb_News.Size = new System.Drawing.Size(844, 197);
|
|
this.wb_News.TabIndex = 0;
|
|
this.wb_News.ScriptErrorsSuppressed = true;
|
|
this.wb_News.Url = global::AirScout.Properties.Settings.Default.News_URL;
|
|
this.tp_News.Controls.Add(this.wb_News);
|
|
}
|
|
|
|
private void UpdateAirports()
|
|
{
|
|
// clear airports first
|
|
gmo_Airports.Clear();
|
|
if (!Properties.Settings.Default.Airports_Activate)
|
|
return;
|
|
if ((Airports == null) || (Airports.Count == 0))
|
|
return;
|
|
foreach (AirportDesignator airport in Airports)
|
|
{
|
|
try
|
|
{
|
|
GMarkerGoogle gm = new GMarkerGoogle(new PointLatLng(airport.Lat, airport.Lon), ToolTipFont, RotateImageByAngle(il_Airports.Images[0], 0));
|
|
gm.ToolTipText = airport.Airport + "\n" +
|
|
airport.IATA + "/" + airport.ICAO;
|
|
gm.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
gm.Tag = airport.IATA + "," + airport.ICAO;
|
|
gmo_Airports.Markers.Add(gm);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
gm_Main.Refresh();
|
|
}
|
|
|
|
private void ti_Startup_Tick(object sender, EventArgs e)
|
|
{
|
|
FinishStartup();
|
|
ti_Startup.Stop();
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region User Settings
|
|
|
|
private string GetUserSettingsPath()
|
|
{
|
|
if (!SupportFunctions.IsMono)
|
|
return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath;
|
|
|
|
// try to build a path to user specific settings under Linux/Mono
|
|
string usersettingspath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
usersettingspath = Path.Combine(usersettingspath, Application.CompanyName, AppDomain.CurrentDomain.FriendlyName);
|
|
usersettingspath += "_Url_";
|
|
Assembly assembly = Assembly.GetEntryAssembly();
|
|
if (assembly == null)
|
|
{
|
|
assembly = Assembly.GetCallingAssembly();
|
|
}
|
|
byte[] pkt = assembly.GetName().GetPublicKeyToken();
|
|
byte[] hash = SHA1.Create().ComputeHash((pkt != null && pkt.Length > 0) ? pkt : Encoding.UTF8.GetBytes(assembly.EscapedCodeBase));
|
|
StringBuilder evidence_string = new StringBuilder();
|
|
byte[] array = hash;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
byte b = array[i];
|
|
evidence_string.AppendFormat("{0:x2}", b);
|
|
}
|
|
usersettingspath += evidence_string.ToString();
|
|
if (!Directory.Exists(usersettingspath))
|
|
{
|
|
Directory.CreateDirectory(usersettingspath);
|
|
}
|
|
usersettingspath = Path.Combine(usersettingspath, "user.config");
|
|
return usersettingspath;
|
|
}
|
|
|
|
private void LoadSettingsFromJSON(ApplicationSettingsBase settings)
|
|
{
|
|
string filename = GetUserSettingsPath().Replace("user.config", settings.GetType().FullName + ".json");
|
|
|
|
if (!File.Exists(filename))
|
|
return;
|
|
JsonSerializerSettings serializersettings = new JsonSerializerSettings();
|
|
Dictionary<string, string> props =
|
|
JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(filename));
|
|
foreach (string key in props.Keys)
|
|
{
|
|
try
|
|
{
|
|
settings[key] = JsonConvert.DeserializeObject(props[key], settings.Properties[key].PropertyType);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Error while loading user setting: " + ex.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadUserSettings()
|
|
{
|
|
try
|
|
{
|
|
Console.WriteLine("Loading user settings...");
|
|
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
// use Windows standard Properties.Settings.Default behavoir
|
|
ScoutBase.Elevation.Properties.Settings.Default.Reload();
|
|
ScoutBase.Stations.Properties.Settings.Default.Reload();
|
|
ScoutBase.Propagation.Properties.Settings.Default.Reload();
|
|
ScoutBase.CAT.Properties.Settings.Default.Reload();
|
|
AirScout.Aircrafts.Properties.Settings.Default.Reload();
|
|
AirScout.PlaneFeeds.Properties.Settings.Default.Reload();
|
|
AirScout.CAT.Properties.Settings.Default.Reload();
|
|
Properties.Settings.Default.Reload();
|
|
|
|
return;
|
|
}
|
|
|
|
// Mono hack to assure that default values were initilaized
|
|
ScoutBase.Elevation.Properties.Settings.Default.Reset();
|
|
ScoutBase.Stations.Properties.Settings.Default.Reset();
|
|
ScoutBase.Propagation.Properties.Settings.Default.Reset();
|
|
ScoutBase.CAT.Properties.Settings.Default.Reset();
|
|
AirScout.Aircrafts.Properties.Settings.Default.Reset();
|
|
AirScout.PlaneFeeds.Properties.Settings.Default.Reset();
|
|
AirScout.CAT.Properties.Settings.Default.Reset();
|
|
Properties.Settings.Default.Reset();
|
|
|
|
// Rather load settings as JSON
|
|
LoadSettingsFromJSON(ScoutBase.Elevation.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(ScoutBase.Stations.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(ScoutBase.Propagation.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(ScoutBase.CAT.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(AirScout.Aircrafts.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(AirScout.PlaneFeeds.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(AirScout.CAT.Properties.Settings.Default);
|
|
LoadSettingsFromJSON(Properties.Settings.Default);
|
|
|
|
Console.WriteLine("Loading user settings finished successfully.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Error while loading user settings: " + ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void SaveSettingsToJSON(ApplicationSettingsBase settings)
|
|
{
|
|
string filename = GetUserSettingsPath().Replace("user.config", settings.GetType().FullName + ".json");
|
|
|
|
Dictionary<string, object> props = new Dictionary<string, object>();
|
|
foreach (SettingsProperty prop in settings.Properties)
|
|
{
|
|
props.Add(prop.Name, JsonConvert.SerializeObject(settings[prop.Name]));
|
|
}
|
|
File.WriteAllText(filename, JsonConvert.SerializeObject(props, Newtonsoft.Json.Formatting.Indented));
|
|
}
|
|
|
|
private void SaveUserSettings()
|
|
{
|
|
try
|
|
{
|
|
Console.WriteLine("Saving configuration, FirstRun = " + Properties.Settings.Default.FirstRun);
|
|
Log.WriteMessage("Saving configuration...");
|
|
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
// save all settings
|
|
ScoutBase.CAT.Properties.Settings.Default.Save();
|
|
ScoutBase.Elevation.Properties.Settings.Default.Save();
|
|
ScoutBase.Stations.Properties.Settings.Default.Save();
|
|
ScoutBase.Propagation.Properties.Settings.Default.Save();
|
|
AirScout.Aircrafts.Properties.Settings.Default.Save();
|
|
AirScout.CAT.Properties.Settings.Default.Save();
|
|
Properties.Settings.Default.Save();
|
|
|
|
return;
|
|
}
|
|
|
|
// Rather save settings as JSON
|
|
SaveSettingsToJSON(Properties.Settings.Default);
|
|
SaveSettingsToJSON(AirScout.Aircrafts.Properties.Settings.Default);
|
|
SaveSettingsToJSON(AirScout.CAT.Properties.Settings.Default);
|
|
SaveSettingsToJSON(ScoutBase.Propagation.Properties.Settings.Default);
|
|
SaveSettingsToJSON(ScoutBase.Stations.Properties.Settings.Default);
|
|
SaveSettingsToJSON(ScoutBase.Elevation.Properties.Settings.Default);
|
|
SaveSettingsToJSON(ScoutBase.CAT.Properties.Settings.Default);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Unable to save settings: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Idle
|
|
|
|
private void OnIdle(object sender, EventArgs args)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Closing Down
|
|
|
|
private void MapDlg_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (Log != null)
|
|
{
|
|
Log.WriteMessage(Application.ProductName + " is closing.");
|
|
// flush the Log for the first time to save all messages
|
|
Log.FlushLog();
|
|
}
|
|
|
|
// stop playing when in PLAY mode
|
|
if (PlayMode != AIRSCOUTPLAYMODE.PAUSE)
|
|
Pause();
|
|
|
|
//save window size, state and location
|
|
if (this.WindowState == FormWindowState.Normal)
|
|
{
|
|
Properties.Settings.Default.General_WindowSize = this.Size;
|
|
Properties.Settings.Default.General_WindowLocation = this.Location;
|
|
}
|
|
else
|
|
{
|
|
Properties.Settings.Default.General_WindowSize = this.RestoreBounds.Size;
|
|
Properties.Settings.Default.General_WindowLocation = this.RestoreBounds.Location;
|
|
}
|
|
Properties.Settings.Default.General_WindowState = this.WindowState;
|
|
|
|
// save properties to file
|
|
SaveUserSettings();
|
|
|
|
Say("Waiting for background threads to close...");
|
|
// close background threads, save database and settings
|
|
try
|
|
{
|
|
// cancel background workers
|
|
// causes ThreadAbortExceptions on Linux ?!?
|
|
try
|
|
{
|
|
CancelAllBackgroundWorkers();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
// save splitter positions
|
|
Properties.Settings.Default.MainSplitter_Distance = MainSplitterDistance;
|
|
Properties.Settings.Default.MapSplitter_Distance = MapSplitterDistance;
|
|
|
|
// stop tracking
|
|
if (ConnectedRig != null)
|
|
{
|
|
ConnectedRig.LeaveDoppler();
|
|
}
|
|
TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
finally
|
|
{
|
|
// save InMemory databases if any
|
|
if (StationData.Database.IsInMemory())
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving station database...");
|
|
StationData.Database.BackupDatabase();
|
|
st.Stop();
|
|
Log.WriteMessage("Station database saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (PropagationData.Database.IsInMemory(ELEVATIONMODEL.GLOBE))
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving GLOBE database...");
|
|
PropagationData.Database.BackupDatabase(ELEVATIONMODEL.GLOBE);
|
|
st.Stop();
|
|
Log.WriteMessage("Propagation database GLOBE saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (PropagationData.Database.IsInMemory(ELEVATIONMODEL.SRTM3))
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving SRTM3 database...");
|
|
PropagationData.Database.BackupDatabase(ELEVATIONMODEL.SRTM3);
|
|
st.Stop();
|
|
Log.WriteMessage("Propagation database SRTM3 saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (PropagationData.Database.IsInMemory(ELEVATIONMODEL.SRTM1))
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving SRTM1 database...");
|
|
PropagationData.Database.BackupDatabase(ELEVATIONMODEL.SRTM1);
|
|
st.Stop();
|
|
Log.WriteMessage("Propagation database SRTM1 saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (PropagationData.Database.IsInMemory(ELEVATIONMODEL.ASTER3))
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving ASTER3 database...");
|
|
PropagationData.Database.BackupDatabase(ELEVATIONMODEL.ASTER3);
|
|
st.Stop();
|
|
Log.WriteMessage("Propagation database ASTER3 saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (PropagationData.Database.IsInMemory(ELEVATIONMODEL.ASTER1))
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving ASTER1 database...");
|
|
PropagationData.Database.BackupDatabase(ELEVATIONMODEL.ASTER1);
|
|
st.Stop();
|
|
Log.WriteMessage("Propagation database ASTER1 saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
if (AircraftData.Database.IsInMemory())
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
SayDatabase("Saving aircraft database...");
|
|
AircraftData.Database.BackupDatabase();
|
|
st.Stop();
|
|
Log.WriteMessage("Aircraft database saved, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
|
|
// flush the Log again in case of any exception to save all messages
|
|
Log.FlushLog();
|
|
}
|
|
}
|
|
|
|
private void MapDlg_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
Log.WriteMessage(Application.ProductName + " is closed.");
|
|
// flush the Log for the first time to save all messages
|
|
Log.FlushLog();
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Service Functions
|
|
|
|
private void Say(string text)
|
|
{
|
|
try
|
|
{
|
|
if (String.Compare(tsl_Status.Text, text) == 0)
|
|
return;
|
|
tsl_Status.Text = text;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private void SayDatabase(string text)
|
|
{
|
|
try
|
|
{
|
|
if (String.Compare(tsl_Database.Text, text) == 0)
|
|
return;
|
|
tsl_Database.Text = text;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private void SayCalculations(string text)
|
|
{
|
|
try
|
|
{
|
|
if (String.Compare(tsl_Calculations.Text, text) == 0)
|
|
return;
|
|
tsl_Calculations.Text = text;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private void SayAnalysis(string text)
|
|
{
|
|
try
|
|
{
|
|
if (String.Compare(tb_Analysis_Status.Text, text) == 0)
|
|
return;
|
|
tb_Analysis_Status.Text = text;
|
|
tb_Analysis_Status.Refresh();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private void SayTrack(string text, Color forecolor, Color backcolor)
|
|
{
|
|
try
|
|
{
|
|
if (tsl_Track.Text != text)
|
|
{
|
|
tsl_Track.Text = text;
|
|
}
|
|
if (tsl_Track.ForeColor != forecolor)
|
|
{
|
|
tsl_Track.ForeColor = forecolor;
|
|
}
|
|
if (tsl_Track.BackColor != backcolor)
|
|
{
|
|
tsl_Track.BackColor = backcolor;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
private void SayRot(string text, Color forecolor, Color backcolor)
|
|
{
|
|
try
|
|
{
|
|
if (tsl_Rot.Text != text)
|
|
{
|
|
tsl_Rot.Text = text;
|
|
}
|
|
if (tsl_Rot.ForeColor != forecolor)
|
|
{
|
|
tsl_Rot.ForeColor = forecolor;
|
|
}
|
|
if (tsl_Rot.BackColor != backcolor)
|
|
{
|
|
tsl_Rot.BackColor = backcolor;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
private void SayCAT(string text, Color forecolor, Color backcolor)
|
|
{
|
|
try
|
|
{
|
|
if (tsl_CAT.Text != text)
|
|
{
|
|
tsl_CAT.Text = text;
|
|
}
|
|
if (tsl_CAT.ForeColor != forecolor)
|
|
{
|
|
tsl_CAT.ForeColor = forecolor;
|
|
}
|
|
if (tsl_CAT.BackColor != backcolor)
|
|
{
|
|
tsl_CAT.BackColor = backcolor;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
private void UpdateStatus()
|
|
{
|
|
// upddate TextBoxes
|
|
tb_UTC.Text = CurrentTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
if (Properties.Settings.Default.Time_Mode_Online)
|
|
tb_UTC.BackColor = Color.LightSalmon;
|
|
else
|
|
tb_UTC.BackColor = Color.Plum;
|
|
string call = Properties.Settings.Default.MyCall;
|
|
cb_MyCall.SilentText = Properties.Settings.Default.MyCall;
|
|
cb_MyLoc.SilentText = MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon,
|
|
Properties.Settings.Default.Locator_SmallLettersForSubsquares,
|
|
(int)Properties.Settings.Default.Locator_MaxLength / 2,
|
|
Properties.Settings.Default.Locator_AutoLength);
|
|
cb_DXCall.Text = Properties.Settings.Default.DXCall;
|
|
cb_DXLoc.SilentText = MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon,
|
|
Properties.Settings.Default.Locator_SmallLettersForSubsquares,
|
|
(int)Properties.Settings.Default.Locator_MaxLength / 2,
|
|
Properties.Settings.Default.Locator_AutoLength);
|
|
if (MaidenheadLocator.Check(cb_MyLoc.Text) && MaidenheadLocator.Check(cb_DXLoc.Text))
|
|
{
|
|
tb_QTF.Text = Math.Round(LatLon.Bearing(Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon)).ToString("F0");
|
|
tb_QRB.Text = Math.Round(LatLon.Distance(Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon)).ToString("F0");
|
|
}
|
|
else
|
|
{
|
|
tb_QRB.Text = "0";
|
|
tb_QTF.Text = "0";
|
|
}
|
|
// colour Textbox if more precise lat/lon information is available
|
|
if (MaidenheadLocator.IsPrecise(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, 3))
|
|
{
|
|
cb_MyLoc.BackColor = Color.PaleGreen;
|
|
}
|
|
else
|
|
{
|
|
cb_MyLoc.BackColor = Color.FloralWhite;
|
|
}
|
|
// colour Textbox if more precise lat/lon information is available
|
|
if (MaidenheadLocator.IsPrecise(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, 3))
|
|
{
|
|
cb_DXLoc.BackColor = Color.PaleGreen;
|
|
}
|
|
else
|
|
{
|
|
cb_DXLoc.BackColor = Color.FloralWhite;
|
|
}
|
|
cb_Band.SelectedItem = Bands.GetStringValue(Properties.Settings.Default.Band);
|
|
}
|
|
|
|
private void Alarm(string msg)
|
|
{
|
|
if (Properties.Settings.Default.Alarm_Activate)
|
|
{
|
|
gb_Map_Alarms.BackColor = Color.Plum;
|
|
if (Properties.Settings.Default.Alarm_BringWindowToFront)
|
|
{
|
|
// try different methods to bring the window to front under WinXP and Win7
|
|
this.TopMost = true;
|
|
SetForegroundWindow(this.Handle);
|
|
// restore window size, state and location
|
|
try
|
|
{
|
|
this.WindowState = Properties.Settings.Default.General_WindowState;
|
|
this.Size = Properties.Settings.Default.General_WindowSize;
|
|
this.Location = Properties.Settings.Default.General_WindowLocation;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if failed
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
this.BringToFront();
|
|
this.Activate();
|
|
this.TopMost = false;
|
|
}
|
|
if (Properties.Settings.Default.Alarm_PlaySound)
|
|
System.Media.SystemSounds.Beep.Play();
|
|
}
|
|
}
|
|
|
|
private void MapSave()
|
|
{
|
|
Log.WriteMessage("Started.");
|
|
try
|
|
{
|
|
Bitmap bmp = new Bitmap(this.Width, this.Height);
|
|
this.DrawToBitmap(bmp, new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), this.Size));
|
|
EncoderParameters encoderParameters = new EncoderParameters(1);
|
|
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
|
|
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
|
|
foreach (ImageCodecInfo codec in codecs)
|
|
{
|
|
if (codec.FormatID == System.Drawing.Imaging.ImageFormat.Jpeg.Guid)
|
|
{
|
|
bmp.Save(TmpDirectory + Path.DirectorySeparatorChar + Properties.Settings.Default.Band + "_" + Properties.Settings.Default.MyCall.Replace("/", "_") + "_" + Properties.Settings.Default.DXCall.Replace("/", "_") + "_" + CurrentTime.ToString("yyyyMMdd") + "_" + CurrentTime.ToString("HHmmss") + ".jpg", codec, encoderParameters);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
|
|
private void cb_Alarms_Activate_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
if (!cb_Alarms_Activate.Checked)
|
|
gb_Map_Alarms.BackColor = SystemColors.Control;
|
|
}
|
|
|
|
private void tb_UTC_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (PlayMode != AIRSCOUTPLAYMODE.PAUSE)
|
|
return;
|
|
SetTimeDlg Dlg = new SetTimeDlg();
|
|
Dlg.cb_Time_Online.Checked = Properties.Settings.Default.Time_Mode_Online;
|
|
Dlg.dtp_SetTimeDlg_Start.Value = Properties.Settings.Default.Time_Offline;
|
|
if (Dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
Properties.Settings.Default.Time_Offline = Dlg.dtp_SetTimeDlg_Start.Value;
|
|
Properties.Settings.Default.Time_Mode_Online = Dlg.cb_Time_Online.Checked;
|
|
UpdateStatus();
|
|
}
|
|
}
|
|
|
|
private void UpdateLocation(string call, double lat, double lon, GEOSOURCE source)
|
|
{
|
|
// update callsign database with new lat/lon info
|
|
if (Callsign.Check(call))
|
|
StationData.Database.LocationInsertOrUpdateIfNewer(new LocationDesignator(call, lat, lon, source));
|
|
}
|
|
|
|
public LocationDesignator LocationFindOrCreate(string call, string loc)
|
|
{
|
|
// check all parameters
|
|
if (!Callsign.Check(call))
|
|
return null;
|
|
if (!MaidenheadLocator.Check(loc))
|
|
return null;
|
|
// get location info
|
|
LocationDesignator ld = StationData.Database.LocationFindOrCreate(call, loc);
|
|
// get elevation
|
|
ld.Elevation = GetElevation(ld.Lat, ld.Lon);
|
|
ld.BestCaseElevation = false;
|
|
// modify location in case of best case elevation is selected --> but do not store in database or settings!
|
|
if (Properties.Settings.Default.Path_BestCaseElevation)
|
|
{
|
|
if (!MaidenheadLocator.IsPrecise(ld.Lat, ld.Lon, 3))
|
|
{
|
|
ElvMinMaxInfo maxinfo = GetMinMaxElevationLoc(ld.Loc);
|
|
if (maxinfo.MaxElv != ElevationData.Database.ElvMissingFlag)
|
|
{
|
|
ld.Lat = maxinfo.MaxLat;
|
|
ld.Lon = maxinfo.MaxLon;
|
|
ld.Elevation = maxinfo.MaxElv;
|
|
ld.BestCaseElevation = true;
|
|
}
|
|
}
|
|
}
|
|
return ld;
|
|
}
|
|
|
|
public LocationDesignator LocationFindOrUpdateOrCreate(string call, double lat, double lon)
|
|
{
|
|
// check all parameters
|
|
if (!Callsign.Check(call))
|
|
return null;
|
|
if (!GeographicalPoint.Check(lat, lon))
|
|
return null;
|
|
// get location info
|
|
LocationDesignator ld = StationData.Database.LocationFindOrUpdateOrCreate(call, lat, lon);
|
|
// get elevation
|
|
ld.Elevation = GetElevation(ld.Lat, ld.Lon);
|
|
ld.BestCaseElevation = false;
|
|
// modify location in case of best case elevation is selected --> but do not store in database or settings!
|
|
if (Properties.Settings.Default.Path_BestCaseElevation)
|
|
{
|
|
if (!MaidenheadLocator.IsPrecise(ld.Lat, ld.Lon, 3))
|
|
{
|
|
ElvMinMaxInfo maxinfo = GetMinMaxElevationLoc(ld.Loc);
|
|
if (maxinfo.MaxElv != ElevationData.Database.ElvMissingFlag)
|
|
{
|
|
ld.Lat = maxinfo.MaxLat;
|
|
ld.Lon = maxinfo.MaxLon;
|
|
ld.Elevation = maxinfo.MaxElv;
|
|
ld.BestCaseElevation = true;
|
|
}
|
|
}
|
|
}
|
|
return ld;
|
|
}
|
|
|
|
public LocationDesignator LocationFind(string call, string loc = "")
|
|
{
|
|
// check all parameters
|
|
if (!Callsign.Check(call))
|
|
return null;
|
|
if (!String.IsNullOrEmpty(loc) && !MaidenheadLocator.Check(loc))
|
|
return null;
|
|
// get location info
|
|
LocationDesignator ld = (String.IsNullOrEmpty(loc)) ? StationData.Database.LocationFind(call) : StationData.Database.LocationFind(call, loc);
|
|
// return null if not found
|
|
if (ld == null)
|
|
return null;
|
|
// get elevation
|
|
ld.Elevation = GetElevation(ld.Lat, ld.Lon);
|
|
ld.BestCaseElevation = false;
|
|
// modify location in case of best case elevation is selected --> but do not store in database or settings!
|
|
if (Properties.Settings.Default.Path_BestCaseElevation)
|
|
{
|
|
if (!MaidenheadLocator.IsPrecise(ld.Lat, ld.Lon, 3))
|
|
{
|
|
ElvMinMaxInfo maxinfo = GetMinMaxElevationLoc(ld.Loc);
|
|
if (maxinfo.MaxElv != ElevationData.Database.ElvMissingFlag)
|
|
{
|
|
ld.Lat = maxinfo.MaxLat;
|
|
ld.Lon = maxinfo.MaxLon;
|
|
ld.Elevation = maxinfo.MaxElv;
|
|
ld.BestCaseElevation = true;
|
|
}
|
|
}
|
|
}
|
|
return ld;
|
|
}
|
|
|
|
public short GetElevation(string loc)
|
|
{
|
|
return GetElevation(MaidenheadLocator.LatFromLoc(loc), MaidenheadLocator.LonFromLoc(loc));
|
|
}
|
|
|
|
public short GetElevation(double lat, double lon)
|
|
{
|
|
if (!GeographicalPoint.Check(lat, lon))
|
|
return 0;
|
|
short elv = ElevationData.Database.ElvMissingFlag;
|
|
// try to get elevation data from distinct elevation model
|
|
// start with detailed one
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (elv == ElevationData.Database.ElvMissingFlag))
|
|
elv = ElevationData.Database[lat, lon, ELEVATIONMODEL.ASTER1, false];
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (elv == ElevationData.Database.ElvMissingFlag))
|
|
elv = ElevationData.Database[lat, lon, ELEVATIONMODEL.ASTER3, false];
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (elv == ElevationData.Database.ElvMissingFlag))
|
|
elv = ElevationData.Database[lat, lon, ELEVATIONMODEL.SRTM1, false];
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (elv == ElevationData.Database.ElvMissingFlag))
|
|
elv = ElevationData.Database[lat, lon, ELEVATIONMODEL.SRTM3, false];
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (elv == ElevationData.Database.ElvMissingFlag))
|
|
elv = ElevationData.Database[lat, lon, ELEVATIONMODEL.GLOBE, false];
|
|
// set it to zero if still invalid
|
|
if (elv <= ElevationData.Database.TileMissingFlag)
|
|
elv = 0;
|
|
return elv;
|
|
}
|
|
|
|
public ElvMinMaxInfo GetMinMaxElevationLoc(string loc)
|
|
{
|
|
ElvMinMaxInfo elv = new ElvMinMaxInfo();
|
|
// try to get elevation data from distinct elevation model
|
|
// start with detailed one
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled && (elv.MaxElv == ElevationData.Database.ElvMissingFlag))
|
|
{
|
|
ElvMinMaxInfo info = ElevationData.Database.GetMaxElvLoc(loc, ELEVATIONMODEL.ASTER1, false);
|
|
if (info != null)
|
|
{
|
|
elv.MaxLat = info.MaxLat;
|
|
elv.MaxLon = info.MaxLon;
|
|
elv.MaxElv = info.MaxElv;
|
|
elv.MinLat = info.MinLat;
|
|
elv.MinLon = info.MinLon;
|
|
elv.MinElv = info.MinElv;
|
|
}
|
|
}
|
|
if (Properties.Settings.Default.Elevation_ASTER3_Enabled && (elv.MaxElv == ElevationData.Database.ElvMissingFlag))
|
|
{
|
|
ElvMinMaxInfo info = ElevationData.Database.GetMaxElvLoc(loc, ELEVATIONMODEL.ASTER3, false);
|
|
if (info != null)
|
|
{
|
|
elv.MaxLat = info.MaxLat;
|
|
elv.MaxLon = info.MaxLon;
|
|
elv.MaxElv = info.MaxElv;
|
|
elv.MinLat = info.MinLat;
|
|
elv.MinLon = info.MinLon;
|
|
elv.MinElv = info.MinElv;
|
|
}
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM1_Enabled && (elv.MaxElv == ElevationData.Database.ElvMissingFlag))
|
|
{
|
|
ElvMinMaxInfo info = ElevationData.Database.GetMaxElvLoc(loc, ELEVATIONMODEL.SRTM1, false);
|
|
if (info != null)
|
|
{
|
|
elv.MaxLat = info.MaxLat;
|
|
elv.MaxLon = info.MaxLon;
|
|
elv.MaxElv = info.MaxElv;
|
|
elv.MinLat = info.MinLat;
|
|
elv.MinLon = info.MinLon;
|
|
elv.MinElv = info.MinElv;
|
|
}
|
|
}
|
|
if (Properties.Settings.Default.Elevation_SRTM3_Enabled && (elv.MaxElv == ElevationData.Database.ElvMissingFlag))
|
|
{
|
|
ElvMinMaxInfo info = ElevationData.Database.GetMaxElvLoc(loc, ELEVATIONMODEL.SRTM3, false);
|
|
if (info != null)
|
|
{
|
|
elv.MaxLat = info.MaxLat;
|
|
elv.MaxLon = info.MaxLon;
|
|
elv.MaxElv = info.MaxElv;
|
|
elv.MinLat = info.MinLat;
|
|
elv.MinLon = info.MinLon;
|
|
elv.MinElv = info.MinElv;
|
|
}
|
|
}
|
|
if (Properties.Settings.Default.Elevation_GLOBE_Enabled && (elv.MaxElv == ElevationData.Database.ElvMissingFlag))
|
|
{
|
|
ElvMinMaxInfo info = ElevationData.Database.GetMaxElvLoc(loc, ELEVATIONMODEL.GLOBE, false);
|
|
if (info != null)
|
|
{
|
|
elv.MaxLat = info.MaxLat;
|
|
elv.MaxLon = info.MaxLon;
|
|
elv.MaxElv = info.MaxElv;
|
|
elv.MinLat = info.MinLat;
|
|
elv.MinLon = info.MinLon;
|
|
elv.MinElv = info.MinElv;
|
|
}
|
|
}
|
|
/*
|
|
// set it to zero if still invalid
|
|
if (elv.MaxElv == ElevationData.Database.ElvMissingFlag)
|
|
elv.MaxElv = 0;
|
|
if (elv.MinElv == ElevationData.Database.ElvMissingFlag)
|
|
elv.MinElv = 0;
|
|
*/
|
|
return elv;
|
|
}
|
|
|
|
public void SetElevationModel()
|
|
{
|
|
if (Properties.Settings.Default.Elevation_ASTER1_Enabled)
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.ASTER1;
|
|
else if (Properties.Settings.Default.Elevation_ASTER3_Enabled)
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.ASTER3;
|
|
else if (Properties.Settings.Default.Elevation_SRTM1_Enabled)
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.SRTM1;
|
|
else if (Properties.Settings.Default.Elevation_SRTM3_Enabled)
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.SRTM3;
|
|
else if (Properties.Settings.Default.Elevation_GLOBE_Enabled)
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.GLOBE;
|
|
else
|
|
Properties.Settings.Default.ElevationModel = ELEVATIONMODEL.NONE;
|
|
}
|
|
|
|
public static Font CreateFontFromString(string font)
|
|
{
|
|
try
|
|
{
|
|
string[] a = Properties.Settings.Default.Map_ToolTipFont.Split(';');
|
|
string fontfamily = a[0].Trim();
|
|
float emsize = 0;
|
|
float.TryParse(a[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out emsize);
|
|
FontStyle fontstyle = 0;
|
|
// check if any additional font style is given
|
|
if (a.Length > 2)
|
|
{
|
|
if (a[2].ToUpper().IndexOf("BOLD") >= 0)
|
|
fontstyle = fontstyle | FontStyle.Bold;
|
|
if (a[2].ToUpper().IndexOf("ITALIC") >= 0)
|
|
fontstyle = fontstyle | FontStyle.Italic;
|
|
if (a[2].ToUpper().IndexOf("UNDERLINE") >= 0)
|
|
fontstyle = fontstyle | FontStyle.Underline;
|
|
if (a[2].ToUpper().IndexOf("STRIKEOUT") >= 0)
|
|
fontstyle = fontstyle | FontStyle.Strikeout;
|
|
}
|
|
else
|
|
{
|
|
fontstyle = FontStyle.Regular;
|
|
}
|
|
return new Font(fontfamily, emsize, fontstyle, GraphicsUnit.Point);
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
return null;
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
|
|
|
|
[DllImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
|
|
enum ShowWindowCommands : int
|
|
{
|
|
/// <summary>
|
|
/// Hides the window and activates another window.
|
|
/// </summary>
|
|
Hide = 0,
|
|
/// <summary>
|
|
/// Activates and displays a window. If the window is minimized or
|
|
/// maximized, the system restores it to its original size and position.
|
|
/// An application should specify this flag when displaying the window
|
|
/// for the first time.
|
|
/// </summary>
|
|
Normal = 1,
|
|
/// <summary>
|
|
/// Activates the window and displays it as a minimized window.
|
|
/// </summary>
|
|
ShowMinimized = 2,
|
|
/// <summary>
|
|
/// Maximizes the specified window.
|
|
/// </summary>
|
|
Maximize = 3, // is this the right value?
|
|
/// <summary>
|
|
/// Activates the window and displays it as a maximized window.
|
|
/// </summary>
|
|
ShowMaximized = 3,
|
|
/// <summary>
|
|
/// Displays a window in its most recent size and position. This value
|
|
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
|
|
/// the window is not activated.
|
|
/// </summary>
|
|
ShowNoActivate = 4,
|
|
/// <summary>
|
|
/// Activates the window and displays it in its current size and position.
|
|
/// </summary>
|
|
Show = 5,
|
|
/// <summary>
|
|
/// Minimizes the specified window and activates the next top-level
|
|
/// window in the Z order.
|
|
/// </summary>
|
|
Minimize = 6,
|
|
/// <summary>
|
|
/// Displays the window as a minimized window. This value is similar to
|
|
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
|
|
/// window is not activated.
|
|
/// </summary>
|
|
ShowMinNoActive = 7,
|
|
/// <summary>
|
|
/// Displays the window in its current size and position. This value is
|
|
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
|
|
/// window is not activated.
|
|
/// </summary>
|
|
ShowNA = 8,
|
|
/// <summary>
|
|
/// Activates and displays the window. If the window is minimized or
|
|
/// maximized, the system restores it to its original size and position.
|
|
/// An application should specify this flag when restoring a minimized window.
|
|
/// </summary>
|
|
Restore = 9,
|
|
/// <summary>
|
|
/// Sets the show state based on the SW_* value specified in the
|
|
/// STARTUPINFO structure passed to the CreateProcess function by the
|
|
/// program that started the application.
|
|
/// </summary>
|
|
ShowDefault = 10,
|
|
/// <summary>
|
|
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
|
|
/// that owns the window is not responding. This flag should only be
|
|
/// used when minimizing windows from a different thread.
|
|
/// </summary>
|
|
ForceMinimize = 11
|
|
}
|
|
|
|
private void ShowOptionsDlg()
|
|
{
|
|
// disable buttons
|
|
btn_Map_PlayPause.Enabled = false;
|
|
btn_Map_Save.Enabled = false;
|
|
btn_Options.Enabled = false;
|
|
|
|
// stop background threads
|
|
Say("Waiting for background threads to close....");
|
|
StopAllBackgroundWorkers();
|
|
// save current settings
|
|
SaveUserSettings();
|
|
// show options dialog
|
|
OptionsDlg Dlg = new OptionsDlg(this);
|
|
Say("Options");
|
|
if (Dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
// save current settings
|
|
SaveUserSettings();
|
|
// enbale/disable manage watchlist button
|
|
btn_Control_Manage_Watchlist.Enabled = !Properties.Settings.Default.Watchlist_SyncWithKST || !Properties.Settings.Default.Server_Activate;
|
|
// Re-initialze charts
|
|
InitializeCharts();
|
|
// clear paths cache assuming that new options were set
|
|
ElevationPaths.Clear();
|
|
PropagationPaths.Clear();
|
|
// check and update station infos
|
|
LocationDesignator ld = StationData.Database.LocationFind(Properties.Settings.Default.MyCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, false,3));
|
|
if ((ld == null) || (ld.Lat != Properties.Settings.Default.MyLat) || (ld.Lon != Properties.Settings.Default.MyLon))
|
|
{
|
|
UpdateLocation(Properties.Settings.Default.MyCall,
|
|
Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
MaidenheadLocator.IsPrecise(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, 3) ? GEOSOURCE.FROMUSER : GEOSOURCE.FROMLOC);
|
|
}
|
|
ld = StationData.Database.LocationFind(Properties.Settings.Default.DXCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, false, 3));
|
|
if ((ld == null) || (ld.Lat != Properties.Settings.Default.DXLat) || (ld.Lon != Properties.Settings.Default.DXLon))
|
|
{
|
|
UpdateLocation(Properties.Settings.Default.DXCall,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon,
|
|
MaidenheadLocator.IsPrecise(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, 3) ? GEOSOURCE.FROMUSER : GEOSOURCE.FROMLOC);
|
|
}
|
|
// update map provider
|
|
gm_Main.MapProvider = GMapProviders.Find(Properties.Settings.Default.Map_Provider);
|
|
|
|
// update ToolTipFont
|
|
ToolTipFont = CreateFontFromString(Properties.Settings.Default.Map_ToolTipFont);
|
|
|
|
// update planefeeds
|
|
bw_PlaneFeed1 = null;
|
|
bw_PlaneFeed2 = null;
|
|
bw_PlaneFeed3 = null;
|
|
|
|
if (PlaneFeedPlugins != null)
|
|
{
|
|
foreach (IPlaneFeedPlugin plugin in PlaneFeedPlugins)
|
|
{
|
|
if (Properties.Settings.Default.Planes_PlaneFeed1 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed1 = new PlaneFeed();
|
|
bw_PlaneFeed1.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed2 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed2 = new PlaneFeed();
|
|
bw_PlaneFeed2.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
if (Properties.Settings.Default.Planes_PlaneFeed3 == plugin.Name)
|
|
{
|
|
bw_PlaneFeed3 = new PlaneFeed();
|
|
bw_PlaneFeed3.ProgressChanged += new ProgressChangedEventHandler(bw_PlaneFeed_ProgressChanged);
|
|
}
|
|
}
|
|
}
|
|
// update timer interval
|
|
ti_Progress.Interval = Properties.Settings.Default.Map_Update * 1000;
|
|
// update background update intervals
|
|
ScoutBase.Elevation.Properties.Settings.Default.Datatbase_BackgroundUpdate_Period = (int)Properties.Settings.Default.Background_Update_Period;
|
|
ScoutBase.Stations.Properties.Settings.Default.Database_BackgroundUpdate_Period = (int)Properties.Settings.Default.Background_Update_Period;
|
|
AirScout.Aircrafts.Properties.Settings.Default.Database_BackgroundUpdate_Period = (int)Properties.Settings.Default.Background_Update_Period;
|
|
// update database path path and elevation model
|
|
InitializeDatabase();
|
|
|
|
// resize map window
|
|
gm_Main_SizeChanged(this, null);
|
|
}
|
|
else
|
|
{
|
|
// nothing was changed --> reload settings
|
|
LoadUserSettings();
|
|
}
|
|
|
|
// (re)initialize maps
|
|
InitializeMaps();
|
|
|
|
// start permanent background workers
|
|
StartAllBackgroundWorkers();
|
|
|
|
// enable buttons
|
|
btn_Map_PlayPause.Enabled = true;
|
|
btn_Map_Save.Enabled = true;
|
|
btn_Options.Enabled = true;
|
|
|
|
// update status window
|
|
UpdateStatus();
|
|
UpdateAirports();
|
|
UpdateWatchlistInMap();
|
|
RefreshWatchlistView();
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Play & Pause
|
|
|
|
private void Play()
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.FORWARD;
|
|
// switch tab control according to path mode
|
|
if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
tc_Control.SelectedTab = tp_Control_Single;
|
|
else if (PathMode == AIRSCOUTPATHMODE.MULTI)
|
|
tc_Control.SelectedTab = tp_Control_Multi;
|
|
|
|
// create distances, if enabled
|
|
if (Properties.Settings.Default.Map_ShowDistances)
|
|
CreateDistances();
|
|
|
|
// update tab control
|
|
tc_Control.Refresh();
|
|
// refresh watch list
|
|
RefreshWatchlistView();
|
|
// update all current paths
|
|
UpdatePaths();
|
|
// clear spectrum
|
|
try
|
|
{
|
|
Spectrum.Points.Clear();
|
|
SpectrumPointsCount = 0;
|
|
Spectrum_X.Reset();
|
|
SpectrumRecord.Points.Clear();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
|
|
// Linux/Mono hack to display text in button instead of symbols
|
|
if (SupportFunctions.IsMono)
|
|
{
|
|
btn_Map_PlayPause.Image = null;
|
|
btn_Map_PlayPause.Text = "Pause";
|
|
btn_Map_PlayPause.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
|
btn_Map_PlayPause.Font = new Font(btn_Map_PlayPause.Font, FontStyle.Bold);
|
|
}
|
|
else
|
|
{
|
|
// change button image
|
|
btn_Map_PlayPause.Text = "";
|
|
btn_Map_PlayPause.Image = il_Main.Images[0];
|
|
}
|
|
|
|
// disable controls
|
|
cb_Band.Enabled = false;
|
|
btn_Options.Enabled = false;
|
|
cb_MyCall.Enabled = false;
|
|
cb_MyLoc.Enabled = false;
|
|
cb_DXCall.Enabled = false;
|
|
cb_DXLoc.Enabled = false;
|
|
// tc_Control.Enabled = false;
|
|
pa_Planes_Filter.Enabled = false;
|
|
gb_Analysis_Controls.Enabled = false;
|
|
gb_Analysis_Database.Enabled = false;
|
|
gb_Analysis_Player.Enabled = false;
|
|
//referesh main window
|
|
this.Refresh();
|
|
}
|
|
|
|
private void Pause()
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
|
|
// Linux/Mono hack to display text in button instead of symbols
|
|
if (SupportFunctions.IsMono)
|
|
{
|
|
btn_Map_PlayPause.Image = null;
|
|
btn_Map_PlayPause.Text = "Play";
|
|
btn_Map_PlayPause.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
|
btn_Map_PlayPause.Font = new Font(btn_Map_PlayPause.Font, FontStyle.Bold);
|
|
}
|
|
else
|
|
{
|
|
// change button image
|
|
btn_Map_PlayPause.Text = "";
|
|
btn_Map_PlayPause.Image = il_Main.Images[1];
|
|
}
|
|
// update tab control
|
|
tc_Control.Refresh();
|
|
// enable controls
|
|
cb_Band.Enabled = true;
|
|
btn_Options.Enabled = true;
|
|
cb_MyCall.Enabled = true;
|
|
cb_MyLoc.Enabled = true;
|
|
cb_DXCall.Enabled = true;
|
|
cb_DXLoc.Enabled = true;
|
|
tc_Control.Enabled = true;
|
|
pa_Planes_Filter.Enabled = true;
|
|
gb_Analysis_Controls.Enabled = true;
|
|
gb_Analysis_Database.Enabled = true;
|
|
gb_Analysis_Player.Enabled = true;
|
|
tc_Main.Enabled = true;
|
|
tc_Map.Enabled = true;
|
|
// stop tracking
|
|
TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
//referesh main window
|
|
this.Refresh();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Paths
|
|
|
|
private double GetMinH(double max_alt, double H1, double H2)
|
|
{
|
|
double max = Math.Max(H1, H2);
|
|
if (max <= max_alt)
|
|
return max;
|
|
return max_alt;
|
|
}
|
|
|
|
private void ClearAllPathsInMap()
|
|
{
|
|
gmo_PropagationPaths.Clear();
|
|
}
|
|
|
|
private void DrawPath(PropagationPathDesignator ppath)
|
|
{
|
|
// draws a propagation path to map
|
|
PropagationPoint[] ppoints = new PropagationPoint[0];
|
|
try
|
|
{
|
|
// get infopoints for map
|
|
ppoints = ppath.GetInfoPoints();
|
|
// calculate midpoint
|
|
ScoutBase.Core.LatLon.GPoint midpoint = LatLon.MidPoint(ppath.Lat1, ppath.Lon1, ppath.Lat2, ppath.Lon2);
|
|
GMapMarker gmmid = new GMarkerGoogle(new PointLatLng(midpoint.Lat, midpoint.Lon), ToolTipFont, ((PathMode == AIRSCOUTPATHMODE.MULTI) && Properties.Settings.Default.Map_SmallMarkers) ? GMarkerGoogleType.blue_small : GMarkerGoogleType.blue_dot);
|
|
gmmid.ToolTipText = ppath.Location1.Call + " <> " + ppath.Location2.Call;
|
|
gmmid.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
gmo_CallsignDetails.Markers.Add(gmmid);
|
|
// calculate dx end
|
|
gmm_DXLoc = new GMarkerGoogle(new PointLatLng(ppath.Lat2, ppath.Lon2), ToolTipFont, ((PathMode == AIRSCOUTPATHMODE.MULTI) && Properties.Settings.Default.Map_SmallMarkers) ? GMarkerGoogleType.yellow_small : GMarkerGoogleType.yellow_dot);
|
|
gmm_DXLoc.ToolTipText = ppath.Location2.Call + "\n" +
|
|
ppath.Location2.Lat.ToString("F8", CultureInfo.InvariantCulture) + "\n" +
|
|
ppath.Location2.Lon.ToString("F8", CultureInfo.InvariantCulture) + "\n" +
|
|
ppath.Location2.Loc + "\n" +
|
|
GetElevation(ppath.Location2.Lat, ppath.Location2.Lon).ToString("F0") + "m\n" +
|
|
LatLon.Bearing(ppath.Location1.Lat, ppath.Location1.Lon, ppath.Location2.Lat, ppath.Location2.Lon).ToString("F0") + "°\n" +
|
|
LatLon.Distance(ppath.Location1.Lat, ppath.Location1.Lon, ppath.Location2.Lat, ppath.Location2.Lon).ToString("F0") + "km";
|
|
if (Properties.Settings.Default.Track_Activate)
|
|
gmm_DXLoc.ToolTipText += "\nRight+Click to Turn Antenna";
|
|
gmm_DXLoc.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
gmm_DXLoc.Tag = ppath.Location2.Call;
|
|
gmo_CallsignDetails.Markers.Add(gmm_DXLoc);
|
|
// set three small points for hot path, if one
|
|
if (!Properties.Settings.Default.Map_SmallMarkers)
|
|
{
|
|
int i1 = -1;
|
|
int i3 = -1;
|
|
for (int i = 0; i < ppoints.Length; i++)
|
|
{
|
|
if (Math.Max(ppoints[i].H1, ppoints[i].H2) < Properties.Settings.Default.Planes_MaxAlt)
|
|
{
|
|
if (i1 == -1)
|
|
i1 = i;
|
|
else i3 = i;
|
|
|
|
}
|
|
}
|
|
if ((i1 >= 0) && (i3 >= 0))
|
|
{
|
|
GMapMarker gmi1 = new GMarkerGoogle(new PointLatLng(ppoints[i1].Lat, ppoints[i1].Lon), GMarkerGoogleType.red_small);
|
|
gmo_Objects.Markers.Add(gmi1);
|
|
LatLon.GPoint gp = LatLon.MidPoint(ppoints[i1].Lat, ppoints[i1].Lon, ppoints[i3].Lat, ppoints[i3].Lon);
|
|
GMapMarker gmi2 = new GMarkerGoogle(new PointLatLng(gp.Lat, gp.Lon), GMarkerGoogleType.blue_small);
|
|
gmo_Objects.Markers.Add(gmi2);
|
|
GMapMarker gmi3 = new GMarkerGoogle(new PointLatLng(ppoints[i3].Lat, ppoints[i3].Lon), GMarkerGoogleType.yellow_small);
|
|
gmo_Objects.Markers.Add(gmi3);
|
|
}
|
|
}
|
|
// draw propagation path according to path status
|
|
// valid: black
|
|
// invalid: red
|
|
gmr_FullPath = new GMapRoute("fullpath");
|
|
gmr_FullPath.Stroke = (ppath.Valid) ? new Pen(Color.Black, 3) : new Pen(Color.Red, 3);
|
|
gmo_PropagationPaths.Routes.Add(gmr_FullPath);
|
|
gmr_NearestFull = new GMapRoute("fullpath");
|
|
gmr_NearestFull.Stroke = (ppath.Valid) ? new Pen(Color.Black, 3) : new Pen(Color.Red, 3);
|
|
gmo_NearestPaths.Routes.Add(gmr_NearestFull);
|
|
foreach (PropagationPoint ppoint in ppoints)
|
|
{
|
|
gmr_FullPath.Points.Add(new PointLatLng(ppoint.Lat, ppoint.Lon));
|
|
gmr_NearestFull.Points.Add(new PointLatLng(ppoint.Lat, ppoint.Lon));
|
|
}
|
|
// draw mutual visible path
|
|
gmr_VisiblePpath = new GMapRoute("visiblepath");
|
|
gmr_VisiblePpath.Stroke = new Pen(Color.Magenta, 3);
|
|
gmr_NearestVisible = new GMapRoute("visiblepath");
|
|
gmr_NearestVisible.Stroke = new Pen(Color.Magenta, 3);
|
|
for (int i = 0; i < ppoints.Length; i++)
|
|
{
|
|
if ((Math.Max(ppoints[i].H1, ppoints[i].H2) > 0) && (Math.Max(ppoints[i].H1, ppoints[i].H2) < Properties.Settings.Default.Planes_MaxAlt))
|
|
{
|
|
PointLatLng p = new PointLatLng(ppoints[i].Lat, ppoints[i].Lon);
|
|
gmr_VisiblePpath.Points.Add(p);
|
|
gmr_NearestVisible.Points.Add(p);
|
|
}
|
|
}
|
|
gmo_PropagationPaths.Routes.Add(gmr_VisiblePpath);
|
|
gmo_NearestPaths.Routes.Add(gmr_NearestVisible);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void UpdatePaths()
|
|
{
|
|
// updates all current path to calculate
|
|
try
|
|
{
|
|
Log.WriteMessage("UpdatePath started.");
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
|
|
// check if there are a valid home settings
|
|
if (!Callsign.Check(Properties.Settings.Default.MyCall) ||
|
|
!GeographicalPoint.Check(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon))
|
|
return;
|
|
|
|
// OK valid, lets continue
|
|
|
|
// slow down background calculations
|
|
Properties.Settings.Default.Background_Calculations_ThreadWait = 1000;
|
|
|
|
//clear map overlays
|
|
gmo_PropagationPaths.Clear();
|
|
gmo_NearestPaths.Clear();
|
|
gmo_Objects.Clear();
|
|
|
|
// clear all planes and tooltips
|
|
gmo_Planes.Clear();
|
|
|
|
// clear paths
|
|
ElevationPaths.Clear();
|
|
PropagationPaths.Clear();
|
|
|
|
// clear charts
|
|
ClearCharts();
|
|
|
|
// put call on MyCalls last recent collection if not already in
|
|
if (Properties.Settings.Default.MyCalls.IndexOf(Properties.Settings.Default.MyCall) < 0)
|
|
{
|
|
Properties.Settings.Default.MyCalls.Insert(0, Properties.Settings.Default.MyCall);
|
|
}
|
|
|
|
// keep the MyCalls list small
|
|
while (Properties.Settings.Default.MyCalls.Count > 10)
|
|
{
|
|
Properties.Settings.Default.MyCalls.RemoveAt(Properties.Settings.Default.MyCalls.Count - 1);
|
|
}
|
|
|
|
|
|
// check and update station database
|
|
LocationDesignator myloc = LocationFindOrUpdateOrCreate(Properties.Settings.Default.MyCall, Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
Properties.Settings.Default.MyElevation = myloc.Elevation;
|
|
|
|
// get qrv info or create default
|
|
QRVDesignator myqrv = StationData.Database.QRVFindOrCreateDefault(myloc.Call, myloc.Loc, Properties.Settings.Default.Band);
|
|
// set qrv defaults if zero
|
|
if (myqrv.AntennaHeight == 0)
|
|
myqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (myqrv.AntennaGain == 0)
|
|
myqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (myqrv.Power == 0)
|
|
myqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
// draw my end on the map
|
|
gmm_MyLoc = new GMarkerGoogle(new PointLatLng(myloc.Lat, myloc.Lon), ToolTipFont, ((PathMode == AIRSCOUTPATHMODE.MULTI) && Properties.Settings.Default.Map_SmallMarkers) ? GMarkerGoogleType.red_small : GMarkerGoogleType.red_dot);
|
|
gmm_MyLoc.ToolTipText = myloc.Call + "\n" +
|
|
myloc.Lat.ToString("F8", CultureInfo.InvariantCulture) + "\n" +
|
|
myloc.Lon.ToString("F8", CultureInfo.InvariantCulture) + "\n" +
|
|
myloc.Loc + "\n" +
|
|
GetElevation(myloc.Lat, myloc.Lon).ToString("F0") + "m";
|
|
gmm_MyLoc.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
gmm_MyLoc.Tag = myloc.Call;
|
|
gmo_Objects.Markers.Add(gmm_MyLoc);
|
|
|
|
// do single path mode
|
|
if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
{
|
|
// check if there are a valid DX settings
|
|
if (!Callsign.Check(Properties.Settings.Default.DXCall) ||
|
|
!GeographicalPoint.Check(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon))
|
|
return;
|
|
|
|
// OK valid, lets continue
|
|
// check and update station database
|
|
LocationDesignator dxloc = LocationFindOrUpdateOrCreate(Properties.Settings.Default.DXCall, Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon);
|
|
Properties.Settings.Default.DXElevation = dxloc.Elevation;
|
|
|
|
// get qrv info or create default
|
|
QRVDesignator dxqrv = StationData.Database.QRVFindOrCreateDefault(dxloc.Call, dxloc.Loc, Properties.Settings.Default.Band);
|
|
// set qrv defaults if zero
|
|
if (dxqrv.AntennaHeight == 0)
|
|
dxqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (dxqrv.AntennaGain == 0)
|
|
dxqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (dxqrv.Power == 0)
|
|
dxqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
|
|
// find local obstruction, if any
|
|
LocalObstructionDesignator o = ElevationData.Database.LocalObstructionFind(myloc.Lat, myloc.Lon, Properties.Settings.Default.ElevationModel);
|
|
double mybearing = LatLon.Bearing(myloc.Lat, myloc.Lon, dxloc.Lat, dxloc.Lon);
|
|
double myobstr = (o != null) ? o.GetObstruction(myqrv.AntennaHeight, mybearing) : double.MinValue;
|
|
|
|
// try to find elevation path in database or create new one and store
|
|
ElevationPathDesignator epath = ElevationData.Database.ElevationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel);
|
|
// add additional info to ppath
|
|
epath.Location1 = myloc;
|
|
epath.Location2 = dxloc;
|
|
epath.QRV1 = myqrv;
|
|
epath.QRV2 = dxqrv;
|
|
|
|
// try to find propagation path in database or create new one and store
|
|
PropagationPathDesignator ppath = PropagationData.Database.PropagationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
GetElevation(myloc.Lat, myloc.Lon) + myqrv.AntennaHeight,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
GetElevation(dxloc.Lat, dxloc.Lon) + dxqrv.AntennaHeight,
|
|
Bands.ToGHz(Properties.Settings.Default.Band),
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor,
|
|
Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].F1_Clearance,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel,
|
|
myobstr);
|
|
|
|
// add additional info to ppath
|
|
ppath.Location1 = myloc;
|
|
ppath.Location2 = dxloc;
|
|
ppath.QRV1 = myqrv;
|
|
ppath.QRV2 = dxqrv;
|
|
|
|
// add single path to paths list
|
|
ElevationPaths.Add(epath);
|
|
PropagationPaths.Add(ppath);
|
|
// put DXCall on the watchlist if not already in
|
|
if (Properties.Settings.Default.Watchlist.IndexOf(Properties.Settings.Default.DXCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, false, 3)) < 0)
|
|
{
|
|
Properties.Settings.Default.Watchlist.Insert(0, new WatchlistItem(Properties.Settings.Default.DXCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, false, 3), ppath.Distance > Properties.Settings.Default.Path_MaxLength));
|
|
}
|
|
// keep the watchlist small
|
|
while (Properties.Settings.Default.Watchlist.Count() > Properties.Settings.Default.Watchlist_MaxCount)
|
|
{
|
|
Properties.Settings.Default.Watchlist.RemoveAt(Properties.Settings.Default.Watchlist.Count() - 1);
|
|
}
|
|
|
|
}
|
|
else if (PathMode == AIRSCOUTPATHMODE.MULTI)
|
|
{
|
|
// iterate through watchlist and add selected
|
|
foreach (ListViewItem item in lv_Control_Watchlist.Items)
|
|
{
|
|
// use only selected items
|
|
if (!item.Checked)
|
|
continue;
|
|
string call = item.Text;
|
|
string loc = item.SubItems[1].Text;
|
|
|
|
// check if call & loc are valid
|
|
if (!Callsign.Check(call) || !MaidenheadLocator.Check(loc))
|
|
continue;
|
|
|
|
// check and update station database
|
|
LocationDesignator dxloc = LocationFindOrCreate(call, loc);
|
|
|
|
// get qrv info or create default
|
|
QRVDesignator dxqrv = StationData.Database.QRVFindOrCreateDefault(dxloc.Call, dxloc.Loc, Properties.Settings.Default.Band);
|
|
// set qrv defaults if zero
|
|
if (dxqrv.AntennaHeight == 0)
|
|
dxqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (dxqrv.AntennaGain == 0)
|
|
dxqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (dxqrv.Power == 0)
|
|
dxqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
|
|
// find local obstruction, if any
|
|
LocalObstructionDesignator o = ElevationData.Database.LocalObstructionFind(myloc.Lat, myloc.Lon, Properties.Settings.Default.ElevationModel);
|
|
double mybearing = LatLon.Bearing(myloc.Lat, myloc.Lon, dxloc.Lat, dxloc.Lon);
|
|
double myobstr = (o != null) ? o.GetObstruction(myqrv.AntennaHeight, mybearing) : double.MinValue;
|
|
|
|
// try to find elevation path in database or create new one and store
|
|
ElevationPathDesignator epath = ElevationData.Database.ElevationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel);
|
|
// try to find propagation path in database or create new one and store
|
|
PropagationPathDesignator ppath = PropagationData.Database.PropagationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
GetElevation(myloc.Lat, myloc.Lon) + myqrv.AntennaHeight,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
GetElevation(dxloc.Lat, dxloc.Lon) + dxqrv.AntennaHeight,
|
|
Bands.ToGHz(Properties.Settings.Default.Band),
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor,
|
|
Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].F1_Clearance,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel,
|
|
myobstr);
|
|
// add additional info to ppath
|
|
ppath.Location1 = myloc;
|
|
ppath.Location2 = dxloc;
|
|
ppath.QRV1 = myqrv;
|
|
ppath.QRV2 = dxqrv;
|
|
// add path to paths list
|
|
|
|
ElevationPaths.Add(epath);
|
|
PropagationPaths.Add(ppath);
|
|
}
|
|
}
|
|
|
|
// calculate the area to show in map
|
|
// initially set to my location
|
|
double minlat = myloc.Lat;
|
|
double minlon = myloc.Lon;
|
|
double maxlat = myloc.Lat;
|
|
double maxlon = myloc.Lon;
|
|
|
|
double centerlat = myloc.Lat;
|
|
double centerlon = myloc.Lon;
|
|
|
|
// now do the drawing
|
|
foreach (PropagationPathDesignator ppath in PropagationPaths)
|
|
{
|
|
DrawPath(ppath);
|
|
|
|
// maintain Min/Max values
|
|
minlat = Math.Min(minlat, ppath.Lat2);
|
|
minlon = Math.Min(minlon, ppath.Lon2);
|
|
maxlat = Math.Max(maxlat, ppath.Lat2);
|
|
maxlon = Math.Max(maxlon, ppath.Lon2);
|
|
}
|
|
|
|
// show diagram when in SINGLE mode
|
|
if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
{
|
|
// both Elevationpaths & PropagationPaths should contain only one entry
|
|
if ((ElevationPaths.Count > 0) && (PropagationPaths.Count > 0))
|
|
UpdateCharts(ElevationPaths[ElevationPaths.Count - 1], PropagationPaths[PropagationPaths.Count - 1]);
|
|
}
|
|
|
|
// calculate center
|
|
centerlat = LatLon.MidPoint(minlat, minlon, maxlat, maxlon).Lat;
|
|
centerlon = LatLon.MidPoint(minlat, minlon, maxlat, maxlon).Lon;
|
|
|
|
// ensure that whole path is visible and optionally centered
|
|
gm_Main.SetZoomToFitRect(RectLatLng.FromLTRB(minlon, maxlat, maxlon, minlat));
|
|
if (Properties.Settings.Default.Map_AutoCenter)
|
|
gm_Main.Position = new PointLatLng(centerlat, centerlon);
|
|
|
|
// clear all selections
|
|
SelectedPlanes.Clear();
|
|
|
|
// update watchlist locations in map
|
|
UpdateWatchlistInMap();
|
|
|
|
// update status window
|
|
UpdateStatus();
|
|
|
|
// stop tracking
|
|
//TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
|
|
// speed up background calculations
|
|
Properties.Settings.Default.Background_Calculations_ThreadWait = 0;
|
|
|
|
st.Stop();
|
|
Log.WriteMessage("UpdatePath finished, " + st.ElapsedMilliseconds.ToString() + "ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Say("Error while updating path: " + ex.Message);
|
|
Log.WriteMessage("Error while updating path: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Charts
|
|
|
|
private void UpdateCharts(ElevationPathDesignator epath, PropagationPathDesignator ppath)
|
|
{
|
|
// updates the diagram area
|
|
short[] epoints = new short[0];
|
|
PropagationPoint[] ppoints = new PropagationPoint[0];
|
|
try
|
|
{
|
|
ClearCharts();
|
|
// adjust diagram axes
|
|
Path_X.Maximum = ppath.Distance;
|
|
Elevation_X.Maximum = epath.Distance;
|
|
// get infopoints for charting
|
|
epoints = epath.GetInfoPoints();
|
|
ppoints = ppath.GetInfoPoints();
|
|
// calculate epsilon for LOS
|
|
double eps_los = Propagation.EpsilonFromHeights(GetElevation(ppath.Lat1, ppath.Lon1) + ppath.QRV1.AntennaHeight, ppath.Distance, GetElevation(ppath.Lat2, ppath.Lon2) + ppath.QRV2.AntennaHeight, LatLon.Earth.Radius);
|
|
// fill chart
|
|
short maxelv = short.MinValue;
|
|
double myelev = GetElevation(ppath.Lat1, ppath.Lon1);
|
|
for (int i = 0; i < epoints.Length; i++)
|
|
{
|
|
Path_Elevation.Points.Add(new OxyPlot.DataPoint(i, epoints[i]));
|
|
Min_H1.Points.Add(new OxyPlot.DataPoint(i, ppoints[i].H1));
|
|
Min_H2.Points.Add(new OxyPlot.DataPoint(i, ppoints[i].H2));
|
|
Max_H.Points.Add(new OxyPlot.DataPoint(i, Properties.Settings.Default.Planes_MaxAlt));
|
|
Min_H.Points.Add(new OxyPlot.DataPoint(i, Properties.Settings.Default.Planes_MaxAlt));
|
|
Min_H.Points2.Add(new OxyPlot.DataPoint(i, GetMinH(Properties.Settings.Default.Planes_MaxAlt, Min_H1.Points[i].Y, Min_H2.Points[i].Y)));
|
|
LOS.Points.Add(new OxyPlot.DataPoint(i, Propagation.HeightFromEpsilon(myelev + ppath.QRV1.AntennaHeight, i, eps_los, LatLon.Earth.Radius)));
|
|
Elevation.Points.Add(new OxyPlot.DataPoint(i, epoints[i]));
|
|
if (maxelv < epoints[i])
|
|
maxelv = epoints[i];
|
|
}
|
|
// adjust Y-axis --> max elv + 10%
|
|
Elevation_Y.Maximum = maxelv + maxelv * 0.1;
|
|
// invalidate plots
|
|
pm_Path.InvalidatePlot(true);
|
|
pm_Elevation.InvalidatePlot(true);
|
|
// show path legends
|
|
Charts_ShowLegends(5000);
|
|
// refresh path info
|
|
tp_Elevation.Text = "Pathinfo ";
|
|
if (Properties.Settings.Default.ElevationModel == ELEVATIONMODEL.ASTER1)
|
|
tp_Elevation.Text = tp_Elevation.Text + "[ASTER1]";
|
|
else if (Properties.Settings.Default.ElevationModel == ELEVATIONMODEL.ASTER3)
|
|
tp_Elevation.Text = tp_Elevation.Text + "[ASTER3]";
|
|
else if (Properties.Settings.Default.ElevationModel == ELEVATIONMODEL.SRTM1)
|
|
tp_Elevation.Text = tp_Elevation.Text + "[SRTM1]";
|
|
else if (Properties.Settings.Default.ElevationModel == ELEVATIONMODEL.SRTM3)
|
|
tp_Elevation.Text = tp_Elevation.Text + "[SRTM3]";
|
|
else if (Properties.Settings.Default.ElevationModel == ELEVATIONMODEL.GLOBE)
|
|
tp_Elevation.Text = tp_Elevation.Text + "[GLOBE]";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void ClearCharts()
|
|
{
|
|
try
|
|
{
|
|
// clear all points
|
|
Path_Elevation.Points.Clear();
|
|
Min_H1.Points.Clear();
|
|
Min_H2.Points.Clear();
|
|
Max_H.Points.Clear();
|
|
Min_H.Points.Clear();
|
|
Min_H.Points2.Clear();
|
|
Planes_Hi.Points.Clear();
|
|
Planes_Lo.Points.Clear();
|
|
Elevation.Points.Clear();
|
|
LOS.Points.Clear();
|
|
// update view
|
|
pm_Path.InvalidatePlot(true);
|
|
pm_Elevation.InvalidatePlot(true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void Charts_ShowLegends(int ms)
|
|
{
|
|
// enable path legends for some seconds
|
|
pm_Path.IsLegendVisible = true;
|
|
pm_Path.InvalidatePlot(true);
|
|
pm_Elevation.IsLegendVisible = true;
|
|
pm_Elevation.InvalidatePlot(true);
|
|
ti_ShowLegends.Interval = ms;
|
|
ti_ShowLegends.Start();
|
|
}
|
|
|
|
private void ti_ShowLegends_Tick(object sender, EventArgs e)
|
|
{
|
|
pm_Path.IsLegendVisible = false;
|
|
pm_Path.InvalidatePlot(true);
|
|
pm_Elevation.IsLegendVisible = false;
|
|
pm_Elevation.InvalidatePlot(true);
|
|
ti_ShowLegends.Enabled = false;
|
|
}
|
|
|
|
private void pv_Path_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
// draw calsign s on chart
|
|
string mycall = Properties.Settings.Default.MyCall;
|
|
string dxcall = Properties.Settings.Default.DXCall;
|
|
int top = pv_Path.Bottom - pv_Path.Height / 2;
|
|
int left = pv_Path.Left + 50;
|
|
int right = pv_Path.Width - 38;
|
|
Font font = new Font(FontFamily.GenericSansSerif, 8, FontStyle.Bold);
|
|
Graphics g = e.Graphics;
|
|
using (StringFormat format = new StringFormat(StringFormatFlags.DirectionVertical))
|
|
{
|
|
// measure text to emulate TextAlign.Middle
|
|
int mywidth = (int)g.MeasureString(mycall, font).Width;
|
|
int dxwidth = (int)g.MeasureString(dxcall, font).Width;
|
|
using (SolidBrush brush = new SolidBrush(Color.Black))
|
|
{
|
|
if (pv_Path.Height - 50 > mywidth)
|
|
g.DrawString(mycall, font, brush, left, top - mywidth / 2, format);
|
|
if (pv_Path.Height - 50 > dxwidth)
|
|
g.DrawString(dxcall, font, brush, right, top - dxwidth / 2, format);
|
|
/*
|
|
if (pv_Path.Height > 2 * mywidth + 50)
|
|
g.DrawString(mycall, font, brush, left, top, format);
|
|
if (pv_Path.Height > 2 * dxwdith + 50)
|
|
g.DrawString(dxcall, font, brush, right, top, format);
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Planes
|
|
|
|
private static Bitmap RotateImageByAngle(System.Drawing.Image oldBitmap, float angle)
|
|
{
|
|
var newBitmap = new Bitmap(oldBitmap.Width, oldBitmap.Height);
|
|
var graphics = Graphics.FromImage(newBitmap);
|
|
graphics.TranslateTransform((float)oldBitmap.Width / 2, (float)oldBitmap.Height / 2);
|
|
graphics.RotateTransform(angle);
|
|
graphics.TranslateTransform(-(float)oldBitmap.Width / 2, -(float)oldBitmap.Height / 2);
|
|
graphics.DrawImage(oldBitmap, new System.Drawing.Point(0, 0));
|
|
return newBitmap;
|
|
}
|
|
|
|
private GMarkerGoogle CreatePlaneSimple(PlaneInfo info, bool selected)
|
|
{
|
|
// return on empty info
|
|
if (info == null)
|
|
return null;
|
|
// show flight info only
|
|
// get bitmap according to category
|
|
Bitmap bm;
|
|
int bmindex = bmindex_gray;
|
|
Brush brush = new SolidBrush(Color.FromArgb(180, Color.White));
|
|
if (info.Potential == 100)
|
|
{
|
|
bmindex = bmindex_magenta;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.Plum));
|
|
}
|
|
else if (info.Potential == 75)
|
|
{
|
|
bmindex = bmindex_red;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.Red));
|
|
}
|
|
else if (info.Potential == 50)
|
|
{
|
|
bmindex = bmindex_darkorange;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.DarkOrange));
|
|
}
|
|
if (info.Category == PLANECATEGORY.SUPERHEAVY)
|
|
bm = new Bitmap(il_Planes_S.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.HEAVY)
|
|
bm = new Bitmap(il_Planes_H.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.MEDIUM)
|
|
bm = new Bitmap(il_Planes_M.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.LIGHT)
|
|
bm = new Bitmap(il_Planes_L.Images[bmindex]);
|
|
else
|
|
bm = new Bitmap(il_Planes_M.Images[bmindex]);
|
|
GMarkerGoogle m = new GMarkerGoogle(new PointLatLng(info.Lat, info.Lon), ToolTipFont, RotateImageByAngle(bm, ((info.Track >= 0) && (info.Track <= 360))? (float)info.Track : 0));
|
|
m.Tag = info.Hex;
|
|
string lat = "";
|
|
if (info.Lat >= 0)
|
|
lat = Math.Abs(info.Lat).ToString("00.00") + "°N";
|
|
else
|
|
lat = Math.Abs(info.Lat).ToString("00.00") + "°S";
|
|
string lon = "";
|
|
if (info.Lon >= 0)
|
|
lon = Math.Abs(info.Lon).ToString("000.00") + "°E";
|
|
else
|
|
lon = Math.Abs(info.Lon).ToString("000.00") + "°W";
|
|
m.ToolTipText = info.Call + "\n--------------------";
|
|
if (Properties.Settings.Default.InfoWin_Position)
|
|
m.ToolTipText += "\nPos: " + lat + " , " + lon;
|
|
if (Properties.Settings.Default.InfoWin_Alt)
|
|
{
|
|
if (Properties.Settings.Default.InfoWin_Metric)
|
|
m.ToolTipText += "\nAlt: " + (int)info.Alt_m + "m";
|
|
else
|
|
m.ToolTipText += "\nAlt: " + (int)info.Alt + "ft";
|
|
}
|
|
if (Properties.Settings.Default.InfoWin_Track)
|
|
m.ToolTipText += "\nTrack: " + (int)info.Track + "°";
|
|
if (Properties.Settings.Default.InfoWin_Type)
|
|
m.ToolTipText += "\nType: " + info.Manufacturer + " " + info.Model + " [" + PlaneCategories.GetShortStringValue(info.Category) + "]";
|
|
// set tooltip on if hot
|
|
if (selected)
|
|
m.ToolTipMode = MarkerTooltipMode.Always;
|
|
else
|
|
m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
if (m.ToolTip != null)
|
|
m.ToolTip.Fill = brush;
|
|
return m;
|
|
}
|
|
|
|
private GMarkerGoogle CreatePlaneDetailed(PlaneInfo info, bool selected)
|
|
{
|
|
// return on empty info
|
|
if (info == null)
|
|
return null;
|
|
// get bitmap according to category
|
|
Bitmap bm;
|
|
int bmindex = bmindex_gray;
|
|
Brush brush = new SolidBrush(Color.FromArgb(180, Color.White));
|
|
if (info.Potential == 100)
|
|
{
|
|
bmindex = bmindex_magenta;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.Plum));
|
|
}
|
|
else if (info.Potential == 75)
|
|
{
|
|
bmindex = bmindex_red;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.Red));
|
|
}
|
|
else if (info.Potential == 50)
|
|
{
|
|
bmindex = bmindex_darkorange;
|
|
brush = new SolidBrush(Color.FromArgb(150, Color.DarkOrange));
|
|
}
|
|
if (info.Category == PLANECATEGORY.SUPERHEAVY)
|
|
bm = new Bitmap(il_Planes_S.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.HEAVY)
|
|
bm = new Bitmap(il_Planes_H.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.MEDIUM)
|
|
bm = new Bitmap(il_Planes_M.Images[bmindex]);
|
|
else if (info.Category == PLANECATEGORY.LIGHT)
|
|
bm = new Bitmap(il_Planes_L.Images[bmindex]);
|
|
else
|
|
bm = new Bitmap(il_Planes_M.Images[bmindex]);
|
|
GMarkerGoogle m = new GMarkerGoogle(new PointLatLng(info.Lat, info.Lon), ToolTipFont, RotateImageByAngle(bm, ((info.Track >= 0) && (info.Track <= 360)) ? (float)info.Track : 0));
|
|
m.Tag = info.Hex;
|
|
string lat = "";
|
|
if (info.Lat >= 0)
|
|
lat = Math.Abs(info.Lat).ToString("00.00") + "°N";
|
|
else
|
|
lat = Math.Abs(info.Lat).ToString("00.00") + "°S";
|
|
string lon = "";
|
|
if (info.Lon >= 0)
|
|
lon = Math.Abs(info.Lon).ToString("000.00") + "°E";
|
|
else
|
|
lon = Math.Abs(info.Lon).ToString("000.00") + "°W";
|
|
int mins = 0;
|
|
if (info.Speed > 0)
|
|
mins = (int)(info.IntQRB / UnitConverter.kts_kmh(info.Speed) * 60.0);
|
|
// fill tooltip texts
|
|
m.ToolTipText = info.Call + "\n--------------------";
|
|
if (Properties.Settings.Default.InfoWin_Position)
|
|
m.ToolTipText += "\nPos: " + lat + " , " + lon;
|
|
if (Properties.Settings.Default.InfoWin_Alt)
|
|
{
|
|
if (Properties.Settings.Default.InfoWin_Metric)
|
|
m.ToolTipText += "\nAlt: " + (int)info.Alt_m + "m [" + info.AltDiff.ToString("+#;-#;0") + "m]";
|
|
else
|
|
m.ToolTipText += "\nAlt: " + (int)info.Alt + "ft [" + UnitConverter.m_ft(info.AltDiff).ToString("+#;-#;0") + "ft]";
|
|
}
|
|
if (Properties.Settings.Default.InfoWin_Track)
|
|
m.ToolTipText += "\nTrack: " + (int)info.Track + "°";
|
|
if (Properties.Settings.Default.InfoWin_Speed)
|
|
{
|
|
if (Properties.Settings.Default.InfoWin_Metric)
|
|
m.ToolTipText += "\nSpeed: " + info.Speed_kmh.ToString("F0") + "km/h";
|
|
else
|
|
m.ToolTipText += "\nSpeed: " + info.Speed.ToString("F0") + "kts";
|
|
}
|
|
if (Properties.Settings.Default.InfoWin_Type)
|
|
m.ToolTipText += "\nType: " + info.Manufacturer + " " + info.Model + " [" + PlaneCategories.GetShortStringValue(info.Category) + "]";
|
|
|
|
if (info.Potential > 0)
|
|
{
|
|
if (Properties.Settings.Default.InfoWin_Dist)
|
|
{
|
|
if (Properties.Settings.Default.InfoWin_Metric)
|
|
m.ToolTipText += "\nDist: " + info.IntQRB.ToString("F0") + "km";
|
|
else
|
|
m.ToolTipText += "\nDist: " + UnitConverter.km_mi(info.IntQRB).ToString("F0") + "mi";
|
|
}
|
|
if (Properties.Settings.Default.InfoWin_Time)
|
|
m.ToolTipText += "\nTime: " + (CurrentTime + new TimeSpan(0, mins, 0)).ToString("HH:mm") + " [ " + mins.ToString("") + "min]";
|
|
if (Properties.Settings.Default.InfoWin_Angle)
|
|
m.ToolTipText += "\nAngle: " + (info.Angle / Math.PI * 180.0).ToString("F0") + "°";
|
|
if (Properties.Settings.Default.InfoWin_Epsilon)
|
|
m.ToolTipText += "\nEps: " + (info.Eps1 / Math.PI * 180.0).ToString("00.00") + "° <> " + (info.Eps2 / Math.PI * 180.0).ToString("00.00") + "°";
|
|
if (Properties.Settings.Default.InfoWin_Squint)
|
|
m.ToolTipText += "\nSquint: " + (info.Squint / Math.PI * 180).ToString("00.00") + "°";
|
|
}
|
|
|
|
if ((TrackMode == AIRSCOUTTRACKMODE.TRACK) && (TrackValues != null) && (
|
|
(Properties.Settings.Default.InfoWin_MyAzimuth) ||
|
|
(Properties.Settings.Default.InfoWin_MyElevation) ||
|
|
(Properties.Settings.Default.InfoWin_MyDoppler)
|
|
))
|
|
{
|
|
m.ToolTipText += "\n--------------------";
|
|
if (Properties.Settings.Default.InfoWin_MyAzimuth)
|
|
m.ToolTipText += "\nMyAzimuth: " + TrackValues.MyAzimuth.ToString("00.00") + "°";
|
|
if (Properties.Settings.Default.InfoWin_MyElevation)
|
|
m.ToolTipText += "\nMyElevation: " + TrackValues.MyElevation.ToString("00.00") + "°";
|
|
if (Properties.Settings.Default.InfoWin_MyDoppler)
|
|
m.ToolTipText += "\nMyDoppler: " + TrackValues.MyDoppler.ToString("F0") + "Hz";
|
|
}
|
|
if ((TrackMode == AIRSCOUTTRACKMODE.TRACK) && (TrackValues != null) && (
|
|
(Properties.Settings.Default.InfoWin_DXAzimuth) ||
|
|
(Properties.Settings.Default.InfoWin_DXElevation) ||
|
|
(Properties.Settings.Default.InfoWin_DXDoppler)
|
|
))
|
|
{
|
|
m.ToolTipText += "\n--------------------";
|
|
if (Properties.Settings.Default.InfoWin_DXAzimuth)
|
|
m.ToolTipText += "\nDXAzimuth: " + TrackValues.DXAzimuth.ToString("00.00") + "°";
|
|
if (Properties.Settings.Default.InfoWin_DXElevation)
|
|
m.ToolTipText += "\nDXElevation: " + TrackValues.DXElevation.ToString("00.00") + "°";
|
|
if (Properties.Settings.Default.InfoWin_DXDoppler)
|
|
m.ToolTipText += "\nDXDoppler: " + TrackValues.DXDoppler.ToString("F0") + "Hz";
|
|
}
|
|
|
|
|
|
if (selected)
|
|
{
|
|
m.ToolTipMode = MarkerTooltipMode.Always;
|
|
}
|
|
else
|
|
{
|
|
m.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
}
|
|
if (m.ToolTip != null)
|
|
m.ToolTip.Fill = brush;
|
|
return m;
|
|
}
|
|
|
|
private void DrawPlanes()
|
|
{
|
|
bool alarm = false;
|
|
bool isselected = false;
|
|
string alarm_msg = "";
|
|
|
|
List<PlaneInfo> pathplanes = new List<PlaneInfo>();
|
|
|
|
// check if any plane is on list --> return empty list
|
|
if ((ActivePlanes == null) || (ActivePlanes.Count == 0))
|
|
return;
|
|
bool anyselected = false;
|
|
List<TooltipDataPoint> planes_hi = new List<TooltipDataPoint>();
|
|
List<TooltipDataPoint> planes_lo = new List<TooltipDataPoint>();
|
|
// draw all planes
|
|
foreach (PlaneInfo plane in ActivePlanes.Values)
|
|
{
|
|
try
|
|
{
|
|
// show planes if it meets filter criteria
|
|
if ((plane.Alt_m >= Properties.Settings.Default.Planes_MinAlt) && (plane.Category >= Properties.Settings.Default.Planes_Filter_Min_Category))
|
|
{
|
|
// check selected state
|
|
isselected = SelectedPlanes.IndexOf(plane.Hex) >= 0;
|
|
// now, show plane according to potential
|
|
switch (plane.Potential)
|
|
{
|
|
case 100:
|
|
gmo_Planes.Markers.Add(CreatePlaneDetailed(plane, isselected));
|
|
// set alarm
|
|
if (plane.IntQRB < Properties.Settings.Default.Alarm_Distance)
|
|
{
|
|
alarm = true;
|
|
alarm_msg = plane.Call;
|
|
}
|
|
break;
|
|
case 75:
|
|
gmo_Planes.Markers.Add(CreatePlaneDetailed(plane, isselected));
|
|
// set alarm
|
|
if (plane.IntQRB < Properties.Settings.Default.Alarm_Distance)
|
|
{
|
|
alarm = true;
|
|
alarm_msg = plane.Call;
|
|
}
|
|
break;
|
|
case 50:
|
|
gmo_Planes.Markers.Add(CreatePlaneDetailed(plane, isselected));
|
|
break;
|
|
default:
|
|
if (Properties.Settings.Default.InfoWin_AlwaysDetailed)
|
|
{
|
|
gmo_Planes.Markers.Add(CreatePlaneDetailed(plane, isselected));
|
|
}
|
|
else
|
|
{
|
|
gmo_Planes.Markers.Add(CreatePlaneSimple(plane, isselected));
|
|
}
|
|
break;
|
|
}
|
|
|
|
// count the planes drawed and update caption, if not under Linux
|
|
// Linux/Mono is drawing the whole control again --> performance issue!
|
|
if (!SupportFunctions.IsMono)
|
|
tp_Map.Text = "Map [" + gmo_Planes.Markers.Count.ToString() + " plane(s)]";
|
|
// if selected: draw the thin path to crossing point if one
|
|
if (isselected)
|
|
{
|
|
anyselected = true;
|
|
if (plane.IntPoint != null)
|
|
{
|
|
GMapRoute intpath = new GMapRoute(plane.Call);
|
|
intpath.Stroke = new Pen(Color.Black, 1);
|
|
intpath.Points.Add(new PointLatLng(plane.Lat, plane.Lon));
|
|
intpath.Points.Add(new PointLatLng(plane.IntPoint.Lat, plane.IntPoint.Lon));
|
|
gmo_Routes.Routes.Add(intpath);
|
|
// Console.WriteLine(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + ";" + info.IntQRB.ToString("F3"));
|
|
}
|
|
// track plane, if enabled
|
|
if (Properties.Settings.Default.Track_Activate)
|
|
{
|
|
Properties.Settings.Default.Track_CurrentPlane = plane.Hex;
|
|
}
|
|
}
|
|
|
|
// show planes on chart if in sigle path mode
|
|
if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
{
|
|
if ((plane.IntPoint != null) && (plane.IntQRB <= Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].MaxDistance))
|
|
{
|
|
// calculate distance from mylat/mylon
|
|
double dist = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, plane.IntPoint.Lat, plane.IntPoint.Lon);
|
|
// add new data points
|
|
/*
|
|
if (plane.AltDiff > 0)
|
|
{
|
|
Planes_Hi.Points.Add(new DataPoint(dist, plane.Alt_m));
|
|
}
|
|
else
|
|
{
|
|
Planes_Lo.Points.Add(new DataPoint(dist, plane.Alt_m));
|
|
}
|
|
*/
|
|
|
|
TooltipDataPoint p = new TooltipDataPoint(dist, plane.Alt_m,plane.Call);
|
|
if (plane.AltDiff > 0)
|
|
{
|
|
planes_hi.Add(p);
|
|
}
|
|
else
|
|
{
|
|
planes_lo.Add(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add planes to chart
|
|
Planes_Hi.ItemsSource = planes_hi;
|
|
Planes_Lo.ItemsSource = planes_lo;
|
|
|
|
// change tracker display
|
|
Planes_Hi.TrackerFormatString = "{Tooltip}";
|
|
Planes_Lo.TrackerFormatString = "{Tooltip}";
|
|
|
|
// invalidate chart
|
|
pm_Path.InvalidatePlot(true);
|
|
|
|
// set alarm if one
|
|
if (alarm)
|
|
Alarm(alarm_msg);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
// stop tracking if selected object is lost for any reason
|
|
if (!anyselected)
|
|
{
|
|
TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
}
|
|
|
|
}
|
|
|
|
private void UpdatePlanes()
|
|
{
|
|
|
|
// get current time
|
|
|
|
// update status
|
|
UpdateStatus();
|
|
|
|
// check for filter settings
|
|
// and color filter box
|
|
int planes_filter_minalt = 0;
|
|
planes_filter_minalt = Properties.Settings.Default.Planes_Filter_Min_Alt;
|
|
if (planes_filter_minalt < 0)
|
|
planes_filter_minalt = 0;
|
|
if ((planes_filter_minalt != 0) || (Properties.Settings.Default.Planes_Filter_Min_Category > PLANECATEGORY.LIGHT))
|
|
{
|
|
pa_Planes_Filter.BackColor = Color.Plum;
|
|
}
|
|
else
|
|
{
|
|
pa_Planes_Filter.BackColor = SystemColors.Control;
|
|
}
|
|
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
List<PlaneInfo> allplanes = Planes.GetAll(CurrentTime, Properties.Settings.Default.Planes_Position_TTL);
|
|
// TODO: maintain selected status
|
|
st.Stop();
|
|
// Log.WriteMessage("Getting plane positions from database: " + allplanes.Count().ToString() + " plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
// clear active planes
|
|
ActivePlanes.Clear();
|
|
|
|
foreach (PropagationPathDesignator ppath in PropagationPaths)
|
|
{
|
|
st.Reset();
|
|
st.Start();
|
|
NearestPlane = null;
|
|
double highestpotential = 0;
|
|
// get nearest planes per path
|
|
List<PlaneInfo> nearestplanes = AircraftData.Database.GetNearestPlanes(DateTime.UtcNow, ppath, allplanes, Properties.Settings.Default.Planes_Filter_Max_Circumcircle, Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].MaxDistance, Properties.Settings.Default.Planes_MaxAlt);
|
|
|
|
foreach (PlaneInfo plane in nearestplanes)
|
|
{
|
|
// maintain highest potential
|
|
if ((plane.Alt_m >= Properties.Settings.Default.Planes_Filter_Min_Alt) && (plane.Category >= Properties.Settings.Default.Planes_Filter_Min_Category) && (plane.Potential > highestpotential))
|
|
highestpotential = plane.Potential;
|
|
// add or update plane in active planes list
|
|
PlaneInfo activeplane;
|
|
if (ActivePlanes.TryGetValue(plane.Hex, out activeplane))
|
|
{
|
|
// plane found --> update if necessary
|
|
bool update = false;
|
|
// plane has higher potential
|
|
if ((plane.IntPoint != null) && (plane.Potential > activeplane.Potential))
|
|
update = true;
|
|
// plane has same potetial but is nearer to path
|
|
else if ((plane.Potential == activeplane.Potential) && (plane.IntQRB < activeplane.IntQRB))
|
|
update = true;
|
|
// update if necessary
|
|
if (update)
|
|
{
|
|
ActivePlanes.Remove(activeplane.Hex);
|
|
ActivePlanes.Add(plane.Hex, plane);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// add plane to list if not foound
|
|
ActivePlanes.Add(plane.Hex, plane);
|
|
}
|
|
// maintain nearest plane info
|
|
// check if plane is within MaxDistance
|
|
if (plane.IntQRB < Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].MaxDistance)
|
|
{
|
|
if (NearestPlane == null)
|
|
{
|
|
// set first nearest plane info anyway
|
|
NearestPlane = plane;
|
|
}
|
|
// use higher potential anyway
|
|
if (plane.Potential > NearestPlane.Potential)
|
|
{
|
|
NearestPlane = plane;
|
|
}
|
|
else if (plane.Potential == NearestPlane.Potential)
|
|
{
|
|
// use nearer plane if same potential
|
|
if (plane.IntQRB < NearestPlane.IntQRB)
|
|
NearestPlane = plane;
|
|
}
|
|
}
|
|
}
|
|
// colour callsign in watchlist if in MULTIPATH mode
|
|
if (PathMode == AIRSCOUTPATHMODE.MULTI)
|
|
{
|
|
string dxcall = ppath.Location2.Call;
|
|
ListViewItem item = lv_Control_Watchlist.FindItemWithText(dxcall);
|
|
if (item != null)
|
|
{
|
|
// store potential in watchlist item and refresh if necessaray
|
|
if (item.ToolTipText != highestpotential.ToString())
|
|
{
|
|
item.ToolTipText = highestpotential.ToString();
|
|
lv_Control_Watchlist.Refresh();
|
|
}
|
|
}
|
|
}
|
|
st.Stop();
|
|
// Log.WriteMessage("Get nearest planes: " + ActivePlanes.Count.ToString() + " plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
st.Start();
|
|
// clear planes overlay in map
|
|
gmo_Planes.Clear();
|
|
// clear all routes except paths
|
|
gmo_Routes.Clear();
|
|
|
|
// clear data points in chart
|
|
Planes_Hi.Points.Clear();
|
|
Planes_Lo.Points.Clear();
|
|
pm_Path.Annotations.Clear();
|
|
|
|
// draw planes
|
|
DrawPlanes();
|
|
st.Stop();
|
|
// Log.WriteMessage("Drawing planes: " + ActivePlanes.Count.ToString() + " plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
|
|
// set focus on the map object
|
|
this.ActiveControl = gm_Main;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Watchlist
|
|
|
|
private void UpdateWatchlistInMap()
|
|
{
|
|
// show callsigns from watchlist
|
|
gmo_Callsigns.Clear();
|
|
if (!Properties.Settings.Default.Watchlist_Activated)
|
|
return;
|
|
// create new watchlist if null
|
|
if (Properties.Settings.Default.Watchlist == null)
|
|
Properties.Settings.Default.Watchlist = new Watchlist();
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
LocationDesignator dxloc = LocationFindOrCreate(item.Call, item.Loc);
|
|
GMarkerGoogle gm = new GMarkerGoogle(new PointLatLng(dxloc.Lat, dxloc.Lon), ToolTipFont, (dxloc.Source == GEOSOURCE.FROMUSER) ? GMarkerGoogleType.green_small : GMarkerGoogleType.white_small);
|
|
gm.ToolTipText = dxloc.Call;
|
|
if ((PathMode == AIRSCOUTPATHMODE.MULTI) && Properties.Settings.Default.Map_LabelCalls && item.Checked)
|
|
gm.ToolTipMode = MarkerTooltipMode.Always;
|
|
else
|
|
gm.ToolTipMode = MarkerTooltipMode.OnMouseOver;
|
|
gm.Tag = dxloc.Call;
|
|
gmo_Callsigns.Markers.Add(gm);
|
|
}
|
|
}
|
|
|
|
private void AddListViewItem (WatchlistItem item)
|
|
{
|
|
LocationDesignator dxcall = StationData.Database.LocationFindOrCreate(item.Call, item.Loc);
|
|
ListViewItem lvi = new ListViewItem(item.Call);
|
|
lvi.Name = "Call";
|
|
ListViewItem.ListViewSubItem lsi = new ListViewItem.ListViewSubItem(lvi, item.Loc);
|
|
lsi.Name = "Loc";
|
|
lvi.SubItems.Add(lsi);
|
|
lv_Control_Watchlist.Items.Add(lvi);
|
|
if (item.Checked)
|
|
lvi.Checked = true;
|
|
if (item.Selected)
|
|
lvi.Selected = true;
|
|
// tag item as "Out of Range"
|
|
if (item.OutOfRange)
|
|
{
|
|
lvi.Tag = "OOR";
|
|
lvi.ForeColor = Color.LightGray;
|
|
}
|
|
else
|
|
{
|
|
lvi.BackColor = (dxcall.Source == GEOSOURCE.FROMUSER) ? Color.PaleGreen : Color.White;
|
|
}
|
|
|
|
}
|
|
|
|
private void RefreshWatchlistView()
|
|
{
|
|
|
|
// set watchlistupdating flag
|
|
WatchlistUpdating = true;
|
|
// keep scroll position
|
|
int topItemIndex = 0;
|
|
try
|
|
{
|
|
if ((PlayMode != AIRSCOUTPLAYMODE.FORWARD) && (lv_Control_Watchlist.TopItem != null))
|
|
{
|
|
topItemIndex = lv_Control_Watchlist.TopItem.Index;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
// update listview
|
|
lv_Control_Watchlist.BeginUpdate();
|
|
lv_Control_Watchlist.Items.Clear();
|
|
Properties.Settings.Default.Watchlist.Sort();
|
|
// run twice, add checked items first, then all others
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
if (item.Checked)
|
|
AddListViewItem(item);
|
|
}
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
if (!item.Checked)
|
|
AddListViewItem(item);
|
|
}
|
|
// lv_Control_Watchlist.Sort();
|
|
lv_Control_Watchlist.EndUpdate();
|
|
// restore scroll position
|
|
try
|
|
{
|
|
lv_Control_Watchlist.TopItem = lv_Control_Watchlist.Items[topItemIndex];
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
// reset watchlistupdating flag
|
|
WatchlistUpdating = false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region User Interface
|
|
|
|
private void MapDlg_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void MapDlg_Resize(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void ti_Progress_Tick(object sender, EventArgs e)
|
|
{
|
|
// prevent timer tick from overflow when heavy loaded
|
|
// stop timer --> do update procedure --> start timer again
|
|
ti_Progress.Stop();
|
|
if (LifeMode == AIRSCOUTLIFEMODE.LIFE)
|
|
{
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
{
|
|
// update current time
|
|
if (Properties.Settings.Default.Time_Mode_Online)
|
|
{
|
|
CurrentTime = DateTime.UtcNow;
|
|
UpdatePlanes();
|
|
}
|
|
}
|
|
}
|
|
else if (LifeMode == AIRSCOUTLIFEMODE.HISTORY)
|
|
{
|
|
if (PlayMode != AIRSCOUTPLAYMODE.PAUSE)
|
|
{
|
|
Properties.Settings.Default.Time_Offline = Properties.Settings.Default.Time_Offline.AddSeconds(Time_Offline_Interval);
|
|
if (Properties.Settings.Default.Time_Offline < dtp_Analysis_MinValue.Value)
|
|
Properties.Settings.Default.Time_Offline = dtp_Analysis_MinValue.Value;
|
|
if (Properties.Settings.Default.Time_Offline > dtp_Analysis_MaxValue.Value)
|
|
Properties.Settings.Default.Time_Offline = dtp_Analysis_MaxValue.Value;
|
|
CurrentTime = Properties.Settings.Default.Time_Offline;
|
|
tb_Analysis_Time.Text = CurrentTime.ToString("yyyy-MM-hh HH:mm:ss");
|
|
double span = (CurrentTime - dtp_Analysis_MinValue.Value).TotalSeconds;
|
|
if ((span > sb_Analysis_Play.Minimum) && (span < sb_Analysis_Play.Maximum))
|
|
sb_Analysis_Play.Value = (int)span;
|
|
UpdatePlanes();
|
|
}
|
|
}
|
|
// restart timer
|
|
ti_Progress.Start();
|
|
}
|
|
|
|
private void sc_Main_SplitterMoved(object sender, SplitterEventArgs e)
|
|
{
|
|
}
|
|
|
|
private void sc_Map_SplitterMoved(object sender, SplitterEventArgs e)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
#region Map
|
|
|
|
private void gm_Main_OnMapZoomChanged()
|
|
{
|
|
double midlat = LatLon.MidPoint(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon).Lat;
|
|
double midlon = LatLon.MidPoint(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon).Lon;
|
|
if ((PlayMode == AIRSCOUTPLAYMODE.FORWARD) && Properties.Settings.Default.Map_AutoCenter)
|
|
gm_Main.Position = new PointLatLng(midlat, midlon);
|
|
tb_Zoom.Text = gm_Main.Zoom.ToString();
|
|
|
|
// (re)initialize locator overlay
|
|
InitializeLocators();
|
|
}
|
|
|
|
private void gm_Main_OnMarkerClick(GMapMarker item, MouseEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
|
{
|
|
// check if callsign clicked
|
|
if (item.Overlay == gmo_Callsigns)
|
|
{
|
|
string call = (string)item.Tag;
|
|
// check if callsign clicked and not own callsign
|
|
if (Callsign.Check(call) && (call != Properties.Settings.Default.MyCall))
|
|
{
|
|
if (PathMode == AIRSCOUTPATHMODE.MULTI)
|
|
{
|
|
// search call on watchlist
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(call);
|
|
if (index >= 0)
|
|
{
|
|
// toggle checked state
|
|
Properties.Settings.Default.Watchlist.ElementAt(index).Checked = !Properties.Settings.Default.Watchlist.ElementAt(index).Checked;
|
|
// refresh watchlist view
|
|
RefreshWatchlistView();
|
|
// update paths if running
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
UpdatePaths();
|
|
}
|
|
}
|
|
else if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
{
|
|
// search call on watchlist
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(call);
|
|
if (index >= 0)
|
|
{
|
|
string loc = Properties.Settings.Default.Watchlist.ElementAt(index).Loc;
|
|
// get location info from database
|
|
LocationDesignator ld = LocationFindOrCreate(call, loc);
|
|
Properties.Settings.Default.DXCall = ld.Call;
|
|
Properties.Settings.Default.DXLat = ld.Lat;
|
|
Properties.Settings.Default.DXLon = ld.Lon;
|
|
UpdateStatus();
|
|
// update paths if running
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
UpdatePaths();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// check if plane clicked
|
|
else if (item.Overlay == gmo_Planes)
|
|
{
|
|
// keep the selected state
|
|
int selectedindex = SelectedPlanes.IndexOf((string)item.Tag);
|
|
// clear all other selections if tracking is enabled
|
|
if (Properties.Settings.Default.Track_Activate)
|
|
{
|
|
SelectedPlanes.Clear();
|
|
if (selectedindex < 0)
|
|
{
|
|
SelectedPlanes.Add((string)item.Tag);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// toogle selection of the selected plane
|
|
if (selectedindex >= 0)
|
|
{
|
|
// remove item from selected planes list
|
|
SelectedPlanes.RemoveAt(selectedindex);
|
|
// invalidate tracking
|
|
TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
}
|
|
else
|
|
{
|
|
SelectedPlanes.Add((string)item.Tag);
|
|
}
|
|
}
|
|
// set track mode
|
|
if (Properties.Settings.Default.Track_Activate)
|
|
{
|
|
TrackMode = AIRSCOUTTRACKMODE.TRACK;
|
|
}
|
|
}
|
|
// check if call clicked
|
|
else if (item.Overlay == gmo_Callsigns)
|
|
{
|
|
LocationDesignator ld = StationData.Database.LocationFind(item.Tag.ToString());
|
|
if (ld != null)
|
|
{
|
|
if (PlayMode != AIRSCOUTPLAYMODE.PAUSE)
|
|
this.Pause();
|
|
Properties.Settings.Default.DXCall = item.Tag.ToString();
|
|
Properties.Settings.Default.DXLat = ld.Lat;
|
|
Properties.Settings.Default.DXLon = ld.Lon;
|
|
UpdateStatus();
|
|
this.Play();
|
|
}
|
|
}
|
|
}
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Right)
|
|
{
|
|
// new for tracking antenna
|
|
if ((string)item.Tag == Properties.Settings.Default.DXCall)
|
|
{
|
|
// Right click on DXCall needle --> set antenna position
|
|
// get antenna direction
|
|
double qtf = LatLon.Bearing(Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon);
|
|
// store new QTF in properties
|
|
lock (Properties.Settings.Default)
|
|
{
|
|
TrackMode = AIRSCOUTTRACKMODE.SINGLE;
|
|
Properties.Settings.Default.Track_SetAz = qtf;
|
|
Properties.Settings.Default.Track_SetEl = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if item not found in planes list
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void gm_Main_OnMarkerEnter(GMapMarker item)
|
|
{
|
|
if (((item == gmm_MyLoc) || (item == gmm_DXLoc)) && !isDraggingMarker)
|
|
gmm_CurrentMarker = item;
|
|
}
|
|
|
|
private void gm_Main_OnMarkerLeave(GMapMarker item)
|
|
{
|
|
|
|
}
|
|
|
|
private void gm_Main_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left && gmm_CurrentMarker != null && gmm_CurrentMarker.IsMouseOver)
|
|
isDraggingMarker = true;
|
|
}
|
|
|
|
private void gm_Main_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
}
|
|
|
|
private void gm_Main_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (isDraggingMarker)
|
|
{
|
|
isDraggingMarker = false;
|
|
}
|
|
|
|
if (isDraggingMap)
|
|
{
|
|
// (re)initialize locator overlay
|
|
InitializeLocators();
|
|
isDraggingMap = false;
|
|
}
|
|
}
|
|
|
|
private void gm_Main_OnMapDrag()
|
|
{
|
|
// set dragging mode
|
|
isDraggingMap = true;
|
|
|
|
// switch off locator overlay
|
|
gmo_Locators.IsVisibile = false;
|
|
}
|
|
|
|
|
|
private void gm_Main_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
if (Properties.Settings.Default.Map_TrackingGaugesShow && (TrackMode == AIRSCOUTTRACKMODE.TRACK) && (TrackValues != null))
|
|
{
|
|
// paint gauges on top of the map if enabled
|
|
ag_Azimuth.Value = (float)TrackValues.MyAzimuth;
|
|
ag_Elevation.Value = (float)TrackValues.MyElevation;
|
|
|
|
// get gauges forecolor from properties
|
|
Color gaugescolor = Color.FromName(Properties.Settings.Default.Map_TrackingGaugeColor);
|
|
if (gaugescolor == null)
|
|
{
|
|
// set to black if fails
|
|
gaugescolor = Color.Black;
|
|
}
|
|
|
|
// get brushes, pens and fonts
|
|
Brush gaugesbrush = new SolidBrush(gaugescolor);
|
|
Pen gaugespen = new Pen(gaugesbrush, 3);
|
|
Font trackfont = new Font("Courier New", (int)((double)pa_Rig.Height / 7.0), FontStyle.Bold);
|
|
|
|
// set colors, brushes and pens
|
|
ag_Azimuth.ForeColor = gaugescolor;
|
|
ag_Elevation.ForeColor = gaugescolor;
|
|
|
|
e.Graphics.DrawRectangle(gaugespen, new Rectangle(ag_Azimuth.Left, ag_Azimuth.Top, ag_Azimuth.Width + ag_Elevation.Width + 20, ag_Elevation.Height));
|
|
|
|
// draw elements
|
|
int ofsX = ag_Azimuth.Left;
|
|
int ofsY = ag_Azimuth.Top;
|
|
ag_Azimuth.DrawDialText(e.Graphics, ofsX, ofsY);
|
|
ag_Azimuth.DisplayNumber(e.Graphics, ofsX, ofsY);
|
|
ag_Azimuth.DrawCalibration(e.Graphics, ofsX, ofsY);
|
|
ag_Azimuth.DrawCenterPoint(e.Graphics, ofsX, ofsY);
|
|
ag_Azimuth.DrawPointer(e.Graphics, ofsX, ofsY);
|
|
|
|
ofsX = ag_Elevation.Left;
|
|
ofsY = ag_Elevation.Top;
|
|
ag_Elevation.DrawDialText(e.Graphics, ofsX, ofsY);
|
|
ag_Elevation.DisplayNumber(e.Graphics, ofsX, ofsY);
|
|
ag_Elevation.DrawCalibration(e.Graphics, ofsX, ofsY);
|
|
ag_Elevation.DrawCenterPoint(e.Graphics, ofsX, ofsY);
|
|
ag_Elevation.DrawPointer(e.Graphics, ofsX, ofsY);
|
|
|
|
if (!Properties.Settings.Default.Doppler_Strategy_None)
|
|
{
|
|
// paint rig frequencies on top of the map if doppler compensation enabled
|
|
NumberFormatInfo info = new NumberFormatInfo();
|
|
info.NumberDecimalSeparator = ",";
|
|
info.NumberGroupSeparator = ".";
|
|
int top = 0;
|
|
int left = 10;
|
|
e.Graphics.DrawRectangle(gaugespen, new Rectangle(pa_Rig.Left, pa_Rig.Top, pa_Rig.Width, pa_Rig.Height));
|
|
e.Graphics.DrawString("MyDop: " + TrackValues.MyDoppler.ToString("F0"), trackfont, gaugesbrush, new PointF(pa_Rig.Left + left, pa_Rig.Top + top));
|
|
e.Graphics.DrawString("DXDop: " + TrackValues.DXDoppler.ToString("F0"), trackfont, gaugesbrush, new PointF(pa_Rig.Left + left + pa_Rig.Width / 2, pa_Rig.Top + top));
|
|
e.Graphics.DrawString("Dial : " + Properties.Settings.Default.Doppler_DialFreq.ToString(info), trackfont, gaugesbrush, new PointF(pa_Rig.Left + left, pa_Rig.Top + top + pa_Rig.Height / 4 * 1));
|
|
e.Graphics.DrawString("RX : " + TrackValues.RXFrequency.ToString(info), trackfont, gaugesbrush, new PointF(pa_Rig.Left + left, pa_Rig.Top + top + pa_Rig.Height / 4 * 2));
|
|
e.Graphics.DrawString("TX : " + TrackValues.TXFrequency.ToString(info), trackfont, gaugesbrush, new PointF(pa_Rig.Left + left, pa_Rig.Top + top + pa_Rig.Height / 4 * 3));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void gm_Main_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// get width from properties
|
|
int width = (int)Properties.Settings.Default.Map_TrackingGaugeWidth;
|
|
|
|
|
|
// check bounds
|
|
if (width < 175)
|
|
width = 175;
|
|
if (width > this.Width / 2)
|
|
width = this.Width / 2;
|
|
|
|
// adjust position and size of gauges
|
|
ag_Azimuth.Width = width;
|
|
ag_Elevation.Width = width;
|
|
ag_Azimuth.Left = gm_Main.Right - ag_Azimuth.Width - ag_Elevation.Width - 40;
|
|
ag_Azimuth.Top = gm_Main.Bottom - ag_Azimuth.Height - 20;
|
|
|
|
ag_Elevation.Left = gm_Main.Right - ag_Elevation.Width - 20;
|
|
ag_Elevation.Top = gm_Main.Bottom - ag_Elevation.Height - 20;
|
|
|
|
// adjust position and size of rig panel
|
|
pa_Rig.Width = ag_Elevation.Right - ag_Azimuth.Left;
|
|
pa_Rig.Height = ag_Azimuth.Height / 2;
|
|
pa_Rig.Left = ag_Azimuth.Left;
|
|
pa_Rig.Top = gm_Main.Bottom - ag_Azimuth.Height - pa_Rig.Height - 30;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private void gm_Main_OnPositionChanged(PointLatLng point)
|
|
{
|
|
}
|
|
|
|
private void gm_Main_OnTileLoadComplete(long ElapsedMilliseconds)
|
|
{
|
|
// use thread safe call here!
|
|
this.BeginInvoke((Action)delegate ()
|
|
{
|
|
InitializeLocators();
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Right Controls
|
|
|
|
private void cb_Band_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (cb_Band.SelectedItem != null)
|
|
Properties.Settings.Default.Band = Bands.ParseStringValue((string)cb_Band.SelectedItem);
|
|
else Properties.Settings.Default.Band = BAND.BNONE;
|
|
|
|
// SaveUserSettings();
|
|
// Properties.Settings.Default.Reload();
|
|
|
|
}
|
|
|
|
#region Tab Control Control Panel
|
|
|
|
private void tc_Control_DrawItem(object sender, DrawItemEventArgs e)
|
|
{
|
|
// This event is called once for each tab button in your tab control
|
|
// First paint the background with a color based on the current tab
|
|
// e.Index is the index of the tab in the TabPages collection.
|
|
switch (e.Index)
|
|
{
|
|
case 0:
|
|
e.Graphics.FillRectangle(new SolidBrush(SystemColors.Control), e.Bounds);
|
|
break;
|
|
case 1:
|
|
e.Graphics.FillRectangle(new SolidBrush(SystemColors.Control), e.Bounds);
|
|
break;
|
|
case 2:
|
|
e.Graphics.FillRectangle(new SolidBrush((Properties.Settings.Default.Planes_Filter_Min_Category > PLANECATEGORY.LIGHT) ? Color.Plum : SystemColors.Control), e.Bounds);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Then draw the current tab button text
|
|
Rectangle paddedBounds = e.Bounds;
|
|
paddedBounds.Inflate(-2, -2);
|
|
e.Graphics.DrawString(tc_Control.TabPages[e.Index].Text, tc_Control.Font, (tc_Control.Enabled) ? SystemBrushes.ControlText : SystemBrushes.GrayText, paddedBounds);
|
|
}
|
|
|
|
|
|
#region Single Tab
|
|
|
|
private void tp_Control_Single_Enter(object sender, EventArgs e)
|
|
{
|
|
if (PathMode != AIRSCOUTPATHMODE.SINGLE)
|
|
{
|
|
PathMode = AIRSCOUTPATHMODE.SINGLE;
|
|
tc_Map.SelectedTab = tp_Map;
|
|
}
|
|
// update all info
|
|
UpdateStatus();
|
|
}
|
|
|
|
private void gb_Map_Info_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
// get font size in pixels
|
|
double pixels;
|
|
using (Graphics g = this.CreateGraphics())
|
|
{
|
|
pixels = gb_Map_Info.Font.SizeInPoints * g.DpiX / 72;
|
|
}
|
|
if ((e.Y <= pixels) && (e.Button == MouseButtons.Left))
|
|
{
|
|
Properties.Settings.Default.Map_ShowInfoBox = !Properties.Settings.Default.Map_ShowInfoBox;
|
|
}
|
|
}
|
|
|
|
|
|
private void cb_MyCall_TextChanged(object sender, EventArgs e)
|
|
{
|
|
int i = cb_MyCall.SelectionStart;
|
|
Properties.Settings.Default.MyCall = cb_MyCall.Text;
|
|
// clear locator entries
|
|
cb_MyLoc.Text = "";
|
|
cb_MyLoc.Items.Clear();
|
|
Properties.Settings.Default.MyLat = double.NaN;
|
|
Properties.Settings.Default.MyLon = double.NaN;
|
|
Properties.Settings.Default.MyElevation = 0;
|
|
if (Callsign.Check(cb_MyCall.Text))
|
|
{
|
|
// select last recent loc
|
|
LocationDesignator ld = StationData.Database.LocationFind(cb_MyCall.Text);
|
|
if (ld != null)
|
|
{
|
|
Properties.Settings.Default.MyLat = ld.Lat;
|
|
Properties.Settings.Default.MyLon = ld.Lon;
|
|
Properties.Settings.Default.MyElevation = GetElevation(ld.Lat, ld.Lon);
|
|
}
|
|
}
|
|
UpdateStatus();
|
|
cb_MyCall.Select(i, 0);
|
|
}
|
|
|
|
private void cb_MyCall_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (cb_MyCall.SelectedItem != null)
|
|
{
|
|
cb_MyCall.Text = cb_MyCall.SelectedItem.ToString();
|
|
LocationDesignator ld = StationData.Database.LocationFind(cb_MyCall.Text);
|
|
if (Callsign.Check(cb_MyCall.Text) && (ld != null))
|
|
{
|
|
// update Settings
|
|
cb_MyLoc.Text = MaidenheadLocator.LocFromLatLon(ld.Lat, ld.Lon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, (int)Properties.Settings.Default.Locator_MaxLength / 2, Properties.Settings.Default.Locator_AutoLength);
|
|
Properties.Settings.Default.MyCall = cb_MyCall.Text;
|
|
Properties.Settings.Default.MyLat = ld.Lat;
|
|
Properties.Settings.Default.MyLon = ld.Lon;
|
|
Properties.Settings.Default.MyElevation = GetElevation(ld.Lat, ld.Lon);
|
|
Properties.Settings.Default.MyHeight = 10;
|
|
}
|
|
else
|
|
{
|
|
Properties.Settings.Default.MyLat = double.NaN;
|
|
Properties.Settings.Default.MyLon = double.NaN;
|
|
Properties.Settings.Default.MyElevation = 0;
|
|
Properties.Settings.Default.MyHeight = 0;
|
|
}
|
|
UpdateStatus();
|
|
}
|
|
}
|
|
|
|
private void cb_MyCall_DropDown(object sender, EventArgs e)
|
|
{
|
|
// poulate from MyCalls last recent collection
|
|
// populate drop down list
|
|
cb_MyCall.Items.Clear();
|
|
foreach (string call in Properties.Settings.Default.MyCalls)
|
|
{
|
|
cb_MyCall.Items.Add(call);
|
|
}
|
|
}
|
|
|
|
private void cb_MyLoc_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (cb_MyLoc.Focused)
|
|
{
|
|
if (MaidenheadLocator.Check(cb_MyLoc.Text) && (cb_MyLoc.Text.Length >= 6))
|
|
{
|
|
Properties.Settings.Default.MyLat = cb_MyLoc.GeoLocation.Lat;
|
|
Properties.Settings.Default.MyLon = cb_MyLoc.GeoLocation.Lon;
|
|
Properties.Settings.Default.MyElevation = GetElevation(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
Properties.Settings.Default.MyHeight = 10;
|
|
// colour Textbox if more precise lat/lon information is available
|
|
if (MaidenheadLocator.IsPrecise(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, 3))
|
|
{
|
|
cb_MyLoc.BackColor = Color.PaleGreen;
|
|
}
|
|
UpdateStatus();
|
|
}
|
|
else
|
|
{
|
|
cb_MyLoc.BackColor = Color.FloralWhite;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cb_MyLoc_DropDown(object sender, EventArgs e)
|
|
{
|
|
// fill MyLoc combo box with all known locators
|
|
cb_MyLoc.BackColor = Color.FloralWhite;
|
|
cb_MyLoc.SilentText = "";
|
|
cb_MyLoc.Items.Clear();
|
|
List<LocationDesignator> lds = StationData.Database.LocationFindAll(cb_MyCall.Text);
|
|
if (lds != null)
|
|
{
|
|
// fill item list of locator box
|
|
foreach (LocationDesignator ld in lds)
|
|
{
|
|
LocatorDropDownItem ldd = new LocatorDropDownItem(MaidenheadLocator.LocFromLatLon(ld.Lat, ld.Lon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, (int)Properties.Settings.Default.Locator_MaxLength / 2, Properties.Settings.Default.Locator_AutoLength), new LatLon.GPoint(ld.Lat, ld.Lon));
|
|
cb_MyLoc.Items.Add(ldd);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cb_MyLoc_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
LocatorDropDownItem ldd = (LocatorDropDownItem)cb_MyLoc.SelectedItem;
|
|
if (ldd != null)
|
|
{
|
|
// update properties
|
|
cb_MyLoc.Precision = (int)Properties.Settings.Default.Locator_MaxLength / 2;
|
|
cb_MyLoc.SmallLettersForSubsquares = Properties.Settings.Default.Locator_SmallLettersForSubsquares;
|
|
cb_MyLoc.AutoLength = Properties.Settings.Default.Locator_AutoLength;
|
|
// set geolocation instead of text
|
|
cb_MyLoc.GeoLocation = ldd.GeoLocation;
|
|
}
|
|
}
|
|
|
|
private void cb_MyLoc_SelectionChangeCommittedWithNoUpdate(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void cb_DXCall_TextChanged(object sender, EventArgs e)
|
|
{
|
|
int i = cb_DXCall.SelectionStart;
|
|
Properties.Settings.Default.DXCall = cb_DXCall.Text;
|
|
// clear locator entries
|
|
cb_DXLoc.Text = "";
|
|
cb_DXLoc.Items.Clear();
|
|
Properties.Settings.Default.DXLat = double.NaN;
|
|
Properties.Settings.Default.DXLon = double.NaN;
|
|
Properties.Settings.Default.DXElevation = 0;
|
|
if (Callsign.Check(cb_DXCall.Text))
|
|
{
|
|
// select last recent loc
|
|
LocationDesignator ld = StationData.Database.LocationFind(cb_DXCall.Text);
|
|
if (ld != null)
|
|
{
|
|
Properties.Settings.Default.DXLat = ld.Lat;
|
|
Properties.Settings.Default.DXLon = ld.Lon;
|
|
Properties.Settings.Default.DXElevation = GetElevation(ld.Lat, ld.Lon);
|
|
}
|
|
}
|
|
UpdateStatus();
|
|
cb_DXCall.Select(i, 0);
|
|
}
|
|
|
|
private void cb_DXCall_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
if (cb_DXCall.SelectedItem != null)
|
|
{
|
|
cb_DXCall.Text = cb_DXCall.SelectedItem.ToString();
|
|
LocationDesignator ld = StationData.Database.LocationFind(cb_DXCall.Text);
|
|
if (Callsign.Check(cb_DXCall.Text) && (ld != null))
|
|
{
|
|
// update Settings
|
|
cb_DXLoc.Text = MaidenheadLocator.LocFromLatLon(ld.Lat, ld.Lon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, (int)Properties.Settings.Default.Locator_MaxLength / 2, Properties.Settings.Default.Locator_AutoLength);
|
|
Properties.Settings.Default.DXCall = cb_DXCall.Text;
|
|
Properties.Settings.Default.DXLat = ld.Lat;
|
|
Properties.Settings.Default.DXLon = ld.Lon;
|
|
Properties.Settings.Default.DXElevation = GetElevation(ld.Lat, ld.Lon);
|
|
Properties.Settings.Default.DXHeight = 10;
|
|
}
|
|
else
|
|
{
|
|
Properties.Settings.Default.DXLat = double.NaN;
|
|
Properties.Settings.Default.DXLon = double.NaN;
|
|
Properties.Settings.Default.DXElevation = 0;
|
|
Properties.Settings.Default.DXHeight = 0;
|
|
}
|
|
UpdateStatus();
|
|
}
|
|
}
|
|
|
|
private void cb_DXCall_DropDown(object sender, EventArgs e)
|
|
{
|
|
// populate from watchlist
|
|
// return on empty watchlist
|
|
if (Properties.Settings.Default.Watchlist == null)
|
|
return;
|
|
// populate drop down list
|
|
List<string> dxcalls = new List<string>();
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
dxcalls.Add(item.Call);
|
|
}
|
|
dxcalls.Sort();
|
|
cb_DXCall.Items.Clear();
|
|
cb_DXCall.Items.AddRange(dxcalls.ToArray());
|
|
}
|
|
|
|
|
|
private void cb_DXLoc_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (cb_DXLoc.Focused)
|
|
{
|
|
if (MaidenheadLocator.Check(cb_DXLoc.Text) && (cb_DXLoc.Text.Length >= 6))
|
|
{
|
|
Properties.Settings.Default.DXLat = cb_DXLoc.GeoLocation.Lat;
|
|
Properties.Settings.Default.DXLon = cb_DXLoc.GeoLocation.Lon;
|
|
Properties.Settings.Default.DXElevation = GetElevation(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon);
|
|
Properties.Settings.Default.DXHeight = 10;
|
|
// colour Textbox if more precise lat/lon information is available
|
|
if (MaidenheadLocator.IsPrecise(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, 3))
|
|
{
|
|
cb_DXLoc.BackColor = Color.PaleGreen;
|
|
}
|
|
UpdateStatus();
|
|
}
|
|
else
|
|
{
|
|
cb_DXLoc.BackColor = Color.FloralWhite;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cb_DXLoc_DropDown(object sender, EventArgs e)
|
|
{
|
|
// fill DXLoc combo box with all known locators
|
|
cb_DXLoc.BackColor = Color.FloralWhite;
|
|
cb_DXLoc.SilentText = "";
|
|
cb_DXLoc.Items.Clear();
|
|
List<LocationDesignator> lds = StationData.Database.LocationFindAll(cb_DXCall.Text);
|
|
if (lds != null)
|
|
{
|
|
// fill item list of locator box
|
|
foreach (LocationDesignator ld in lds)
|
|
{
|
|
LocatorDropDownItem ldd = new LocatorDropDownItem(MaidenheadLocator.LocFromLatLon(ld.Lat, ld.Lon, Properties.Settings.Default.Locator_SmallLettersForSubsquares, (int)Properties.Settings.Default.Locator_MaxLength / 2, Properties.Settings.Default.Locator_AutoLength), new LatLon.GPoint(ld.Lat, ld.Lon));
|
|
cb_DXLoc.Items.Add(ldd);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cb_DXLoc_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
LocatorDropDownItem ldd = (LocatorDropDownItem)cb_DXLoc.SelectedItem;
|
|
if (ldd != null)
|
|
{
|
|
// update properties
|
|
cb_DXLoc.Precision = (int)Properties.Settings.Default.Locator_MaxLength / 2;
|
|
cb_DXLoc.SmallLettersForSubsquares = Properties.Settings.Default.Locator_SmallLettersForSubsquares;
|
|
cb_DXLoc.AutoLength = Properties.Settings.Default.Locator_AutoLength;
|
|
// set geolocation instead of text
|
|
cb_DXLoc.GeoLocation = ldd.GeoLocation;
|
|
}
|
|
}
|
|
|
|
private void cb_DXLoc_SelectionChangeCommittedWithNoUpdate(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tab Multi
|
|
|
|
private void tp_Control_Multi_Enter(object sender, EventArgs e)
|
|
{
|
|
// enbale/disable manage watchlist button
|
|
btn_Control_Manage_Watchlist.Enabled = !Properties.Settings.Default.Watchlist_SyncWithKST || !Properties.Settings.Default.Server_Activate;
|
|
|
|
if (PathMode != AIRSCOUTPATHMODE.MULTI)
|
|
{
|
|
PathMode = AIRSCOUTPATHMODE.MULTI;
|
|
tc_Map.SelectedTab = tp_Map;
|
|
}
|
|
tp_Control_Multi.Refresh();
|
|
}
|
|
|
|
private void lv_Control_Watchlist_Resize(object sender, EventArgs e)
|
|
{
|
|
// list view resized
|
|
// resize locator column to fit the client size
|
|
try
|
|
{
|
|
lv_Control_Watchlist.Columns[1].Width = lv_Control_Watchlist.ClientSize.Width - lv_Control_Watchlist.Columns[0].Width;
|
|
}
|
|
catch
|
|
{
|
|
// do nothing, if resize fails
|
|
}
|
|
}
|
|
|
|
private void lv_Control_Watchlist_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
|
|
{
|
|
// adjust width of Locator column to list view width
|
|
if (e.ColumnIndex == 0)
|
|
{
|
|
// call sign column changed
|
|
// resize locator column to fit the client size
|
|
try
|
|
{
|
|
lv_Control_Watchlist.Columns[1].Width = lv_Control_Watchlist.ClientSize.Width - lv_Control_Watchlist.Columns[0].Width;
|
|
}
|
|
catch
|
|
{
|
|
// do nothing, if resize fails
|
|
}
|
|
}
|
|
}
|
|
|
|
private void lv_Control_Watchlist_ItemCheck(object sender, ItemCheckEventArgs e)
|
|
{
|
|
// ignore when in PLAY mode
|
|
if (!WatchlistUpdating && (PlayMode == AIRSCOUTPLAYMODE.FORWARD))
|
|
e.NewValue = e.CurrentValue;
|
|
}
|
|
|
|
private void lv_Control_Watchlist_ItemChecked(object sender, ItemCheckedEventArgs e)
|
|
{
|
|
// ignore event while populating list view
|
|
if (WatchlistUpdating)
|
|
return;
|
|
// sync watchlist with list view
|
|
ListViewItem lvi = e.Item;
|
|
if (lvi == null)
|
|
return;
|
|
// search item in watchlist
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(lvi.Text, lvi.SubItems[1].Text);
|
|
if (index >= 0)
|
|
Properties.Settings.Default.Watchlist[index].Checked = lvi.Checked;
|
|
if (WatchlistAllCheckedChanging)
|
|
return;
|
|
// maintain AllChecked checkbox
|
|
foreach (ListViewItem item in lv_Control_Watchlist.Items)
|
|
{
|
|
// stop on first different checked state
|
|
if ((item != null) && (item.Checked != lvi.Checked))
|
|
{
|
|
WatchlistAllCheckedState = CheckBoxState.MixedNormal;
|
|
lv_Control_Watchlist.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.HeaderSize);
|
|
return;
|
|
}
|
|
}
|
|
// all items in the same state
|
|
WatchlistAllCheckedState = (lvi.Checked) ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal;
|
|
lv_Control_Watchlist.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.HeaderSize);
|
|
}
|
|
|
|
private void lv_Control_Watchlist_ColumnClick(object sender, ColumnClickEventArgs e)
|
|
{
|
|
// ignore when in PLAY mode
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
return;
|
|
WatchlistAllCheckedChanging = true;
|
|
if (!WatchlistAllChecked)
|
|
{
|
|
WatchlistAllChecked = true;
|
|
WatchlistAllCheckedState = CheckBoxState.CheckedPressed;
|
|
foreach (ListViewItem item in lv_Control_Watchlist.Items)
|
|
{
|
|
// check all items within range
|
|
if ((item.Tag == null) || (item.Tag.ToString() != "OOR"))
|
|
item.Checked = true;
|
|
}
|
|
|
|
Invalidate();
|
|
}
|
|
else
|
|
{
|
|
WatchlistAllChecked = false;
|
|
WatchlistAllCheckedState = CheckBoxState.UncheckedNormal;
|
|
Invalidate();
|
|
|
|
foreach (ListViewItem item in lv_Control_Watchlist.Items)
|
|
{
|
|
item.Checked = false;
|
|
}
|
|
}
|
|
WatchlistAllCheckedChanging = false;
|
|
}
|
|
|
|
private void lv_Control_Watchlist_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
|
|
{
|
|
TextFormatFlags flags = TextFormatFlags.LeftAndRightPadding;
|
|
e.DrawBackground();
|
|
CheckBoxRenderer.DrawCheckBox(e.Graphics, new System.Drawing.Point(ClientRectangle.Location.X + 4, ClientRectangle.Location.Y + 1), WatchlistAllCheckedState);
|
|
e.DrawText(flags);
|
|
}
|
|
|
|
private void lv_Control_Watchlist_DrawItem(object sender, DrawListViewItemEventArgs e)
|
|
{
|
|
if (e.Item != null)
|
|
{
|
|
if ((PlayMode == AIRSCOUTPLAYMODE.FORWARD) && !String.IsNullOrEmpty(e.Item.ToolTipText))
|
|
{
|
|
Color bkcolor = e.Item.BackColor;
|
|
try
|
|
{
|
|
double potential = double.Parse(e.Item.ToolTipText);
|
|
// set default color
|
|
bkcolor = Color.White;
|
|
if (potential > 0)
|
|
bkcolor = Color.Orange;
|
|
if (potential > 50)
|
|
bkcolor = Color.Red;
|
|
if (potential > 75)
|
|
bkcolor = Color.Magenta;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
if (bkcolor != e.Item.BackColor)
|
|
{
|
|
e.Item.BackColor = bkcolor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e.Item.BackColor = Color.White;
|
|
}
|
|
}
|
|
e.DrawDefault = true;
|
|
}
|
|
|
|
|
|
private void lv_Control_Watchlist_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
|
|
{
|
|
e.DrawDefault = true;
|
|
}
|
|
|
|
private void lv_Control_Watchlist_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
// synchronize station in SINGLE mode when selection changed in MULTI mode
|
|
try
|
|
{
|
|
if ((lv_Control_Watchlist.SelectedItems != null) && (lv_Control_Watchlist.SelectedItems.Count == 1))
|
|
{
|
|
string call = lv_Control_Watchlist.SelectedItems[0].Text;
|
|
string loc = lv_Control_Watchlist.SelectedItems[0].SubItems[1].Text;
|
|
double lat = MaidenheadLocator.LatFromLoc(loc);
|
|
double lon = MaidenheadLocator.LonFromLoc(loc);
|
|
LocationDesignator ld = StationData.Database.LocationFind(call, loc);
|
|
if (ld != null)
|
|
{
|
|
// update lat/lon from database if found
|
|
lat = ld.Lat;
|
|
lon = ld.Lon;
|
|
}
|
|
Properties.Settings.Default.DXCall = call;
|
|
Properties.Settings.Default.DXLat = lat;
|
|
Properties.Settings.Default.DXLon = lon;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void btn_Control_Manage_Watchlist_Click(object sender, EventArgs e)
|
|
{
|
|
// sync watchlist, try to keep previously checked calls
|
|
// you can have a call only once in the watch list
|
|
List<string> checkedcalls = new List<string>();
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
if (item.Checked)
|
|
checkedcalls.Add(item.Call);
|
|
}
|
|
WatchlistDlg Dlg = new WatchlistDlg();
|
|
if (Dlg.ShowDialog() == DialogResult.OK)
|
|
{
|
|
// clear watch list
|
|
Properties.Settings.Default.Watchlist.Clear();
|
|
foreach (DataGridViewRow row in Dlg.dgv_Watchlist_Selected.Rows)
|
|
{
|
|
string call = row.Cells[0].Value.ToString();
|
|
string loc = row.Cells[1].Value.ToString();
|
|
bool oor = true;
|
|
// try to get the location from database
|
|
LocationDesignator dxloc = StationData.Database.LocationFind(call, loc);
|
|
if (dxloc != null)
|
|
{
|
|
oor = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, dxloc.Lat, dxloc.Lon) > Properties.Settings.Default.Path_MaxLength;
|
|
}
|
|
// add call to watch list
|
|
WatchlistItem item = new WatchlistItem(call, loc, oor);
|
|
Properties.Settings.Default.Watchlist.Add(item);
|
|
}
|
|
// reselect previously selected
|
|
foreach (string checkedcall in checkedcalls)
|
|
{
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(checkedcall);
|
|
if (index >= 0)
|
|
Properties.Settings.Default.Watchlist[index].Checked = true;
|
|
}
|
|
// refresh watchlist view
|
|
RefreshWatchlistView();
|
|
}
|
|
}
|
|
|
|
private void ShowToolTip(ToolTip tt, string text, Control control, System.Drawing.Point p, int ms = 5000)
|
|
{
|
|
if (String.IsNullOrEmpty(text))
|
|
return;
|
|
// int BorderWidth = this.Width – this.ClientSize.Width)/2;
|
|
// int TitlebarHeight = this.Height – this.ClientSize.Height – 2 * BorderWidth;
|
|
int BorderWith = (this.Width - this.ClientSize.Width) / 2;
|
|
int TitleBarHeight = this.Height - this.ClientSize.Height - 2 * BorderWith;
|
|
p = control.PointToScreen(p);
|
|
p = this.PointToClient(p);
|
|
p.X = p.X + BorderWith;
|
|
p.Y = p.Y + TitleBarHeight + Cursor.Size.Height;
|
|
tt.Show(text, this, p, ms);
|
|
}
|
|
|
|
private void lv_Control_Watchlist_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs e)
|
|
{
|
|
}
|
|
|
|
private void lv_Control_Watchlist_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
System.Drawing.Point p = new System.Drawing.Point(e.X, e.Y);
|
|
ListViewHitTestInfo info = lv_Control_Watchlist.HitTest(p);
|
|
if ((WatchlistOldMousePos != p) && (info != null) && (info.SubItem != null))
|
|
{
|
|
WatchlistOldMousePos = p;
|
|
// check whether the column name is one of the following
|
|
if (info.SubItem.Name == "Call")
|
|
{
|
|
string dxcall = info.Item.SubItems[0].Text;
|
|
string dxloc = info.Item.SubItems[1].Text;
|
|
LocationDesignator ld = StationData.Database.LocationFind(dxcall, dxloc);
|
|
// location found --> show Tooltip with details
|
|
if (ld != null)
|
|
{
|
|
string qrb = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, ld.Lat, ld.Lon).ToString("F0", CultureInfo.InvariantCulture);
|
|
string qtf = LatLon.Bearing(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, ld.Lat, ld.Lon).ToString("F0", CultureInfo.InvariantCulture);
|
|
ShowToolTip(tt_Control_Watchlist, dxcall + "\n" + dxloc + "\n" + qrb + " km\n" + qtf + "°", lv_Control_Watchlist, p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tab Options
|
|
|
|
private void tp_Control_Options_Enter(object sender, EventArgs e)
|
|
{
|
|
// set plane filter
|
|
try
|
|
{
|
|
cb_Planes_Filter_Min_Cat.SelectedItem = PlaneCategories.GetStringValue(Properties.Settings.Default.Planes_Filter_Min_Category);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void gb_Map_Zoom_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
// get font size in pixels
|
|
double pixels;
|
|
using (Graphics g = this.CreateGraphics())
|
|
{
|
|
pixels = gb_Map_Zoom.Font.SizeInPoints * g.DpiX / 72;
|
|
}
|
|
if ((e.Y <= pixels) && (e.Button == MouseButtons.Left))
|
|
{
|
|
Properties.Settings.Default.Map_ShowZoomBox = !Properties.Settings.Default.Map_ShowZoomBox;
|
|
}
|
|
}
|
|
|
|
private void gb_Map_Filter_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
// get font size in pixels
|
|
double pixels;
|
|
using (Graphics g = this.CreateGraphics())
|
|
{
|
|
pixels = gb_Map_Filter.Font.SizeInPoints * g.DpiX / 72;
|
|
}
|
|
if ((e.Y <= pixels) && (e.Button == MouseButtons.Left))
|
|
{
|
|
Properties.Settings.Default.Map_ShowFilterBox = !Properties.Settings.Default.Map_ShowFilterBox;
|
|
}
|
|
}
|
|
|
|
private void gb_Map_Alarms_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
// get font size in pixels
|
|
double pixels;
|
|
using (Graphics g = this.CreateGraphics())
|
|
{
|
|
pixels = gb_Map_Alarms.Font.SizeInPoints * g.DpiX / 72;
|
|
}
|
|
if ((e.Y <= pixels) && (e.Button == MouseButtons.Left))
|
|
{
|
|
Properties.Settings.Default.Map_ShowAlarmBox = !Properties.Settings.Default.Map_ShowAlarmBox;
|
|
}
|
|
}
|
|
|
|
private void btn_Zoom_In_Click(object sender, EventArgs e)
|
|
{
|
|
if (gm_Main.Zoom < 20)
|
|
gm_Main.Zoom++;
|
|
}
|
|
|
|
private void btn_Zoom_Out_Click(object sender, EventArgs e)
|
|
{
|
|
if (gm_Main.Zoom > 0)
|
|
gm_Main.Zoom--;
|
|
}
|
|
|
|
private void cb_Planes_Filter_Min_Category_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
Properties.Settings.Default.Planes_Filter_Min_Category = PlaneCategories.ParseStringValue((string)cb_Planes_Filter_Min_Cat.SelectedItem);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Buttons
|
|
|
|
private void btn_Options_Click(object sender, EventArgs e)
|
|
{
|
|
ShowOptionsDlg();
|
|
}
|
|
|
|
private void btn_Map_Save_Click(object sender, EventArgs e)
|
|
{
|
|
MapSave();
|
|
}
|
|
|
|
private void btn_Map_PlayPause_Click(object sender, EventArgs e)
|
|
{
|
|
if (PlayMode != AIRSCOUTPLAYMODE.FORWARD)
|
|
{
|
|
Play();
|
|
}
|
|
else
|
|
{
|
|
Pause();
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Main Tab Control
|
|
|
|
private void tc_Main_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void tc_Main_DrawItem(object sender, DrawItemEventArgs e)
|
|
{
|
|
// This event is called once for each tab button in your tab control
|
|
// First paint the background with a color based on the current tab
|
|
// e.Index is the index of the tab in the TabPages collection.
|
|
// fill background
|
|
e.Graphics.FillRectangle(new SolidBrush(SystemColors.Control), e.Bounds);
|
|
// Then draw the current tab button text
|
|
Rectangle paddedBounds = e.Bounds;
|
|
paddedBounds.Inflate(-2, -2);
|
|
e.Graphics.DrawString(tc_Main.TabPages[e.Index].Text, tc_Main.Font, (tc_Main.Enabled) ? SystemBrushes.ControlText : SystemBrushes.GrayText, paddedBounds);
|
|
|
|
}
|
|
|
|
#region Tab Page Spectrum
|
|
|
|
private void tp_Spectrum_Enter(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void tp_Spectrum_Resize(object sender, EventArgs e)
|
|
{
|
|
// adjust group boxes
|
|
// get quadratical nearest plane box
|
|
gb_NearestPlaneMap.Width = gb_NearestPlaneMap.Height;
|
|
gb_NearestPlaneMap.Left = tp_Spectrum.Width - gb_NearestPlaneMap.Width - 5;
|
|
// adjust plane info box
|
|
gb_Spectrum_NearestInfo.Left = tp_Spectrum.Width - gb_NearestPlaneMap.Width - gb_Spectrum_NearestInfo.Width - 10;
|
|
// adjust spectrum box
|
|
gb_Spectrum.Width = tp_Spectrum.Width - gb_NearestPlaneMap.Width - gb_Spectrum_NearestInfo.Width - 30;
|
|
tb_Spectrum_Status.Left = 5;
|
|
tb_Spectrum_Status.Width = pv_Spectrum.Width - 10;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tab Page Elevation
|
|
|
|
private void tp_Elevation_Enter(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void tp_Elevation_Resize(object sender, EventArgs e)
|
|
{
|
|
// adjust charts
|
|
pv_Path.Location = new System.Drawing.Point(0, 0);
|
|
pv_Path.Width = tp_Elevation.Width;
|
|
pv_Path.Height = tp_Elevation.Height / 2;
|
|
pv_Elevation.Location = new System.Drawing.Point(0, tp_Elevation.Height / 2);
|
|
pv_Elevation.Width = tp_Elevation.Width;
|
|
pv_Elevation.Height = tp_Elevation.Height / 2;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Tab Page Analysis
|
|
|
|
private void UpdatePlayer()
|
|
{
|
|
// set players bounds
|
|
sb_Analysis_Play.Minimum = 0;
|
|
sb_Analysis_Play.Maximum = (int)(dtp_Analysis_MaxValue.Value - dtp_Analysis_MinValue.Value).TotalSeconds;
|
|
sb_Analysis_Play.Value = 0;
|
|
}
|
|
|
|
private void tp_Analysis_Enter(object sender, EventArgs e)
|
|
{
|
|
if (LifeMode == AIRSCOUTLIFEMODE.LIFE)
|
|
{
|
|
btn_Analysis_ON.Enabled = true;
|
|
btn_Analysis_ON.BackColor = Color.YellowGreen;
|
|
btn_Analysis_OFF.Enabled = false;
|
|
btn_Analysis_OFF.BackColor = Color.Gray;
|
|
}
|
|
else
|
|
{
|
|
btn_Analysis_ON.Enabled = false;
|
|
btn_Analysis_ON.BackColor = Color.Gray;
|
|
btn_Analysis_OFF.Enabled = true;
|
|
btn_Analysis_OFF.BackColor = Color.LightCoral;
|
|
}
|
|
SayAnalysis("Press <ON> to start analysis.");
|
|
}
|
|
|
|
private void tp_Analysis_Leave(object sender, EventArgs e)
|
|
{
|
|
}
|
|
|
|
private void btn_Analysis_ON_Click(object sender, EventArgs e)
|
|
{
|
|
SayAnalysis("Getting database properties, please wait...");
|
|
// go into offline mode
|
|
btn_Analysis_ON.Enabled = false;
|
|
btn_Analysis_ON.BackColor = Color.Gray;
|
|
btn_Analysis_OFF.Enabled = true;
|
|
btn_Analysis_OFF.BackColor = Color.LightCoral;
|
|
btn_Map_PlayPause.Enabled = false;
|
|
LifeMode = AIRSCOUTLIFEMODE.HISTORY;
|
|
PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
if (!bw_Analysis_DataGetter.IsBusy)
|
|
bw_Analysis_DataGetter.RunWorkerAsync();
|
|
}
|
|
|
|
private void btn_Analysis_OFF_Click(object sender, EventArgs e)
|
|
{
|
|
if (bw_Analysis_FileSaver.IsBusy)
|
|
bw_Analysis_FileSaver.CancelAsync();
|
|
if (bw_Analysis_FileLoader.IsBusy)
|
|
bw_Analysis_FileLoader.CancelAsync();
|
|
if (bw_Analysis_DataGetter.IsBusy)
|
|
{
|
|
SayAnalysis("Cancelling background thread, please wait...");
|
|
bw_Analysis_DataGetter.CancelAsync();
|
|
}
|
|
else
|
|
{
|
|
btn_Analysis_ON.Enabled = true;
|
|
btn_Analysis_ON.BackColor = Color.YellowGreen;
|
|
}
|
|
lock (AllPositions)
|
|
{
|
|
AllPositions.Clear();
|
|
}
|
|
GC.Collect();
|
|
// go into online mode
|
|
btn_Analysis_OFF.Enabled = false;
|
|
btn_Analysis_OFF.BackColor = Color.Gray;
|
|
btn_Analysis_Planes_Load.Enabled = false;
|
|
btn_Analysis_Planes_Save.Enabled = false;
|
|
btn_Analysis_Planes_Clear.Enabled = false;
|
|
btn_Analysis_Planes_History.Enabled = false;
|
|
btn_Analysis_Planes_ShowTraffic.Enabled = false;
|
|
btn_Analysis_Path_SaveToFile.Enabled = false;
|
|
btn_Analysis_CrossingHistory.Enabled = false;
|
|
btn_Analysis_Plane_History.Enabled = false;
|
|
btn_Analysis_Rewind.Enabled = false;
|
|
btn_Analysis_Back.Enabled = false;
|
|
btn_Analysis_Pause.Enabled = false;
|
|
btn_Analysis_Forward.Enabled = false;
|
|
btn_Analysis_FastForward.Enabled = false;
|
|
sb_Analysis_Play.Enabled = false;
|
|
dtp_Analysis_MinValue.Enabled = false;
|
|
dtp_Analysis_MaxValue.Enabled = false;
|
|
btn_Map_PlayPause.Enabled = true;
|
|
LifeMode = AIRSCOUTLIFEMODE.LIFE;
|
|
PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
UpdateStatus();
|
|
btn_Map_PlayPause.Focus();
|
|
}
|
|
|
|
private void btn_Analysis_Planes_Save_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
SaveFileDialog Dlg = new SaveFileDialog();
|
|
Dlg.AddExtension = true;
|
|
Dlg.Filter = "Java Script Object Notation File|*.json|Comma Separated Values|*.csv";
|
|
Dlg.DefaultExt = "json";
|
|
Dlg.FileName = "Plane Positions " + dtp_Analysis_MinValue.Value.ToString("yyyy_MM_dd_HH_mm_ss") + " to " + dtp_Analysis_MaxValue.Value.ToString("yyyy_MM_dd_HH_mm_ss");
|
|
Dlg.InitialDirectory = TmpDirectory;
|
|
Dlg.OverwritePrompt = true;
|
|
if (Dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
if (!bw_Analysis_FileSaver.IsBusy)
|
|
{
|
|
btn_Analysis_Planes_Save.Enabled = false;
|
|
bw_Analysis_FileSaver.RunWorkerAsync(Dlg.FileName);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Say(ex.Message);
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void btn_Analysis_Planes_Load_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
OpenFileDialog Dlg = new OpenFileDialog();
|
|
Dlg.Filter = "Java Script Object Notation File|*.json|Comma Separated Values|*.csv";
|
|
Dlg.DefaultExt = "json";
|
|
Dlg.CheckFileExists = true;
|
|
Dlg.CheckPathExists = true;
|
|
Dlg.Multiselect = false;
|
|
Dlg.InitialDirectory = TmpDirectory;
|
|
if (Dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
if (!bw_Analysis_FileLoader.IsBusy)
|
|
{
|
|
btn_Analysis_Planes_Load.Enabled = false;
|
|
bw_Analysis_FileLoader.RunWorkerAsync(Dlg.FileName);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Say(ex.Message);
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void btn_Analysis_Planes_Clear_Click(object sender, EventArgs e)
|
|
{
|
|
AircraftPositionData.Database.AircraftPositionDeleteAll();
|
|
}
|
|
|
|
private void btn_Analysis_Planes_History_Click(object sender, EventArgs e)
|
|
{
|
|
HistoryFromURLDlg Dlg = new HistoryFromURLDlg();
|
|
if (Dlg.ShowDialog() == DialogResult.OK)
|
|
{
|
|
btn_Analysis_Planes_History.Enabled = false;
|
|
bw_HistoryDownloader.RunWorkerAsync(Properties.Settings.Default.Analysis_History_Date);
|
|
}
|
|
}
|
|
|
|
private void btn_Analysis_Planes_ShowTraffic_Click(object sender, EventArgs e)
|
|
{
|
|
TrafficDlg Dlg = new TrafficDlg();
|
|
Dlg.ShowDialog();
|
|
}
|
|
|
|
private void btn_Analysis_Path_SaveToFile_Click(object sender, EventArgs e)
|
|
{
|
|
SaveFileDialog Dlg = new SaveFileDialog();
|
|
Dlg.CheckPathExists = true;
|
|
Dlg.AddExtension = true;
|
|
Dlg.DefaultExt = "csv";
|
|
Dlg.Filter = "Comma Separated Values *.csv |csv";
|
|
Dlg.FileName = "Path Information " + Properties.Settings.Default.MyCall.Replace("/", "_") + " to " + Properties.Settings.Default.DXCall.Replace("/", "_");
|
|
Dlg.InitialDirectory = TmpDirectory;
|
|
Dlg.OverwritePrompt = true;
|
|
if (Dlg.ShowDialog() == DialogResult.OK)
|
|
{
|
|
try
|
|
{
|
|
// calculate propagation path
|
|
|
|
// check and update station database
|
|
LocationDesignator myloc = LocationFindOrUpdateOrCreate(Properties.Settings.Default.MyCall, Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
Properties.Settings.Default.MyElevation = myloc.Elevation;
|
|
|
|
// get qrv info or create default
|
|
QRVDesignator myqrv = StationData.Database.QRVFindOrCreateDefault(myloc.Call, myloc.Loc, Properties.Settings.Default.Band);
|
|
// set qrv defaults if zero
|
|
if (myqrv.AntennaHeight == 0)
|
|
myqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (myqrv.AntennaGain == 0)
|
|
myqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (myqrv.Power == 0)
|
|
myqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
// check if there are a valid DX settings
|
|
if (!Callsign.Check(Properties.Settings.Default.DXCall) ||
|
|
!GeographicalPoint.Check(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon))
|
|
return;
|
|
|
|
// OK valid, lets continue
|
|
// check and update station database
|
|
LocationDesignator dxloc = LocationFindOrUpdateOrCreate(Properties.Settings.Default.DXCall, Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon);
|
|
Properties.Settings.Default.DXElevation = dxloc.Elevation;
|
|
// get qrv info or create default
|
|
QRVDesignator dxqrv = StationData.Database.QRVFindOrCreateDefault(dxloc.Call, dxloc.Loc, Properties.Settings.Default.Band);
|
|
// set qrv defaults if zero
|
|
if (dxqrv.AntennaHeight == 0)
|
|
dxqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (dxqrv.AntennaGain == 0)
|
|
dxqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (dxqrv.Power == 0)
|
|
dxqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
|
|
// find local obstruction, if any
|
|
LocalObstructionDesignator o = ElevationData.Database.LocalObstructionFind(myloc.Lat, myloc.Lon, Properties.Settings.Default.ElevationModel);
|
|
double mybearing = LatLon.Bearing(myloc.Lat, myloc.Lon, dxloc.Lat, dxloc.Lon);
|
|
double myobstr = (o != null) ? o.GetObstruction(myqrv.AntennaHeight, mybearing) : double.MinValue;
|
|
|
|
// try to find elevation path in database or create new one and store
|
|
ElevationPathDesignator epath = ElevationData.Database.ElevationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel);
|
|
// add additional info to ppath
|
|
epath.Location1 = myloc;
|
|
epath.Location2 = dxloc;
|
|
epath.QRV1 = myqrv;
|
|
epath.QRV2 = dxqrv;
|
|
|
|
// try to find propagation path in database or create new one and store
|
|
PropagationPathDesignator ppath = PropagationData.Database.PropagationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
GetElevation(myloc.Lat, myloc.Lon) + myqrv.AntennaHeight,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
GetElevation(dxloc.Lat, dxloc.Lon) + dxqrv.AntennaHeight,
|
|
Bands.ToGHz(Properties.Settings.Default.Band),
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor,
|
|
Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].F1_Clearance,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel,
|
|
myobstr);
|
|
|
|
// add additional info to ppath
|
|
ppath.Location1 = myloc;
|
|
ppath.Location2 = dxloc;
|
|
ppath.QRV1 = myqrv;
|
|
ppath.QRV2 = dxqrv;
|
|
using (StreamWriter sw = new StreamWriter(Dlg.FileName))
|
|
{
|
|
sw.WriteLine("Distance[km];Lat[deg];Lon[deg];Elevation[m]; Min_h1[m]; Min_h2[m]; Min_h[m]; Max_h[m]; F1[m];eps1[deg];eps2[deg];eps1_min[deg];eps2_min[deg];ElevationModel");
|
|
for (int i = 0; i < epath.Count; i++)
|
|
{
|
|
double dist = (double)i * epath.StepWidth / 1000.0;
|
|
PropagationPoint p = ppath.GetInfoPoint(dist);
|
|
sw.WriteLine(dist.ToString() + ";" +
|
|
p.Lat.ToString() + ";" +
|
|
p.Lon.ToString() + ";" +
|
|
epath.Path[i].ToString() + ";" +
|
|
p.H1.ToString() + ";" +
|
|
p.H2.ToString() + ";" +
|
|
Math.Max(p.H1, p.H2).ToString() + ";" +
|
|
Properties.Settings.Default.Planes_MaxAlt.ToString() + ";" +
|
|
p.F1.ToString() + ";" +
|
|
(Propagation.EpsilonFromHeights(ppath.h1, dist, epath.Path[i],ppath.Radius) / Math.PI * 180.0).ToString() + ";" +
|
|
(Propagation.EpsilonFromHeights(ppath.h2, ppath.Distance-dist, epath.Path[i], ppath.Radius) / Math.PI * 180.0).ToString() + ";" +
|
|
(ppath.Eps1_Min / Math.PI * 180.0).ToString() + ";" +
|
|
(ppath.Eps2_Min / Math.PI * 180.0).ToString());
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage("Error while saving path to file [" + Dlg.FileName + "]:" + ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void btn_Analysis_CrossingHistory_Click(object sender, EventArgs e)
|
|
{
|
|
if (dtp_Analysis_MaxValue.Value <= dtp_Analysis_MinValue.Value)
|
|
return;
|
|
if (Time_Offline_Interval <= 0)
|
|
Time_Offline_Interval = 1;
|
|
if ((AllPositions == null) || (AllPositions.Count == 0))
|
|
return;
|
|
CrossingHistoryDlg Dlg = new CrossingHistoryDlg(dtp_Analysis_MinValue.Value, dtp_Analysis_MaxValue.Value, Time_Offline_Interval, ref AllPositions);
|
|
Dlg.ShowDialog();
|
|
}
|
|
|
|
private void sb_Analysis_Play_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
// handle change of scrollbar
|
|
// set scrollbar markers
|
|
// reduce them to one marker per pixel
|
|
// get initial scrollbar width and build array
|
|
int[] sb = new int[sb_Analysis_Play.Width];
|
|
double stepwidth = (double)sb.Length / (sb_Analysis_Play.Maximum - sb_Analysis_Play.Minimum);
|
|
foreach (DateTime dt in AllLastUpdated)
|
|
{
|
|
int index = (int)((dt - dtp_Analysis_MinValue.Value).TotalSeconds * stepwidth);
|
|
int i = (int)(dt - dtp_Analysis_MinValue.Value).TotalSeconds;
|
|
if ((i > sb_Analysis_Play.Minimum) && (i < sb_Analysis_Play.Maximum))
|
|
sb[index] = i;
|
|
}
|
|
sb_Analysis_Play.BackgroundMarkers = sb.ToList<int>();
|
|
}
|
|
|
|
private void gb_Analysis_Player_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
// handle change of size --> arrange elements
|
|
sb_Analysis_Play.Left = dtp_Analysis_MinValue.Right + 10;
|
|
sb_Analysis_Play.Width = dtp_Analysis_MaxValue.Left - dtp_Analysis_MinValue.Width - 20;
|
|
sb_Analysis_Play.Height = dtp_Analysis_MinValue.Height;
|
|
}
|
|
|
|
private void btn_Analysis_Rewind_Click(object sender, EventArgs e)
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.FASTBACK;
|
|
Time_Offline_Interval -= 10;
|
|
if (Time_Offline_Interval < 1)
|
|
Time_Offline_Interval = 1;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
}
|
|
|
|
private void btn_Analysis_Back_Click(object sender, EventArgs e)
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.BACK;
|
|
Time_Offline_Interval -= 1;
|
|
if (Time_Offline_Interval < 1)
|
|
Time_Offline_Interval = 1;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
}
|
|
|
|
private void btn_Analysis_Pause_Click(object sender, EventArgs e)
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
Time_Offline_Interval = 0;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
}
|
|
|
|
private void btn_Analysis_Forward_Click(object sender, EventArgs e)
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.FORWARD;
|
|
Time_Offline_Interval += 1;
|
|
if (Time_Offline_Interval > 3600)
|
|
Time_Offline_Interval = 3600;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
}
|
|
|
|
private void btn_Analysis_FastForward_Click(object sender, EventArgs e)
|
|
{
|
|
PlayMode = AIRSCOUTPLAYMODE.FASTFORWARD;
|
|
Time_Offline_Interval += 10;
|
|
if (Time_Offline_Interval > 3600)
|
|
Time_Offline_Interval = 3600;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
}
|
|
|
|
private void sb_Analysis_Play_Scroll(object sender, ScrollEventArgs e)
|
|
{
|
|
// PlayMode = AIRSCOUTPLAYMODE.PAUSE;
|
|
// Time_Offline_Interval = 0;
|
|
tb_Analysis_Stepwidth.Text = Time_Offline_Interval.ToString();
|
|
Properties.Settings.Default.Time_Offline = dtp_Analysis_MinValue.Value.AddSeconds(sb_Analysis_Play.Value);
|
|
if (Properties.Settings.Default.Time_Offline < dtp_Analysis_MinValue.Value)
|
|
Properties.Settings.Default.Time_Offline = dtp_Analysis_MinValue.Value;
|
|
if (Properties.Settings.Default.Time_Offline > dtp_Analysis_MaxValue.Value)
|
|
Properties.Settings.Default.Time_Offline = dtp_Analysis_MaxValue.Value;
|
|
CurrentTime = Properties.Settings.Default.Time_Offline;
|
|
tb_Analysis_Time.Text = CurrentTime.ToString("yyyy-MM-hh HH:mm:ss");
|
|
UpdatePlanes();
|
|
|
|
}
|
|
|
|
private void dtp_Analysis_MinValue_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
// check bounds
|
|
if (dtp_Analysis_MinValue.Value < History_OldestEntry)
|
|
dtp_Analysis_MinValue.Value = History_OldestEntry;
|
|
if (dtp_Analysis_MinValue.Value > History_YoungestEntry)
|
|
dtp_Analysis_MinValue.Value = History_YoungestEntry;
|
|
UpdatePlayer();
|
|
}
|
|
|
|
private void dtp_Analysis_MaxValue_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
// check bounds
|
|
if (dtp_Analysis_MinValue.Value < History_OldestEntry)
|
|
dtp_Analysis_MinValue.Value = History_OldestEntry;
|
|
if (dtp_Analysis_MinValue.Value > History_YoungestEntry)
|
|
dtp_Analysis_MinValue.Value = History_YoungestEntry;
|
|
UpdatePlayer();
|
|
}
|
|
|
|
private void btn_Analysis_Plane_History_Click(object sender, EventArgs e)
|
|
{
|
|
PlaneHistoryDlg Dlg = new PlaneHistoryDlg(dtp_Analysis_MinValue.Value, dtp_Analysis_MaxValue.Value, TmpDirectory);
|
|
Dlg.ShowDialog();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Map Tab Control
|
|
|
|
private void tp_Map_Enter(object sender, EventArgs e)
|
|
{
|
|
if (PathMode == AIRSCOUTPATHMODE.SINGLE)
|
|
sc_Map.Panel2Collapsed = false;
|
|
else if (PathMode == AIRSCOUTPATHMODE.MULTI)
|
|
sc_Map.Panel2Collapsed = true;
|
|
}
|
|
|
|
private void tp_News_Enter(object sender, EventArgs e)
|
|
{
|
|
sc_Map.Panel2Collapsed = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Background Workers
|
|
|
|
#region PlaneFeed
|
|
|
|
private void bw_PlaneFeed_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage == (int)PROGRESS.ERROR)
|
|
{
|
|
if (e.UserState == null)
|
|
return;
|
|
Say((string)e.UserState);
|
|
}
|
|
else if (e.ProgressPercentage == (int)PROGRESS.STATUS)
|
|
{
|
|
if (e.UserState == null)
|
|
return;
|
|
Say((string)e.UserState);
|
|
}
|
|
else if (e.ProgressPercentage == (int)PROGRESS.PLANES)
|
|
{
|
|
List<PlaneInfo> planes = (List<PlaneInfo>)e.UserState;
|
|
Planes.BulkInsertOrUpdateIfNewer(planes);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WinTestReceive
|
|
|
|
// suppress console output when in debug mode, needs "Just my code" set in Tools\Options\Debugging
|
|
[System.Diagnostics.DebuggerNonUserCode]
|
|
private void bw_WinTestReceive_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
// Background thread for receiving Win-Test messages
|
|
// listens to the UDP broadcasts
|
|
// use the ReportProgress method to
|
|
// return status code and received message
|
|
// status values are: <0 = error orrcured (not supported yet)
|
|
// 0 = function calls OK, but no bytes received
|
|
// >0 = function calls OK, number of bytes received
|
|
Log.WriteMessage("Started.");
|
|
if (Thread.CurrentThread.Name == null)
|
|
Thread.CurrentThread.Name = "bw_WinTestReceive";
|
|
// Get own IP addresses
|
|
string hostname;
|
|
IPAddress[] hostaddresses = new IPAddress[256];
|
|
try
|
|
{
|
|
hostname = Dns.GetHostName();
|
|
hostaddresses = Dns.GetHostAddresses(hostname);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
// initialize UDP socket
|
|
IPEndPoint ep = new IPEndPoint(IPAddress.Any, Properties.Settings.Default.Server_Port);
|
|
UdpClient u = new UdpClient();
|
|
u.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
|
|
u.Client.ReceiveTimeout = 1000;
|
|
try
|
|
{
|
|
u.Client.Bind(ep);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
|
|
// receive Win-Test messages in a loop
|
|
while (!bw_WinTestReceive.CancellationPending)
|
|
{
|
|
try
|
|
{
|
|
// receive bytes in blocking mode
|
|
// handle the receive timeout and cancellation
|
|
try
|
|
{
|
|
byte[] data = u.Receive(ref ep);
|
|
wtMessage Msg = new wtMessage(data);
|
|
// check if message is directed to server
|
|
if (Msg.Dst == Properties.Settings.Default.Server_Name)
|
|
DispatchWinTestMsg(Msg);
|
|
}
|
|
catch (SocketException ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void ASShowPath(wtMessage msg)
|
|
{
|
|
// a show path message received
|
|
try
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
if (PlayMode != AIRSCOUTPLAYMODE.PAUSE)
|
|
Pause();
|
|
// set single mode
|
|
tc_Control.SelectedTab = tp_Control_Single;
|
|
PathMode = AIRSCOUTPATHMODE.SINGLE;
|
|
string[] a = msg.Data.Split(',');
|
|
string qrgstr = a[0].Replace("\"", "");
|
|
string mycallstr = a[1].Replace("\"", "");
|
|
string myloc = a[2].Replace("\"", "").Substring(0, 6);
|
|
double mylat = MaidenheadLocator.LatFromLoc(myloc);
|
|
double mylon = MaidenheadLocator.LonFromLoc(myloc);
|
|
string dxcallstr = a[3].Replace("\"", "");
|
|
string dxloc = a[4].Replace("\"", "").Substring(0, 6);
|
|
double dxlat = MaidenheadLocator.LatFromLoc(dxloc);
|
|
double dxlon = MaidenheadLocator.LonFromLoc(dxloc);
|
|
if (Callsign.Check(mycallstr) &&
|
|
Callsign.Check(dxcallstr) &&
|
|
MaidenheadLocator.Check(myloc) &&
|
|
MaidenheadLocator.Check(dxloc))
|
|
{
|
|
Properties.Settings.Default.MyCall = mycallstr;
|
|
Properties.Settings.Default.MyLat = mylat;
|
|
Properties.Settings.Default.MyLon = mylon;
|
|
Properties.Settings.Default.MyHeight = 10;
|
|
Properties.Settings.Default.DXCall = dxcallstr;
|
|
Properties.Settings.Default.DXLat = dxlat;
|
|
Properties.Settings.Default.DXLon = dxlon;
|
|
Properties.Settings.Default.DXHeight = 10;
|
|
Properties.Settings.Default.MyElevation = GetElevation(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
LocationDesignator info = StationData.Database.LocationFind(mycallstr);
|
|
if ((info != null) && (MaidenheadLocator.LocFromLatLon(info.Lat, info.Lon, false, 3) == myloc))
|
|
{
|
|
// loc is matching with database --> use detailed info then
|
|
Properties.Settings.Default.MyLat = info.Lat;
|
|
Properties.Settings.Default.MyLon = info.Lon;
|
|
Properties.Settings.Default.MyElevation = GetElevation(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon);
|
|
}
|
|
else
|
|
{
|
|
// update database if not found or locator does not match
|
|
UpdateLocation(mycallstr, mylat, mylon, GEOSOURCE.FROMLOC);
|
|
}
|
|
info = StationData.Database.LocationFind(dxcallstr);
|
|
if ((info != null) && (MaidenheadLocator.LocFromLatLon(info.Lat, info.Lon, false, 3) == dxloc))
|
|
{
|
|
// loc is matching with database --> use detailed info then
|
|
Properties.Settings.Default.DXLat = info.Lat;
|
|
Properties.Settings.Default.DXLon = info.Lon;
|
|
Properties.Settings.Default.DXElevation = GetElevation(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon);
|
|
}
|
|
else
|
|
{
|
|
// update database if not found or locator does not match
|
|
UpdateLocation(dxcallstr, dxlat, dxlon, GEOSOURCE.FROMLOC);
|
|
}
|
|
if (qrgstr == "500000")
|
|
Properties.Settings.Default.Band = BAND.B50M;
|
|
if (qrgstr == "700000")
|
|
Properties.Settings.Default.Band = BAND.B70M;
|
|
if (qrgstr == "1440000")
|
|
Properties.Settings.Default.Band = BAND.B144M;
|
|
if (qrgstr == "4320000")
|
|
Properties.Settings.Default.Band = BAND.B432M;
|
|
if (qrgstr == "12960000")
|
|
Properties.Settings.Default.Band = BAND.B1_2G;
|
|
if (qrgstr == "23200000")
|
|
Properties.Settings.Default.Band = BAND.B2_3G;
|
|
if (qrgstr == "34000000")
|
|
Properties.Settings.Default.Band = BAND.B3_4G;
|
|
if (qrgstr == "57600000")
|
|
Properties.Settings.Default.Band = BAND.B5_7G;
|
|
if (qrgstr == "103680000")
|
|
Properties.Settings.Default.Band = BAND.B10G;
|
|
if (qrgstr == "240480000")
|
|
Properties.Settings.Default.Band = BAND.B24G;
|
|
if (qrgstr == "470880000")
|
|
Properties.Settings.Default.Band = BAND.B47G;
|
|
if (qrgstr == "760320000")
|
|
Properties.Settings.Default.Band = BAND.B76G;
|
|
UpdateStatus();
|
|
Play();
|
|
// try different methods to bring the window to front under WinXP and Win7
|
|
bool max = this.WindowState == FormWindowState.Maximized;
|
|
// try to restore window from minimized and normal state --> normal state
|
|
this.TopMost = true;
|
|
SetForegroundWindow(this.Handle);
|
|
ShowWindow(this.Handle, ShowWindowCommands.ShowNoActivate);
|
|
this.BringToFront();
|
|
this.TopMost = false;
|
|
// maximize it if it was maximized before
|
|
if (max)
|
|
this.WindowState = FormWindowState.Maximized;
|
|
// set antenna direction
|
|
double az = LatLon.Bearing(Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon);
|
|
// set tracking values
|
|
Properties.Settings.Default.Track_SetAz = az;
|
|
Properties.Settings.Default.Track_SetEl = 0;
|
|
}
|
|
st.Stop();
|
|
Log.WriteMessage("Processing ASSHOWPATH[" + mycallstr + "," + dxcallstr + "]: " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
|
|
}
|
|
|
|
private void ASSetPath(wtMessage msg)
|
|
{
|
|
try
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
string[] a = msg.Data.Split(',');
|
|
int qrg = 1296;
|
|
int.TryParse(a[0].Replace("\"", ""), out qrg);
|
|
qrg = qrg / 10000;
|
|
BAND band = BAND.BNONE;
|
|
try
|
|
{
|
|
band = (BAND)qrg;
|
|
}
|
|
catch
|
|
{
|
|
// do nothing
|
|
}
|
|
string mycallstr = a[1].Replace("\"", "");
|
|
string mylocstr = a[2].Replace("\"", "").Substring(0, 6);
|
|
string dxcallstr = a[3].Replace("\"", "");
|
|
string dxlocstr = a[4].Replace("\"", "").Substring(0, 6);
|
|
int count = 0;
|
|
// return on failure
|
|
if (!Callsign.Check(mycallstr))
|
|
return;
|
|
if (!Callsign.Check(dxcallstr))
|
|
return;
|
|
if (!MaidenheadLocator.Check(mylocstr))
|
|
return;
|
|
if (!MaidenheadLocator.Check(dxlocstr))
|
|
return;
|
|
// get my location info --> if loc is matching, use precise information automatically
|
|
LocationDesignator myloc = StationData.Database.LocationFindOrCreate(mycallstr, mylocstr);
|
|
// get my QRV info
|
|
QRVDesignator myqrv = StationData.Database.QRVFindOrCreateDefault(mycallstr, mylocstr, band);
|
|
// set qrv defaults if zero
|
|
if (myqrv.AntennaHeight == 0)
|
|
myqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (myqrv.AntennaGain == 0)
|
|
myqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (myqrv.Power == 0)
|
|
myqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
// get dx location info --> if loc is matching, use precise information automatically
|
|
LocationDesignator dxloc = LocationFindOrCreate(dxcallstr, dxlocstr);
|
|
// get dx QRV info
|
|
QRVDesignator dxqrv = StationData.Database.QRVFindOrCreateDefault(dxcallstr, dxlocstr, band);
|
|
// set qrv defaults if zero
|
|
if (dxqrv.AntennaHeight == 0)
|
|
dxqrv.AntennaHeight = StationData.Database.QRVGetDefaultAntennaHeight(Properties.Settings.Default.Band);
|
|
if (dxqrv.AntennaGain == 0)
|
|
dxqrv.AntennaGain = StationData.Database.QRVGetDefaultAntennaGain(Properties.Settings.Default.Band);
|
|
if (dxqrv.Power == 0)
|
|
dxqrv.Power = StationData.Database.QRVGetDefaultPower(Properties.Settings.Default.Band);
|
|
// find local obstruction, if any
|
|
LocalObstructionDesignator o = ElevationData.Database.LocalObstructionFind(myloc.Lat, myloc.Lon, Properties.Settings.Default.ElevationModel);
|
|
double mybearing = LatLon.Bearing(myloc.Lat, myloc.Lon, dxloc.Lat, dxloc.Lon);
|
|
double myobstr = (o != null) ? o.GetObstruction(myqrv.AntennaHeight, mybearing) : double.MinValue;
|
|
|
|
// try to find propagation path in database or create new one and store
|
|
PropagationPathDesignator ppath = PropagationData.Database.PropagationPathFindOrCreateFromLatLon(
|
|
null,
|
|
myloc.Lat,
|
|
myloc.Lon,
|
|
GetElevation(myloc.Lat, myloc.Lon) + myqrv.AntennaHeight,
|
|
dxloc.Lat,
|
|
dxloc.Lon,
|
|
GetElevation(dxloc.Lat, dxloc.Lon) + dxqrv.AntennaHeight,
|
|
Bands.ToGHz(Properties.Settings.Default.Band),
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor,
|
|
Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].F1_Clearance,
|
|
ElevationData.Database.GetDefaultStepWidth(Properties.Settings.Default.ElevationModel),
|
|
Properties.Settings.Default.ElevationModel,
|
|
myobstr);
|
|
List<PlaneInfo> allplanes = Planes.GetAll(DateTime.UtcNow, Properties.Settings.Default.Planes_Position_TTL);
|
|
List<PlaneInfo> nearestplanes = AircraftData.Database.GetNearestPlanes(DateTime.UtcNow, ppath, allplanes, Properties.Settings.Default.Planes_Filter_Max_Circumcircle, Properties.Settings.Default.Path_Band_Settings[band].MaxDistance, Properties.Settings.Default.Planes_MaxAlt);
|
|
count = 0;
|
|
string planes = "";
|
|
wtMessage SendMsg = new wtMessage(WTMESSAGES.ASNEAREST,
|
|
Properties.Settings.Default.Server_Name,
|
|
msg.Src,
|
|
DateTime.UtcNow.ToString("u") + "," +
|
|
mycallstr + "," +
|
|
mylocstr + "," +
|
|
dxcallstr + "," +
|
|
dxlocstr + ",");
|
|
if ((nearestplanes != null) && (nearestplanes.Count() > 0))
|
|
{
|
|
foreach (PlaneInfo planeinfo in nearestplanes)
|
|
{
|
|
if ((planeinfo.IntPoint != null) && (planeinfo.Potential > 0))
|
|
{
|
|
int mins = 0;
|
|
if (planeinfo.Speed > 0)
|
|
mins = (int)(planeinfo.IntQRB / (double)planeinfo.Speed / 1.852 * 60.0);
|
|
planes = planes + planeinfo.Call + "," + PlaneCategories.GetShortStringValue(planeinfo.Category) + "," + ((int)planeinfo.IntQRB).ToString() + "," + planeinfo.Potential.ToString() + "," + mins.ToString() + ",";
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
planes = planes.TrimEnd(',');
|
|
SendMsg.Data = SendMsg.Data + count.ToString() + "," + planes;
|
|
SendMsg.Data = SendMsg.Data.TrimEnd(',');
|
|
SendMsg.HasChecksum = true;
|
|
// send message
|
|
UdpClient client = new UdpClient();
|
|
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
|
|
client.Client.ReceiveTimeout = 10000; // 10s Receive timeout
|
|
IPEndPoint groupEp = new IPEndPoint(IPAddress.Broadcast, Properties.Settings.Default.Server_Port);
|
|
client.Connect(groupEp);
|
|
byte[] b = SendMsg.ToBytes();
|
|
client.Send(b, b.Length);
|
|
client.Close();
|
|
st.Stop();
|
|
Log.WriteMessage("Processing ASSETPATH[" + mycallstr + "," + dxcallstr + "]: " + count.ToString() + " Plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void ASWatchlist(wtMessage msg)
|
|
{
|
|
if (!Properties.Settings.Default.Watchlist_SyncWithKST)
|
|
return;
|
|
// maintain watchlist
|
|
try
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
// mark all watchlist items to remove wich are not currently tracked
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
if (!item.Checked)
|
|
item.Remove = true;
|
|
}
|
|
// split message
|
|
string[] a = msg.Data.Split(',');
|
|
// ignore band string so far
|
|
string qrgstr = a[0];
|
|
// iterate through calls
|
|
for (int i = 1; i < a.Length - 1; i += 2)
|
|
{
|
|
// get call
|
|
string dxcallstr = a[i].Trim().ToUpper();
|
|
// get loc
|
|
string dxlocstr = a[i + 1].Trim().ToUpper();
|
|
// skip when invalid
|
|
if (!Callsign.Check(dxcallstr))
|
|
continue;
|
|
if (!MaidenheadLocator.Check(dxlocstr))
|
|
continue;
|
|
// skip own callsign
|
|
if (dxcallstr == Callsign.Cut(Properties.Settings.Default.MyCall))
|
|
continue;
|
|
// find or create call & loc combination in station database
|
|
LocationDesignator dxcall = StationData.Database.LocationFindOrCreate(dxcallstr, dxlocstr);
|
|
double qrb = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, dxcall.Lat, dxcall.Lon);
|
|
// add to watchlist
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(dxcallstr, dxlocstr);
|
|
// reset remove flag if item found, add to watchlist if not
|
|
if (index >= 0)
|
|
{
|
|
Properties.Settings.Default.Watchlist[index].Remove = false;
|
|
Properties.Settings.Default.Watchlist[index].OutOfRange = qrb > Properties.Settings.Default.Path_MaxLength;
|
|
}
|
|
else
|
|
{
|
|
Properties.Settings.Default.Watchlist.Add(new WatchlistItem(dxcallstr, dxlocstr, qrb > Properties.Settings.Default.Path_MaxLength));
|
|
}
|
|
}
|
|
|
|
// remove all items from watchlist which are not logged in anymore
|
|
Properties.Settings.Default.Watchlist.RemoveAll(item => item.Remove);
|
|
|
|
// update watchlist in map
|
|
UpdateWatchlistInMap();
|
|
|
|
// update ListView control
|
|
RefreshWatchlistView();
|
|
st.Stop();
|
|
Log.WriteMessage("Processing ASWATCHLIST: " + Properties.Settings.Default.Watchlist.Count.ToString() + " call(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void ASAddWatch(wtMessage msg)
|
|
{
|
|
// abort if in wtKST sync mode
|
|
if (Properties.Settings.Default.Watchlist_SyncWithKST)
|
|
return;
|
|
|
|
// maintain watchlist
|
|
try
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
|
|
// check for malformatted message
|
|
if (!msg.Data.Contains(","))
|
|
return;
|
|
|
|
// split message
|
|
string[] a = msg.Data.Split(',');
|
|
|
|
// check for malformatted message
|
|
if ((a.Length - 1) % 3 != 0)
|
|
return;
|
|
|
|
// ignore band string so far
|
|
string qrgstr = a[0];
|
|
// iterate through calls
|
|
for (int i = 1; i < a.Length - 2; i += 3)
|
|
{
|
|
// get call
|
|
string dxcallstr = a[i].Trim().ToUpper();
|
|
// get loc
|
|
string dxlocstr = a[i + 1].Trim().ToUpper();
|
|
// get checked
|
|
string checkstr = a[i + 2].Trim().ToUpper();
|
|
|
|
// skip when invalid
|
|
if (!Callsign.Check(dxcallstr))
|
|
continue;
|
|
|
|
// empty loc --> try to find one in the database
|
|
if (String.IsNullOrEmpty(dxlocstr))
|
|
{
|
|
LocationDesignator ld = StationData.Database.LocationFindLastRecent(dxcallstr);
|
|
if (ld != null)
|
|
dxlocstr = ld.Loc;
|
|
}
|
|
// skip when loc is still invalid
|
|
if (!MaidenheadLocator.Check(dxlocstr))
|
|
continue;
|
|
|
|
// skip own callsign
|
|
if (dxcallstr == Callsign.Cut(Properties.Settings.Default.MyCall))
|
|
continue;
|
|
|
|
// find or create call & loc combination in station database
|
|
LocationDesignator dxcall = StationData.Database.LocationFindOrCreate(dxcallstr, dxlocstr);
|
|
double qrb = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, dxcall.Lat, dxcall.Lon);
|
|
|
|
// add to watchlist
|
|
int index = Properties.Settings.Default.Watchlist.IndexOf(dxcallstr, dxlocstr);
|
|
// reset remove flag if item found, add to watchlist if not
|
|
if (index >= 0)
|
|
{
|
|
Properties.Settings.Default.Watchlist[index].Remove = false;
|
|
Properties.Settings.Default.Watchlist[index].OutOfRange = qrb > Properties.Settings.Default.Path_MaxLength;
|
|
if (!Properties.Settings.Default.Watchlist[index].OutOfRange)
|
|
{
|
|
Properties.Settings.Default.Watchlist[index].Checked = checkstr == "1";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (qrb > Properties.Settings.Default.Path_MaxLength)
|
|
{
|
|
Properties.Settings.Default.Watchlist.Add(new WatchlistItem(dxcallstr, dxlocstr, true));
|
|
}
|
|
else
|
|
{
|
|
Properties.Settings.Default.Watchlist.Add(new WatchlistItem(dxcallstr, dxlocstr, false, checkstr == "1"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// update watchlist in map
|
|
UpdateWatchlistInMap();
|
|
|
|
// update ListView control
|
|
RefreshWatchlistView();
|
|
|
|
// refresh paths
|
|
UpdatePaths();
|
|
|
|
// start playing if at least one active watch
|
|
if (Properties.Settings.Default.Watchlist.Find(item => item.Checked) != null)
|
|
{
|
|
if (PlayMode == AIRSCOUTPLAYMODE.PAUSE)
|
|
Play();
|
|
}
|
|
|
|
st.Stop();
|
|
Log.WriteMessage("Processing ASADDWATCH: " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void ASRemoveWatch(wtMessage msg)
|
|
{
|
|
// abort if in wtKST sync mode
|
|
if (Properties.Settings.Default.Watchlist_SyncWithKST)
|
|
return;
|
|
|
|
// maintain watchlist
|
|
try
|
|
{
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
|
|
// check for empty call sign list --> remove all
|
|
if (!msg.Data.Contains(","))
|
|
{
|
|
// mark all watchlist items to remove wich are not currently tracked
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
item.Remove = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// split message
|
|
string[] a = msg.Data.Split(',');
|
|
// ignore band string so far
|
|
string qrgstr = a[0];
|
|
for (int i = 1; i < a.Length; i++)
|
|
{
|
|
// get call
|
|
string dxcallstr = a[i].Trim().ToUpper();
|
|
|
|
// mark all watchlist items to remove wich are not currently tracked
|
|
foreach (WatchlistItem item in Properties.Settings.Default.Watchlist)
|
|
{
|
|
// nasty!! Should never be null!
|
|
if (item == null)
|
|
continue;
|
|
if (item.Call == dxcallstr)
|
|
item.Remove = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove all items from watchlist which marked as remove
|
|
Properties.Settings.Default.Watchlist.RemoveAll(item => item.Remove);
|
|
|
|
// update watchlist in map
|
|
UpdateWatchlistInMap();
|
|
|
|
// update ListView control
|
|
RefreshWatchlistView();
|
|
|
|
// refresh paths
|
|
UpdatePaths();
|
|
|
|
// stop playing if no more active watches
|
|
if (Properties.Settings.Default.Watchlist.Find(item => item.Checked) == null)
|
|
{
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
Pause();
|
|
}
|
|
|
|
st.Stop();
|
|
Log.WriteMessage("Processing ASREMOVEWATCH: " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void DispatchWinTestMsg(wtMessage msg)
|
|
{
|
|
// a Win-Test message was received by the background thread
|
|
if (msg.Msg == WTMESSAGES.ASSHOWPATH)
|
|
{
|
|
// a show path message received
|
|
// dispatch it to main thread
|
|
bw_WinTestReceive.ReportProgress(1, msg);
|
|
}
|
|
else if (msg.Msg == WTMESSAGES.ASSETPATH)
|
|
{
|
|
// a path calculation message received
|
|
// keep it in the background thread and calculate
|
|
ASSetPath(msg);
|
|
}
|
|
else if (msg.Msg == WTMESSAGES.ASWATCHLIST)
|
|
{
|
|
// set users list on watchlist
|
|
// dispatch it to main thread
|
|
bw_WinTestReceive.ReportProgress(1, msg);
|
|
}
|
|
else if (msg.Msg == WTMESSAGES.ASADDWATCH)
|
|
{
|
|
// add call to watchlist
|
|
// dispatch it to main thread
|
|
bw_WinTestReceive.ReportProgress(1, msg);
|
|
}
|
|
else if (msg.Msg == WTMESSAGES.ASREMOVEWATCH)
|
|
{
|
|
// add call to watchlist
|
|
// dispatch it to main thread
|
|
bw_WinTestReceive.ReportProgress(1, msg);
|
|
}
|
|
}
|
|
|
|
private void bw_WinTestReceive_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
// a Win-Test message was received by the background thread
|
|
NumberFormatInfo provider = new NumberFormatInfo();
|
|
provider.NumberDecimalSeparator = ".";
|
|
provider.NumberGroupSeparator = ",";
|
|
provider.NumberGroupSizes = new int[] { 3 };
|
|
|
|
wtMessage msg = (wtMessage)e.UserState;
|
|
if (msg.Msg == WTMESSAGES.ASSHOWPATH)
|
|
ASShowPath(msg);
|
|
else if (msg.Msg == WTMESSAGES.ASWATCHLIST)
|
|
ASWatchlist(msg);
|
|
else if (msg.Msg == WTMESSAGES.ASADDWATCH)
|
|
ASAddWatch(msg);
|
|
else if (msg.Msg == WTMESSAGES.ASREMOVEWATCH)
|
|
ASRemoveWatch(msg);
|
|
}
|
|
|
|
private void bw_WinTestReceive_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
# region SpecLabReceive
|
|
|
|
// suppress console output when in debug mode, needs "Just my code" set in Tools\Options\Debugging
|
|
// [System.Diagnostics.DebuggerNonUserCode]
|
|
private void bw_SpecLab_Receive_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_SpecLabReceive";
|
|
Log.WriteMessage("Started.");
|
|
// get the update interval
|
|
int interval = System.Convert.ToInt32(Properties.Settings.Default.SpecLab_Update) * 1000;
|
|
// check for minimum
|
|
if (interval < 1000)
|
|
interval = 1000;
|
|
bw_SpecLab_Receive.ReportProgress(0);
|
|
int maxcount = 60;
|
|
List<SignalLevelDesignator> ads = new List<SignalLevelDesignator>();
|
|
while (!bw_SpecLab_Receive.CancellationPending)
|
|
{
|
|
Thread.Sleep(interval);
|
|
// do nothing when not in play mode
|
|
if ((LifeMode != AIRSCOUTLIFEMODE.LIFE) || (PlayMode != AIRSCOUTPLAYMODE.FORWARD))
|
|
continue;
|
|
try
|
|
{
|
|
// get boundary frequencies
|
|
int f1 = Properties.Settings.Default.SpecLab_F1;
|
|
if (f1 < 0)
|
|
f1 = 0;
|
|
if (f1 > 3000)
|
|
f1 = 3000;
|
|
int f2 = Properties.Settings.Default.SpecLab_F2;
|
|
if (f2 < 1)
|
|
f2 = 1;
|
|
if (f2 > 3000)
|
|
f2 = 3000;
|
|
if (f1 >= f2)
|
|
f1 = f2 - 1;
|
|
// get the url
|
|
string url = Properties.Settings.Default.SpecLab_URL;
|
|
// get the filename
|
|
string filename = Properties.Settings.Default.SpecLab_FileName;
|
|
if (!url.EndsWith("/"))
|
|
url = url + "/";
|
|
url = url + filename + "?f1=" + f1.ToString() + "?f2=" + f2.ToString();
|
|
string msg = "";
|
|
bw_SpecLab_Receive.ReportProgress(1, "Trying to connect to Spectrum Lab...");
|
|
WebRequest myWebRequest = WebRequest.Create(url);
|
|
WebResponse myWebResponse = myWebRequest.GetResponse();
|
|
Stream ReceiveStream = myWebResponse.GetResponseStream();
|
|
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
|
|
StreamReader readStream = new StreamReader(ReceiveStream, encode);
|
|
string json = readStream.ReadToEnd();
|
|
if (!json.StartsWith("["))
|
|
throw (new FormatException("Format Exception: Not a JSON file."));
|
|
// split the JSON string
|
|
// a[1] contains the header
|
|
// h contains alle header items
|
|
// d contains all data items
|
|
string[] a = json.Split('[');
|
|
a[1] = a[1].Replace(":", ",");
|
|
string[] h = a[1].Split(',');
|
|
a[2] = a[2].Replace("\r\n", "");
|
|
a[2] = a[2].Remove(a[2].IndexOf("]") - 1);
|
|
a[2] = a[2].Replace(",", ";");
|
|
a[2] = a[2].Replace(".", ",");
|
|
double[] d = System.Array.ConvertAll(a[2].Split(';'), new Converter<string, double>(Double.Parse));
|
|
// get the time stamp
|
|
long l = (long)System.Convert.ToDouble(h[1], CultureInfo.InvariantCulture);
|
|
DateTime utc = new System.DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
|
utc = utc.AddSeconds(l);
|
|
// get number of bins
|
|
int count = System.Convert.ToInt32(h[13]);
|
|
msg = "FFT-Data received: " + count.ToString() + "bins. F1=" + f1.ToString() + "Hz, F2=" + f2.ToString() + "Hz";
|
|
bw_SpecLab_Receive.ReportProgress(1, msg);
|
|
double max = d.Max();
|
|
// collect and save maximum if in play mode and NearestPlane != null
|
|
if ((PlayMode == AIRSCOUTPLAYMODE.FORWARD) && (NearestPlane != null))
|
|
ads.Add(new SignalLevelDesignator(max, utc));
|
|
// bulk save maximum to database if maxcount is reached
|
|
if (ads.Count > maxcount)
|
|
{
|
|
SignalData.Database.SignalLevelBulkInsertOrUpdateIfNewer(ads);
|
|
ads.Clear();
|
|
}
|
|
// report maximum
|
|
bw_SpecLab_Receive.ReportProgress(100, max);
|
|
}
|
|
catch (WebException ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
catch (SocketException ex)
|
|
{
|
|
// do nothing
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
bw_SpecLab_Receive.ReportProgress(-1, ex.Message);
|
|
}
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void bw_SpecLab_Receive_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// an error occured
|
|
tb_Spectrum_Status.ForeColor = Color.White;
|
|
tb_Spectrum_Status.BackColor = Color.Red;
|
|
tb_Spectrum_Status.Text = (string)e.UserState;
|
|
}
|
|
if (e.ProgressPercentage == 0)
|
|
{
|
|
// a init message occured
|
|
Spectrum.Points.Clear();
|
|
SpectrumPointsCount = 0;
|
|
Spectrum_X.Reset();
|
|
SpectrumRecord.Points.Clear();
|
|
}
|
|
if (e.ProgressPercentage == 1)
|
|
{
|
|
// a status message occured
|
|
tb_Spectrum_Status.ForeColor = Color.Black;
|
|
tb_Spectrum_Status.BackColor = SystemColors.Control;
|
|
tb_Spectrum_Status.Text = (string)e.UserState;
|
|
}
|
|
if (e.ProgressPercentage == 100)
|
|
{
|
|
// FFT - data received
|
|
if ((LifeMode == AIRSCOUTLIFEMODE.LIFE) && (PlayMode == AIRSCOUTPLAYMODE.FORWARD))
|
|
{
|
|
// draw data
|
|
double max = (double)e.UserState;
|
|
if (Spectrum.Points.Count >= SpectrumMaxPoints)
|
|
{
|
|
double pan = -(Spectrum_X.ScreenMax.X - Spectrum_X.ScreenMin.X) / (double)SpectrumMaxPoints;
|
|
Spectrum_X.Pan(pan);
|
|
Spectrum.Points.RemoveAt(0);
|
|
SpectrumRecord.Points.RemoveAt(0);
|
|
}
|
|
// add background area
|
|
SpectrumRecord.Fill = OxyColor.FromArgb(20, 255, 0, 255);
|
|
double on, off;
|
|
if (Spectrum_Y.Minimum < 0)
|
|
{
|
|
on = -1000;
|
|
off = 1000;
|
|
}
|
|
else
|
|
{
|
|
on = 1000;
|
|
off = -1000;
|
|
}
|
|
if (NearestPlane == null)
|
|
SpectrumRecord.Points.Add(new DataPoint(SpectrumPointsCount, off));
|
|
else
|
|
SpectrumRecord.Points.Add(new DataPoint(SpectrumPointsCount, on));
|
|
// add signal level point
|
|
Spectrum.Points.Add(new DataPoint(SpectrumPointsCount, max));
|
|
SpectrumPointsCount++;
|
|
// autoscale Y axis
|
|
double y_min = double.MaxValue;
|
|
double y_max = double.MinValue;
|
|
foreach (DataPoint p in Spectrum.Points)
|
|
{
|
|
if (p.Y > y_max)
|
|
y_max = p.Y;
|
|
if (p.Y < y_min)
|
|
y_min = p.Y;
|
|
}
|
|
// enlarge scaling Y-axis by 10% in both directions
|
|
double y_diff = (y_max - y_min) * 0.1;
|
|
Spectrum_Y.Minimum = y_min - y_diff;
|
|
Spectrum_Y.Maximum = y_max + y_diff;
|
|
pm_Spectrum.InvalidatePlot(true);
|
|
}
|
|
}
|
|
// maintain nearest plane map
|
|
if (NearestPlane != null)
|
|
{
|
|
lbl_Nearest_Call.Text = NearestPlane.Call;
|
|
lbl_Nearest_Type.Text = NearestPlane.Type;
|
|
lbl_Nearest_Cat.Text = PlaneCategories.GetStringValue(NearestPlane.Category);
|
|
lbl_Nearest_Alt.Text = NearestPlane.Alt_m.ToString("F0") + "m";
|
|
lbl_Nearest_Angle.Text = (NearestPlane.Angle / Math.PI * 180.0).ToString("F0") + "°";
|
|
lbl_Nearest_Dist.Text = NearestPlane.IntQRB.ToString("F0") + "km";
|
|
gmo_NearestPlanes.Clear();
|
|
gmo_NearestPlanes.Markers.Add(CreatePlaneDetailed(NearestPlane, false));
|
|
gm_Nearest.Position = new PointLatLng(NearestPlane.IntPoint.Lat, NearestPlane.IntPoint.Lon);
|
|
gm_Nearest.Zoom = 10;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void bw_SpecLab_Receive_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
# endregion
|
|
|
|
#region Track
|
|
|
|
private bool Track_DDE_HRD(DdeClient client, double az, double el)
|
|
{
|
|
// send Az/EL vie DDE to Ham Radio Deluxe Rotor Control (HRDRotator.exe)
|
|
// no position feedback expected
|
|
if (client == null)
|
|
throw new NullReferenceException("[DDE]: Client not initialized.");
|
|
if (!client.IsConnected)
|
|
throw new InvalidOperationException("[DDE]: Client not connected.");
|
|
|
|
byte[] data;
|
|
if ((az >= 0) && (az <= 360))
|
|
{
|
|
// send azimuth data
|
|
data = Encoding.ASCII.GetBytes("SET-AZ:" + az.ToString("F1"));
|
|
client.TryPoke("PositionData", data, 1, 10000);
|
|
}
|
|
if ((el >= 0) && (el <= 90))
|
|
{
|
|
// send elevation data
|
|
data = Encoding.ASCII.GetBytes("SET-EL:" + el.ToString("F1"));
|
|
client.TryPoke("PositionData", data, 1, 10000);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool Track_UDP_WinTest(UdpClient client, IPEndPoint ip, double az, double el)
|
|
{
|
|
// send UDP broadcast like Win-Test
|
|
// no position feedback expected
|
|
if ((client == null) || (ip == null))
|
|
if (client == null)
|
|
throw new NullReferenceException("[UDP]: Client and/or IP endpoint not initialized.");
|
|
wtMessage msg = new wtMessage(WTMESSAGES.SETAZIMUTH, Properties.Settings.Default.Server_Name, "", "AUTO", " 00 " + az.ToString("000"));
|
|
byte[] bytes = msg.ToBytes();
|
|
client.Send(bytes, bytes.Length, ip);
|
|
return true;
|
|
}
|
|
|
|
private bool Track_UDP_AirScout(UdpClient client, IPEndPoint ip, double az, double el)
|
|
{
|
|
// send UDP broadcast like Win-Test
|
|
// no position feedback expected
|
|
if ((client == null) || (ip == null))
|
|
throw new NullReferenceException("[UDP]: Client and/or IP endpoint not initialized.");
|
|
wtMessage msg;
|
|
msg = new wtMessage(WTMESSAGES.SETAZIMUTH, Properties.Settings.Default.Server_Name, "", "AUTO", " 00 " + az.ToString("000"));
|
|
byte[] bytes = msg.ToBytes();
|
|
client.Send(bytes, bytes.Length, ip);
|
|
msg = new wtMessage(WTMESSAGES.SETELEVATION, Properties.Settings.Default.Server_Name, "", "AUTO", " 00 " + el.ToString("000"));
|
|
bytes = msg.ToBytes();
|
|
client.Send(bytes, bytes.Length, ip);
|
|
// new: high precision az/el
|
|
msg = new wtMessage(WTMESSAGES.SETAZEL, Properties.Settings.Default.Server_Name, "", "AUTO", " 00 " + az.ToString("F8", CultureInfo.InvariantCulture) + " " + el.ToString("F8", CultureInfo.InvariantCulture));
|
|
bytes = msg.ToBytes();
|
|
client.Send(bytes, bytes.Length, ip);
|
|
return true;
|
|
}
|
|
|
|
private string Serial_SendCommand(SerialPort sp, string command, bool waitanswer)
|
|
{
|
|
// sends a command via serial port (and optional wait fo answer)
|
|
if ((sp == null) || (!sp.IsOpen))
|
|
return "";
|
|
string s = "";
|
|
{
|
|
sp.WriteLine(command);
|
|
if (waitanswer)
|
|
{
|
|
s = sp.ReadLine();
|
|
s = s.Replace("\n", "");
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
|
|
private bool Track_SER__GS_232A_AZ(SerialPort sp, double az)
|
|
{
|
|
// send Az value via serial port (GS-232A protocol)
|
|
// communictaion test --> get azimuth value
|
|
if (sp == null)
|
|
throw new NullReferenceException("[Serial]: Port not initialized.");
|
|
if (!sp.IsOpen)
|
|
throw new InvalidOperationException("[Serial]: Port not open.");
|
|
// communictaion test --> get azimuth value
|
|
string s = Serial_SendCommand(sp, "C", true);
|
|
if (!s.StartsWith("+0"))
|
|
throw new FormatException("[Serial]: Wrong serial data format.");
|
|
try
|
|
{
|
|
double result = System.Convert.ToDouble(s.Substring(2, 3), CultureInfo.InvariantCulture);
|
|
}
|
|
catch
|
|
{
|
|
throw new FormatException("[Serial]: Wrong serial data format.");
|
|
}
|
|
// set azimuth value --> no feedback
|
|
Serial_SendCommand(sp, "M" + az.ToString("000"), false);
|
|
return true;
|
|
}
|
|
|
|
private bool Track_SER__GS_232A_AZEL(SerialPort sp, double az, double el)
|
|
{
|
|
// send Az/El value via serial port (GS-232A protocol)
|
|
if (sp == null)
|
|
throw new NullReferenceException("[Serial]: Port not initialized.");
|
|
if (!sp.IsOpen)
|
|
throw new InvalidOperationException("[Serial]: Port not open.");
|
|
// communictaion test --> get azimuth and elevation value
|
|
string s = Serial_SendCommand(sp, "C2", true);
|
|
if (!s.StartsWith("+0"))
|
|
throw new FormatException("[Serial]: Wrong serial data format.");
|
|
try
|
|
{
|
|
double result = System.Convert.ToDouble(s.Substring(2, 3), CultureInfo.InvariantCulture);
|
|
}
|
|
catch
|
|
{
|
|
throw new FormatException("[Serial]: Wrong serial data format.");
|
|
}
|
|
// set azimuth value --> no feedback
|
|
Serial_SendCommand(sp, "W" + az.ToString("000") + " " + el.ToString("000"), false);
|
|
return true;
|
|
}
|
|
|
|
private void Track_File_Native(double az, double el)
|
|
{
|
|
// writes a file with Az/El values in a file (native)
|
|
// Syntax: <Az value>,<El value>
|
|
using (StreamWriter sw = new StreamWriter(TmpDirectory + Path.DirectorySeparatorChar + "azel.dat"))
|
|
{
|
|
sw.WriteLine(az.ToString("F1", CultureInfo.InvariantCulture) + "," + el.ToString("F1", CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
|
|
private void Track_File_WSJT(double az, double el)
|
|
{
|
|
// writes a file with Az/El values in a file (WSJT)
|
|
// the info is filled in the "Source" line (originally intended to follow a radio source
|
|
using (StreamWriter sw = new StreamWriter(TmpDirectory + Path.DirectorySeparatorChar + "azel.dat"))
|
|
{
|
|
string utc = DateTime.UtcNow.ToString("HH:mm:ss");
|
|
sw.WriteLine(utc + ",0,0,Moon");
|
|
sw.WriteLine(utc + ",0,0,Sun");
|
|
sw.WriteLine(utc + "," + az.ToString("F1", CultureInfo.InvariantCulture) + "," + el.ToString("F1", CultureInfo.InvariantCulture) + ",Source");
|
|
sw.WriteLine("0, 0, 0, 0, 0,Doppler, R");
|
|
}
|
|
}
|
|
|
|
private void bw_Track_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
Log.WriteMessage("Started.");
|
|
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_Track";
|
|
|
|
// last recent calculated values
|
|
TrackValues oldvalues = null;
|
|
TRACKSTATUS oldstatus = TRACKSTATUS.NONE;
|
|
|
|
// clients and ports
|
|
DdeClient ddeclient = null;
|
|
UdpClient udpclient = null;
|
|
IPEndPoint udpip = null;
|
|
SerialPort serialport = null;
|
|
|
|
// error counters
|
|
int ddeerr = 0;
|
|
int udperr = 0;
|
|
int serialerr = 0;
|
|
int maxerr = 10;
|
|
|
|
// outer loop
|
|
do
|
|
{
|
|
try
|
|
{
|
|
// intializations
|
|
if (Properties.Settings.Default.Track_DDE_HRD)
|
|
{
|
|
ddeclient = new DdeClient("HRDRotator", "Position");
|
|
int result = ddeclient.TryConnect();
|
|
|
|
}
|
|
if (Properties.Settings.Default.Track_UDP_WinTest)
|
|
{
|
|
udpclient = new UdpClient();
|
|
udpip = new IPEndPoint(IPAddress.Broadcast, Properties.Settings.Default.Track_UDP_WinTest_Port);
|
|
}
|
|
else if (Properties.Settings.Default.Track_UDP_AirScout)
|
|
{
|
|
udpclient = new UdpClient();
|
|
udpip = new IPEndPoint(IPAddress.Broadcast, Properties.Settings.Default.Track_UDP_AirScout_Port);
|
|
}
|
|
if ((Properties.Settings.Default.Track_Serial_GS232_AZ) || (Properties.Settings.Default.Track_Serial_GS232_AZEL))
|
|
{
|
|
serialport = new SerialPort(Properties.Settings.Default.Track_Serial_Port,
|
|
Properties.Settings.Default.Track_Serial_Baudrate,
|
|
System.IO.Ports.Parity.None,
|
|
8,
|
|
System.IO.Ports.StopBits.One);
|
|
serialport.Handshake = System.IO.Ports.Handshake.None;
|
|
serialport.NewLine = "\r";
|
|
serialport.Encoding = Encoding.ASCII;
|
|
serialport.ReadTimeout = 1000;
|
|
serialport.WriteTimeout = 1000;
|
|
serialport.Open();
|
|
}
|
|
|
|
// init OK --> ready for tracking
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.STOPPED);
|
|
bw_Track.ReportProgress(2, ROTSTATUS.STOPPED);
|
|
|
|
// inner loop
|
|
while (Properties.Settings.Default.Track_Activate && !bw_Track.CancellationPending)
|
|
{
|
|
try
|
|
{
|
|
// get current plane position and calculate set of tracking values
|
|
DateTime time = DateTime.UtcNow.AddSeconds(Properties.Settings.Default.Track_Offset);
|
|
TrackValues trackvalues = new TrackValues();
|
|
trackvalues.Timestamp = time;
|
|
if (TrackMode == AIRSCOUTTRACKMODE.TRACK)
|
|
{
|
|
// invalidate oldvalues on plane change
|
|
if ((oldvalues != null) && (Properties.Settings.Default.Track_CurrentPlane != null) && (oldvalues.Hex != Properties.Settings.Default.Track_CurrentPlane))
|
|
{
|
|
oldvalues = null;
|
|
}
|
|
// track plane --> get plane position and calculate values
|
|
PlaneInfo plane = Planes.Get(Properties.Settings.Default.Track_CurrentPlane, time, Properties.Settings.Default.Planes_Position_TTL);
|
|
if (plane != null)
|
|
{
|
|
trackvalues.Hex = Properties.Settings.Default.Track_CurrentPlane;
|
|
trackvalues.MyAzimuth = LatLon.Bearing(Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
plane.Lat,
|
|
plane.Lon);
|
|
trackvalues.DXAzimuth = LatLon.Bearing(Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon,
|
|
plane.Lat,
|
|
plane.Lon);
|
|
double myh = (GetElevation(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon) + Properties.Settings.Default.MyHeight);
|
|
double dxh = (GetElevation(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon) + Properties.Settings.Default.DXHeight);
|
|
double H = plane.Alt_m;
|
|
trackvalues.MyDistance = LatLon.Distance(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, plane.Lat, plane.Lon);
|
|
trackvalues.MySlantRange = Propagation.SlantRangeFromHeights(
|
|
myh,
|
|
Properties.Settings.Default.MyLat,
|
|
Properties.Settings.Default.MyLon,
|
|
plane.Lat,
|
|
plane.Lon,
|
|
H,
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor);
|
|
trackvalues.MyElevation = Propagation.EpsilonFromHeights(myh,
|
|
trackvalues.MyDistance,
|
|
H,
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor)
|
|
/ Math.PI * 180;
|
|
trackvalues.DXDistance = LatLon.Distance(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, plane.Lat, plane.Lon);
|
|
trackvalues.DXSlantRange = Propagation.SlantRangeFromHeights(
|
|
dxh,
|
|
Properties.Settings.Default.DXLat,
|
|
Properties.Settings.Default.DXLon,
|
|
plane.Lat,
|
|
plane.Lon,
|
|
H,
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor);
|
|
trackvalues.DXElevation = Propagation.EpsilonFromHeights(dxh,
|
|
trackvalues.DXDistance,
|
|
H,
|
|
LatLon.Earth.Radius * Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].K_Factor)
|
|
/ Math.PI * 180;
|
|
|
|
// calculate doppler, we need a last recent calculated values to calculate relative speed
|
|
if (oldvalues != null)
|
|
{
|
|
// get both resulting speeds in m/s
|
|
double timediff = (trackvalues.Timestamp - oldvalues.Timestamp).TotalSeconds;
|
|
double myspeed = 0;
|
|
double dxspeed = 0;
|
|
|
|
if (timediff > 0)
|
|
{
|
|
myspeed = (oldvalues.MySlantRange - trackvalues.MySlantRange) * 1000.0 / timediff;
|
|
dxspeed = (oldvalues.DXSlantRange - trackvalues.DXSlantRange) * 1000.0 / timediff;
|
|
}
|
|
|
|
// calculate both doppler shifts
|
|
trackvalues.MyDoppler = Propagation.DopplerShift(Bands.ToHz(Properties.Settings.Default.Band), myspeed);
|
|
trackvalues.DXDoppler = Propagation.DopplerShift(Bands.ToHz(Properties.Settings.Default.Band), dxspeed);
|
|
}
|
|
}
|
|
}
|
|
else if (TrackMode == AIRSCOUTTRACKMODE.SINGLE)
|
|
{
|
|
// single shot --> get values from settings and track only once
|
|
trackvalues.MyAzimuth = Properties.Settings.Default.Track_SetAz;
|
|
trackvalues.MyElevation = Properties.Settings.Default.Track_SetEl;
|
|
}
|
|
|
|
// valid values --> start tracking
|
|
if (!double.IsNaN(trackvalues.MyAzimuth) &&
|
|
!double.IsNaN(trackvalues.MyElevation) &&
|
|
(trackvalues.MyAzimuth >= 0) &&
|
|
(trackvalues.MyAzimuth < 360))
|
|
{
|
|
// report track start
|
|
if (TrackMode == AIRSCOUTTRACKMODE.SINGLE)
|
|
{
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.SINGLE);
|
|
}
|
|
else if (TrackMode == AIRSCOUTTRACKMODE.TRACK)
|
|
{
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.TRACKING);
|
|
}
|
|
|
|
// rotator control
|
|
try
|
|
{
|
|
// log tracking to console
|
|
Console.WriteLine("Tracking[" + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss,fff") + "]: Az=" + trackvalues.MyAzimuth + ", El=" + trackvalues.MyElevation);
|
|
if (Properties.Settings.Default.Track_DDE_HRD)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_DDE_HRD(ddeclient, trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
if (Properties.Settings.Default.Track_UDP_WinTest)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_UDP_WinTest(udpclient, udpip, trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
if (Properties.Settings.Default.Track_UDP_AirScout)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_UDP_AirScout(udpclient, udpip, trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
if (Properties.Settings.Default.Track_Serial_GS232_AZ)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_SER__GS_232A_AZ(serialport, trackvalues.MyAzimuth);
|
|
}
|
|
if (Properties.Settings.Default.Track_Serial_GS232_AZEL)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_SER__GS_232A_AZEL(serialport, trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
if (Properties.Settings.Default.Track_File_Native)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_File_Native(trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
if (Properties.Settings.Default.Track_File_WSJT)
|
|
{
|
|
bw_Track.ReportProgress(2, ROTSTATUS.TRACKING);
|
|
Track_File_WSJT(trackvalues.MyAzimuth, trackvalues.MyElevation);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
//report error
|
|
bw_Track.ReportProgress(-1, ex.Message);
|
|
// increment error counters and switch off in case of subsequent errors
|
|
if (ex.Message.StartsWith("[DDE]:"))
|
|
{
|
|
ddeerr++;
|
|
if (ddeerr > maxerr)
|
|
{
|
|
// switch off DDE
|
|
Properties.Settings.Default.Track_DDE_None = true;
|
|
Properties.Settings.Default.Track_DDE_HRD = false;
|
|
bw_Track.ReportProgress(-1, "Tracking via DDE disabled.");
|
|
bw_Track.ReportProgress(2, ROTSTATUS.ERROR);
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.ERROR);
|
|
|
|
}
|
|
}
|
|
if (ex.Message.StartsWith("[UDP]:"))
|
|
{
|
|
udperr++;
|
|
if (udperr > maxerr)
|
|
{
|
|
// switch off UDP
|
|
Properties.Settings.Default.Track_UDP_None = true;
|
|
Properties.Settings.Default.Track_UDP_WinTest = false;
|
|
Properties.Settings.Default.Track_UDP_AirScout = false;
|
|
bw_Track.ReportProgress(-1, "Tracking via UDP disabled.");
|
|
bw_Track.ReportProgress(2, ROTSTATUS.ERROR);
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.ERROR);
|
|
}
|
|
}
|
|
if (ex.Message.StartsWith("[Serial]:"))
|
|
{
|
|
serialerr++;
|
|
if (serialerr > maxerr)
|
|
{
|
|
// switch off Serial
|
|
Properties.Settings.Default.Track_Serial_None = true;
|
|
Properties.Settings.Default.Track_Serial_GS232_AZ = false;
|
|
Properties.Settings.Default.Track_Serial_GS232_AZEL = false;
|
|
bw_Track.ReportProgress(-1, "Tracking via Serial disabled.");
|
|
bw_Track.ReportProgress(2, ROTSTATUS.ERROR);
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.ERROR);
|
|
}
|
|
if (ex.Message.StartsWith("[Serial]:"))
|
|
serialerr++;
|
|
}
|
|
|
|
}
|
|
|
|
// doppler shift compensation if activated
|
|
if (Properties.Settings.Default.Doppler_Strategy_A)
|
|
{
|
|
trackvalues.RXFrequency = Properties.Settings.Default.Doppler_DialFreq +
|
|
(long)trackvalues.MyDoppler +
|
|
(long)trackvalues.DXDoppler;
|
|
trackvalues.TXFrequency = Properties.Settings.Default.Doppler_DialFreq;
|
|
}
|
|
else if (Properties.Settings.Default.Doppler_Strategy_B)
|
|
{
|
|
trackvalues.RXFrequency = Properties.Settings.Default.Doppler_DialFreq;
|
|
trackvalues.TXFrequency = Properties.Settings.Default.Doppler_DialFreq -
|
|
(long)trackvalues.MyDoppler -
|
|
(long)trackvalues.DXDoppler;
|
|
}
|
|
else if (Properties.Settings.Default.Doppler_Strategy_C)
|
|
{
|
|
trackvalues.RXFrequency = Properties.Settings.Default.Doppler_DialFreq +
|
|
(long)trackvalues.MyDoppler +
|
|
(long)trackvalues.DXDoppler;
|
|
trackvalues.TXFrequency = Properties.Settings.Default.Doppler_DialFreq -
|
|
(long)trackvalues.MyDoppler -
|
|
(long)trackvalues.DXDoppler;
|
|
}
|
|
else if (Properties.Settings.Default.Doppler_Strategy_D)
|
|
{
|
|
trackvalues.RXFrequency = Properties.Settings.Default.Doppler_DialFreq +
|
|
(long)trackvalues.MyDoppler;
|
|
trackvalues.TXFrequency = Properties.Settings.Default.Doppler_DialFreq -
|
|
(long)trackvalues.MyDoppler;
|
|
}
|
|
|
|
// report values
|
|
bw_Track.ReportProgress(3, trackvalues);
|
|
|
|
// store last values
|
|
oldvalues = trackvalues;
|
|
|
|
// stop tracking when single shot
|
|
if (TrackMode == AIRSCOUTTRACKMODE.SINGLE)
|
|
{
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.STOPPED);
|
|
bw_Track.ReportProgress(2, ROTSTATUS.STOPPED);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// no tracking!
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.STOPPED);
|
|
bw_Track.ReportProgress(2, ROTSTATUS.STOPPED);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// leave inner loop
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.ERROR);
|
|
break;
|
|
}
|
|
Thread.Sleep(1000);
|
|
}
|
|
Thread.Sleep(Properties.Settings.Default.Track_Update);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
bw_Track.ReportProgress(-1, "Track error: " + ex.Message);
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.ERROR);
|
|
}
|
|
|
|
}
|
|
while (!bw_Track.CancellationPending);
|
|
|
|
// try to close all connections
|
|
try
|
|
{
|
|
if ((ddeclient != null) && (ddeclient.IsConnected))
|
|
ddeclient.Disconnect();
|
|
if (udpclient != null)
|
|
udpclient.Close();
|
|
if ((serialport != null) && (serialport.IsOpen))
|
|
serialport.Close();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
|
|
bw_Track.ReportProgress(1, TRACKSTATUS.NONE);
|
|
bw_Track.ReportProgress(2, ROTSTATUS.NONE);
|
|
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void bw_Track_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage <= 0)
|
|
{
|
|
// report Error
|
|
tsl_Status.Text = (string)e.UserState;
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
// report tracking status
|
|
TRACKSTATUS trackstatus = (TRACKSTATUS)e.UserState;
|
|
switch (trackstatus)
|
|
{
|
|
case TRACKSTATUS.NONE:
|
|
SayTrack("TRK", Color.DarkGray, SystemColors.Control);
|
|
break;
|
|
case TRACKSTATUS.STOPPED:
|
|
// TrackMode = AIRSCOUTTRACKMODE.NONE;
|
|
SayTrack("TRK", SystemColors.Control, Color.DarkGray);
|
|
break;
|
|
case TRACKSTATUS.SINGLE:
|
|
case TRACKSTATUS.TRACKING:
|
|
SayTrack("TRK", Color.White, Color.DarkGreen);
|
|
break;
|
|
case TRACKSTATUS.ERROR:
|
|
SayTrack("TRK", Color.Yellow, Color.Red);
|
|
break;
|
|
default:
|
|
SayTrack("TRK", Color.DarkGray, SystemColors.Control);
|
|
break;
|
|
}
|
|
|
|
// restore settings when returning from tracking
|
|
if ((trackstatus == TRACKSTATUS.TRACKING) || (trackstatus == TRACKSTATUS.SINGLE))
|
|
{
|
|
if (bw_CAT != null)
|
|
{
|
|
if (Properties.Settings.Default.Doppler_Strategy_A)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_A;
|
|
else if (Properties.Settings.Default.Doppler_Strategy_B)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_B;
|
|
else if (Properties.Settings.Default.Doppler_Strategy_C)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_C;
|
|
else if (Properties.Settings.Default.Doppler_Strategy_D)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_D;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bw_CAT != null)
|
|
{
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_NONE;
|
|
}
|
|
}
|
|
|
|
// save TrackStatus
|
|
TrackStatus = trackstatus;
|
|
}
|
|
else if (e.ProgressPercentage == 2)
|
|
{
|
|
// report Status
|
|
RotStatus = (ROTSTATUS)e.UserState;
|
|
switch (RotStatus)
|
|
{
|
|
case ROTSTATUS.STOPPED:
|
|
SayRot("ROT", SystemColors.Control, Color.DarkGray);
|
|
break;
|
|
case ROTSTATUS.TRACKING:
|
|
SayRot("ROT", Color.White, Color.DarkGreen);
|
|
break;
|
|
case ROTSTATUS.ERROR:
|
|
SayRot("ROT", Color.Yellow, Color.Red);
|
|
break;
|
|
default:
|
|
SayRot("ROT", Color.DarkGray, SystemColors.Control);
|
|
break;
|
|
}
|
|
}
|
|
else if (e.ProgressPercentage == 3)
|
|
{
|
|
// report track values
|
|
TrackValues = (TrackValues)e.UserState;
|
|
if (Properties.Settings.Default.Doppler_Strategy_A ||
|
|
Properties.Settings.Default.Doppler_Strategy_B ||
|
|
Properties.Settings.Default.Doppler_Strategy_C ||
|
|
Properties.Settings.Default.Doppler_Strategy_D)
|
|
{
|
|
// adjust rig if frequencies are valid
|
|
if ((bw_CAT != null) && (TrackValues.RXFrequency != 0) && (TrackValues.TXFrequency != 0))
|
|
{
|
|
if (Properties.Settings.Default.Doppler_Strategy_A)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_A;
|
|
if (Properties.Settings.Default.Doppler_Strategy_B)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_B;
|
|
if (Properties.Settings.Default.Doppler_Strategy_C)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_C;
|
|
if (Properties.Settings.Default.Doppler_Strategy_D)
|
|
bw_CAT.DopplerStrategy = DOPPLERSTRATEGY.DOPPLER_D;
|
|
bw_CAT.RxFrequency = TrackValues.RXFrequency;
|
|
bw_CAT.TxFrequency = TrackValues.TXFrequency;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bw_Track_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JSONWriter
|
|
|
|
private void bw_JSONWriter_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
Log.WriteMessage("Started.");
|
|
int interval = 60;
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_JSONWriter";
|
|
while (!bw_JSONWriter.CancellationPending)
|
|
{
|
|
// get planes each minute
|
|
List<PlaneInfo> list = Planes.GetAll(DateTime.UtcNow, Properties.Settings.Default.Planes_Position_TTL);
|
|
if (list.Count > 0)
|
|
{
|
|
// write json file
|
|
try
|
|
{
|
|
using (StreamWriter sw = new StreamWriter(TmpDirectory + Path.DirectorySeparatorChar + "planes.json"))
|
|
{
|
|
int major = Assembly.GetExecutingAssembly().GetName().Version.Major;
|
|
sw.Write("{\"full_count\":" + list.Count().ToString() + ",\"version\":" + major.ToString());
|
|
int i = 0;
|
|
foreach (PlaneInfo info in list)
|
|
{
|
|
string index = "\"" + i.ToString("x8") + "\"";
|
|
string hex = "\"" + info.Hex + "\"";
|
|
string lat = info.Lat.ToString("F4", CultureInfo.InvariantCulture);
|
|
string lon = info.Lon.ToString("F4", CultureInfo.InvariantCulture);
|
|
string track = info.Track.ToString("F0", CultureInfo.InvariantCulture);
|
|
string alt = info.Alt.ToString("F0", CultureInfo.InvariantCulture);
|
|
string speed = info.Speed.ToString("F0", CultureInfo.InvariantCulture);
|
|
string squawk = "\"" + "" + "\"";
|
|
string radar = "\"" + "" + "\"";
|
|
string type = "\"" + info.Type + "\"";
|
|
string reg = "\"" + info.Reg + "\"";
|
|
DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
string time = ((long)(info.Time - sTime).TotalSeconds).ToString();
|
|
string dep = "\"\"";
|
|
string dest = "\"\"";
|
|
string flight = "\"\"";
|
|
string dummy1 = "0";
|
|
string dummy2 = "0";
|
|
string call = "\"" + info.Call + "\"";
|
|
string dummy3 = "0";
|
|
sw.WriteLine("," + index + ":[" +
|
|
hex + "," +
|
|
lat + "," +
|
|
lon + "," +
|
|
track + "," +
|
|
alt + "," +
|
|
speed + "," +
|
|
squawk + "," +
|
|
radar + "," +
|
|
type + "," +
|
|
reg + "," +
|
|
time + "," +
|
|
dep + "," +
|
|
dest + "," +
|
|
flight + "," +
|
|
dummy1 + "," +
|
|
dummy2 + "," +
|
|
call + "," +
|
|
dummy3 +
|
|
"]");
|
|
i++;
|
|
}
|
|
sw.WriteLine("}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
// do nothing
|
|
}
|
|
}
|
|
int ii = 0;
|
|
while (!bw_JSONWriter.CancellationPending && (ii < interval))
|
|
{
|
|
Thread.Sleep(1000);
|
|
ii++;
|
|
}
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region NewsFeed
|
|
|
|
private void bw_NewsFeed_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
Log.WriteMessage("Started.");
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_NewsFeed";
|
|
Uri uri = Properties.Settings.Default.News_URL;
|
|
int interval = Properties.Settings.Default.News_Interval;
|
|
while (!bw_NewsFeed.CancellationPending)
|
|
{
|
|
if (Properties.Settings.Default.NewsFeed_Enabled)
|
|
{
|
|
try
|
|
{
|
|
// get the last modified time of the website
|
|
AutoDecompressionWebClient cl = new AutoDecompressionWebClient();
|
|
DateTime dt = cl.GetWebCreationTimeUtc(Properties.Settings.Default.News_URL);
|
|
Log.WriteMessage("Checking news page: " + dt.ToString("yyyy-MM-dd HH:mm:ss") + "<> " + Properties.Settings.Default.News_LastUpdate.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
Console.WriteLine("Checking news page: " + dt.ToString("yyyy-MM-dd HH:mm:ss") + "<> " + Properties.Settings.Default.News_LastUpdate.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
// report latest news if updated
|
|
if (dt > Properties.Settings.Default.News_LastUpdate)
|
|
{
|
|
// report news to main window
|
|
bw_NewsFeed.ReportProgress(1, dt);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// report error
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
bw_NewsFeed.ReportProgress(-1, DateTime.UtcNow.ToString("[" + "HH:mm:ss") + "] Error while reading the website " + uri.ToString() + ": " + ex.Message);
|
|
}
|
|
}
|
|
|
|
int i = 0;
|
|
while (!bw_NewsFeed.CancellationPending && (i < interval))
|
|
{
|
|
Thread.Sleep(1000);
|
|
i++;
|
|
}
|
|
}
|
|
Log.WriteMessage("Finished.");
|
|
}
|
|
|
|
private void bw_NewsFeed_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// report error
|
|
Say((string)e.UserState);
|
|
}
|
|
else
|
|
{
|
|
// stop background thread
|
|
while (bw_NewsFeed.IsBusy)
|
|
{
|
|
bw_NewsFeed.CancelAsync();
|
|
Application.DoEvents();
|
|
}
|
|
|
|
// report website changes
|
|
DateTime dt = (DateTime)e.UserState;
|
|
if (!SupportFunctions.IsMono)
|
|
{
|
|
if (MessageBox.Show("There are news on the website. Latest update: " + dt.ToString() + "\n Do you want to read it now?", "Website News", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
|
|
{
|
|
try
|
|
{
|
|
if (wb_News != null)
|
|
wb_News.Refresh();
|
|
tc_Map.SelectedTab = tp_News;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// do nothing if wb_News fails to refresh
|
|
}
|
|
}
|
|
// save time to settings
|
|
Properties.Settings.Default.News_LastUpdate = dt;
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("There are news on the website. Latest update: " + dt.ToString() + "\n Do you want to read it now?\n\n Under Linux/Mono open web browser of your choice and goto: \n" + Properties.Settings.Default.News_URL + "\n\n", "Website News", MessageBoxButtons.YesNo);
|
|
// save time to settings
|
|
Properties.Settings.Default.News_LastUpdate = dt;
|
|
|
|
}
|
|
|
|
// restart background thread
|
|
if (!bw_NewsFeed.IsBusy)
|
|
bw_NewsFeed.RunWorkerAsync();
|
|
}
|
|
}
|
|
|
|
private void bw_NewsFeed_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HistoryDownloader
|
|
|
|
private void HistoryDownloader_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
|
{
|
|
// get byte in GB
|
|
double bytesin = double.Parse(e.BytesReceived.ToString()) / 1024.0 / 1024.0 / 1024.0;
|
|
double totalbytes = double.Parse(e.TotalBytesToReceive.ToString()) / 1024.0 / 1024.0 / 1024.0;
|
|
double percentage = bytesin / totalbytes * 100;
|
|
try
|
|
{
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(1, "Downloaded " + bytesin.ToString("F2") + " GB of " + totalbytes.ToString("F2") + " GB (" + percentage.ToString("F2") + "%).");
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
private string ReadPropertyString(JObject o, string propertyname)
|
|
{
|
|
if (o.Property(propertyname) == null)
|
|
return null;
|
|
return o.Property(propertyname).Value.Value<string>();
|
|
}
|
|
|
|
private int ReadPropertyDoubleToInt(JObject o, string propertyname)
|
|
{
|
|
if (o.Property(propertyname) == null)
|
|
return int.MinValue;
|
|
double d = ReadPropertyDouble(o, propertyname);
|
|
if ((d != double.MinValue) && (d >= int.MinValue) && (d <= int.MaxValue))
|
|
return (int)d;
|
|
return int.MinValue;
|
|
}
|
|
|
|
private double ReadPropertyDouble(JObject o, string propertyname)
|
|
{
|
|
if (o.Property(propertyname) == null)
|
|
return double.MinValue;
|
|
return o.Property(propertyname).Value.Value<double>();
|
|
}
|
|
|
|
private long ReadPropertyLong(JObject o, string propertyname)
|
|
{
|
|
if (o.Property(propertyname) == null)
|
|
return long.MinValue;
|
|
return o.Property(propertyname).Value.Value<long>();
|
|
}
|
|
|
|
private void HistoryDownloader_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(1, "Reading " + Properties.Settings.Default.Analysis_History_ZIPFileName);
|
|
// unzip the file
|
|
if (File.Exists(Properties.Settings.Default.Analysis_History_ZIPFileName))
|
|
{
|
|
string filename = Properties.Settings.Default.Analysis_History_ZIPFileName;
|
|
// unzips a zip file content to the same directory
|
|
string downloaddir = Path.GetDirectoryName(Properties.Settings.Default.Analysis_History_ZIPFileName);
|
|
// set path to calling assembly's path if not otherwise specified
|
|
if (String.IsNullOrEmpty(downloaddir))
|
|
downloaddir = Assembly.GetCallingAssembly().Location;
|
|
// open the zip file
|
|
using (ZipFile zip = new ZipFile(filename))
|
|
{
|
|
zip.ZipErrorAction = ZipErrorAction.Skip;
|
|
// here, we extract every entry, but we could extract conditionally
|
|
// based on entry name, size, date, checkbox status, etc.
|
|
foreach (ZipEntry ze in zip)
|
|
{
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(1, "Extracting " + ze.FileName);
|
|
try
|
|
{
|
|
/*
|
|
ze.Extract(downloaddir, ExtractExistingFileAction.OverwriteSilently);
|
|
string fname = Path.Combine(downloaddir, ze.FileName);
|
|
File.SetLastWriteTime(fname, ze.LastModified);
|
|
*/
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(-1, ex.Message);
|
|
}
|
|
}
|
|
}
|
|
// create csv to load into database
|
|
using (StreamWriter sw = new StreamWriter(Properties.Settings.Default.Analysis_History_ZIPFileName.ToLower().Replace(".zip", ".csv")))
|
|
{
|
|
sw.WriteLine("time;call;reg;hex;lat;lon;track;alt;speed;squawk;radar;type");
|
|
// read all files
|
|
for (int i = 0; i < 1440; i += (int)Properties.Settings.Default.Analysis_History_Stepwidth)
|
|
{
|
|
// calculate filename
|
|
int hours = i / 60;
|
|
int minutes = i % 60;
|
|
string fname = Path.Combine(Properties.Settings.Default.Analysis_History_Directory, Properties.Settings.Default.Analysis_History_Date.ToString("yyyy-MM-dd") + "-" + hours.ToString("00") + minutes.ToString("00") + "Z.json");
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(1, "Processing " + fname);
|
|
if (File.Exists(fname))
|
|
{
|
|
string json = "";
|
|
using (StreamReader sr = new StreamReader(fname))
|
|
json = sr.ReadToEnd();
|
|
// analyze json string for planes data
|
|
JObject root = (JObject)JsonConvert.DeserializeObject(json);
|
|
foreach (JProperty proot in root.Children<JProperty>())
|
|
{
|
|
// get the planes position list
|
|
if (proot.Name == "acList")
|
|
{
|
|
foreach (JArray a in proot.Children<JArray>())
|
|
{
|
|
foreach (JObject o in a.Values<JObject>())
|
|
{
|
|
PlaneInfo info = new PlaneInfo();
|
|
try
|
|
{
|
|
info.Call = ReadPropertyString(o, "Call");
|
|
info.Lat = ReadPropertyDouble(o, "Lat");
|
|
info.Lon = ReadPropertyDouble(o, "Long");
|
|
info.Track = ReadPropertyDoubleToInt(o, "Trak");
|
|
// 2017-07-23: take "GAlt" (corrected altitude by air pressure) rather than "Alt"
|
|
info.Alt = ReadPropertyDoubleToInt(o, "GAlt");
|
|
// info.Alt = ReadPropertyDoubleToInt(o, "Alt");
|
|
info.Speed = ReadPropertyDoubleToInt(o, "Spd");
|
|
info.Reg = ReadPropertyString(o, "Reg");
|
|
try
|
|
{
|
|
string squawk = ReadPropertyString(o, "Sqk");
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
info.Hex = ReadPropertyString(o, "Icao");
|
|
info.Type = ReadPropertyString(o, "Type");
|
|
// complete type info
|
|
AircraftTypeDesignator td = AircraftData.Database.AircraftTypeFindByICAO(info.Type);
|
|
if (td != null)
|
|
{
|
|
info.Manufacturer = td.Manufacturer;
|
|
info.Model = td.Model;
|
|
info.Category = td.Category;
|
|
}
|
|
else
|
|
{
|
|
info.Manufacturer = "[unknown]";
|
|
info.Model = "[unknown]";
|
|
info.Category = PLANECATEGORY.NONE;
|
|
}
|
|
// CAUTION!! time is UNIX time in milliseconds
|
|
long l = ReadPropertyLong(o, "PosTime");
|
|
if (l != long.MinValue)
|
|
{
|
|
DateTime timestamp = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
timestamp = timestamp.AddMilliseconds(l);
|
|
info.Time = timestamp;
|
|
}
|
|
else
|
|
{
|
|
info.Time = DateTime.MinValue;
|
|
}
|
|
if (PlaneInfoChecker.Check(info) &&
|
|
(info.Alt_m >= Properties.Settings.Default.Planes_MinAlt) &&
|
|
(info.Alt_m <= Properties.Settings.Default.Planes_MaxAlt) &&
|
|
(info.Lat >= Properties.Settings.Default.MinLat) &&
|
|
(info.Lat <= Properties.Settings.Default.MaxLat) &&
|
|
(info.Lon >= Properties.Settings.Default.MinLon) &&
|
|
(info.Lon <= Properties.Settings.Default.MaxLon))
|
|
{
|
|
sw.WriteLine(info.Time.ToString("u") + ";" +
|
|
info.Call + ";" +
|
|
info.Reg + ";" +
|
|
info.Hex + ";" +
|
|
info.Lat.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
info.Lon.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
info.Track.ToString() + ";" +
|
|
info.Alt.ToString() + ";" +
|
|
info.Speed.ToString() + ";" +
|
|
"" + ";" +
|
|
"" + ";" +
|
|
info.Type);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (bw_HistoryDownloader.IsBusy)
|
|
bw_HistoryDownloader.ReportProgress(-1, ex.Message);
|
|
}
|
|
// job is done
|
|
// cancel backgroundworker
|
|
bw_HistoryDownloader.CancelAsync();
|
|
}
|
|
|
|
private void bw_HistoryDownloader_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_HistoryDownloader";
|
|
try
|
|
{
|
|
DateTime date = (DateTime)e.Argument;
|
|
// check history directory first
|
|
if (!Directory.Exists(Properties.Settings.Default.Analysis_History_Directory))
|
|
Properties.Settings.Default.Analysis_History_Directory = TmpDirectory;
|
|
// check free disk space
|
|
System.IO.DriveInfo drive = new System.IO.DriveInfo(Properties.Settings.Default.Analysis_History_Directory);
|
|
System.IO.DriveInfo a = new System.IO.DriveInfo(drive.Name);
|
|
if (a.AvailableFreeSpace < 50.0 * 1024.0 * 1024.0 * 1024.0)
|
|
throw new ArgumentException("Not enough disk space to run this operation.");
|
|
string url = Properties.Settings.Default.Analysis_History_URL;
|
|
Properties.Settings.Default.Analysis_History_ZIPFileName = Path.Combine(Properties.Settings.Default.Analysis_History_Directory, date.ToString("yyyy-MM-dd") + ".zip");
|
|
if (!File.Exists(Properties.Settings.Default.Analysis_History_ZIPFileName))
|
|
{
|
|
// file not found --> donwload it from url
|
|
// complete url with "/" and date
|
|
if (!url.EndsWith("/"))
|
|
url = url + "/";
|
|
url = url + date.ToString("yyyy-MM-dd") + ".zip";
|
|
// create web client for download
|
|
WebClient client = new WebClient();
|
|
// register asynchronous file download event handler
|
|
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(HistoryDownloader_DownloadProgressChanged);
|
|
client.DownloadFileCompleted += new AsyncCompletedEventHandler(HistoryDownloader_DownloadFileCompleted);
|
|
client.DownloadFileAsync(new Uri(url), Properties.Settings.Default.Analysis_History_ZIPFileName);
|
|
// remain here in a loop until job is finished
|
|
// cancellation will be initiated after download and unzip is complet
|
|
}
|
|
else
|
|
{ // call download completed handler directly
|
|
HistoryDownloader_DownloadFileCompleted(this, null);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
bw_HistoryDownloader.ReportProgress(-1, ex.Message);
|
|
}
|
|
}
|
|
|
|
private void bw_HistoryDownloader_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
string s = (string)e.UserState;
|
|
if (String.IsNullOrEmpty(s))
|
|
return;
|
|
tb_Analysis_Status.Text = s;
|
|
}
|
|
|
|
private void bw_HistoryDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
btn_Analysis_Planes_History.Enabled = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region ElevationDatabaseUpdater
|
|
|
|
private void bw_ElevationDatabaseUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// error message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 0)
|
|
{
|
|
// status message received
|
|
string msg = (string)e.UserState;
|
|
// redirect output to splash screen on first run
|
|
if (FirstRun && SplashDlg != null)
|
|
Splash("Preparing database for first run: " + msg + " (please wait)", Color.Yellow);
|
|
else
|
|
{
|
|
SayDatabase(msg);
|
|
Log.WriteMessage(msg);
|
|
}
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
// database status update message received
|
|
if (sender == this.bw_GLOBEUpdater)
|
|
{
|
|
Properties.Settings.Default.Elevation_GLOBE_DatabaseStatus = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.Elevation_GLOBE_DatabaseStatus);
|
|
if (tsl_Database_LED_GLOBE.BackColor != color)
|
|
tsl_Database_LED_GLOBE.BackColor = color;
|
|
string text = "GLOBE Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.Elevation_GLOBE_DatabaseStatus);
|
|
if (tsl_Database_LED_GLOBE.ToolTipText != text)
|
|
tsl_Database_LED_GLOBE.ToolTipText = text;
|
|
}
|
|
else if (sender == this.bw_SRTM3Updater)
|
|
{
|
|
Properties.Settings.Default.Elevation_SRTM3_DatabaseStatus = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.Elevation_SRTM3_DatabaseStatus);
|
|
if (tsl_Database_LED_SRTM3.BackColor != color)
|
|
tsl_Database_LED_SRTM3.BackColor = color;
|
|
string text = "SRTM3 Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.Elevation_SRTM3_DatabaseStatus);
|
|
if (tsl_Database_LED_SRTM3.ToolTipText != text)
|
|
tsl_Database_LED_SRTM3.ToolTipText = text;
|
|
}
|
|
else if (sender == this.bw_SRTM1Updater)
|
|
{
|
|
Properties.Settings.Default.Elevation_SRTM1_DatabaseStatus = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.Elevation_SRTM1_DatabaseStatus);
|
|
if (tsl_Database_LED_SRTM1.BackColor != color)
|
|
tsl_Database_LED_SRTM1.BackColor = color;
|
|
string text = "SRTM1 Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.Elevation_SRTM1_DatabaseStatus);
|
|
if (tsl_Database_LED_SRTM1.ToolTipText != text)
|
|
tsl_Database_LED_SRTM1.ToolTipText = text;
|
|
}
|
|
else if (sender == this.bw_ASTER3Updater)
|
|
{
|
|
Properties.Settings.Default.Elevation_ASTER3_DatabaseStatus = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.Elevation_ASTER3_DatabaseStatus);
|
|
if (tsl_Database_LED_ASTER3.BackColor != color)
|
|
tsl_Database_LED_ASTER3.BackColor = color;
|
|
string text = "ASTER3 Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.Elevation_ASTER3_DatabaseStatus);
|
|
if (tsl_Database_LED_ASTER3.ToolTipText != text)
|
|
tsl_Database_LED_ASTER3.ToolTipText = text;
|
|
}
|
|
else if (sender == this.bw_ASTER1Updater)
|
|
{
|
|
Properties.Settings.Default.Elevation_ASTER1_DatabaseStatus = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.Elevation_ASTER1_DatabaseStatus);
|
|
if (tsl_Database_LED_ASTER1.BackColor != color)
|
|
tsl_Database_LED_ASTER1.BackColor = color;
|
|
string text = "ASTER1 Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.Elevation_ASTER1_DatabaseStatus);
|
|
if (tsl_Database_LED_ASTER1.ToolTipText != text)
|
|
tsl_Database_LED_ASTER1.ToolTipText = text;
|
|
}
|
|
}
|
|
if (!this.Disposing && (ss_Main != null))
|
|
ss_Main.Update();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region ElevationPathCalculator
|
|
|
|
private void bw_ElevationPathCalculator_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage == 0)
|
|
SayCalculations((string)e.UserState);
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region StationDatabaseUpdater
|
|
|
|
private void bw_StationDatabaseUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// error message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 0)
|
|
{
|
|
// status message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg);
|
|
// redirect output to splash screen on first run
|
|
if (FirstRun && SplashDlg != null)
|
|
Splash("Preparing database for first run: " + msg + " (please wait)", Color.Yellow);
|
|
else
|
|
{
|
|
SayDatabase(msg);
|
|
}
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
Properties.Settings.Default.StationsDatabase_Status = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.StationsDatabase_Status);
|
|
if (tsl_Database_LED_Stations.BackColor != color)
|
|
tsl_Database_LED_Stations.BackColor = color;
|
|
string text = "Stations Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.StationsDatabase_Status);
|
|
if (tsl_Database_LED_Stations.ToolTipText != text)
|
|
tsl_Database_LED_Stations.ToolTipText = text;
|
|
}
|
|
if (!this.Disposing && (ss_Main != null))
|
|
ss_Main.Update();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void bw_StationDatabaseUpdater_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
// refresh display
|
|
if (!this.IsDisposed)
|
|
{
|
|
UpdateAirports();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AircraftDatabaseUpdater
|
|
|
|
private void bw_AircraftDatabaseUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// error message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 0)
|
|
{
|
|
// status message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg);
|
|
// redirect output to splash screen on first run
|
|
if (FirstRun && SplashDlg != null)
|
|
Splash("Preparing database for first run: " + msg + " (please wait)", Color.Yellow);
|
|
else
|
|
{
|
|
SayDatabase(msg);
|
|
}
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
Properties.Settings.Default.AircraftDatabase_Status = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.AircraftDatabase_Status);
|
|
if (tsl_Database_LED_Aircraft.BackColor != color)
|
|
{
|
|
tsl_Database_LED_Aircraft.BackColor = color;
|
|
}
|
|
string text = "Aircraft Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.AircraftDatabase_Status);
|
|
if (tsl_Database_LED_Aircraft.ToolTipText != text)
|
|
tsl_Database_LED_Aircraft.ToolTipText = text;
|
|
}
|
|
if (!this.Disposing && (ss_Main != null))
|
|
ss_Main.Update();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void bw_AircraftDatabaseUpdater_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
// refresh data tables and display
|
|
if (!this.IsDisposed)
|
|
{
|
|
// refresh all dictionnariees
|
|
// ScoutData.Database.UpdateFromDataTables(false);
|
|
// refresh airports and map
|
|
// UpdateAirports();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AircraftDatabaseMaintainer
|
|
|
|
private void bw_AircraftDatabaseMaintainer_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// error message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 0)
|
|
{
|
|
// status message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg);
|
|
// redirect output to splash screen on first run
|
|
if (FirstRun && SplashDlg != null)
|
|
Splash("Preparing database for first run: " + msg + " (please wait)", Color.Yellow);
|
|
else
|
|
{
|
|
SayDatabase(msg);
|
|
}
|
|
}
|
|
if (!this.Disposing && (ss_Main != null))
|
|
ss_Main.Update();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private void bw_AircraftDatabaseMaintainer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MapPreloader
|
|
|
|
private void bw_MapPreloader_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage == 0)
|
|
SayCalculations((string)e.UserState);
|
|
else
|
|
{
|
|
PointLatLng p = (PointLatLng)e.UserState;
|
|
SayCalculations("Preloading map tile: " + MaidenheadLocator.LocFromLatLon(p.Lat, p.Lng, false, 2) + ", level " + e.ProgressPercentage);
|
|
gm_Cache.Zoom = e.ProgressPercentage;
|
|
gm_Cache.Position = p;
|
|
gm_Cache.ReloadMap();
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region CATUpdater
|
|
|
|
private void bw_CATUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage < 0)
|
|
{
|
|
// error message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 0)
|
|
{
|
|
// status message received
|
|
string msg = (string)e.UserState;
|
|
Log.WriteMessage(msg);
|
|
// redirect output to splash screen on first run
|
|
if (FirstRun && SplashDlg != null)
|
|
Splash("Preparing database for first run: " + msg + " (please wait)", Color.Yellow);
|
|
else
|
|
{
|
|
SayDatabase(msg);
|
|
}
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
Properties.Settings.Default.RigDatabase_Status = (DATABASESTATUS)e.UserState;
|
|
Color color = DatabaseStatus.GetDatabaseStatusColor(Properties.Settings.Default.RigDatabase_Status);
|
|
if (tsl_Database_LED_Rig.BackColor != color)
|
|
{
|
|
tsl_Database_LED_Rig.BackColor = color;
|
|
}
|
|
string text = "Rig Database Status\n\n" + DatabaseStatus.GetDatabaseStatusText(Properties.Settings.Default.RigDatabase_Status);
|
|
if (tsl_Database_LED_Rig.ToolTipText != text)
|
|
tsl_Database_LED_Rig.ToolTipText = text;
|
|
}
|
|
if (!this.Disposing && (ss_Main != null))
|
|
ss_Main.Update();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region CAT
|
|
|
|
private void bw_CAT_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (e.ProgressPercentage <= 0)
|
|
{
|
|
Say((string)e.UserState);
|
|
}
|
|
else if (e.ProgressPercentage == 1)
|
|
{
|
|
// new rig status received
|
|
RIGSTATUS status = (RIGSTATUS)e.UserState;
|
|
switch (status)
|
|
{
|
|
case RIGSTATUS.ONLINE:
|
|
SayCAT("CAT", Color.White, Color.DarkGreen);
|
|
break;
|
|
case RIGSTATUS.ERROR:
|
|
case RIGSTATUS.NOCAT:
|
|
case RIGSTATUS.NOPORT:
|
|
case RIGSTATUS.NORIG:
|
|
case RIGSTATUS.NOTSUITABLE:
|
|
SayCAT("CAT", Color.Yellow, Color.Red);
|
|
break;
|
|
case RIGSTATUS.OFFLINE:
|
|
SayCAT("CAT", Color.White, Color.DarkOrange);
|
|
break;
|
|
default:
|
|
SayCAT("CAT", Color.DarkGray, SystemColors.Control);
|
|
break;
|
|
}
|
|
|
|
RigStatus = status;
|
|
}
|
|
else if (e.ProgressPercentage == 2)
|
|
{
|
|
// new rig info received
|
|
IRig rig = (IRig)e.UserState;
|
|
|
|
// save info if a valid tracking is not going on
|
|
if (TrackStatus != TRACKSTATUS.TRACKING)
|
|
{
|
|
if (rig != null)
|
|
{
|
|
ConnectedRig = rig;
|
|
// save latest rig settings to switch back after tracking
|
|
Properties.Settings.Default.Doppler_DialFreq = rig.GetRxFrequency();
|
|
Properties.Settings.Default.Doppler_DialMode = rig.GetMode();
|
|
Properties.Settings.Default.Doppler_DialSplit = rig.GetSplit();
|
|
Properties.Settings.Default.Doppler_DialRit = rig.GetRit();
|
|
}
|
|
}
|
|
|
|
// report to status bar
|
|
NumberFormatInfo info = new NumberFormatInfo();
|
|
info.NumberDecimalSeparator = ";";
|
|
info.NumberGroupSeparator = ".";
|
|
Say("Rig reports RX: " + rig.GetRxFrequency().ToString(info) + ", TX: " + rig.GetTxFrequency().ToString(info) + "Hz, Mode: " + rig.GetMode().ToString() + ", RIT: " + ((rig.GetRit() == RIGRIT.RITON) ? "ON" : "OFF") + ", Split: " + ((rig.GetSplit() == RIGSPLIT.SPLITON) ? "ON" : "OFF"));
|
|
}
|
|
|
|
// set Tooltip
|
|
if (ConnectedRig != null)
|
|
{
|
|
tsl_CAT.ToolTipText = ConnectedRig.CatVersion + "\n" + ConnectedRig.Settings.Type + "\n\n";
|
|
}
|
|
else
|
|
{
|
|
tsl_CAT.ToolTipText = "CAT error!" + "\n\n";
|
|
}
|
|
tsl_CAT.ToolTipText = tsl_CAT.ToolTipText + RigStatus.ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RigStatus = RIGSTATUS.ERROR;
|
|
tsl_CAT.ToolTipText = "CAT error: " + ex.Message;
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
#region Analysis_DataGetter
|
|
|
|
private void bw_Analysis_DataGetter_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_Analysis_DataGetter";
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
bw_Analysis_DataGetter.ReportProgress(0, "Getting timespan of all positions in database...");
|
|
// calculate min/max values for timespan
|
|
History_OldestEntry = AircraftPositionData.Database.AircraftPositionOldestEntry();
|
|
if (bw_Analysis_DataGetter.CancellationPending)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
History_YoungestEntry = AircraftPositionData.Database.AircraftPositionYoungestEntry();
|
|
if (bw_Analysis_DataGetter.CancellationPending)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
bw_Analysis_DataGetter.ReportProgress(0, "Getting positions...");
|
|
AircraftPositionsCount = AircraftPositionData.Database.AircraftPositionCount();
|
|
// get all aircraft positions into cache
|
|
lock (AllPositions)
|
|
{
|
|
AllPositions.Clear();
|
|
}
|
|
lock (AllPositions)
|
|
{
|
|
// get all positions from database, can be interrupted
|
|
AllPositions = AircraftPositionData.Database.AircraftPositionGetAll(this.bw_Analysis_DataGetter);
|
|
if (bw_Analysis_DataGetter.CancellationPending)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
}
|
|
st.Stop();
|
|
bw_Analysis_DataGetter.ReportProgress(0, "Getting positions finished, " + AllPositions.Count.ToString() + " positions, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
|
|
private void bw_Analysis_DataGetter_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage == 0)
|
|
{
|
|
string msg = (string)e.UserState;
|
|
// NASTY!! Add the total count of positions after the "of" in the message
|
|
// total count is calculated once in DoWork
|
|
if (msg.EndsWith("of)"))
|
|
msg = msg + " " + AircraftPositionsCount.ToString();
|
|
SayAnalysis(msg);
|
|
}
|
|
}
|
|
|
|
private void bw_Analysis_DataGetter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
// check if cancelled
|
|
// return to default state
|
|
if (e.Cancelled)
|
|
{
|
|
SayAnalysis("Cancelled.");
|
|
btn_Analysis_ON.Enabled = true;
|
|
btn_Analysis_ON.BackColor = Color.YellowGreen;
|
|
return;
|
|
}
|
|
else
|
|
SayAnalysis("Ready.");
|
|
// nothing found in database --> show message box and do not enter analysis mode
|
|
if ((History_YoungestEntry == DateTime.MinValue) || (History_OldestEntry == DateTime.MinValue))
|
|
{
|
|
MessageBox.Show("Nothing found for analysis. Please let AirScout run in PLAY mode for a while to collect some data.", "AirScout Analysis", MessageBoxButtons.OK);
|
|
return;
|
|
}
|
|
// set scroll bar bounds
|
|
dtp_Analysis_MinValue.Value = History_OldestEntry;
|
|
dtp_Analysis_MaxValue.Value = History_YoungestEntry;
|
|
// enable buttons
|
|
btn_Analysis_Planes_Load.Enabled = true;
|
|
btn_Analysis_Planes_Save.Enabled = true;
|
|
btn_Analysis_Planes_Clear.Enabled = true;
|
|
btn_Analysis_Planes_History.Enabled = true;
|
|
btn_Analysis_Planes_ShowTraffic.Enabled = true;
|
|
btn_Analysis_Path_SaveToFile.Enabled = true;
|
|
btn_Analysis_CrossingHistory.Enabled = true;
|
|
btn_Analysis_Plane_History.Enabled = true;
|
|
btn_Analysis_Rewind.Enabled = true;
|
|
btn_Analysis_Back.Enabled = true;
|
|
btn_Analysis_Pause.Enabled = true;
|
|
btn_Analysis_Forward.Enabled = true;
|
|
btn_Analysis_FastForward.Enabled = true;
|
|
sb_Analysis_Play.Enabled = true;
|
|
dtp_Analysis_MinValue.Enabled = true;
|
|
dtp_Analysis_MaxValue.Enabled = true;
|
|
UpdatePlayer();
|
|
// set time to oldest entry
|
|
Properties.Settings.Default.Time_Offline = History_OldestEntry;
|
|
gb_Analysis_Player_SizeChanged(this, null);
|
|
UpdatePaths();
|
|
UpdateStatus();
|
|
btn_Analysis_Planes_Load.Focus();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Analysis_FileSaver
|
|
|
|
|
|
private void Analysis_Planes_Save_JSON(string filename)
|
|
{
|
|
int saved = 0;
|
|
using (StreamWriter sw = new StreamWriter(filename))
|
|
{
|
|
sw.WriteLine("[");
|
|
for (int i = 0; i < AllPositions.Count; i++)
|
|
{
|
|
if (AllPositions[i].LastUpdated < dtp_Analysis_MinValue.Value)
|
|
continue;
|
|
if (AllPositions[i].LastUpdated > dtp_Analysis_MaxValue.Value)
|
|
continue;
|
|
string json = AllPositions[i].ToJSON();
|
|
sw.Write(json);
|
|
if (i < AllPositions.Count - 1)
|
|
{
|
|
sw.WriteLine(",");
|
|
}
|
|
else
|
|
sw.WriteLine();
|
|
saved++;
|
|
if (saved % 1000 == 0)
|
|
bw_Analysis_FileSaver.ReportProgress(0, "Saving position " + saved.ToString() + "...");
|
|
if (bw_Analysis_FileSaver.CancellationPending)
|
|
return;
|
|
}
|
|
sw.WriteLine("]");
|
|
}
|
|
}
|
|
|
|
private void Analysis_Planes_Save_CSV(string filename)
|
|
{
|
|
int saved = 0;
|
|
using (StreamWriter sw = new StreamWriter(filename))
|
|
{
|
|
sw.WriteLine("time[utc];hex;call;lat[deg];lon[deg];alt[ft];track[deg];speed[kts]");
|
|
foreach (AircraftPositionDesignator ap in AllPositions)
|
|
{
|
|
if (ap.LastUpdated < dtp_Analysis_MinValue.Value)
|
|
continue;
|
|
if (ap.LastUpdated > dtp_Analysis_MaxValue.Value)
|
|
continue;
|
|
sw.WriteLine(ap.LastUpdated.ToString("yyyy-MM-dd HH:mm:ssZ") + ";" +
|
|
ap.Hex + ";" +
|
|
ap.Call + ";" +
|
|
ap.Lat.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
ap.Lon.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
ap.Alt.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
ap.Track.ToString("F8", CultureInfo.InvariantCulture) + ";" +
|
|
ap.Speed.ToString("F8", CultureInfo.InvariantCulture)
|
|
);
|
|
saved++;
|
|
if (saved % 1000 == 0)
|
|
bw_Analysis_FileSaver.ReportProgress(0, "Saving position " + saved.ToString() + "...");
|
|
if (bw_Analysis_FileSaver.CancellationPending)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bw_Analysis_FileSaver_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
string filename = (string)e.Argument;
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_Analysis_FileSaver";
|
|
try
|
|
{
|
|
if (filename.ToLower().EndsWith(".json"))
|
|
Analysis_Planes_Save_JSON(filename);
|
|
else if (filename.ToLower().EndsWith(".csv"))
|
|
Analysis_Planes_Save_CSV(filename);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
bw_Analysis_FileSaver.ReportProgress(-1, ex.Message);
|
|
}
|
|
if (bw_Analysis_FileSaver.CancellationPending)
|
|
e.Cancel = true;
|
|
}
|
|
|
|
private void bw_Analysis_FileSaver_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage <= 0)
|
|
SayAnalysis((string)e.UserState);
|
|
}
|
|
|
|
private void bw_Analysis_FileSaver_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
if (e.Cancelled)
|
|
SayAnalysis("Cancelled.");
|
|
else
|
|
{
|
|
btn_Analysis_Planes_Save.Enabled = true;
|
|
SayAnalysis("Ready.");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Analysis_FileLoader
|
|
|
|
private void Analysis_Planes_Load_JSON(string filename)
|
|
{
|
|
JsonSerializerSettings settings = new JsonSerializerSettings();
|
|
settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
|
|
settings.FloatFormatHandling = FloatFormatHandling.String;
|
|
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
|
|
settings.Culture = CultureInfo.InvariantCulture;
|
|
List<AircraftPositionDesignator> aps = new List<AircraftPositionDesignator>();
|
|
bw_Analysis_FileLoader.ReportProgress(0, "Opening file...");
|
|
using (StreamReader sr = new StreamReader(File.Open(filename, FileMode.Open)))
|
|
{
|
|
// check for starting bracket of array
|
|
char c = (char)sr.Read();
|
|
if (c != '[')
|
|
return;
|
|
// read 1000 positions and update database
|
|
int count = 0;
|
|
int updated = 0;
|
|
while (!sr.EndOfStream)
|
|
{
|
|
aps.Clear();
|
|
int j = 0;
|
|
while ((j < 1000) && !sr.EndOfStream)
|
|
{
|
|
char nextChar;
|
|
StringBuilder line = new StringBuilder();
|
|
while ((j < 1000) && sr.Peek() > 0)
|
|
{
|
|
nextChar = (char)sr.Read();
|
|
line.Append(nextChar);
|
|
if (line[0] != '{')
|
|
line.Clear();
|
|
if (nextChar == '}')
|
|
{
|
|
AircraftPositionDesignator ap = JsonConvert.DeserializeObject<AircraftPositionDesignator>(line.ToString(), settings);
|
|
line.Clear();
|
|
aps.Add(ap);
|
|
j++;
|
|
}
|
|
}
|
|
if (bw_Analysis_FileLoader.CancellationPending)
|
|
return;
|
|
}
|
|
count = count + j;
|
|
updated = updated + AircraftPositionData.Database.AircraftPositionBulkInsertOrUpdateIfNewer(aps);
|
|
bw_Analysis_FileLoader.ReportProgress(0, "Updating position " + count.ToString() + ", " + updated.ToString() + " updated so far...");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void Analysis_Planes_Load_CSV(string filename)
|
|
{
|
|
List<AircraftPositionDesignator> aps = new List<AircraftPositionDesignator>();
|
|
bw_Analysis_FileLoader.ReportProgress(0, "Opening file...");
|
|
using (StreamReader sr = new StreamReader(File.Open(filename, FileMode.Open)))
|
|
{
|
|
// read header
|
|
string header = sr.ReadLine();
|
|
// split header
|
|
string[] a = header.Split(';');
|
|
// remove unit brackets and lower all
|
|
for (int i = 0; i < a.Length; i++)
|
|
{
|
|
a[i] = a[i].ToLower();
|
|
if (a[i].IndexOf('[') >= 0)
|
|
a[i] = a[i].Substring(0, a[i].IndexOf('['));
|
|
}
|
|
int lastupdated_index = Array.IndexOf(a, "time");
|
|
int hex_index = Array.IndexOf(a, "hex");
|
|
int call_index = Array.IndexOf(a, "call");
|
|
int lat_index = Array.IndexOf(a, "lat");
|
|
int lon_index = Array.IndexOf(a, "lon");
|
|
int alt_index = Array.IndexOf(a, "alt");
|
|
int track_index = Array.IndexOf(a, "track");
|
|
int speed_index = Array.IndexOf(a, "speed");
|
|
bw_Analysis_FileLoader.ReportProgress(0, "Creating position list...");
|
|
// read 1000 positions and update database
|
|
int count = 0;
|
|
int updated = 0;
|
|
while (!sr.EndOfStream)
|
|
{
|
|
aps.Clear();
|
|
int j = 0;
|
|
while ((j < 1000) && !sr.EndOfStream)
|
|
{
|
|
string s = sr.ReadLine();
|
|
if (!s.Contains(";"))
|
|
continue;
|
|
a = s.Split(';');
|
|
DateTime lastupdated = System.Convert.ToDateTime(a[lastupdated_index]).ToUniversalTime();
|
|
string hex = a[hex_index].ToUpper();
|
|
string call = a[call_index].ToUpper();
|
|
double lat = System.Convert.ToDouble(a[lat_index], CultureInfo.InvariantCulture);
|
|
double lon = System.Convert.ToDouble(a[lon_index], CultureInfo.InvariantCulture);
|
|
double alt = System.Convert.ToDouble(a[alt_index], CultureInfo.InvariantCulture);
|
|
double track = System.Convert.ToDouble(a[track_index], CultureInfo.InvariantCulture);
|
|
double speed = System.Convert.ToDouble(a[speed_index], CultureInfo.InvariantCulture);
|
|
AircraftPositionDesignator ap = new AircraftPositionDesignator(hex, call, lat, lon, alt, track, speed, lastupdated);
|
|
aps.Add(ap);
|
|
j++;
|
|
if (bw_Analysis_FileLoader.CancellationPending)
|
|
return;
|
|
}
|
|
count = count + j;
|
|
updated = updated + AircraftPositionData.Database.AircraftPositionBulkInsertOrUpdateIfNewer(aps);
|
|
bw_Analysis_FileLoader.ReportProgress(0, "Updating position " + count.ToString() + ", " + updated.ToString() + " updated so far...");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private void bw_Analysis_FileLoader_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
string filename = (string)e.Argument;
|
|
// name the thread for debugging
|
|
if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
|
|
Thread.CurrentThread.Name = "bw_Analysis_FileLoader";
|
|
try
|
|
{
|
|
if (filename.ToLower().EndsWith(".json"))
|
|
Analysis_Planes_Load_JSON(filename);
|
|
else if (filename.ToLower().EndsWith(".csv"))
|
|
Analysis_Planes_Load_CSV(filename);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.WriteMessage(ex.ToString(), LogLevel.Error);
|
|
bw_Analysis_FileLoader.ReportProgress(-1, ex.Message);
|
|
}
|
|
if (bw_Analysis_FileLoader.CancellationPending)
|
|
e.Cancel = true;
|
|
}
|
|
|
|
private void bw_Analysis_FileLoader_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage <= 0)
|
|
SayAnalysis((string)e.UserState);
|
|
}
|
|
|
|
private void bw_Analysis_FileLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
if (e.Cancelled)
|
|
SayAnalysis("Cancelled.");
|
|
else
|
|
{
|
|
btn_Analysis_Planes_Load.Enabled = true;
|
|
SayAnalysis("Ready.");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region AirportMapper
|
|
|
|
private void bw_AirportMapper_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
bw_AirportMapper.ReportProgress(0, "Getting airports from database...");
|
|
Stopwatch st = new Stopwatch();
|
|
st.Start();
|
|
// fill the airports layer of maps
|
|
// return if switched off
|
|
if (!Properties.Settings.Default.Airports_Activate)
|
|
return;
|
|
List<AirportDesignator> airports = new List<AirportDesignator>();
|
|
airports = AircraftData.Database.AirportGetAll(bw_AirportMapper);
|
|
if (airports != null)
|
|
bw_AirportMapper.ReportProgress(100, airports);
|
|
st.Stop();
|
|
bw_AirportMapper.ReportProgress(0, airports.Count.ToString() + " airports updated, " + st.ElapsedMilliseconds.ToString() + " ms.");
|
|
}
|
|
|
|
private void bw_AirportMapper_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
if (e.ProgressPercentage == 0)
|
|
{
|
|
// log error message
|
|
string msg = (string)e.UserState;
|
|
Say(msg);
|
|
Log.WriteMessage(msg, LogLevel.Error);
|
|
}
|
|
else if (e.ProgressPercentage == 100)
|
|
{
|
|
// add aiports to overlay
|
|
lock (Airports)
|
|
{
|
|
Airports = (List<AirportDesignator>)e.UserState;
|
|
}
|
|
UpdateAirports();
|
|
}
|
|
}
|
|
|
|
private void bw_AirportMapper_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void gm_Main_Load(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void tc_Main_Selecting(object sender, TabControlCancelEventArgs e)
|
|
{
|
|
// cancel tab change when in PLAY mode
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
e.Cancel = true;
|
|
}
|
|
|
|
private void tc_Map_Selecting(object sender, TabControlCancelEventArgs e)
|
|
{
|
|
// cancel tab change when in PLAY mode
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
e.Cancel = true;
|
|
}
|
|
|
|
private void tc_Control_Selecting(object sender, TabControlCancelEventArgs e)
|
|
{
|
|
// cancel tab change when in PLAY mode
|
|
if (PlayMode == AIRSCOUTPLAYMODE.FORWARD)
|
|
e.Cancel = true;
|
|
}
|
|
}
|
|
|
|
|
|
public class ClippingToolStripRenderer : ToolStripSystemRenderer
|
|
{
|
|
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
|
{
|
|
ToolStripStatusLabel label = e.Item as ToolStripStatusLabel;
|
|
|
|
if (label != null)
|
|
{
|
|
TextRenderer.DrawText(e.Graphics, label.Text,
|
|
label.Font, e.TextRectangle,
|
|
label.ForeColor,
|
|
TextFormatFlags.EndEllipsis);
|
|
}
|
|
else
|
|
{
|
|
base.OnRenderItemText(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class LocatorDropDownItem
|
|
{
|
|
public string Locator { get; set; }
|
|
public LatLon.GPoint GeoLocation { get; set; }
|
|
|
|
public LocatorDropDownItem(string locator, LatLon.GPoint geolocation)
|
|
{
|
|
Locator = locator;
|
|
GeoLocation = geolocation;
|
|
}
|
|
}
|
|
|
|
}
|