// 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 . 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> LazyPlaneFeedPlugins = new List>(); public List PlaneFeedPlugins = new List(); // 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 ActivePlanes = new SortedList(); private DateTime History_OldestEntry = DateTime.MinValue; private DateTime History_YoungestEntry = DateTime.MinValue; private List SelectedPlanes = new List(); // Path public List ElevationPaths = new List(); public List PropagationPaths = new List(); // 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 AllLastUpdated = new List(); private List AllPositions = new List(); private long AircraftPositionsCount = 0; // Nearest plane private PlaneInfo NearestPlane = null; // Airports private List Airports = new List(); // 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 // after that, try to call each plugin's constructor and collect "clean" plugins in a separate list for further use try { List catalog = new List(); 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 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."); } /// /// Returns the default value of a property /// /// The property name. /// The property value. 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(); 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 l = new List(); 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 props = JsonConvert.DeserializeObject>(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 props = new Dictionary(); 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 { /// /// Hides the window and activates another window. /// Hide = 0, /// /// 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. /// Normal = 1, /// /// Activates the window and displays it as a minimized window. /// ShowMinimized = 2, /// /// Maximizes the specified window. /// Maximize = 3, // is this the right value? /// /// Activates the window and displays it as a maximized window. /// ShowMaximized = 3, /// /// Displays a window in its most recent size and position. This value /// is similar to , except /// the window is not activated. /// ShowNoActivate = 4, /// /// Activates the window and displays it in its current size and position. /// Show = 5, /// /// Minimizes the specified window and activates the next top-level /// window in the Z order. /// Minimize = 6, /// /// Displays the window as a minimized window. This value is similar to /// , except the /// window is not activated. /// ShowMinNoActive = 7, /// /// Displays the window in its current size and position. This value is /// similar to , except the /// window is not activated. /// ShowNA = 8, /// /// 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. /// Restore = 9, /// /// 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. /// ShowDefault = 10, /// /// Windows 2000/XP: 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. /// 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 pathplanes = new List(); // check if any plane is on list --> return empty list if ((ActivePlanes == null) || (ActivePlanes.Count == 0)) return; bool anyselected = false; List planes_hi = new List(); List planes_lo = new List(); // 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 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 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 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 dxcalls = new List(); 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 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 checkedcalls = new List(); 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 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(); } 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 planes = (List)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 allplanes = Planes.GetAll(DateTime.UtcNow, Properties.Settings.Default.Planes_Position_TTL); List 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 ads = new List(); 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(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: , 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 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(); } 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(); } private long ReadPropertyLong(JObject o, string propertyname) { if (o.Property(propertyname) == null) return long.MinValue; return o.Property(propertyname).Value.Value(); } 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()) { // get the planes position list if (proot.Name == "acList") { foreach (JArray a in proot.Children()) { foreach (JObject o in a.Values()) { 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 aps = new List(); 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(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 aps = new List(); 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 airports = new List(); 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)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; } } }