2019-03-19 21:09:03 +00:00
// AirScout Aircraft Scatter Prediction
// Copyright (C) DL2ALF
/ /
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
/ /
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
/ /
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Data ;
using System.Drawing ;
using System.Drawing.Drawing2D ;
using System.Drawing.Imaging ;
using System.Linq ;
using System.Text ;
using System.Windows ;
using System.Windows.Forms ;
using System.Windows.Forms.VisualStyles ;
using GMap.NET ;
using GMap.NET.MapProviders ;
using GMap.NET.WindowsForms ;
using GMap.NET.WindowsForms.Markers ;
using GMap.NET.WindowsForms.ToolTips ;
using System.IO ;
using System.IO.Ports ;
using System.Net ;
using System.Net.Sockets ;
using System.Threading ;
using Zeptomoby.OrbitTools ;
using System.Globalization ;
using System.Runtime.InteropServices ;
using System.Reflection ;
using System.Configuration ;
using WinTest ;
using System.Diagnostics ;
using AquaControls ;
using NDde ;
using NDde.Server ;
using NDde.Client ;
using ScoutBase ;
using ScoutBase.Core ;
2020-02-12 10:45:19 +00:00
using ScoutBase.Database ;
2019-03-19 21:09:03 +00:00
using ScoutBase.Elevation ;
using ScoutBase.Stations ;
using ScoutBase.Propagation ;
2020-04-10 15:36:18 +00:00
using ScoutBase.Maps ;
2021-12-31 08:08:48 +00:00
using ScoutBase.CAT ;
2019-03-19 21:09:03 +00:00
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 ;
2020-02-12 10:45:19 +00:00
using System.ComponentModel.Composition ;
using System.ComponentModel.Composition.Hosting ;
2019-03-19 21:09:03 +00:00
using OxyPlot ;
using OxyPlot.WindowsForms ;
using OxyPlot.Series ;
using OxyPlot.Axes ;
using System.Data.SQLite ;
2020-02-12 10:45:19 +00:00
using DeviceId ;
2020-03-01 15:12:08 +00:00
using AirScout.Properties ;
2020-02-12 10:45:19 +00:00
using AirScout.Core ;
using AirScout.Aircrafts ;
using AirScout.PlaneFeeds ;
2019-03-19 21:09:03 +00:00
using AirScout.AircraftPositions ;
using AirScout.Signals ;
2020-02-12 10:45:19 +00:00
using AirScout.PlaneFeeds.Plugin.MEFContract ;
2021-12-31 08:08:48 +00:00
using AirScout.CAT ;
using System.Security.RightsManagement ;
2023-01-30 06:00:58 +00:00
using System.Web ;
2019-03-19 21:09:03 +00:00
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 ) ;
2020-02-12 10:45:19 +00:00
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 ;
}
}
2021-12-31 08:08:48 +00:00
[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 ;
}
}
2023-01-30 06:00:58 +00:00
[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" ) ;
}
}
2020-02-12 10:45:19 +00:00
[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 ;
2020-03-01 15:12:08 +00:00
Console . WriteLine ( "Setting MainSplitterDistance: " + this . Width + "--->" + sc_Main . SplitterDistance ) ;
2019-03-19 21:09:03 +00:00
}
}
2020-02-12 10:45:19 +00:00
[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 ;
2020-03-01 15:12:08 +00:00
Console . WriteLine ( "Setting MapSplitterDistance: " + this . Height + "--->" + sc_Map . SplitterDistance ) ;
2020-02-12 10:45:19 +00:00
}
}
[ImportMany(AllowRecomposition = true)] // This is a signal to the MEF framework to load all matching exported assemblies.
public List < Lazy < IPlaneFeedPlugin > > LazyPlaneFeedPlugins = new List < Lazy < IPlaneFeedPlugin > > ( ) ;
public List < IPlaneFeedPlugin > PlaneFeedPlugins = new List < IPlaneFeedPlugin > ( ) ;
2021-12-31 08:08:48 +00:00
// Default colors
private readonly new Color DefaultBackColor = SystemColors . Control ;
private readonly new Color DefaultForeColor = Color . Black ;
2020-02-12 10:45:19 +00:00
// Log
2019-03-19 21:09:03 +00:00
public static LogWriter Log ;
public VarConverter VC = new VarConverter ( ) ;
private int cntdn = 0 ;
DateTime CurrentTime = DateTime . UtcNow ;
// FlightRadar
PlaneInfoCache Planes = new PlaneInfoCache ( ) ;
SortedList < string , PlaneInfo > ActivePlanes = new SortedList < string , PlaneInfo > ( ) ;
private DateTime History_OldestEntry = DateTime . MinValue ;
private DateTime History_YoungestEntry = DateTime . MinValue ;
private List < string > SelectedPlanes = new List < string > ( ) ;
// Path
public List < ElevationPathDesignator > ElevationPaths = new List < ElevationPathDesignator > ( ) ;
public List < PropagationPathDesignator > PropagationPaths = new List < PropagationPathDesignator > ( ) ;
// Map
// Overlays
GMapOverlay gmo_Routes = new GMapOverlay ( "Routes" ) ;
GMapOverlay gmo_PropagationPaths = new GMapOverlay ( "PropagationPaths" ) ;
GMapOverlay gmo_Objects = new GMapOverlay ( "Objects" ) ;
GMapOverlay gmo_Planes = new GMapOverlay ( "Planes" ) ;
GMapOverlay gmo_Airports = new GMapOverlay ( "Airports" ) ;
GMapOverlay gmo_Callsigns = new GMapOverlay ( "Callsigns" ) ;
GMapOverlay gmo_NearestPaths = new GMapOverlay ( "PropagationPaths" ) ;
GMapOverlay gmo_NearestPlanes = new GMapOverlay ( "Planes" ) ;
2021-12-31 08:08:48 +00:00
GMapOverlay gmo_Locators = new GMapOverlay ( "Locators" ) ;
GMapOverlay gmo_Distances = new GMapOverlay ( "Distances" ) ;
2022-08-27 12:13:47 +00:00
GMapOverlay gmo_CallsignDetails = new GMapOverlay ( "CallsignDetails" ) ;
2019-03-19 21:09:03 +00:00
// 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 ;
2021-12-31 08:08:48 +00:00
// dragging
bool isDraggingMarker = false ;
bool isDraggingMap = false ;
2020-02-12 10:45:19 +00:00
// 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 ;
2019-03-19 21:09:03 +00:00
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 ;
2020-04-10 15:36:18 +00:00
private Splash SplashDlg ;
2019-03-19 21:09:03 +00:00
// Background workers
public ElevationDatabaseUpdater bw_GLOBEUpdater = new ElevationDatabaseUpdater ( ) ;
public ElevationDatabaseUpdater bw_SRTM3Updater = new ElevationDatabaseUpdater ( ) ;
public ElevationDatabaseUpdater bw_SRTM1Updater = new ElevationDatabaseUpdater ( ) ;
2020-04-25 06:00:15 +00:00
public ElevationDatabaseUpdater bw_ASTER3Updater = new ElevationDatabaseUpdater ( ) ;
public ElevationDatabaseUpdater bw_ASTER1Updater = new ElevationDatabaseUpdater ( ) ;
2019-03-19 21:09:03 +00:00
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 ) ;
2020-04-25 06:00:15 +00:00
public PathCalculator bw_ASTER3PathCalculator = new PathCalculator ( ELEVATIONMODEL . ASTER3 ) ;
public PathCalculator bw_ASTER1PathCalculator = new PathCalculator ( ELEVATIONMODEL . ASTER1 ) ;
2019-03-19 21:09:03 +00:00
2021-12-31 08:08:48 +00:00
public CATUpdater bw_CATUpdater = new CATUpdater ( ) ;
public CATWorker bw_CAT = new CATWorker ( ) ;
2020-04-10 15:36:18 +00:00
public MapPreloader bw_MapPreloader = new MapPreloader ( ) ;
2020-02-12 10:45:19 +00:00
// Operating modes
2019-03-19 21:09:03 +00:00
AIRSCOUTPATHMODE PathMode = AIRSCOUTPATHMODE . NONE ;
AIRSCOUTLIFEMODE LifeMode = AIRSCOUTLIFEMODE . NONE ;
AIRSCOUTPLAYMODE PlayMode = AIRSCOUTPLAYMODE . NONE ;
private int Time_Offline_Interval = 0 ;
2020-02-12 10:45:19 +00:00
// Charting
2019-03-19 21:09:03 +00:00
// 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 ;
2020-02-12 10:45:19 +00:00
// Webbrowser
2019-03-19 21:09:03 +00:00
private System . Windows . Forms . WebBrowser wb_News = null ;
CultureInfo LocalCulture ;
// Watchlist control
private bool WatchlistUpdating = false ;
private bool WatchlistAllCheckedChanging = false ;
bool WatchlistAllChecked = false ;
CheckBoxState WatchlistAllCheckedState = CheckBoxState . UncheckedNormal ;
System . Drawing . Point WatchlistOldMousePos = new System . Drawing . Point ( 0 , 0 ) ;
// Analysis
private List < DateTime > AllLastUpdated = new List < DateTime > ( ) ;
private List < AircraftPositionDesignator > AllPositions = new List < AircraftPositionDesignator > ( ) ;
private long AircraftPositionsCount = 0 ;
2020-02-12 10:45:19 +00:00
// Nearest plane
2019-03-19 21:09:03 +00:00
private PlaneInfo NearestPlane = null ;
// Airports
private List < AirportDesignator > Airports = new List < AirportDesignator > ( ) ;
2020-02-12 10:45:19 +00:00
// Session key
public string SessionKey = "" ;
2021-12-31 08:08:48 +00:00
// 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 ;
2022-08-27 12:13:47 +00:00
// Gauges display
public Color GaugesColor = Color . Black ;
public Font TrackDisplayFont = new Font ( "Courier New" , 16 , FontStyle . Bold ) ;
2021-12-31 08:08:48 +00:00
2022-08-27 12:13:47 +00:00
// Location grid updating
public bool UpdateLocationGrid = false ;
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
#region Startup & Initialization
public MapDlg ( )
{
// save current local LocalCulture
LocalCulture = Application . CurrentCulture ;
// force culture invariant language for GUI
Application . CurrentCulture = CultureInfo . InvariantCulture ;
2020-04-25 06:00:15 +00:00
// 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
2019-03-19 21:09:03 +00:00
InitializeComponent ( ) ;
2022-08-27 12:13:47 +00:00
// 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." ) ;
}
2019-03-19 21:09:03 +00:00
// do basic initialization
2020-02-12 10:45:19 +00:00
this . Text = "AirScout - Aircraft Scatter Prediction V" + Application . ProductVersion + " (c) 2013-2020 DL2ALF" ;
2019-03-19 21:09:03 +00:00
// create a new renderer wich is clipping the status text on overflow
ss_Main . Renderer = new ClippingToolStripRenderer ( ) ;
// initialize settings
InitializeSettings ( ) ;
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
// initialize charting
InitializeCharts ( ) ;
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
// 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 )
2020-04-10 15:36:18 +00:00
{
// re-initialize settings as they can be lost during clean-up
InitializeSettings ( ) ;
// set a clean run flag
2019-03-19 21:09:03 +00:00
CleanRun = true ;
2020-04-10 15:36:18 +00:00
}
2019-03-19 21:09:03 +00:00
}
}
// 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 ) ;
2020-04-25 06:00:15 +00:00
bw_ASTER3Updater . ProgressChanged + = new ProgressChangedEventHandler ( bw_ElevationDatabaseUpdater_ProgressChanged ) ;
bw_ASTER1Updater . ProgressChanged + = new ProgressChangedEventHandler ( bw_ElevationDatabaseUpdater_ProgressChanged ) ;
2019-03-19 21:09:03 +00:00
// 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 ) ;
2020-04-25 06:00:15 +00:00
bw_ASTER3PathCalculator . ProgressChanged + = new ProgressChangedEventHandler ( bw_ElevationPathCalculator_ProgressChanged ) ;
bw_ASTER1PathCalculator . ProgressChanged + = new ProgressChangedEventHandler ( bw_ElevationPathCalculator_ProgressChanged ) ;
2020-02-12 10:45:19 +00:00
2020-04-10 15:36:18 +00:00
// set map preloader event handler
bw_MapPreloader . ProgressChanged + = new ProgressChangedEventHandler ( bw_MapPreloader_ProgressChanged ) ;
2021-12-31 08:08:48 +00:00
// CAT updater event handler
bw_CATUpdater . ProgressChanged + = bw_CATUpdater_ProgressChanged ;
// CAT interface event handler
bw_CAT . ProgressChanged + = new ProgressChangedEventHandler ( bw_CAT_ProgressChanged ) ;
2019-03-19 21:09:03 +00:00
// save FirstRun property before trying to upgrade user settings
FirstRun = Properties . Settings . Default . FirstRun ;
}
2020-02-12 10:45:19 +00:00
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." ) ;
}
2019-03-19 21:09:03 +00:00
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 ) ;
2020-02-12 10:45:19 +00:00
if ( ! Directory . Exists ( PluginDirectory ) )
Directory . CreateDirectory ( PluginDirectory ) ;
2021-12-31 08:08:48 +00:00
if ( ! Directory . Exists ( RigDirectory ) )
Directory . CreateDirectory ( RigDirectory ) ;
2023-01-30 06:00:58 +00:00
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
}
}
2021-12-31 08:08:48 +00:00
}
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 ) ;
}
2020-02-12 10:45:19 +00:00
}
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
2021-12-31 08:08:48 +00:00
CopyPluginWithPDB ( srcplugin , dstplugin ) ;
2020-02-12 10:45:19 +00:00
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
2021-12-31 08:08:48 +00:00
CopyPluginWithPDB ( srcplugin , dstplugin ) ;
2020-02-12 10:45:19 +00:00
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
2021-12-31 08:08:48 +00:00
CopyPluginWithPDB ( srcplugin , dstplugin ) ;
2020-02-12 10:45:19 +00:00
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
2020-03-15 14:29:02 +00:00
CopyPlugins ( Path . Combine ( AppDirectory , "Plugin" ) , PluginDirectory , filespec ) ;
2020-02-12 10:45:19 +00:00
// check for new plugins on the web resource
try
{
// clear temporary files
try
{
SupportFunctions . DeleteFilesFromDirectory ( TmpDirectory , new string [ ] { "*.tmp" , "*.PendingOverwrite" } ) ;
SupportFunctions . DeleteFilesFromDirectory ( TmpDirectory , filespec ) ;
}
catch ( Exception ex )
{
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
}
// calculate url
string url = Properties . Settings . Default . Plugins_Update_URL + "/" + mainversion + "/" + "planefeeds.zip" ;
string filename = Path . Combine ( TmpDirectory , "planefeeds.zip" ) ;
// get zip file
AutoDecompressionWebClient cl = new AutoDecompressionWebClient ( ) ;
DOWNLOADFILESTATUS status = cl . DownloadFileIfNewer ( url , filename , true , true ) ;
if ( ( ( status & DOWNLOADFILESTATUS . ERROR ) > 0 ) & & ( ( status & DOWNLOADFILESTATUS . NOTFOUND ) > 0 ) )
{
Log . WriteMessage ( "PluginManager: checking plugins --> nothing found on web or error while downloading." ) ;
}
else if ( ( ( status & DOWNLOADFILESTATUS . NEWER ) > 0 ) | | ( ( status & DOWNLOADFILESTATUS . NOTNEWER ) > 0 ) )
{
// update files with web resource if newer
// copy plugins from application directory to plugin directory
CopyPlugins ( TmpDirectory , PluginDirectory , filespec ) ;
}
}
catch ( Exception ex )
{
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
}
// load available plugins, we need a robust algorithm here!
// error while composing a single plugin or error during call to plugin constructor must not affect loading of other plugins!
// furthermore: DirectoryCatalog does not work on Linux when plugins are placed in other directory than program's main directory
// solution -->
// try to compose each single plugin first and collect "clean" plugins in a container for error-free composing with Lazy<T>
// after that, try to call each plugin's constructor and collect "clean" plugins in a separate list for further use
try
{
List < AssemblyCatalog > catalog = new List < AssemblyCatalog > ( ) ;
2021-12-31 08:08:48 +00:00
CompositionContainer tmpcontainer = null ;
2020-02-12 10:45:19 +00:00
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 ) ) ;
2021-12-31 08:08:48 +00:00
tmpcontainer = new CompositionContainer ( tmpcatalog ) ;
2020-02-12 10:45:19 +00:00
tmpcontainer . ComposeParts ( this ) ;
// add to main catalog only when composition was OK
tmpcontainer . Dispose ( ) ;
catalog . Add ( tmpcatalog ) ;
}
catch ( Exception ex )
{
2021-12-31 08:08:48 +00:00
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 ) ;
}
2020-02-12 10:45:19 +00:00
}
}
// catalog should cointain only "clean" plugins so composing all parts should be possible without errors
var container = new CompositionContainer ( new AggregateCatalog ( catalog ) ) ;
container . ComposeParts ( this ) ;
foreach ( Lazy < IPlaneFeedPlugin > lazyplugin in LazyPlaneFeedPlugins )
{
try
{
// try to call plaugin constructor and add the value to Planefeeds list
2022-08-27 12:13:47 +00:00
// 2022_04_24 check plugin version against program version: do not load older plugins
2020-02-12 10:45:19 +00:00
var plugin = lazyplugin . Value ;
if ( plugin ! = null )
2022-08-27 12:13:47 +00:00
{
if ( plugin . Version . StartsWith ( mainversion ) )
{
PlaneFeedPlugins . Add ( plugin ) ;
}
}
2020-02-12 10:45:19 +00:00
}
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." ) ;
2019-03-19 21:09:03 +00:00
}
/// <summary>
/// Returns the default value of a property
/// </summary>
/// <param name="propertyname">The property name.</param>
/// <returns>The property value.</returns>
public static dynamic GetPropertyDefaultValue ( string propertyname )
{
2022-08-27 12:13:47 +00:00
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 ( ) ;
2019-03-19 21:09:03 +00:00
Type t = Properties . Settings . Default . Properties [ propertyname ] . PropertyType ;
return Convert . ChangeType ( p , t ) ;
2022-08-27 12:13:47 +00:00
* /
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
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 ;
}
2019-03-19 21:09:03 +00:00
private void InitializeSettings ( )
{
2022-08-27 12:13:47 +00:00
// Load user settings
LoadUserSettings ( ) ;
2019-03-19 21:09:03 +00:00
// 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 ) ) ;
2021-12-31 08:08:48 +00:00
UpdateLocation ( Properties . Settings . Default . MyCall , Properties . Settings . Default . MyLat , Properties . Settings . Default . MyLon , GEOSOURCE . FROMUSER ) ;
2019-03-19 21:09:03 +00:00
}
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 ) ) ;
2021-12-31 08:08:48 +00:00
UpdateLocation ( Properties . Settings . Default . DXCall , Properties . Settings . Default . DXLat , Properties . Settings . Default . DXLon , GEOSOURCE . FROMUSER ) ;
2019-03-19 21:09:03 +00:00
}
// set current elevation model
SetElevationModel ( ) ;
// set antenna height to 10m be default
Properties . Settings . Default . MyHeight = 10 ;
Properties . Settings . Default . DXHeight = 10 ;
2020-02-12 10:45:19 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
}
2022-08-27 12:13:47 +00:00
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 ( ) ) ;
}
}
}
2019-03-19 21:09:03 +00:00
private void CheckSettings ( )
{
Log . WriteMessage ( "Checking properties..." ) ;
// check for empty MyCalls list
if ( Properties . Settings . Default . MyCalls = = null )
{
Properties . Settings . Default . MyCalls = new List < string > ( ) ;
Properties . Settings . Default . MyCalls . Add ( "DL2ALF" ) ;
}
if ( Properties . Settings . Default . MyCalls . Count = = 0 )
Properties . Settings . Default . MyCalls . Add ( "DL2ALF" ) ;
2020-04-10 15:36:18 +00:00
// 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 ) ;
}
2019-03-19 21:09:03 +00:00
// 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 + "/" ;
* /
2020-04-10 15:36:18 +00:00
// check for last saved stations not in database and revert to at least DL2ALF and GB3MHZ if necessary
// first check for saved stations
2020-04-25 05:45:47 +00:00
string mycall = Properties . Settings . Default . MyCall ;
double mylat = Properties . Settings . Default . MyLat ;
double mylon = Properties . Settings . Default . MyLon ;
2020-04-10 15:36:18 +00:00
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 ;
}
2020-04-25 05:45:47 +00:00
string dxcall = Properties . Settings . Default . DXCall ;
double dxlat = Properties . Settings . Default . DXLat ;
double dxlon = Properties . Settings . Default . DXLon ;
2020-04-10 15:36:18 +00:00
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 ;
}
2019-03-19 21:09:03 +00:00
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 ) ;
2020-04-10 15:36:18 +00:00
Log . WriteMessage ( "OS Major version : " + Environment . OSVersion . Version . Major ) ;
Log . WriteMessage ( "OS Minor version : " + Environment . OSVersion . Version . Minor ) ;
2019-03-19 21:09:03 +00:00
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 ) ;
2021-12-31 08:08:48 +00:00
Log . WriteMessage ( "Plugin directory : " + PluginDirectory ) ;
Log . WriteMessage ( "Rig directory : " + RigDirectory ) ;
2019-03-19 21:09:03 +00:00
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 ;
2020-04-25 06:00:15 +00:00
Properties . Settings . Default . Elevation_ASTER3_DatabaseStatus = DATABASESTATUS . UNDEFINED ;
Properties . Settings . Default . Elevation_ASTER1_DatabaseStatus = DATABASESTATUS . UNDEFINED ;
2019-03-19 21:09:03 +00:00
// set nearfield suppression
PropagationData . Database . NearFieldSuppression = Properties . Settings . Default . Path_NearFieldSuppression ;
2020-02-12 10:45:19 +00:00
// 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 ( ) ;
2021-12-31 08:08:48 +00:00
Properties . Settings . Default . Rig_Directory = RigData . Database . DefaultDatabaseDirectory ( ) ;
2020-04-10 15:36:18 +00:00
MapData . Database . DefaultDatabaseDirectory ( ) ;
2019-03-19 21:09:03 +00:00
Log . WriteMessage ( "Finished." ) ;
}
2021-12-31 08:08:48 +00:00
private void CreateDistances ( )
{
2022-08-27 12:13:47 +00:00
gmo_Distances . Clear ( ) ;
2021-12-31 08:08:48 +00:00
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 ) ) ;
}
2022-08-27 12:13:47 +00:00
gmo_Distances . Routes . Add ( circle ) ;
2021-12-31 08:08:48 +00:00
}
}
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 ) ;
2022-08-27 12:13:47 +00:00
gm_Main . Overlays . Add ( gmo_Routes ) ;
2021-12-31 08:08:48 +00:00
gm_Main . Overlays . Add ( gmo_Planes ) ;
gm_Main . Overlays . Add ( gmo_Callsigns ) ;
2022-08-27 12:13:47 +00:00
gm_Main . Overlays . Add ( gmo_CallsignDetails ) ;
2021-12-31 08:08:48 +00:00
gm_Main . Opacity = ( double ) Properties . Settings . Default . Map_Opacity ;
// create locators, if enabled
if ( Properties . Settings . Default . Map_ShowLocators )
InitializeLocators ( ) ;
// setting User Agent to fix Open Street Map issue 2016-09-20
GMap . NET . MapProviders . GMapProvider . UserAgent = "AirScout" ;
// clearing referrer URL issue 2019-12-14
gm_Nearest . MapProvider . RefererUrl = "" ;
// set initial settings for main map
gm_Nearest . MapProvider = GMapProviders . Find ( Properties . Settings . Default . Map_Provider ) ;
gm_Main . MapProvider . RefererUrl = "" ;
gm_Nearest . IgnoreMarkerOnMouseWheel = true ;
gm_Nearest . MinZoom = 0 ;
gm_Nearest . MaxZoom = 20 ;
gm_Nearest . Zoom = 6 ;
gm_Nearest . DragButton = System . Windows . Forms . MouseButtons . Left ;
gm_Nearest . CanDragMap = true ;
gm_Nearest . ScalePen = new Pen ( Color . Black , 3 ) ;
gm_Nearest . MapScaleInfoEnabled = true ;
// clear all overlays
gm_Nearest . Overlays . Clear ( ) ;
gmo_NearestPaths . Clear ( ) ;
gmo_NearestPlanes . Clear ( ) ;
// add all overlays
gm_Nearest . Overlays . Add ( gmo_NearestPaths ) ;
gm_Nearest . Overlays . Add ( gmo_NearestPlanes ) ;
gm_Nearest . Position = new PointLatLng ( Properties . Settings . Default . MyLat , Properties . Settings . Default . MyLon ) ;
gm_Nearest . ShowCenter = false ;
// setting User Agent to fix Open Street Map issue 2016-09-20
GMap . NET . MapProviders . GMapProvider . UserAgent = "AirScout" ;
// clearing referrer URL issue 2019-12-14
gm_Cache . MapProvider . RefererUrl = "" ;
// set initial settings for main map
gm_Cache . MapProvider = GMapProviders . Find ( Properties . Settings . Default . Map_Provider ) ;
}
private void CreateLocators ( double steplat , double steplon , Pen pen )
{
// get visible map bounds first
double minlat = ( int ) ( gm_Main . ViewArea . Bottom / steplat ) * steplat - steplat ;
double maxlat = gm_Main . ViewArea . Top ;
double minlon = ( int ) ( gm_Main . ViewArea . Left / steplon ) * steplon - steplon ;
double maxlon = gm_Main . ViewArea . Right ;
Console . WriteLine ( "ViewArea = " + minlat . ToString ( "F2" ) + "," + minlon . ToString ( "F2" ) + " <> " + maxlat . ToString ( "F2" ) + "," + maxlon . ToString ( "F2" ) ) ;
for ( double lon = minlon ; lon < maxlon ; lon + = steplon )
{
for ( double lat = minlat ; lat < maxlat ; lat + = steplat )
{
// create name
string loc = "" ;
if ( steplat > = 10.0 )
{
loc = MaidenheadLocator . LocFromLatLon ( lat + steplat / 2 , lon + steplon / 2 , false , 1 ) ;
}
else if ( steplat > = 1.0 )
{
loc = MaidenheadLocator . LocFromLatLon ( lat + steplat / 2 , lon + steplon / 2 , false , 2 ) ;
}
else if ( steplat > = 1.0 / 24.0 )
{
loc = MaidenheadLocator . LocFromLatLon ( lat + steplat / 2 , lon + steplon / 2 , false , 3 ) ;
}
else if ( steplat > = 1.0 / 24.0 / 10.0 )
{
loc = MaidenheadLocator . LocFromLatLon ( lat + steplat / 2 , lon + steplon / 2 , false , 4 ) ;
}
else if ( steplat > = 1.0 / 24.0 / 10.0 / 24.0 )
{
loc = MaidenheadLocator . LocFromLatLon ( lat + steplat / 2 , lon + steplon / 2 , false , 5 ) ;
}
// create polygon
List < PointLatLng > l = new List < PointLatLng > ( ) ;
l . Add ( new PointLatLng ( lat , lon ) ) ;
l . Add ( new PointLatLng ( lat , lon + steplon ) ) ;
l . Add ( new PointLatLng ( lat + steplat , lon + steplon ) ) ;
l . Add ( new PointLatLng ( lat + steplat , lon ) ) ;
GMapLocatorPolygon p = new GMapLocatorPolygon ( l , loc ) ;
p . Stroke = pen ;
p . Fill = Brushes . Transparent ;
p . Tag = loc ;
gmo_Locators . Polygons . Add ( p ) ;
}
}
}
private void InitializeLocators ( )
{
2022-08-27 12:13:47 +00:00
// NASTY!! still throws execption sometimes
// when restoring cursor
try
{
// clear locator overlay anyway
gmo_Locators . Clear ( ) ;
}
catch ( Exception ex )
{
// do all most nothing
}
2021-12-31 08:08:48 +00:00
// 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 ) ;
}
}
}
2020-04-10 15:36:18 +00:00
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 ) ;
}
}
2019-03-19 21:09:03 +00:00
private void MapDlg_Load ( object sender , EventArgs e )
{
try
{
// Show splash screen
2020-04-10 15:36:18 +00:00
SplashDlg = new Splash ( ) ;
2019-03-19 21:09:03 +00:00
SplashDlg . Show ( ) ;
// bring window to front
SplashDlg . BringToFront ( ) ;
2020-03-01 15:12:08 +00:00
// wait for splash window is fully visible
while ( SplashDlg . Opacity < 1 )
{
Application . DoEvents ( ) ;
}
// show AirScout main window
this . BringToFront ( ) ;
2019-03-19 21:09:03 +00:00
// Check directories, complete it and create, if not exist
2020-04-10 15:36:18 +00:00
Splash ( "Checking directories..." ) ;
2019-03-19 21:09:03 +00:00
CheckDirectories ( ) ;
// start a log, specify format of logfile and entries
2020-04-10 15:36:18 +00:00
Splash ( "Initializing logfile..." ) ;
2019-03-19 21:09:03 +00:00
InitializeLogfile ( ) ;
// Check properties
2020-04-10 15:36:18 +00:00
Splash ( "Checking settings..." ) ;
2019-03-19 21:09:03 +00:00
CheckSettings ( ) ;
2020-02-12 10:45:19 +00:00
// check, copy and load plugins
2020-04-10 15:36:18 +00:00
Splash ( "Loading plugins..." ) ;
2020-02-12 10:45:19 +00:00
LoadPlugins ( ) ;
2019-03-19 21:09:03 +00:00
// Initialize database
2020-04-10 15:36:18 +00:00
Splash ( "Initializing database..." ) ;
2019-03-19 21:09:03 +00:00
InitializeDatabase ( ) ;
// initialize icons
2020-04-10 15:36:18 +00:00
Splash ( "Creating icons..." ) ;
2019-03-19 21:09:03 +00:00
InitializeIcons ( ) ;
ToolTipFont = CreateFontFromString ( Properties . Settings . Default . Map_ToolTipFont ) ;
2020-04-10 15:36:18 +00:00
Splash ( "Loading Map..." ) ;
2019-03-19 21:09:03 +00:00
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 ) ;
2020-02-12 10:45:19 +00:00
if ( PlaneFeedPlugins ! = null )
2019-03-19 21:09:03 +00:00
{
2020-02-12 10:45:19 +00:00
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 ) ;
}
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
// 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." ) ;
2022-08-27 12:13:47 +00:00
// Reload settings
LoadUserSettings ( ) ;
2019-03-19 21:09:03 +00:00
// try to ugrade settings when not started with /CLEAN option
if ( ! CleanRun )
{
Log . WriteMessage ( "Upgrading settings." ) ;
Properties . Settings . Default . Upgrade ( ) ;
2020-04-19 07:23:30 +00:00
// 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 ) )
2019-03-19 21:09:03 +00:00
{
/ *
// 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 ) ) ;
* /
2020-04-19 07:23:30 +00:00
// reset Sync with KST option
Properties . Settings . Default . Watchlist_SyncWithKST = GetPropertyDefaultValue ( nameof ( Properties . Settings . Default . Watchlist_SyncWithKST ) ) ;
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . Version = Application . ProductVersion ;
SaveUserSettings ( ) ;
}
AirScout . PlaneFeeds . Properties . Settings . Default . Upgrade ( ) ;
}
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
CheckDirectories ( ) ;
CheckSettings ( ) ;
// reset topmost state
2020-04-10 15:36:18 +00:00
if ( SplashDlg ! = null )
SplashDlg . TopMost = false ;
2019-03-19 21:09:03 +00:00
/ *
// run database updater once for basic information
bw_DatabaseUpdater . RunWorkerAsync ( UPDATERSTARTOPTIONS . FIRSTRUN ) ;
// wait till finished
while ( bw_DatabaseUpdater . IsBusy )
Application . DoEvents ( ) ;
* /
2020-04-10 15:36:18 +00:00
if ( SplashDlg ! = null )
SplashDlg . Close ( ) ;
2020-03-15 14:29:02 +00:00
// must have internet connection on FirstRun
CheckInternet ( ) ;
2019-03-19 21:09:03 +00:00
// show FirstRunWizard
try
{
2020-02-12 10:45:19 +00:00
FirstRunWizard Dlg = new FirstRunWizard ( this ) ;
2019-03-19 21:09:03 +00:00
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 ;
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
// 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
// flush the log and exit immediately
Log . FlushLog ( ) ;
System . Environment . Exit ( - 1 ) ;
}
}
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
// get initial widths and heigths
gb_Map_Info_DefaultWidth = gb_Map_Info . Width ;
tc_Main_DefaultHeight = tc_Main . Height ;
2019-03-19 21:09:03 +00:00
// 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 ( ) ;
2020-02-12 10:45:19 +00:00
if ( PlaneFeedPlugins ! = null )
2019-03-19 21:09:03 +00:00
{
2020-02-12 10:45:19 +00:00
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 ) ;
}
}
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
// register this instance of AirScout and get a session key
InitializeSession ( ) ;
2019-03-19 21:09:03 +00:00
// 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
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . NONE ;
2019-03-19 21:09:03 +00:00
// 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 ( ) ;
2021-12-31 08:08:48 +00:00
//initialize maps
InitializeMaps ( ) ;
2019-03-19 21:09:03 +00:00
// 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 ( ) ;
2022-08-27 12:13:47 +00:00
// 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 ) ;
}
2019-03-19 21:09:03 +00:00
// 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
2020-02-12 10:45:19 +00:00
if ( Log ! = null )
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
else
Console . WriteLine ( "Fatal Error: " + ex . ToString ( ) ) ;
2019-03-19 21:09:03 +00:00
// 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
2020-02-12 10:45:19 +00:00
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 ;
}
2022-08-27 12:13:47 +00:00
// 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();
2020-03-01 15:12:08 +00:00
}
private void FinishStartup ( )
{
// finish startup
// close splash window
// set window layout
if ( SplashDlg ! = null )
SplashDlg . Close ( ) ;
2020-02-12 10:45:19 +00:00
// 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
2020-03-01 15:12:08 +00:00
MapSplitterDistance = - 1 ;
MainSplitterDistance = - 1 ;
2020-02-12 10:45:19 +00:00
}
}
catch ( Exception ex )
{
// do nothing if failed
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
// 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 ) ;
}
2020-02-12 10:45:19 +00:00
// 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 ;
2023-01-30 06:00:58 +00:00
feedargs . PlanePositionsDirectory = PlanePositionsDirectory ;
2020-02-12 10:45:19 +00:00
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 ;
2023-01-30 06:00:58 +00:00
feedargs . LogPlanePositions = Properties . Settings . Default . Planes_TracePositions ;
2020-02-12 10:45:19 +00:00
return feedargs ;
}
2019-03-19 21:09:03 +00:00
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" ;
2020-04-10 15:36:18 +00:00
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 ;
2020-02-12 10:45:19 +00:00
startoptions . InstanceID = Properties . Settings . Default . AirScout_Instance_ID ;
startoptions . SessionKey = SessionKey ;
startoptions . GetKeyURL = Properties . Settings . Default . AirScout_GetKey_URL ;
2019-03-19 21:09:03 +00:00
startoptions . Options = BACKGROUNDUPDATERSTARTOPTIONS . RUNONCE ;
bw_StationDatabaseUpdater . RunWorkerAsync ( startoptions ) ;
}
if ( ( bw_AircraftDatabaseUpdater ! = null ) & & ! bw_AircraftDatabaseUpdater . IsBusy )
{
AircraftDatabaseUpdaterStartOptions startoptions = new AircraftDatabaseUpdaterStartOptions ( ) ;
startoptions . Name = "Aircrafts" ;
2020-02-12 10:45:19 +00:00
startoptions . InstanceID = Properties . Settings . Default . AirScout_Instance_ID ;
startoptions . SessionKey = SessionKey ;
startoptions . GetKeyURL = Properties . Settings . Default . AirScout_GetKey_URL ;
2019-03-19 21:09:03 +00:00
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 ) ;
}
2020-04-25 06:00:15 +00:00
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 ) ;
}
2019-03-19 21:09:03 +00:00
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 ) ;
2020-04-25 06:00:15 +00:00
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 ) ;
2020-04-10 15:36:18 +00:00
if ( Properties . Settings . Default . Map_Preloader_Enabled & & ( bw_MapPreloader ! = null ) & & ! bw_MapPreloader . IsBusy )
bw_MapPreloader . RunWorkerAsync ( BACKGROUNDUPDATERSTARTOPTIONS . RUNONCE ) ;
2019-03-19 21:09:03 +00:00
}
else if ( Properties . Settings . Default . Background_Update_Periodically )
{
if ( ( bw_StationDatabaseUpdater ! = null ) & & ! bw_StationDatabaseUpdater . IsBusy )
{
StationDatabaseUpdaterStartOptions startoptions = new StationDatabaseUpdaterStartOptions ( ) ;
startoptions . Name = "Stations" ;
2020-04-10 15:36:18 +00:00
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 ;
2020-02-12 10:45:19 +00:00
startoptions . InstanceID = Properties . Settings . Default . AirScout_Instance_ID ;
startoptions . SessionKey = SessionKey ;
startoptions . GetKeyURL = Properties . Settings . Default . AirScout_GetKey_URL ;
2019-03-19 21:09:03 +00:00
startoptions . Options = BACKGROUNDUPDATERSTARTOPTIONS . RUNPERIODICALLY ;
bw_StationDatabaseUpdater . RunWorkerAsync ( startoptions ) ;
}
if ( ( bw_AircraftDatabaseUpdater ! = null ) & & ! bw_AircraftDatabaseUpdater . IsBusy )
{
AircraftDatabaseUpdaterStartOptions startoptions = new AircraftDatabaseUpdaterStartOptions ( ) ;
startoptions . Name = "Aircrafts" ;
2020-02-12 10:45:19 +00:00
startoptions . InstanceID = Properties . Settings . Default . AirScout_Instance_ID ;
startoptions . SessionKey = SessionKey ;
startoptions . GetKeyURL = Properties . Settings . Default . AirScout_GetKey_URL ;
2019-03-19 21:09:03 +00:00
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 ) ;
}
2020-04-25 06:00:15 +00:00
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 ) ;
}
2019-03-19 21:09:03 +00:00
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 ) ;
2020-04-25 06:00:15 +00:00
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 ) ;
2020-04-10 15:36:18 +00:00
if ( Properties . Settings . Default . Map_Preloader_Enabled & & ( bw_MapPreloader ! = null ) & & ! bw_MapPreloader . IsBusy )
bw_MapPreloader . RunWorkerAsync ( BACKGROUNDUPDATERSTARTOPTIONS . RUNPERIODICALLY ) ;
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
if ( ( bw_PlaneFeed1 ! = null ) & & ( ! bw_PlaneFeed1 . IsBusy ) )
2020-02-12 10:45:19 +00:00
bw_PlaneFeed1 . RunWorkerAsync ( CreatePlaneFeedWorkEventArgs ( Properties . Settings . Default . Planes_PlaneFeed1 ) ) ;
2019-03-19 21:09:03 +00:00
if ( ( bw_PlaneFeed2 ! = null ) & & ( ! bw_PlaneFeed2 . IsBusy ) )
2020-02-12 10:45:19 +00:00
bw_PlaneFeed2 . RunWorkerAsync ( CreatePlaneFeedWorkEventArgs ( Properties . Settings . Default . Planes_PlaneFeed2 ) ) ;
2019-03-19 21:09:03 +00:00
if ( ( bw_PlaneFeed3 ! = null ) & & ( ! bw_PlaneFeed3 . IsBusy ) )
2020-02-12 10:45:19 +00:00
bw_PlaneFeed3 . RunWorkerAsync ( CreatePlaneFeedWorkEventArgs ( Properties . Settings . Default . Planes_PlaneFeed3 ) ) ;
2023-01-30 06:00:58 +00:00
if ( Properties . Settings . Default . Server_Activate )
2019-03-19 21:09:03 +00:00
{
if ( ( bw_WinTestReceive ! = null ) & & ( ! bw_WinTestReceive . IsBusy ) )
bw_WinTestReceive . RunWorkerAsync ( ) ;
2023-01-30 06:00:58 +00:00
WebserverStartArgs args = new WebserverStartArgs ( ) ;
args . TmpDirectory = TmpDirectory ;
args . WebserverDirectory = WebserverDirectory ;
2019-03-19 21:09:03 +00:00
if ( ( bw_Webserver ! = null ) & & ( ! bw_Webserver . IsBusy ) )
2023-01-30 06:00:58 +00:00
bw_Webserver . RunWorkerAsync ( args ) ;
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
if ( Properties . Settings . Default . SpecLab_Enabled )
{
if ( ( bw_SpecLab_Receive ! = null ) & & ( ! bw_SpecLab_Receive . IsBusy ) )
bw_SpecLab_Receive . RunWorkerAsync ( ) ;
}
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
if ( Properties . Settings . Default . Track_Activate )
{
if ( ( bw_Track ! = null ) & & ( ! bw_Track . IsBusy ) )
bw_Track . RunWorkerAsync ( ) ;
}
2023-01-30 06:00:58 +00:00
2021-12-31 08:08:48 +00:00
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 ) ;
}
2019-03-19 21:09:03 +00:00
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
2022-08-27 12:13:47 +00:00
int timeout = 10000 ; // timeout in ms
2019-03-19 21:09:03 +00:00
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
Say ( "Stopping background thread " + count . ToString ( ) + " of " + total . ToString ( ) + " [" + name + "]..." ) ;
while ( ( worker ! = null ) & & worker . IsBusy )
2022-08-27 12:13:47 +00:00
{
2019-03-19 21:09:03 +00:00
Application . DoEvents ( ) ;
2022-08-27 12:13:47 +00:00
}
2019-03-19 21:09:03 +00:00
st . Stop ( ) ;
Log . WriteMessage ( "Stopping " + name + ", " + st . ElapsedMilliseconds . ToString ( ) + " ms." ) ;
}
private void StopAllBackgroundWorkers ( )
{
Say ( "Stopping background threads..." ) ;
// cancel permanent background workers, wait for finish
2021-12-31 08:08:48 +00:00
int bcount = 18 ;
2019-03-19 21:09:03 +00:00
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 + + ;
2020-04-25 06:00:15 +00:00
StopBackgroundworker ( bw_ASTER3PathCalculator , nameof ( bw_ASTER3PathCalculator ) , i , bcount ) ; i + + ;
StopBackgroundworker ( bw_ASTER1PathCalculator , nameof ( bw_ASTER1PathCalculator ) , i , bcount ) ; i + + ;
2019-03-19 21:09:03 +00:00
StopBackgroundworker ( bw_AircraftDatabaseUpdater , nameof ( bw_AircraftDatabaseUpdater ) , i , bcount ) ; i + + ;
StopBackgroundworker ( bw_StationDatabaseUpdater , nameof ( bw_StationDatabaseUpdater ) , i , bcount ) ; i + + ;
2020-04-10 15:36:18 +00:00
StopBackgroundworker ( bw_MapPreloader , nameof ( bw_MapPreloader ) , i , bcount ) ; i + + ;
2021-12-31 08:08:48 +00:00
StopBackgroundworker ( bw_CATUpdater , nameof ( bw_CATUpdater ) , i , bcount ) ; i + + ;
StopBackgroundworker ( bw_CAT , nameof ( bw_CAT ) , i , bcount ) ; i + + ;
2019-03-19 21:09:03 +00:00
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 ( ) ;
2020-04-25 06:00:15 +00:00
if ( bw_ASTER3Updater ! = null )
bw_ASTER3Updater . CancelAsync ( ) ;
if ( bw_ASTER1Updater ! = null )
bw_ASTER1Updater . CancelAsync ( ) ;
2019-03-19 21:09:03 +00:00
if ( bw_GLOBEPathCalculator ! = null )
bw_GLOBEPathCalculator . CancelAsync ( ) ;
if ( bw_SRTM3PathCalculator ! = null )
bw_SRTM3PathCalculator . CancelAsync ( ) ;
if ( bw_SRTM1PathCalculator ! = null )
bw_SRTM1PathCalculator . CancelAsync ( ) ;
2020-04-25 06:00:15 +00:00
if ( bw_ASTER3PathCalculator ! = null )
bw_ASTER3PathCalculator . CancelAsync ( ) ;
if ( bw_ASTER1PathCalculator ! = null )
bw_ASTER1PathCalculator . CancelAsync ( ) ;
2021-12-31 08:08:48 +00:00
if ( bw_CATUpdater ! = null )
bw_CATUpdater . CancelAsync ( ) ;
if ( bw_CAT ! = null )
bw_CAT . CancelAsync ( ) ;
2019-03-19 21:09:03 +00:00
}
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 ) ) ;
2023-01-30 06:00:58 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
Log . WriteMessage ( "Finished." ) ;
}
private void InitializeCharts ( )
{
// propagation path chart
pm_Path . Title = String . Empty ;
2020-03-15 14:29:02 +00:00
pm_Path . DefaultFontSize = ( double ) Properties . Settings . Default . Charts_FontSize ;
2019-03-19 21:09:03 +00:00
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 ;
2020-03-15 14:29:02 +00:00
pm_Elevation . DefaultFontSize = ( double ) Properties . Settings . Default . Charts_FontSize ;
2019-03-19 21:09:03 +00:00
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 ;
2020-03-15 14:29:02 +00:00
pm_Spectrum . DefaultFontSize = ( double ) Properties . Settings . Default . Charts_FontSize ;
2019-03-19 21:09:03 +00:00
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 ;
2022-08-27 12:13:47 +00:00
this . wb_News . ScriptErrorsSuppressed = true ;
2019-03-19 21:09:03 +00:00
this . wb_News . Url = global :: AirScout . Properties . Settings . Default . News_URL ;
this . tp_News . Controls . Add ( this . wb_News ) ;
}
private void UpdateAirports ( )
{
2020-04-10 15:36:18 +00:00
// clear airports first
gmo_Airports . Clear ( ) ;
2019-03-19 21:09:03 +00:00
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
2020-03-01 15:12:08 +00:00
gm_Main . Refresh ( ) ;
2019-03-19 21:09:03 +00:00
}
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 ;
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
// 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 ;
}
2022-08-27 12:13:47 +00:00
private void LoadSettingsFromJSON ( ApplicationSettingsBase settings )
{
string filename = GetUserSettingsPath ( ) . Replace ( "user.config" , settings . GetType ( ) . FullName + ".json" ) ;
if ( ! File . Exists ( filename ) )
return ;
JsonSerializerSettings serializersettings = new JsonSerializerSettings ( ) ;
Dictionary < string , string > props =
JsonConvert . DeserializeObject < Dictionary < string , string > > ( File . ReadAllText ( filename ) ) ;
foreach ( string key in props . Keys )
{
try
{
settings [ key ] = JsonConvert . DeserializeObject ( props [ key ] , settings . Properties [ key ] . PropertyType ) ;
}
catch ( Exception ex )
{
Console . WriteLine ( "Error while loading user setting: " + ex . ToString ( ) ) ;
2020-04-10 15:36:18 +00:00
}
}
2022-08-27 12:13:47 +00:00
}
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 ( ) ;
2023-01-30 06:00:58 +00:00
ScoutBase . CAT . Properties . Settings . Default . Reload ( ) ;
2022-08-27 12:13:47 +00:00
AirScout . Aircrafts . Properties . Settings . Default . Reload ( ) ;
2023-01-30 06:00:58 +00:00
AirScout . PlaneFeeds . Properties . Settings . Default . Reload ( ) ;
AirScout . CAT . Properties . Settings . Default . Reload ( ) ;
2022-08-27 12:13:47 +00:00
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 ( ) ;
2023-01-30 06:00:58 +00:00
ScoutBase . CAT . Properties . Settings . Default . Reset ( ) ;
2022-08-27 12:13:47 +00:00
AirScout . Aircrafts . Properties . Settings . Default . Reset ( ) ;
2023-01-30 06:00:58 +00:00
AirScout . PlaneFeeds . Properties . Settings . Default . Reset ( ) ;
AirScout . CAT . Properties . Settings . Default . Reset ( ) ;
2022-08-27 12:13:47 +00:00
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 ) ;
2023-01-30 06:00:58 +00:00
LoadSettingsFromJSON ( ScoutBase . CAT . Properties . Settings . Default ) ;
2022-08-27 12:13:47 +00:00
LoadSettingsFromJSON ( AirScout . Aircrafts . Properties . Settings . Default ) ;
2023-01-30 06:00:58 +00:00
LoadSettingsFromJSON ( AirScout . PlaneFeeds . Properties . Settings . Default ) ;
LoadSettingsFromJSON ( AirScout . CAT . Properties . Settings . Default ) ;
2022-08-27 12:13:47 +00:00
LoadSettingsFromJSON ( Properties . Settings . Default ) ;
Console . WriteLine ( "Loading user settings finished successfully." ) ;
}
catch ( Exception ex )
{
Console . WriteLine ( "Error while loading user settings: " + ex . ToString ( ) , LogLevel . Error ) ;
}
}
private void SaveSettingsToJSON ( ApplicationSettingsBase settings )
{
string filename = GetUserSettingsPath ( ) . Replace ( "user.config" , settings . GetType ( ) . FullName + ".json" ) ;
Dictionary < string , object > props = new Dictionary < string , object > ( ) ;
foreach ( SettingsProperty prop in settings . Properties )
{
props . Add ( prop . Name , JsonConvert . SerializeObject ( settings [ prop . Name ] ) ) ;
}
File . WriteAllText ( filename , JsonConvert . SerializeObject ( props , Newtonsoft . Json . Formatting . Indented ) ) ;
2020-04-10 15:36:18 +00:00
}
2019-03-19 21:09:03 +00:00
private void SaveUserSettings ( )
{
2020-03-15 14:29:02 +00:00
try
{
2022-08-27 12:13:47 +00:00
Console . WriteLine ( "Saving configuration, FirstRun = " + Properties . Settings . Default . FirstRun ) ;
2020-03-15 14:29:02 +00:00
Log . WriteMessage ( "Saving configuration..." ) ;
2022-08-27 12:13:47 +00:00
2020-03-15 14:29:02 +00:00
if ( ! SupportFunctions . IsMono )
2022-08-27 12:13:47 +00:00
{
// save all settings
2023-01-30 06:00:58 +00:00
ScoutBase . CAT . Properties . Settings . Default . Save ( ) ;
2022-08-27 12:13:47 +00:00
ScoutBase . Elevation . Properties . Settings . Default . Save ( ) ;
ScoutBase . Stations . Properties . Settings . Default . Save ( ) ;
ScoutBase . Propagation . Properties . Settings . Default . Save ( ) ;
AirScout . Aircrafts . Properties . Settings . Default . Save ( ) ;
2023-01-30 06:00:58 +00:00
AirScout . CAT . Properties . Settings . Default . Save ( ) ;
2022-08-27 12:13:47 +00:00
Properties . Settings . Default . Save ( ) ;
2020-03-15 14:29:02 +00:00
return ;
2022-08-27 12:13:47 +00:00
}
// Rather save settings as JSON
SaveSettingsToJSON ( Properties . Settings . Default ) ;
SaveSettingsToJSON ( AirScout . Aircrafts . Properties . Settings . Default ) ;
2023-01-30 06:00:58 +00:00
SaveSettingsToJSON ( AirScout . CAT . Properties . Settings . Default ) ;
2022-08-27 12:13:47 +00:00
SaveSettingsToJSON ( ScoutBase . Propagation . Properties . Settings . Default ) ;
SaveSettingsToJSON ( ScoutBase . Stations . Properties . Settings . Default ) ;
SaveSettingsToJSON ( ScoutBase . Elevation . Properties . Settings . Default ) ;
2023-01-30 06:00:58 +00:00
SaveSettingsToJSON ( ScoutBase . CAT . Properties . Settings . Default ) ;
2022-08-27 12:13:47 +00:00
2020-03-15 14:29:02 +00:00
}
catch ( Exception ex )
{
Console . WriteLine ( "Unable to save settings: " + ex . ToString ( ) ) ;
2019-03-19 21:09:03 +00:00
}
}
# endregion
#region Idle
private void OnIdle ( object sender , EventArgs args )
{
}
# endregion
#region Closing Down
private void MapDlg_FormClosing ( object sender , FormClosingEventArgs e )
{
2020-02-12 10:45:19 +00:00
if ( Log ! = null )
{
Log . WriteMessage ( Application . ProductName + " is closing." ) ;
// flush the Log for the first time to save all messages
Log . FlushLog ( ) ;
}
2021-12-31 08:08:48 +00:00
// stop playing when in PLAY mode
if ( PlayMode ! = AIRSCOUTPLAYMODE . PAUSE )
Pause ( ) ;
2019-03-19 21:09:03 +00:00
//save window size, state and location
if ( this . WindowState = = FormWindowState . Normal )
2020-04-10 15:36:18 +00:00
{
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . General_WindowSize = this . Size ;
2020-04-10 15:36:18 +00:00
Properties . Settings . Default . General_WindowLocation = this . Location ;
}
2019-03-19 21:09:03 +00:00
else
2020-04-10 15:36:18 +00:00
{
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . General_WindowSize = this . RestoreBounds . Size ;
2020-04-10 15:36:18 +00:00
Properties . Settings . Default . General_WindowLocation = this . RestoreBounds . Location ;
}
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . General_WindowState = this . WindowState ;
2022-08-27 12:13:47 +00:00
// save properties to file
SaveUserSettings ( ) ;
2019-03-19 21:09:03 +00:00
Say ( "Waiting for background threads to close..." ) ;
// close background threads, save database and settings
try
{
// cancel background workers
2022-08-27 12:13:47 +00:00
// causes ThreadAbortExceptions on Linux ?!?
try
{
CancelAllBackgroundWorkers ( ) ;
}
catch ( Exception ex )
{
}
2019-03-19 21:09:03 +00:00
// save splitter positions
2020-02-12 10:45:19 +00:00
Properties . Settings . Default . MainSplitter_Distance = MainSplitterDistance ;
Properties . Settings . Default . MapSplitter_Distance = MapSplitterDistance ;
2023-01-30 06:00:58 +00:00
2021-12-31 08:08:48 +00:00
// stop tracking
2023-01-30 06:00:58 +00:00
if ( ConnectedRig ! = null )
{
ConnectedRig . LeaveDoppler ( ) ;
}
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . NONE ;
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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." ) ;
}
2020-04-25 06:00:15 +00:00
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." ) ;
}
2019-03-19 21:09:03 +00:00
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." ) ;
}
2022-08-27 12:13:47 +00:00
2019-03-19 21:09:03 +00:00
// 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 )
{
2020-02-12 10:45:19 +00:00
try
{
if ( String . Compare ( tsl_Status . Text , text ) = = 0 )
return ;
tsl_Status . Text = text ;
}
catch ( Exception ex )
{
}
2019-03-19 21:09:03 +00:00
}
private void SayDatabase ( string text )
{
2020-02-12 10:45:19 +00:00
try
{
if ( String . Compare ( tsl_Database . Text , text ) = = 0 )
return ;
tsl_Database . Text = text ;
}
catch ( Exception ex )
{
}
2019-03-19 21:09:03 +00:00
}
private void SayCalculations ( string text )
{
2020-02-12 10:45:19 +00:00
try
{
if ( String . Compare ( tsl_Calculations . Text , text ) = = 0 )
return ;
tsl_Calculations . Text = text ;
}
catch ( Exception ex )
{
}
2019-03-19 21:09:03 +00:00
}
private void SayAnalysis ( string text )
{
2020-02-12 10:45:19 +00:00
try
{
if ( String . Compare ( tb_Analysis_Status . Text , text ) = = 0 )
return ;
tb_Analysis_Status . Text = text ;
tb_Analysis_Status . Refresh ( ) ;
}
catch ( Exception ex )
{
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
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
}
}
2019-03-19 21:09:03 +00:00
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
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 ) ;
2020-02-12 10:45:19 +00:00
if ( maxinfo . MaxElv ! = ElevationData . Database . ElvMissingFlag )
2019-03-19 21:09:03 +00:00
{
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 ) ;
2020-02-12 10:45:19 +00:00
if ( maxinfo . MaxElv ! = ElevationData . Database . ElvMissingFlag )
2019-03-19 21:09:03 +00:00
{
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 ) ;
2020-02-12 10:45:19 +00:00
if ( maxinfo . MaxElv ! = ElevationData . Database . ElvMissingFlag )
2019-03-19 21:09:03 +00:00
{
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
2020-04-25 06:00:15 +00:00
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 ] ;
2019-03-19 21:09:03 +00:00
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
2020-04-25 06:00:15 +00:00
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 ;
}
}
2019-03-19 21:09:03 +00:00
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 ;
}
}
2020-02-12 10:45:19 +00:00
/ *
2019-03-19 21:09:03 +00:00
// 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 ;
2020-02-12 10:45:19 +00:00
* /
2019-03-19 21:09:03 +00:00
return elv ;
}
public void SetElevationModel ( )
{
2020-04-25 06:00:15 +00:00
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 )
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . ElevationModel = ELEVATIONMODEL . SRTM1 ;
else if ( Properties . Settings . Default . Elevation_SRTM3_Enabled )
Properties . Settings . Default . ElevationModel = ELEVATIONMODEL . SRTM3 ;
else if ( Properties . Settings . Default . Elevation_GLOBE_Enabled )
Properties . Settings . Default . ElevationModel = ELEVATIONMODEL . GLOBE ;
else
Properties . Settings . Default . ElevationModel = ELEVATIONMODEL . NONE ;
}
public static Font CreateFontFromString ( string font )
{
try
{
string [ ] a = Properties . Settings . Default . Map_ToolTipFont . Split ( ';' ) ;
string fontfamily = a [ 0 ] . Trim ( ) ;
float emsize = 0 ;
float . TryParse ( a [ 1 ] . Trim ( ) , NumberStyles . Float , CultureInfo . InvariantCulture , out emsize ) ;
FontStyle fontstyle = 0 ;
// check if any additional font style is given
if ( a . Length > 2 )
{
if ( a [ 2 ] . ToUpper ( ) . IndexOf ( "BOLD" ) > = 0 )
fontstyle = fontstyle | FontStyle . Bold ;
if ( a [ 2 ] . ToUpper ( ) . IndexOf ( "ITALIC" ) > = 0 )
fontstyle = fontstyle | FontStyle . Italic ;
if ( a [ 2 ] . ToUpper ( ) . IndexOf ( "UNDERLINE" ) > = 0 )
fontstyle = fontstyle | FontStyle . Underline ;
if ( a [ 2 ] . ToUpper ( ) . IndexOf ( "STRIKEOUT" ) > = 0 )
fontstyle = fontstyle | FontStyle . Strikeout ;
}
else
{
fontstyle = FontStyle . Regular ;
}
return new Font ( fontfamily , emsize , fontstyle , GraphicsUnit . Point ) ;
}
catch
{
}
return null ;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow ( IntPtr hWnd , ShowWindowCommands nCmdShow ) ;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow ( IntPtr hWnd ) ;
enum ShowWindowCommands : int
{
/// <summary>
/// Hides the window and activates another window.
/// </summary>
Hide = 0 ,
/// <summary>
/// Activates and displays a window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when displaying the window
/// for the first time.
/// </summary>
Normal = 1 ,
/// <summary>
/// Activates the window and displays it as a minimized window.
/// </summary>
ShowMinimized = 2 ,
/// <summary>
/// Maximizes the specified window.
/// </summary>
Maximize = 3 , // is this the right value?
/// <summary>
/// Activates the window and displays it as a maximized window.
/// </summary>
ShowMaximized = 3 ,
/// <summary>
/// Displays a window in its most recent size and position. This value
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
/// the window is not activated.
/// </summary>
ShowNoActivate = 4 ,
/// <summary>
/// Activates the window and displays it in its current size and position.
/// </summary>
Show = 5 ,
/// <summary>
/// Minimizes the specified window and activates the next top-level
/// window in the Z order.
/// </summary>
Minimize = 6 ,
/// <summary>
/// Displays the window as a minimized window. This value is similar to
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
/// window is not activated.
/// </summary>
ShowMinNoActive = 7 ,
/// <summary>
/// Displays the window in its current size and position. This value is
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
/// window is not activated.
/// </summary>
ShowNA = 8 ,
/// <summary>
/// Activates and displays the window. If the window is minimized or
/// maximized, the system restores it to its original size and position.
/// An application should specify this flag when restoring a minimized window.
/// </summary>
Restore = 9 ,
/// <summary>
/// Sets the show state based on the SW_* value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.
/// </summary>
ShowDefault = 10 ,
/// <summary>
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
/// that owns the window is not responding. This flag should only be
/// used when minimizing windows from a different thread.
/// </summary>
ForceMinimize = 11
}
private void ShowOptionsDlg ( )
{
2021-12-31 08:08:48 +00:00
// disable buttons
btn_Map_PlayPause . Enabled = false ;
btn_Map_Save . Enabled = false ;
btn_Options . Enabled = false ;
2019-03-19 21:09:03 +00:00
// 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 )
{
2021-12-31 08:08:48 +00:00
// save current settings
SaveUserSettings ( ) ;
2020-03-15 14:29:02 +00:00
// enbale/disable manage watchlist button
2020-04-19 07:23:30 +00:00
btn_Control_Manage_Watchlist . Enabled = ! Properties . Settings . Default . Watchlist_SyncWithKST | | ! Properties . Settings . Default . Server_Activate ;
2020-03-15 14:29:02 +00:00
// Re-initialze charts
InitializeCharts ( ) ;
2019-03-19 21:09:03 +00:00
// clear paths cache assuming that new options were set
ElevationPaths . Clear ( ) ;
PropagationPaths . Clear ( ) ;
2020-04-10 15:36:18 +00:00
// 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 ) ;
}
2022-08-27 12:13:47 +00:00
// update map provider
gm_Main . MapProvider = GMapProviders . Find ( Properties . Settings . Default . Map_Provider ) ;
2020-04-25 06:00:15 +00:00
2019-03-19 21:09:03 +00:00
// update ToolTipFont
ToolTipFont = CreateFontFromString ( Properties . Settings . Default . Map_ToolTipFont ) ;
// update planefeeds
bw_PlaneFeed1 = null ;
bw_PlaneFeed2 = null ;
bw_PlaneFeed3 = null ;
2020-02-12 10:45:19 +00:00
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 ) ;
}
}
}
2019-03-19 21:09:03 +00:00
// 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 ( ) ;
2022-08-27 12:13:47 +00:00
// resize map window
gm_Main_SizeChanged ( this , null ) ;
2019-03-19 21:09:03 +00:00
}
else
{
2022-08-27 12:13:47 +00:00
// nothing was changed --> reload settings
LoadUserSettings ( ) ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
// (re)initialize maps
InitializeMaps ( ) ;
2019-03-19 21:09:03 +00:00
// start permanent background workers
StartAllBackgroundWorkers ( ) ;
2021-12-31 08:08:48 +00:00
// enable buttons
btn_Map_PlayPause . Enabled = true ;
btn_Map_Save . Enabled = true ;
btn_Options . Enabled = true ;
2019-03-19 21:09:03 +00:00
// update status window
UpdateStatus ( ) ;
UpdateAirports ( ) ;
UpdateWatchlistInMap ( ) ;
RefreshWatchlistView ( ) ;
}
# endregion
#region Play & Pause
private void Play ( )
2022-08-27 12:13:47 +00:00
{
2019-03-19 21:09:03 +00:00
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 ;
2021-12-31 08:08:48 +00:00
// create distances, if enabled
if ( Properties . Settings . Default . Map_ShowDistances )
CreateDistances ( ) ;
2019-03-19 21:09:03 +00:00
// update tab control
tc_Control . Refresh ( ) ;
2020-03-01 15:12:08 +00:00
// refresh watch list
RefreshWatchlistView ( ) ;
2019-03-19 21:09:03 +00:00
// update all current paths
UpdatePaths ( ) ;
// clear spectrum
try
{
Spectrum . Points . Clear ( ) ;
SpectrumPointsCount = 0 ;
Spectrum_X . Reset ( ) ;
SpectrumRecord . Points . Clear ( ) ;
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
2022-08-27 12:13:47 +00:00
// 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 ] ;
}
2019-03-19 21:09:03 +00:00
// 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 ;
2020-03-01 15:12:08 +00:00
// tc_Control.Enabled = false;
2019-03-19 21:09:03 +00:00
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 ;
2022-08-27 12:13:47 +00:00
// 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 ] ;
}
2019-03-19 21:09:03 +00:00
// 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 ;
2020-02-12 10:45:19 +00:00
tc_Map . Enabled = true ;
2019-03-19 21:09:03 +00:00
// stop tracking
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . NONE ;
2019-03-19 21:09:03 +00:00
//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 ) ;
2020-02-12 10:45:19 +00:00
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 ) ;
2019-03-19 21:09:03 +00:00
gmmid . ToolTipText = ppath . Location1 . Call + " <> " + ppath . Location2 . Call ;
gmmid . ToolTipMode = MarkerTooltipMode . OnMouseOver ;
2022-08-27 12:13:47 +00:00
gmo_CallsignDetails . Markers . Add ( gmmid ) ;
2019-03-19 21:09:03 +00:00
// calculate dx end
2020-02-12 10:45:19 +00:00
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 ) ;
2019-03-19 21:09:03 +00:00
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" +
2022-08-27 12:13:47 +00:00
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" ;
2019-03-19 21:09:03 +00:00
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 ;
2022-08-27 12:13:47 +00:00
gmo_CallsignDetails . Markers . Add ( gmm_DXLoc ) ;
2019-03-19 21:09:03 +00:00
// 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
private void UpdatePaths ( )
{
// updates all current path to calculate
2023-01-30 06:00:58 +00:00
try
2019-03-19 21:09:03 +00:00
{
2023-01-30 06:00:58 +00:00
Log . WriteMessage ( "UpdatePath started." ) ;
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ) )
2019-03-19 21:09:03 +00:00
return ;
// OK valid, lets continue
2023-01-30 06:00:58 +00:00
// slow down background calculations
Properties . Settings . Default . Background_Calculations_ThreadWait = 1000 ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
//clear map overlays
gmo_PropagationPaths . Clear ( ) ;
gmo_NearestPaths . Clear ( ) ;
gmo_Objects . Clear ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// clear all planes and tooltips
gmo_Planes . Clear ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// clear paths
ElevationPaths . Clear ( ) ;
PropagationPaths . Clear ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// clear charts
ClearCharts ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// put call on MyCalls last recent collection if not already in
if ( Properties . Settings . Default . MyCalls . IndexOf ( Properties . Settings . Default . MyCall ) < 0 )
2019-03-19 21:09:03 +00:00
{
2023-01-30 06:00:58 +00:00
Properties . Settings . Default . MyCalls . Insert ( 0 , Properties . Settings . Default . MyCall ) ;
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
// keep the MyCalls list small
while ( Properties . Settings . Default . MyCalls . Count > 10 )
2019-03-19 21:09:03 +00:00
{
2023-01-30 06:00:58 +00:00
Properties . Settings . Default . MyCalls . RemoveAt ( Properties . Settings . Default . MyCalls . Count - 1 ) ;
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
// 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 ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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
2019-03-19 21:09:03 +00:00
// check and update station database
2023-01-30 06:00:58 +00:00
LocationDesignator dxloc = LocationFindOrUpdateOrCreate ( Properties . Settings . Default . DXCall , Properties . Settings . Default . DXLat , Properties . Settings . Default . DXLon ) ;
Properties . Settings . Default . DXElevation = dxloc . Elevation ;
2019-03-19 21:09:03 +00:00
// 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 ) ;
2023-01-30 06:00:58 +00:00
// add additional info to ppath
epath . Location1 = myloc ;
epath . Location2 = dxloc ;
epath . QRV1 = myqrv ;
epath . QRV2 = dxqrv ;
2019-03-19 21:09:03 +00:00
// 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 ) ;
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
// add additional info to ppath
ppath . Location1 = myloc ;
ppath . Location2 = dxloc ;
ppath . QRV1 = myqrv ;
ppath . QRV2 = dxqrv ;
2023-01-30 06:00:58 +00:00
// add single path to paths list
2019-03-19 21:09:03 +00:00
ElevationPaths . Add ( epath ) ;
PropagationPaths . Add ( ppath ) ;
2023-01-30 06:00:58 +00:00
// 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 ) ;
}
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
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 ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// check if call & loc are valid
if ( ! Callsign . Check ( call ) | | ! MaidenheadLocator . Check ( loc ) )
continue ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ) ;
}
}
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
double centerlat = myloc . Lat ;
double centerlon = myloc . Lon ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ) ;
}
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ] ) ;
}
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// calculate center
centerlat = LatLon . MidPoint ( minlat , minlon , maxlat , maxlon ) . Lat ;
centerlon = LatLon . MidPoint ( minlat , minlon , maxlat , maxlon ) . Lon ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// clear all selections
SelectedPlanes . Clear ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// update watchlist locations in map
UpdateWatchlistInMap ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// update status window
UpdateStatus ( ) ;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// stop tracking
//TrackMode = AIRSCOUTTRACKMODE.NONE;
2019-03-19 21:09:03 +00:00
2023-01-30 06:00:58 +00:00
// 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 ( ) ) ;
}
2019-03-19 21:09:03 +00:00
}
# 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 " ;
2020-04-25 06:00:15 +00:00
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 )
2019-03-19 21:09:03 +00:00
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 ] ) ;
2023-01-30 06:00:58 +00:00
GMarkerGoogle m = new GMarkerGoogle ( new PointLatLng ( info . Lat , info . Lon ) , ToolTipFont , RotateImageByAngle ( bm , ( ( info . Track > = 0 ) & & ( info . Track < = 360 ) ) ? ( float ) info . Track : 0 ) ) ;
2019-03-19 21:09:03 +00:00
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 ] ) ;
2023-01-30 06:00:58 +00:00
GMarkerGoogle m = new GMarkerGoogle ( new PointLatLng ( info . Lat , info . Lon ) , ToolTipFont , RotateImageByAngle ( bm , ( ( info . Track > = 0 ) & & ( info . Track < = 360 ) ) ? ( float ) info . Track : 0 ) ) ;
2019-03-19 21:09:03 +00:00
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 )
2021-12-31 08:08:48 +00:00
m . ToolTipText + = "\nTrack: " + ( int ) info . Track + "°" ;
2019-03-19 21:09:03 +00:00
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 ) + "]" ;
2022-08-27 12:13:47 +00:00
if ( info . Potential > 0 )
2019-03-19 21:09:03 +00:00
{
2022-08-27 12:13:47 +00:00
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" ;
}
2019-03-19 21:09:03 +00:00
if ( selected )
{
m . ToolTipMode = MarkerTooltipMode . Always ;
}
else
{
m . ToolTipMode = MarkerTooltipMode . OnMouseOver ;
}
if ( m . ToolTip ! = null )
m . ToolTip . Fill = brush ;
return m ;
}
private void DrawPlanes ( )
{
bool alarm = false ;
bool isselected = false ;
string alarm_msg = "" ;
List < PlaneInfo > pathplanes = new List < PlaneInfo > ( ) ;
// check if any plane is on list --> return empty list
if ( ( ActivePlanes = = null ) | | ( ActivePlanes . Count = = 0 ) )
return ;
2020-02-12 10:45:19 +00:00
bool anyselected = false ;
2020-03-01 15:12:08 +00:00
List < TooltipDataPoint > planes_hi = new List < TooltipDataPoint > ( ) ;
List < TooltipDataPoint > planes_lo = new List < TooltipDataPoint > ( ) ;
2019-03-19 21:09:03 +00:00
// 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 :
2022-08-27 12:13:47 +00:00
if ( Properties . Settings . Default . InfoWin_AlwaysDetailed )
{
gmo_Planes . Markers . Add ( CreatePlaneDetailed ( plane , isselected ) ) ;
}
else
{
gmo_Planes . Markers . Add ( CreatePlaneSimple ( plane , isselected ) ) ;
}
2019-03-19 21:09:03 +00:00
break ;
}
2020-03-01 15:12:08 +00:00
// 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)]" ;
2019-03-19 21:09:03 +00:00
// if selected: draw the thin path to crossing point if one
if ( isselected )
{
2020-02-12 10:45:19 +00:00
anyselected = true ;
2019-03-19 21:09:03 +00:00
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 )
{
2021-12-31 08:08:48 +00:00
Properties . Settings . Default . Track_CurrentPlane = plane . Hex ;
2019-03-19 21:09:03 +00:00
}
}
// 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
2020-03-01 15:12:08 +00:00
/ *
2019-03-19 21:09:03 +00:00
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 ) ) ;
}
2020-03-01 15:12:08 +00:00
* /
TooltipDataPoint p = new TooltipDataPoint ( dist , plane . Alt_m , plane . Call ) ;
if ( plane . AltDiff > 0 )
{
planes_hi . Add ( p ) ;
}
else
{
planes_lo . Add ( p ) ;
}
2019-03-19 21:09:03 +00:00
}
}
}
2020-03-01 15:12:08 +00:00
// 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}" ;
2019-03-19 21:09:03 +00:00
// invalidate chart
pm_Path . InvalidatePlot ( true ) ;
// set alarm if one
if ( alarm )
Alarm ( alarm_msg ) ;
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
2020-02-12 10:45:19 +00:00
// stop tracking if selected object is lost for any reason
if ( ! anyselected )
{
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . NONE ;
2020-02-12 10:45:19 +00:00
}
2019-03-19 21:09:03 +00:00
}
private void UpdatePlanes ( )
{
2020-02-12 10:45:19 +00:00
2019-03-19 21:09:03 +00:00
// get current time
// update status
UpdateStatus ( ) ;
// check for filter settings
// and color filter box
int planes_filter_minalt = 0 ;
planes_filter_minalt = Properties . Settings . Default . Planes_Filter_Min_Alt ;
if ( planes_filter_minalt < 0 )
planes_filter_minalt = 0 ;
if ( ( planes_filter_minalt ! = 0 ) | | ( Properties . Settings . Default . Planes_Filter_Min_Category > PLANECATEGORY . LIGHT ) )
{
pa_Planes_Filter . BackColor = Color . Plum ;
}
else
{
pa_Planes_Filter . BackColor = SystemColors . Control ;
}
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
List < PlaneInfo > allplanes = Planes . GetAll ( CurrentTime , Properties . Settings . Default . Planes_Position_TTL ) ;
// TODO: maintain selected status
st . Stop ( ) ;
// Log.WriteMessage("Getting plane positions from database: " + allplanes.Count().ToString() + " plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
// clear active planes
ActivePlanes . Clear ( ) ;
foreach ( PropagationPathDesignator ppath in PropagationPaths )
{
st . Reset ( ) ;
st . Start ( ) ;
NearestPlane = null ;
2020-02-12 10:45:19 +00:00
double highestpotential = 0 ;
2019-03-19 21:09:03 +00:00
// get nearest planes per path
List < PlaneInfo > nearestplanes = AircraftData . Database . GetNearestPlanes ( DateTime . UtcNow , ppath , allplanes , Properties . Settings . Default . Planes_Filter_Max_Circumcircle , Properties . Settings . Default . Path_Band_Settings [ Properties . Settings . Default . Band ] . MaxDistance , Properties . Settings . Default . Planes_MaxAlt ) ;
foreach ( PlaneInfo plane in nearestplanes )
{
2020-02-12 10:45:19 +00:00
// maintain highest potential
2021-12-31 08:08:48 +00:00
if ( ( plane . Alt_m > = Properties . Settings . Default . Planes_Filter_Min_Alt ) & & ( plane . Category > = Properties . Settings . Default . Planes_Filter_Min_Category ) & & ( plane . Potential > highestpotential ) )
2020-02-12 10:45:19 +00:00
highestpotential = plane . Potential ;
2019-03-19 21:09:03 +00:00
// 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
2020-02-12 10:45:19 +00:00
if ( ( plane . IntPoint ! = null ) & & ( plane . Potential > activeplane . Potential ) )
2019-03-19 21:09:03 +00:00
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 ;
}
}
}
2020-02-12 10:45:19 +00:00
// 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 ( ) ;
}
}
}
2019-03-19 21:09:03 +00:00
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 ( ) ;
2020-03-01 15:12:08 +00:00
pm_Path . Annotations . Clear ( ) ;
2019-03-19 21:09:03 +00:00
// draw planes
DrawPlanes ( ) ;
st . Stop ( ) ;
// Log.WriteMessage("Drawing planes: " + ActivePlanes.Count.ToString() + " plane(s), " + st.ElapsedMilliseconds.ToString() + " ms.");
2020-02-12 10:45:19 +00:00
// set focus on the map object
this . ActiveControl = gm_Main ;
2019-03-19 21:09:03 +00:00
}
# 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 ;
2020-02-12 10:45:19 +00:00
if ( ( PathMode = = AIRSCOUTPATHMODE . MULTI ) & & Properties . Settings . Default . Map_LabelCalls & & item . Checked )
gm . ToolTipMode = MarkerTooltipMode . Always ;
else
gm . ToolTipMode = MarkerTooltipMode . OnMouseOver ;
2019-03-19 21:09:03 +00:00
gm . Tag = dxloc . Call ;
gmo_Callsigns . Markers . Add ( gm ) ;
}
}
2020-02-12 10:45:19 +00:00
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 ;
}
}
2019-03-19 21:09:03 +00:00
private void RefreshWatchlistView ( )
{
2020-02-12 10:45:19 +00:00
2019-03-19 21:09:03 +00:00
// set watchlistupdating flag
WatchlistUpdating = true ;
2020-02-12 10:45:19 +00:00
// keep scroll position
int topItemIndex = 0 ;
try
{
2020-04-10 15:36:18 +00:00
if ( ( PlayMode ! = AIRSCOUTPLAYMODE . FORWARD ) & & ( lv_Control_Watchlist . TopItem ! = null ) )
2020-03-01 15:12:08 +00:00
{
topItemIndex = lv_Control_Watchlist . TopItem . Index ;
}
2020-02-12 10:45:19 +00:00
}
catch ( Exception ex )
{
// do nothing
}
2019-03-19 21:09:03 +00:00
// update listview
lv_Control_Watchlist . BeginUpdate ( ) ;
lv_Control_Watchlist . Items . Clear ( ) ;
2020-03-15 14:29:02 +00:00
Properties . Settings . Default . Watchlist . Sort ( ) ;
2020-02-12 10:45:19 +00:00
// run twice, add checked items first, then all others
2019-03-19 21:09:03 +00:00
foreach ( WatchlistItem item in Properties . Settings . Default . Watchlist )
{
// nasty!! Should never be null!
if ( item = = null )
continue ;
if ( item . Checked )
2020-02-12 10:45:19 +00:00
AddListViewItem ( item ) ;
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
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();
2019-03-19 21:09:03 +00:00
lv_Control_Watchlist . EndUpdate ( ) ;
2020-02-12 10:45:19 +00:00
// restore scroll position
try
{
lv_Control_Watchlist . TopItem = lv_Control_Watchlist . Items [ topItemIndex ] ;
}
catch ( Exception ex )
{
// do nothing
}
2019-03-19 21:09:03 +00:00
// 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 )
{
2020-03-01 15:12:08 +00:00
// prevent timer tick from overflow when heavy loaded
// stop timer --> do update procedure --> start timer again
ti_Progress . Stop ( ) ;
2019-03-19 21:09:03 +00:00
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 ( ) ;
}
}
2020-03-01 15:12:08 +00:00
// restart timer
ti_Progress . Start ( ) ;
2019-03-19 21:09:03 +00:00
}
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 ( ) ;
2021-12-31 08:08:48 +00:00
// (re)initialize locator overlay
InitializeLocators ( ) ;
2019-03-19 21:09:03 +00:00
}
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 ;
2020-03-15 14:29:02 +00:00
// check if callsign clicked and not own callsign
2019-03-19 21:09:03 +00:00
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 ( ) ;
}
}
2020-03-15 14:29:02 +00:00
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 ( ) ;
}
}
2019-03-19 21:09:03 +00:00
}
}
// 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 ( ) ;
2021-12-31 08:08:48 +00:00
if ( selectedindex < 0 )
{
SelectedPlanes . Add ( ( string ) item . Tag ) ;
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
else
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 ) ;
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
// set track mode
if ( Properties . Settings . Default . Track_Activate )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . TRACK ;
2019-03-19 21:09:03 +00:00
}
}
// 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 )
{
2021-12-31 08:08:48 +00:00
TrackMode = AIRSCOUTTRACKMODE . SINGLE ;
2019-03-19 21:09:03 +00:00
Properties . Settings . Default . Track_SetAz = qtf ;
Properties . Settings . Default . Track_SetEl = 0 ;
}
}
}
}
catch ( Exception ex )
{
// do nothing if item not found in planes list
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 ;
}
2021-12-31 08:08:48 +00:00
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 ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
private void gm_Main_Paint ( object sender , PaintEventArgs e )
{
2022-08-27 12:13:47 +00:00
if ( Properties . Settings . Default . Map_TrackingGaugesShow & & ( TrackMode = = AIRSCOUTTRACKMODE . TRACK ) & & ( TrackValues ! = null ) )
2021-12-31 08:08:48 +00:00
{
// paint gauges on top of the map if enabled
ag_Azimuth . Value = ( float ) TrackValues . MyAzimuth ;
ag_Elevation . Value = ( float ) TrackValues . MyElevation ;
2022-08-27 12:13:47 +00:00
// 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 ) ) ;
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
// 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 ) ;
2021-12-31 08:08:48 +00:00
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 = "." ;
2022-08-27 12:13:47 +00:00
int top = 0 ;
2021-12-31 08:08:48 +00:00
int left = 10 ;
2022-08-27 12:13:47 +00:00
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 ) ) ;
2021-12-31 08:08:48 +00:00
}
2019-03-19 21:09:03 +00:00
}
}
private void gm_Main_SizeChanged ( object sender , EventArgs e )
{
2022-08-27 12:13:47 +00:00
try
{
// get width from properties
int width = ( int ) Properties . Settings . Default . Map_TrackingGaugeWidth ;
2019-03-19 21:09:03 +00:00
2021-12-31 08:08:48 +00:00
2022-08-27 12:13:47 +00:00
// 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 )
{
}
2021-12-31 08:08:48 +00:00
}
private void gm_Main_OnPositionChanged ( PointLatLng point )
{
}
private void gm_Main_OnTileLoadComplete ( long ElapsedMilliseconds )
{
2022-08-27 12:13:47 +00:00
// use thread safe call here!
2023-01-30 06:00:58 +00:00
this . BeginInvoke ( ( Action ) delegate ( )
2022-08-27 12:13:47 +00:00
{
2023-01-30 06:00:58 +00:00
InitializeLocators ( ) ;
} ) ;
2019-03-19 21:09:03 +00:00
}
# 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 ;
2022-08-27 12:13:47 +00:00
// SaveUserSettings();
// Properties.Settings.Default.Reload();
2019-03-19 21:09:03 +00:00
}
#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 ;
2020-02-12 10:45:19 +00:00
tc_Map . SelectedTab = tp_Map ;
2019-03-19 21:09:03 +00:00
}
2020-03-01 15:12:08 +00:00
// update all info
UpdateStatus ( ) ;
2019-03-19 21:09:03 +00:00
}
private void gb_Map_Info_MouseClick ( object sender , MouseEventArgs e )
{
// get font size in pixels
double pixels ;
using ( Graphics g = this . CreateGraphics ( ) )
{
pixels = gb_Map_Info . Font . SizeInPoints * g . DpiX / 72 ;
}
if ( ( e . Y < = pixels ) & & ( e . Button = = MouseButtons . Left ) )
{
Properties . Settings . Default . Map_ShowInfoBox = ! Properties . Settings . Default . Map_ShowInfoBox ;
}
}
private void cb_MyCall_TextChanged ( object sender , EventArgs e )
{
int i = cb_MyCall . SelectionStart ;
Properties . Settings . Default . MyCall = cb_MyCall . Text ;
// clear locator entries
cb_MyLoc . Text = "" ;
cb_MyLoc . Items . Clear ( ) ;
Properties . Settings . Default . MyLat = double . NaN ;
Properties . Settings . Default . MyLon = double . NaN ;
Properties . Settings . Default . MyElevation = 0 ;
if ( Callsign . Check ( cb_MyCall . Text ) )
{
// select last recent loc
LocationDesignator ld = StationData . Database . LocationFind ( cb_MyCall . Text ) ;
if ( ld ! = null )
{
Properties . Settings . Default . MyLat = ld . Lat ;
Properties . Settings . Default . MyLon = ld . Lon ;
Properties . Settings . Default . MyElevation = GetElevation ( ld . Lat , ld . Lon ) ;
}
}
UpdateStatus ( ) ;
cb_MyCall . Select ( i , 0 ) ;
}
private void cb_MyCall_SelectedIndexChanged ( object sender , EventArgs e )
{
if ( cb_MyCall . SelectedItem ! = null )
{
cb_MyCall . Text = cb_MyCall . SelectedItem . ToString ( ) ;
LocationDesignator ld = StationData . Database . LocationFind ( cb_MyCall . Text ) ;
if ( Callsign . Check ( cb_MyCall . Text ) & & ( ld ! = null ) )
{
// update Settings
cb_MyLoc . Text = MaidenheadLocator . LocFromLatLon ( ld . Lat , ld . Lon , Properties . Settings . Default . Locator_SmallLettersForSubsquares , ( int ) Properties . Settings . Default . Locator_MaxLength / 2 , Properties . Settings . Default . Locator_AutoLength ) ;
Properties . Settings . Default . MyCall = cb_MyCall . Text ;
Properties . Settings . Default . MyLat = ld . Lat ;
Properties . Settings . Default . MyLon = ld . Lon ;
Properties . Settings . Default . MyElevation = GetElevation ( ld . Lat , ld . Lon ) ;
Properties . Settings . Default . MyHeight = 10 ;
}
else
{
Properties . Settings . Default . MyLat = double . NaN ;
Properties . Settings . Default . MyLon = double . NaN ;
Properties . Settings . Default . MyElevation = 0 ;
Properties . Settings . Default . MyHeight = 0 ;
}
UpdateStatus ( ) ;
}
}
private void cb_MyCall_DropDown ( object sender , EventArgs e )
{
// poulate from MyCalls last recent collection
// populate drop down list
cb_MyCall . Items . Clear ( ) ;
foreach ( string call in Properties . Settings . Default . MyCalls )
{
cb_MyCall . Items . Add ( call ) ;
}
}
private void cb_MyLoc_TextChanged ( object sender , EventArgs e )
{
if ( cb_MyLoc . Focused )
{
if ( MaidenheadLocator . Check ( cb_MyLoc . Text ) & & ( cb_MyLoc . Text . Length > = 6 ) )
{
Properties . Settings . Default . MyLat = cb_MyLoc . GeoLocation . Lat ;
Properties . Settings . Default . MyLon = cb_MyLoc . GeoLocation . Lon ;
Properties . Settings . Default . MyElevation = GetElevation ( Properties . Settings . Default . MyLat , Properties . Settings . Default . MyLon ) ;
Properties . Settings . Default . MyHeight = 10 ;
// colour Textbox if more precise lat/lon information is available
if ( MaidenheadLocator . IsPrecise ( Properties . Settings . Default . MyLat , Properties . Settings . Default . MyLon , 3 ) )
{
cb_MyLoc . BackColor = Color . PaleGreen ;
}
UpdateStatus ( ) ;
}
else
{
cb_MyLoc . BackColor = Color . FloralWhite ;
}
}
}
private void cb_MyLoc_DropDown ( object sender , EventArgs e )
{
// fill MyLoc combo box with all known locators
cb_MyLoc . BackColor = Color . FloralWhite ;
cb_MyLoc . SilentText = "" ;
cb_MyLoc . Items . Clear ( ) ;
List < LocationDesignator > lds = StationData . Database . LocationFindAll ( cb_MyCall . Text ) ;
if ( lds ! = null )
{
// fill item list of locator box
foreach ( LocationDesignator ld in lds )
{
LocatorDropDownItem ldd = new LocatorDropDownItem ( MaidenheadLocator . LocFromLatLon ( ld . Lat , ld . Lon , Properties . Settings . Default . Locator_SmallLettersForSubsquares , ( int ) Properties . Settings . Default . Locator_MaxLength / 2 , Properties . Settings . Default . Locator_AutoLength ) , new LatLon . GPoint ( ld . Lat , ld . Lon ) ) ;
cb_MyLoc . Items . Add ( ldd ) ;
}
}
}
private void cb_MyLoc_SelectedIndexChanged ( object sender , EventArgs e )
{
LocatorDropDownItem ldd = ( LocatorDropDownItem ) cb_MyLoc . SelectedItem ;
if ( ldd ! = null )
{
// update properties
cb_MyLoc . Precision = ( int ) Properties . Settings . Default . Locator_MaxLength / 2 ;
cb_MyLoc . SmallLettersForSubsquares = Properties . Settings . Default . Locator_SmallLettersForSubsquares ;
cb_MyLoc . AutoLength = Properties . Settings . Default . Locator_AutoLength ;
// set geolocation instead of text
cb_MyLoc . GeoLocation = ldd . GeoLocation ;
}
}
private void cb_MyLoc_SelectionChangeCommittedWithNoUpdate ( object sender , EventArgs e )
{
}
private void cb_DXCall_TextChanged ( object sender , EventArgs e )
{
int i = cb_DXCall . SelectionStart ;
Properties . Settings . Default . DXCall = cb_DXCall . Text ;
// clear locator entries
cb_DXLoc . Text = "" ;
cb_DXLoc . Items . Clear ( ) ;
Properties . Settings . Default . DXLat = double . NaN ;
Properties . Settings . Default . DXLon = double . NaN ;
Properties . Settings . Default . DXElevation = 0 ;
if ( Callsign . Check ( cb_DXCall . Text ) )
{
// select last recent loc
LocationDesignator ld = StationData . Database . LocationFind ( cb_DXCall . Text ) ;
if ( ld ! = null )
{
Properties . Settings . Default . DXLat = ld . Lat ;
Properties . Settings . Default . DXLon = ld . Lon ;
Properties . Settings . Default . DXElevation = GetElevation ( ld . Lat , ld . Lon ) ;
}
}
UpdateStatus ( ) ;
cb_DXCall . Select ( i , 0 ) ;
}
private void cb_DXCall_SelectedIndexChanged ( object sender , EventArgs e )
{
if ( cb_DXCall . SelectedItem ! = null )
{
cb_DXCall . Text = cb_DXCall . SelectedItem . ToString ( ) ;
LocationDesignator ld = StationData . Database . LocationFind ( cb_DXCall . Text ) ;
if ( Callsign . Check ( cb_DXCall . Text ) & & ( ld ! = null ) )
{
// update Settings
cb_DXLoc . Text = MaidenheadLocator . LocFromLatLon ( ld . Lat , ld . Lon , Properties . Settings . Default . Locator_SmallLettersForSubsquares , ( int ) Properties . Settings . Default . Locator_MaxLength / 2 , Properties . Settings . Default . Locator_AutoLength ) ;
Properties . Settings . Default . DXCall = cb_DXCall . Text ;
Properties . Settings . Default . DXLat = ld . Lat ;
Properties . Settings . Default . DXLon = ld . Lon ;
Properties . Settings . Default . DXElevation = GetElevation ( ld . Lat , ld . Lon ) ;
Properties . Settings . Default . DXHeight = 10 ;
}
else
{
Properties . Settings . Default . DXLat = double . NaN ;
Properties . Settings . Default . DXLon = double . NaN ;
Properties . Settings . Default . DXElevation = 0 ;
Properties . Settings . Default . DXHeight = 0 ;
}
UpdateStatus ( ) ;
}
}
private void cb_DXCall_DropDown ( object sender , EventArgs e )
{
// populate from watchlist
// return on empty watchlist
if ( Properties . Settings . Default . Watchlist = = null )
return ;
// populate drop down list
List < string > dxcalls = new List < string > ( ) ;
foreach ( WatchlistItem item in Properties . Settings . Default . Watchlist )
{
// nasty!! Should never be null!
if ( item = = null )
continue ;
dxcalls . Add ( item . Call ) ;
}
dxcalls . Sort ( ) ;
cb_DXCall . Items . Clear ( ) ;
cb_DXCall . Items . AddRange ( dxcalls . ToArray ( ) ) ;
}
private void cb_DXLoc_TextChanged ( object sender , EventArgs e )
{
if ( cb_DXLoc . Focused )
{
if ( MaidenheadLocator . Check ( cb_DXLoc . Text ) & & ( cb_DXLoc . Text . Length > = 6 ) )
{
Properties . Settings . Default . DXLat = cb_DXLoc . GeoLocation . Lat ;
Properties . Settings . Default . DXLon = cb_DXLoc . GeoLocation . Lon ;
Properties . Settings . Default . DXElevation = GetElevation ( Properties . Settings . Default . DXLat , Properties . Settings . Default . DXLon ) ;
Properties . Settings . Default . DXHeight = 10 ;
// colour Textbox if more precise lat/lon information is available
if ( MaidenheadLocator . IsPrecise ( Properties . Settings . Default . DXLat , Properties . Settings . Default . DXLon , 3 ) )
{
cb_DXLoc . BackColor = Color . PaleGreen ;
}
UpdateStatus ( ) ;
}
else
{
cb_DXLoc . BackColor = Color . FloralWhite ;
}
}
}
private void cb_DXLoc_DropDown ( object sender , EventArgs e )
{
// fill DXLoc combo box with all known locators
cb_DXLoc . BackColor = Color . FloralWhite ;
cb_DXLoc . SilentText = "" ;
cb_DXLoc . Items . Clear ( ) ;
List < LocationDesignator > lds = StationData . Database . LocationFindAll ( cb_DXCall . Text ) ;
if ( lds ! = null )
{
// fill item list of locator box
foreach ( LocationDesignator ld in lds )
{
LocatorDropDownItem ldd = new LocatorDropDownItem ( MaidenheadLocator . LocFromLatLon ( ld . Lat , ld . Lon , Properties . Settings . Default . Locator_SmallLettersForSubsquares , ( int ) Properties . Settings . Default . Locator_MaxLength / 2 , Properties . Settings . Default . Locator_AutoLength ) , new LatLon . GPoint ( ld . Lat , ld . Lon ) ) ;
cb_DXLoc . Items . Add ( ldd ) ;
}
}
}
private void cb_DXLoc_SelectedIndexChanged ( object sender , EventArgs e )
{
LocatorDropDownItem ldd = ( LocatorDropDownItem ) cb_DXLoc . SelectedItem ;
if ( ldd ! = null )
{
// update properties
cb_DXLoc . Precision = ( int ) Properties . Settings . Default . Locator_MaxLength / 2 ;
cb_DXLoc . SmallLettersForSubsquares = Properties . Settings . Default . Locator_SmallLettersForSubsquares ;
cb_DXLoc . AutoLength = Properties . Settings . Default . Locator_AutoLength ;
// set geolocation instead of text
cb_DXLoc . GeoLocation = ldd . GeoLocation ;
}
}
private void cb_DXLoc_SelectionChangeCommittedWithNoUpdate ( object sender , EventArgs e )
{
}
# endregion
#region Tab Multi
private void tp_Control_Multi_Enter ( object sender , EventArgs e )
{
2020-03-15 14:29:02 +00:00
// enbale/disable manage watchlist button
2020-04-19 07:23:30 +00:00
btn_Control_Manage_Watchlist . Enabled = ! Properties . Settings . Default . Watchlist_SyncWithKST | | ! Properties . Settings . Default . Server_Activate ;
2020-03-15 14:29:02 +00:00
2019-03-19 21:09:03 +00:00
if ( PathMode ! = AIRSCOUTPATHMODE . MULTI )
{
PathMode = AIRSCOUTPATHMODE . MULTI ;
2020-02-12 10:45:19 +00:00
tc_Map . SelectedTab = tp_Map ;
2019-03-19 21:09:03 +00:00
}
2020-03-01 15:12:08 +00:00
tp_Control_Multi . Refresh ( ) ;
2019-03-19 21:09:03 +00:00
}
private void lv_Control_Watchlist_Resize ( object sender , EventArgs e )
{
// list view resized
// resize locator column to fit the client size
2020-03-01 15:12:08 +00:00
try
{
lv_Control_Watchlist . Columns [ 1 ] . Width = lv_Control_Watchlist . ClientSize . Width - lv_Control_Watchlist . Columns [ 0 ] . Width ;
}
catch
{
// do nothing, if resize fails
}
2019-03-19 21:09:03 +00:00
}
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
2020-03-01 15:12:08 +00:00
try
{
lv_Control_Watchlist . Columns [ 1 ] . Width = lv_Control_Watchlist . ClientSize . Width - lv_Control_Watchlist . Columns [ 0 ] . Width ;
}
catch
{
// do nothing, if resize fails
}
2019-03-19 21:09:03 +00:00
}
}
2020-03-01 15:12:08 +00:00
private void lv_Control_Watchlist_ItemCheck ( object sender , ItemCheckEventArgs e )
{
// ignore when in PLAY mode
if ( ! WatchlistUpdating & & ( PlayMode = = AIRSCOUTPLAYMODE . FORWARD ) )
e . NewValue = e . CurrentValue ;
}
2019-03-19 21:09:03 +00:00
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 )
{
2020-03-01 15:12:08 +00:00
// ignore when in PLAY mode
if ( PlayMode = = AIRSCOUTPLAYMODE . FORWARD )
return ;
2019-03-19 21:09:03 +00:00
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 ( ) ;
2020-02-12 10:45:19 +00:00
CheckBoxRenderer . DrawCheckBox ( e . Graphics , new System . Drawing . Point ( ClientRectangle . Location . X + 4 , ClientRectangle . Location . Y + 1 ) , WatchlistAllCheckedState ) ;
2019-03-19 21:09:03 +00:00
e . DrawText ( flags ) ;
}
private void lv_Control_Watchlist_DrawItem ( object sender , DrawListViewItemEventArgs e )
2020-02-12 10:45:19 +00:00
{
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 ) ;
2020-04-10 15:36:18 +00:00
// set default color
bkcolor = Color . White ;
2020-02-12 10:45:19 +00:00
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 ;
}
}
2020-03-01 15:12:08 +00:00
e . DrawDefault = true ;
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
2019-03-19 21:09:03 +00:00
private void lv_Control_Watchlist_DrawSubItem ( object sender , DrawListViewSubItemEventArgs e )
{
2020-02-12 10:45:19 +00:00
e . DrawDefault = true ;
2019-03-19 21:09:03 +00:00
}
2020-03-01 15:12:08 +00:00
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 )
2019-03-19 21:09:03 +00:00
{
2020-03-01 15:12:08 +00:00
// sync watchlist, try to keep previously checked calls
// you can have a call only once in the watch list
List < string > checkedcalls = new List < string > ( ) ;
foreach ( WatchlistItem item in Properties . Settings . Default . Watchlist )
{
if ( item . Checked )
checkedcalls . Add ( item . Call ) ;
}
2019-03-19 21:09:03 +00:00
WatchlistDlg Dlg = new WatchlistDlg ( ) ;
if ( Dlg . ShowDialog ( ) = = DialogResult . OK )
{
2020-03-01 15:12:08 +00:00
// clear watch list
Properties . Settings . Default . Watchlist . Clear ( ) ;
foreach ( DataGridViewRow row in Dlg . dgv_Watchlist_Selected . Rows )
2019-03-19 21:09:03 +00:00
{
2020-03-01 15:12:08 +00:00
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 ) ;
2019-03-19 21:09:03 +00:00
}
2020-03-01 15:12:08 +00:00
// reselect previously selected
foreach ( string checkedcall in checkedcalls )
2019-03-19 21:09:03 +00:00
{
2020-03-01 15:12:08 +00:00
int index = Properties . Settings . Default . Watchlist . IndexOf ( checkedcall ) ;
2019-03-19 21:09:03 +00:00
if ( index > = 0 )
2020-03-01 15:12:08 +00:00
Properties . Settings . Default . Watchlist [ index ] . Checked = true ;
2019-03-19 21:09:03 +00:00
}
2020-03-01 15:12:08 +00:00
// refresh watchlist view
2019-03-19 21:09:03 +00:00
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
# 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
# endregion
# endregion
#region Buttons
private void btn_Options_Click ( object sender , EventArgs e )
{
ShowOptionsDlg ( ) ;
}
private void btn_Map_Save_Click ( object sender , EventArgs e )
{
MapSave ( ) ;
}
private void btn_Map_PlayPause_Click ( object sender , EventArgs e )
{
if ( PlayMode ! = AIRSCOUTPLAYMODE . FORWARD )
{
Play ( ) ;
}
else
{
Pause ( ) ;
}
}
# endregion
# endregion
#region Main Tab Control
private void tc_Main_SelectedIndexChanged ( object sender , EventArgs e )
{
}
private void tc_Main_DrawItem ( object sender , DrawItemEventArgs e )
{
// This event is called once for each tab button in your tab control
// First paint the background with a color based on the current tab
// e.Index is the index of the tab in the TabPages collection.
// fill background
e . Graphics . FillRectangle ( new SolidBrush ( SystemColors . Control ) , e . Bounds ) ;
// Then draw the current tab button text
Rectangle paddedBounds = e . Bounds ;
paddedBounds . Inflate ( - 2 , - 2 ) ;
e . Graphics . DrawString ( tc_Main . TabPages [ e . Index ] . Text , tc_Main . Font , ( tc_Main . Enabled ) ? SystemBrushes . ControlText : SystemBrushes . GrayText , paddedBounds ) ;
}
#region Tab Page Spectrum
private void tp_Spectrum_Enter ( object sender , EventArgs e )
{
}
private void tp_Spectrum_Resize ( object sender , EventArgs e )
{
// adjust group boxes
// get quadratical nearest plane box
gb_NearestPlaneMap . Width = gb_NearestPlaneMap . Height ;
gb_NearestPlaneMap . Left = tp_Spectrum . Width - gb_NearestPlaneMap . Width - 5 ;
// adjust plane info box
gb_Spectrum_NearestInfo . Left = tp_Spectrum . Width - gb_NearestPlaneMap . Width - gb_Spectrum_NearestInfo . Width - 10 ;
// adjust spectrum box
gb_Spectrum . Width = tp_Spectrum . Width - gb_NearestPlaneMap . Width - gb_Spectrum_NearestInfo . Width - 30 ;
tb_Spectrum_Status . Left = 5 ;
tb_Spectrum_Status . Width = pv_Spectrum . Width - 10 ;
}
# endregion
#region Tab Page Elevation
private void tp_Elevation_Enter ( object sender , EventArgs e )
{
}
private void tp_Elevation_Resize ( object sender , EventArgs e )
{
// adjust charts
pv_Path . Location = new System . Drawing . Point ( 0 , 0 ) ;
pv_Path . Width = tp_Elevation . Width ;
pv_Path . Height = tp_Elevation . Height / 2 ;
pv_Elevation . Location = new System . Drawing . Point ( 0 , tp_Elevation . Height / 2 ) ;
pv_Elevation . Width = tp_Elevation . Width ;
pv_Elevation . Height = tp_Elevation . Height / 2 ;
}
# endregion
#region Tab Page Analysis
private void UpdatePlayer ( )
{
// set players bounds
sb_Analysis_Play . Minimum = 0 ;
sb_Analysis_Play . Maximum = ( int ) ( dtp_Analysis_MaxValue . Value - dtp_Analysis_MinValue . Value ) . TotalSeconds ;
sb_Analysis_Play . Value = 0 ;
}
private void tp_Analysis_Enter ( object sender , EventArgs e )
{
if ( LifeMode = = AIRSCOUTLIFEMODE . LIFE )
{
btn_Analysis_ON . Enabled = true ;
btn_Analysis_ON . BackColor = Color . YellowGreen ;
btn_Analysis_OFF . Enabled = false ;
btn_Analysis_OFF . BackColor = Color . Gray ;
}
else
{
btn_Analysis_ON . Enabled = false ;
btn_Analysis_ON . BackColor = Color . Gray ;
btn_Analysis_OFF . Enabled = true ;
btn_Analysis_OFF . BackColor = Color . LightCoral ;
}
SayAnalysis ( "Press <ON> to start analysis." ) ;
}
private void tp_Analysis_Leave ( object sender , EventArgs e )
{
}
private void btn_Analysis_ON_Click ( object sender , EventArgs e )
{
SayAnalysis ( "Getting database properties, please wait..." ) ;
// go into offline mode
btn_Analysis_ON . Enabled = false ;
btn_Analysis_ON . BackColor = Color . Gray ;
btn_Analysis_OFF . Enabled = true ;
btn_Analysis_OFF . BackColor = Color . LightCoral ;
btn_Map_PlayPause . Enabled = false ;
LifeMode = AIRSCOUTLIFEMODE . HISTORY ;
PlayMode = AIRSCOUTPLAYMODE . PAUSE ;
if ( ! bw_Analysis_DataGetter . IsBusy )
bw_Analysis_DataGetter . RunWorkerAsync ( ) ;
}
private void btn_Analysis_OFF_Click ( object sender , EventArgs e )
{
if ( bw_Analysis_FileSaver . IsBusy )
bw_Analysis_FileSaver . CancelAsync ( ) ;
if ( bw_Analysis_FileLoader . IsBusy )
bw_Analysis_FileLoader . CancelAsync ( ) ;
if ( bw_Analysis_DataGetter . IsBusy )
{
SayAnalysis ( "Cancelling background thread, please wait..." ) ;
bw_Analysis_DataGetter . CancelAsync ( ) ;
}
else
{
btn_Analysis_ON . Enabled = true ;
btn_Analysis_ON . BackColor = Color . YellowGreen ;
}
lock ( AllPositions )
{
AllPositions . Clear ( ) ;
}
GC . Collect ( ) ;
// go into online mode
btn_Analysis_OFF . Enabled = false ;
btn_Analysis_OFF . BackColor = Color . Gray ;
btn_Analysis_Planes_Load . Enabled = false ;
btn_Analysis_Planes_Save . Enabled = false ;
btn_Analysis_Planes_Clear . Enabled = false ;
btn_Analysis_Planes_History . Enabled = false ;
btn_Analysis_Planes_ShowTraffic . Enabled = false ;
btn_Analysis_Path_SaveToFile . Enabled = false ;
btn_Analysis_CrossingHistory . Enabled = false ;
btn_Analysis_Plane_History . Enabled = false ;
btn_Analysis_Rewind . Enabled = false ;
btn_Analysis_Back . Enabled = false ;
btn_Analysis_Pause . Enabled = false ;
btn_Analysis_Forward . Enabled = false ;
btn_Analysis_FastForward . Enabled = false ;
sb_Analysis_Play . Enabled = false ;
dtp_Analysis_MinValue . Enabled = false ;
dtp_Analysis_MaxValue . Enabled = false ;
btn_Map_PlayPause . Enabled = true ;
LifeMode = AIRSCOUTLIFEMODE . LIFE ;
PlayMode = AIRSCOUTPLAYMODE . PAUSE ;
UpdateStatus ( ) ;
btn_Map_PlayPause . Focus ( ) ;
}
private void btn_Analysis_Planes_Save_Click ( object sender , EventArgs e )
{
try
{
SaveFileDialog Dlg = new SaveFileDialog ( ) ;
Dlg . AddExtension = true ;
Dlg . Filter = "Java Script Object Notation File|*.json|Comma Separated Values|*.csv" ;
Dlg . DefaultExt = "json" ;
Dlg . FileName = "Plane Positions " + dtp_Analysis_MinValue . Value . ToString ( "yyyy_MM_dd_HH_mm_ss" ) + " to " + dtp_Analysis_MaxValue . Value . ToString ( "yyyy_MM_dd_HH_mm_ss" ) ;
Dlg . InitialDirectory = TmpDirectory ;
Dlg . OverwritePrompt = true ;
if ( Dlg . ShowDialog ( ) = = System . Windows . Forms . DialogResult . OK )
{
if ( ! bw_Analysis_FileSaver . IsBusy )
{
btn_Analysis_Planes_Save . Enabled = false ;
bw_Analysis_FileSaver . RunWorkerAsync ( Dlg . FileName ) ;
}
}
}
catch ( Exception ex )
{
Say ( ex . Message ) ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 ) ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( "Error while saving path to file [" + Dlg . FileName + "]:" + ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
}
private void btn_Analysis_CrossingHistory_Click ( object sender , EventArgs e )
{
if ( dtp_Analysis_MaxValue . Value < = dtp_Analysis_MinValue . Value )
return ;
if ( Time_Offline_Interval < = 0 )
Time_Offline_Interval = 1 ;
if ( ( AllPositions = = null ) | | ( AllPositions . Count = = 0 ) )
return ;
CrossingHistoryDlg Dlg = new CrossingHistoryDlg ( dtp_Analysis_MinValue . Value , dtp_Analysis_MaxValue . Value , Time_Offline_Interval , ref AllPositions ) ;
Dlg . ShowDialog ( ) ;
}
private void sb_Analysis_Play_SizeChanged ( object sender , EventArgs e )
{
// handle change of scrollbar
// set scrollbar markers
// reduce them to one marker per pixel
// get initial scrollbar width and build array
int [ ] sb = new int [ sb_Analysis_Play . Width ] ;
double stepwidth = ( double ) sb . Length / ( sb_Analysis_Play . Maximum - sb_Analysis_Play . Minimum ) ;
foreach ( DateTime dt in AllLastUpdated )
{
int index = ( int ) ( ( dt - dtp_Analysis_MinValue . Value ) . TotalSeconds * stepwidth ) ;
int i = ( int ) ( dt - dtp_Analysis_MinValue . Value ) . TotalSeconds ;
if ( ( i > sb_Analysis_Play . Minimum ) & & ( i < sb_Analysis_Play . Maximum ) )
sb [ index ] = i ;
}
sb_Analysis_Play . BackgroundMarkers = sb . ToList < int > ( ) ;
}
private void gb_Analysis_Player_SizeChanged ( object sender , EventArgs e )
{
// handle change of size --> arrange elements
sb_Analysis_Play . Left = dtp_Analysis_MinValue . Right + 10 ;
sb_Analysis_Play . Width = dtp_Analysis_MaxValue . Left - dtp_Analysis_MinValue . Width - 20 ;
sb_Analysis_Play . Height = dtp_Analysis_MinValue . Height ;
}
private void btn_Analysis_Rewind_Click ( object sender , EventArgs e )
{
PlayMode = AIRSCOUTPLAYMODE . FASTBACK ;
Time_Offline_Interval - = 10 ;
if ( Time_Offline_Interval < 1 )
Time_Offline_Interval = 1 ;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
}
private void btn_Analysis_Back_Click ( object sender , EventArgs e )
{
PlayMode = AIRSCOUTPLAYMODE . BACK ;
Time_Offline_Interval - = 1 ;
if ( Time_Offline_Interval < 1 )
Time_Offline_Interval = 1 ;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
}
private void btn_Analysis_Pause_Click ( object sender , EventArgs e )
{
PlayMode = AIRSCOUTPLAYMODE . PAUSE ;
Time_Offline_Interval = 0 ;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
}
private void btn_Analysis_Forward_Click ( object sender , EventArgs e )
{
PlayMode = AIRSCOUTPLAYMODE . FORWARD ;
Time_Offline_Interval + = 1 ;
if ( Time_Offline_Interval > 3600 )
Time_Offline_Interval = 3600 ;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
}
private void btn_Analysis_FastForward_Click ( object sender , EventArgs e )
{
PlayMode = AIRSCOUTPLAYMODE . FASTFORWARD ;
Time_Offline_Interval + = 10 ;
if ( Time_Offline_Interval > 3600 )
Time_Offline_Interval = 3600 ;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
}
private void sb_Analysis_Play_Scroll ( object sender , ScrollEventArgs e )
{
// PlayMode = AIRSCOUTPLAYMODE.PAUSE;
// Time_Offline_Interval = 0;
tb_Analysis_Stepwidth . Text = Time_Offline_Interval . ToString ( ) ;
Properties . Settings . Default . Time_Offline = dtp_Analysis_MinValue . Value . AddSeconds ( sb_Analysis_Play . Value ) ;
if ( Properties . Settings . Default . Time_Offline < dtp_Analysis_MinValue . Value )
Properties . Settings . Default . Time_Offline = dtp_Analysis_MinValue . Value ;
if ( Properties . Settings . Default . Time_Offline > dtp_Analysis_MaxValue . Value )
Properties . Settings . Default . Time_Offline = dtp_Analysis_MaxValue . Value ;
CurrentTime = Properties . Settings . Default . Time_Offline ;
tb_Analysis_Time . Text = CurrentTime . ToString ( "yyyy-MM-hh HH:mm:ss" ) ;
UpdatePlanes ( ) ;
}
private void dtp_Analysis_MinValue_ValueChanged ( object sender , EventArgs e )
{
// check bounds
if ( dtp_Analysis_MinValue . Value < History_OldestEntry )
dtp_Analysis_MinValue . Value = History_OldestEntry ;
if ( dtp_Analysis_MinValue . Value > History_YoungestEntry )
dtp_Analysis_MinValue . Value = History_YoungestEntry ;
UpdatePlayer ( ) ;
}
private void dtp_Analysis_MaxValue_ValueChanged ( object sender , EventArgs e )
{
// check bounds
if ( dtp_Analysis_MinValue . Value < History_OldestEntry )
dtp_Analysis_MinValue . Value = History_OldestEntry ;
if ( dtp_Analysis_MinValue . Value > History_YoungestEntry )
dtp_Analysis_MinValue . Value = History_YoungestEntry ;
UpdatePlayer ( ) ;
}
private void btn_Analysis_Plane_History_Click ( object sender , EventArgs e )
{
PlaneHistoryDlg Dlg = new PlaneHistoryDlg ( dtp_Analysis_MinValue . Value , dtp_Analysis_MaxValue . Value , TmpDirectory ) ;
Dlg . ShowDialog ( ) ;
}
# endregion
# endregion
2020-02-12 10:45:19 +00:00
#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
2019-03-19 21:09:03 +00:00
# endregion
#region Background Workers
#region PlaneFeed
private void bw_PlaneFeed_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
2020-02-12 10:45:19 +00:00
if ( e . ProgressPercentage = = ( int ) PROGRESS . ERROR )
{
if ( e . UserState = = null )
return ;
Say ( ( string ) e . UserState ) ;
}
else if ( e . ProgressPercentage = = ( int ) PROGRESS . STATUS )
2019-03-19 21:09:03 +00:00
{
if ( e . UserState = = null )
return ;
Say ( ( string ) e . UserState ) ;
}
else if ( e . ProgressPercentage = = ( int ) PROGRESS . PLANES )
{
List < PlaneInfo > planes = ( List < PlaneInfo > ) e . UserState ;
Planes . BulkInsertOrUpdateIfNewer ( planes ) ;
}
}
# endregion
#region WinTestReceive
// suppress console output when in debug mode, needs "Just my code" set in Tools\Options\Debugging
[System.Diagnostics.DebuggerNonUserCode]
private void bw_WinTestReceive_DoWork ( object sender , DoWorkEventArgs e )
{
// Background thread for receiving Win-Test messages
// listens to the UDP broadcasts
// use the ReportProgress method to
// return status code and received message
// status values are: <0 = error orrcured (not supported yet)
// 0 = function calls OK, but no bytes received
// >0 = function calls OK, number of bytes received
Log . WriteMessage ( "Started." ) ;
if ( Thread . CurrentThread . Name = = null )
Thread . CurrentThread . Name = "bw_WinTestReceive" ;
// Get own IP addresses
string hostname ;
IPAddress [ ] hostaddresses = new IPAddress [ 256 ] ;
try
{
hostname = Dns . GetHostName ( ) ;
hostaddresses = Dns . GetHostAddresses ( hostname ) ;
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
// 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
// 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
private void ASSetPath ( wtMessage msg )
{
try
{
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
string [ ] a = msg . Data . Split ( ',' ) ;
int qrg = 1296 ;
int . TryParse ( a [ 0 ] . Replace ( "\"" , "" ) , out qrg ) ;
qrg = qrg / 10000 ;
BAND band = BAND . BNONE ;
try
{
band = ( BAND ) qrg ;
}
catch
{
// do nothing
}
string mycallstr = a [ 1 ] . Replace ( "\"" , "" ) ;
string mylocstr = a [ 2 ] . Replace ( "\"" , "" ) . Substring ( 0 , 6 ) ;
string dxcallstr = a [ 3 ] . Replace ( "\"" , "" ) ;
string dxlocstr = a [ 4 ] . Replace ( "\"" , "" ) . Substring ( 0 , 6 ) ;
int count = 0 ;
// return on failure
if ( ! Callsign . Check ( mycallstr ) )
return ;
if ( ! Callsign . Check ( dxcallstr ) )
return ;
if ( ! MaidenheadLocator . Check ( mylocstr ) )
return ;
if ( ! MaidenheadLocator . Check ( dxlocstr ) )
return ;
// get my location info --> if loc is matching, use precise information automatically
LocationDesignator myloc = StationData . Database . LocationFindOrCreate ( mycallstr , mylocstr ) ;
// get my QRV info
QRVDesignator myqrv = StationData . Database . QRVFindOrCreateDefault ( mycallstr , mylocstr , band ) ;
// set qrv defaults if zero
if ( myqrv . AntennaHeight = = 0 )
myqrv . AntennaHeight = StationData . Database . QRVGetDefaultAntennaHeight ( Properties . Settings . Default . Band ) ;
if ( myqrv . AntennaGain = = 0 )
myqrv . AntennaGain = StationData . Database . QRVGetDefaultAntennaGain ( Properties . Settings . Default . Band ) ;
if ( myqrv . Power = = 0 )
myqrv . Power = StationData . Database . QRVGetDefaultPower ( Properties . Settings . Default . Band ) ;
// get dx location info --> if loc is matching, use precise information automatically
LocationDesignator dxloc = LocationFindOrCreate ( dxcallstr , dxlocstr ) ;
// get dx QRV info
QRVDesignator dxqrv = StationData . Database . QRVFindOrCreateDefault ( dxcallstr , dxlocstr , band ) ;
// set qrv defaults if zero
if ( dxqrv . AntennaHeight = = 0 )
dxqrv . AntennaHeight = StationData . Database . QRVGetDefaultAntennaHeight ( Properties . Settings . Default . Band ) ;
if ( dxqrv . AntennaGain = = 0 )
dxqrv . AntennaGain = StationData . Database . QRVGetDefaultAntennaGain ( Properties . Settings . Default . Band ) ;
if ( dxqrv . Power = = 0 )
dxqrv . Power = StationData . Database . QRVGetDefaultPower ( Properties . Settings . Default . Band ) ;
// find local obstruction, if any
LocalObstructionDesignator o = ElevationData . Database . LocalObstructionFind ( myloc . Lat , myloc . Lon , Properties . Settings . Default . ElevationModel ) ;
double mybearing = LatLon . Bearing ( myloc . Lat , myloc . Lon , dxloc . Lat , dxloc . Lon ) ;
double myobstr = ( o ! = null ) ? o . GetObstruction ( myqrv . AntennaHeight , mybearing ) : double . MinValue ;
// try to find propagation path in database or create new one and store
PropagationPathDesignator ppath = PropagationData . Database . PropagationPathFindOrCreateFromLatLon (
null ,
myloc . Lat ,
myloc . Lon ,
GetElevation ( myloc . Lat , myloc . Lon ) + myqrv . AntennaHeight ,
dxloc . Lat ,
dxloc . Lon ,
GetElevation ( dxloc . Lat , dxloc . Lon ) + dxqrv . AntennaHeight ,
Bands . ToGHz ( Properties . Settings . Default . Band ) ,
LatLon . Earth . Radius * Properties . Settings . Default . Path_Band_Settings [ Properties . Settings . Default . Band ] . K_Factor ,
Properties . Settings . Default . Path_Band_Settings [ Properties . Settings . Default . Band ] . F1_Clearance ,
ElevationData . Database . GetDefaultStepWidth ( Properties . Settings . Default . ElevationModel ) ,
Properties . Settings . Default . ElevationModel ,
myobstr ) ;
List < PlaneInfo > allplanes = Planes . GetAll ( DateTime . UtcNow , Properties . Settings . Default . Planes_Position_TTL ) ;
List < PlaneInfo > nearestplanes = AircraftData . Database . GetNearestPlanes ( DateTime . UtcNow , ppath , allplanes , Properties . Settings . Default . Planes_Filter_Max_Circumcircle , Properties . Settings . Default . Path_Band_Settings [ band ] . MaxDistance , Properties . Settings . Default . Planes_MaxAlt ) ;
count = 0 ;
string planes = "" ;
wtMessage SendMsg = new wtMessage ( WTMESSAGES . ASNEAREST ,
Properties . Settings . Default . Server_Name ,
msg . Src ,
DateTime . UtcNow . ToString ( "u" ) + "," +
mycallstr + "," +
mylocstr + "," +
dxcallstr + "," +
dxlocstr + "," ) ;
if ( ( nearestplanes ! = null ) & & ( nearestplanes . Count ( ) > 0 ) )
{
foreach ( PlaneInfo planeinfo in nearestplanes )
{
if ( ( planeinfo . IntPoint ! = null ) & & ( planeinfo . Potential > 0 ) )
{
int mins = 0 ;
if ( planeinfo . Speed > 0 )
mins = ( int ) ( planeinfo . IntQRB / ( double ) planeinfo . Speed / 1.852 * 60.0 ) ;
2020-03-01 15:12:08 +00:00
planes = planes + planeinfo . Call + "," + PlaneCategories . GetShortStringValue ( planeinfo . Category ) + "," + ( ( int ) planeinfo . IntQRB ) . ToString ( ) + "," + planeinfo . Potential . ToString ( ) + "," + mins . ToString ( ) + "," ;
2019-03-19 21:09:03 +00:00
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
2021-12-31 08:08:48 +00:00
private void ASWatchlist ( wtMessage msg )
2019-03-19 21:09:03 +00:00
{
if ( ! Properties . Settings . Default . Watchlist_SyncWithKST )
return ;
// maintain watchlist
try
{
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
2020-03-15 14:29:02 +00:00
// mark all watchlist items to remove wich are not currently tracked
2019-03-19 21:09:03 +00:00
foreach ( WatchlistItem item in Properties . Settings . Default . Watchlist )
{
// nasty!! Should never be null!
if ( item = = null )
continue ;
2020-03-15 14:29:02 +00:00
if ( ! item . Checked )
item . Remove = true ;
2019-03-19 21:09:03 +00:00
}
// 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
2021-12-31 08:08:48 +00:00
private void ASAddWatch ( wtMessage msg )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// abort if in wtKST sync mode
if ( Properties . Settings . Default . Watchlist_SyncWithKST )
return ;
// maintain watchlist
try
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
2019-03-19 21:09:03 +00:00
2021-12-31 08:08:48 +00:00
// check for malformatted message
if ( ! msg . Data . Contains ( "," ) )
return ;
2019-03-19 21:09:03 +00:00
2021-12-31 08:08:48 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
else if ( msg . Msg = = WTMESSAGES . ASWATCHLIST )
2021-12-31 08:08:48 +00:00
ASWatchlist ( msg ) ;
else if ( msg . Msg = = WTMESSAGES . ASADDWATCH )
ASAddWatch ( msg ) ;
else if ( msg . Msg = = WTMESSAGES . ASREMOVEWATCH )
ASRemoveWatch ( msg ) ;
2019-03-19 21:09:03 +00:00
}
private void bw_WinTestReceive_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
}
# endregion
# region SpecLabReceive
// suppress console output when in debug mode, needs "Just my code" set in Tools\Options\Debugging
// [System.Diagnostics.DebuggerNonUserCode]
private void bw_SpecLab_Receive_DoWork ( object sender , DoWorkEventArgs e )
{
// name the thread for debugging
if ( String . IsNullOrEmpty ( Thread . CurrentThread . Name ) )
Thread . CurrentThread . Name = "bw_SpecLabReceive" ;
Log . WriteMessage ( "Started." ) ;
// get the update interval
int interval = System . Convert . ToInt32 ( Properties . Settings . Default . SpecLab_Update ) * 1000 ;
// check for minimum
if ( interval < 1000 )
interval = 1000 ;
bw_SpecLab_Receive . ReportProgress ( 0 ) ;
int maxcount = 60 ;
List < SignalLevelDesignator > ads = new List < SignalLevelDesignator > ( ) ;
while ( ! bw_SpecLab_Receive . CancellationPending )
{
Thread . Sleep ( interval ) ;
// do nothing when not in play mode
if ( ( LifeMode ! = AIRSCOUTLIFEMODE . LIFE ) | | ( PlayMode ! = AIRSCOUTPLAYMODE . FORWARD ) )
continue ;
try
{
// get boundary frequencies
int f1 = Properties . Settings . Default . SpecLab_F1 ;
if ( f1 < 0 )
f1 = 0 ;
if ( f1 > 3000 )
f1 = 3000 ;
int f2 = Properties . Settings . Default . SpecLab_F2 ;
if ( f2 < 1 )
f2 = 1 ;
if ( f2 > 3000 )
f2 = 3000 ;
if ( f1 > = f2 )
f1 = f2 - 1 ;
// get the url
string url = Properties . Settings . Default . SpecLab_URL ;
// get the filename
string filename = Properties . Settings . Default . SpecLab_FileName ;
if ( ! url . EndsWith ( "/" ) )
url = url + "/" ;
url = url + filename + "?f1=" + f1 . ToString ( ) + "?f2=" + f2 . ToString ( ) ;
string msg = "" ;
bw_SpecLab_Receive . ReportProgress ( 1 , "Trying to connect to Spectrum Lab..." ) ;
WebRequest myWebRequest = WebRequest . Create ( url ) ;
WebResponse myWebResponse = myWebRequest . GetResponse ( ) ;
Stream ReceiveStream = myWebResponse . GetResponseStream ( ) ;
Encoding encode = System . Text . Encoding . GetEncoding ( "utf-8" ) ;
StreamReader readStream = new StreamReader ( ReceiveStream , encode ) ;
string json = readStream . ReadToEnd ( ) ;
if ( ! json . StartsWith ( "[" ) )
throw ( new FormatException ( "Format Exception: Not a JSON file." ) ) ;
// split the JSON string
// a[1] contains the header
// h contains alle header items
// d contains all data items
string [ ] a = json . Split ( '[' ) ;
a [ 1 ] = a [ 1 ] . Replace ( ":" , "," ) ;
string [ ] h = a [ 1 ] . Split ( ',' ) ;
a [ 2 ] = a [ 2 ] . Replace ( "\r\n" , "" ) ;
a [ 2 ] = a [ 2 ] . Remove ( a [ 2 ] . IndexOf ( "]" ) - 1 ) ;
a [ 2 ] = a [ 2 ] . Replace ( "," , ";" ) ;
a [ 2 ] = a [ 2 ] . Replace ( "." , "," ) ;
double [ ] d = System . Array . ConvertAll ( a [ 2 ] . Split ( ';' ) , new Converter < string , double > ( Double . Parse ) ) ;
// get the time stamp
long l = ( long ) System . Convert . ToDouble ( h [ 1 ] , CultureInfo . InvariantCulture ) ;
DateTime utc = new System . DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
utc = utc . AddSeconds ( l ) ;
// get number of bins
int count = System . Convert . ToInt32 ( h [ 13 ] ) ;
msg = "FFT-Data received: " + count . ToString ( ) + "bins. F1=" + f1 . ToString ( ) + "Hz, F2=" + f2 . ToString ( ) + "Hz" ;
bw_SpecLab_Receive . ReportProgress ( 1 , msg ) ;
double max = d . Max ( ) ;
// collect and save maximum if in play mode and NearestPlane != null
if ( ( PlayMode = = AIRSCOUTPLAYMODE . FORWARD ) & & ( NearestPlane ! = null ) )
ads . Add ( new SignalLevelDesignator ( max , utc ) ) ;
// bulk save maximum to database if maxcount is reached
if ( ads . Count > maxcount )
{
SignalData . Database . SignalLevelBulkInsertOrUpdateIfNewer ( ads ) ;
ads . Clear ( ) ;
}
// report maximum
bw_SpecLab_Receive . ReportProgress ( 100 , max ) ;
}
catch ( WebException ex )
{
// do nothing
}
catch ( SocketException ex )
{
// do nothing
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 ) ;
2021-12-31 08:08:48 +00:00
msg = new wtMessage ( WTMESSAGES . SETELEVATION , Properties . Settings . Default . Server_Name , "" , "AUTO" , " 00 " + el . ToString ( "000" ) ) ;
bytes = msg . ToBytes ( ) ;
client . Send ( bytes , bytes . Length , ip ) ;
2023-01-30 06:00:58 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
return true ;
}
private string Serial_SendCommand ( SerialPort sp , string command , bool waitanswer )
{
// sends a command via serial port (and optional wait fo answer)
if ( ( sp = = null ) | | ( ! sp . IsOpen ) )
return "" ;
string s = "" ;
{
sp . WriteLine ( command ) ;
if ( waitanswer )
{
s = sp . ReadLine ( ) ;
s = s . Replace ( "\n" , "" ) ;
}
}
return s ;
}
private bool Track_SER__GS_232A_AZ ( SerialPort sp , double az )
{
// send Az value via serial port (GS-232A protocol)
// communictaion test --> get azimuth value
if ( sp = = null )
throw new NullReferenceException ( "[Serial]: Port not initialized." ) ;
if ( ! sp . IsOpen )
throw new InvalidOperationException ( "[Serial]: Port not open." ) ;
// communictaion test --> get azimuth value
string s = Serial_SendCommand ( sp , "C" , true ) ;
if ( ! s . StartsWith ( "+0" ) )
throw new FormatException ( "[Serial]: Wrong serial data format." ) ;
try
{
double result = System . Convert . ToDouble ( s . Substring ( 2 , 3 ) , CultureInfo . InvariantCulture ) ;
}
catch
{
throw new FormatException ( "[Serial]: Wrong serial data format." ) ;
}
// set azimuth value --> no feedback
Serial_SendCommand ( sp , "M" + az . ToString ( "000" ) , false ) ;
return true ;
}
private bool Track_SER__GS_232A_AZEL ( SerialPort sp , double az , double el )
{
// send Az/El value via serial port (GS-232A protocol)
if ( sp = = null )
throw new NullReferenceException ( "[Serial]: Port not initialized." ) ;
if ( ! sp . IsOpen )
throw new InvalidOperationException ( "[Serial]: Port not open." ) ;
// communictaion test --> get azimuth and elevation value
string s = Serial_SendCommand ( sp , "C2" , true ) ;
if ( ! s . StartsWith ( "+0" ) )
throw new FormatException ( "[Serial]: Wrong serial data format." ) ;
try
{
double result = System . Convert . ToDouble ( s . Substring ( 2 , 3 ) , CultureInfo . InvariantCulture ) ;
}
catch
{
throw new FormatException ( "[Serial]: Wrong serial data format." ) ;
}
// set azimuth value --> no feedback
Serial_SendCommand ( sp , "W" + az . ToString ( "000" ) + " " + el . ToString ( "000" ) , false ) ;
return true ;
}
private void Track_File_Native ( double az , double el )
{
// writes a file with Az/El values in a file (native)
// Syntax: <Az value>,<El value>
using ( StreamWriter sw = new StreamWriter ( TmpDirectory + Path . DirectorySeparatorChar + "azel.dat" ) )
{
sw . WriteLine ( az . ToString ( "F1" , CultureInfo . InvariantCulture ) + "," + el . ToString ( "F1" , CultureInfo . InvariantCulture ) ) ;
}
}
private void Track_File_WSJT ( double az , double el )
{
// writes a file with Az/El values in a file (WSJT)
// the info is filled in the "Source" line (originally intended to follow a radio source
using ( StreamWriter sw = new StreamWriter ( TmpDirectory + Path . DirectorySeparatorChar + "azel.dat" ) )
{
string utc = DateTime . UtcNow . ToString ( "HH:mm:ss" ) ;
sw . WriteLine ( utc + ",0,0,Moon" ) ;
sw . WriteLine ( utc + ",0,0,Sun" ) ;
sw . WriteLine ( utc + "," + az . ToString ( "F1" , CultureInfo . InvariantCulture ) + "," + el . ToString ( "F1" , CultureInfo . InvariantCulture ) + ",Source" ) ;
sw . WriteLine ( "0, 0, 0, 0, 0,Doppler, R" ) ;
}
}
private void bw_Track_DoWork ( object sender , DoWorkEventArgs e )
{
Log . WriteMessage ( "Started." ) ;
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
// name the thread for debugging
if ( String . IsNullOrEmpty ( Thread . CurrentThread . Name ) )
Thread . CurrentThread . Name = "bw_Track" ;
2021-12-31 08:08:48 +00:00
// last recent calculated values
TrackValues oldvalues = null ;
TRACKSTATUS oldstatus = TRACKSTATUS . NONE ;
2019-03-19 21:09:03 +00:00
// clients and ports
DdeClient ddeclient = null ;
UdpClient udpclient = null ;
IPEndPoint udpip = null ;
SerialPort serialport = null ;
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
// error counters
int ddeerr = 0 ;
int udperr = 0 ;
int serialerr = 0 ;
int maxerr = 10 ;
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
// outer loop
do
{
2021-12-31 08:08:48 +00:00
try
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// intializations
if ( Properties . Settings . Default . Track_DDE_HRD )
{
ddeclient = new DdeClient ( "HRDRotator" , "Position" ) ;
int result = ddeclient . TryConnect ( ) ;
2019-03-19 21:09:03 +00:00
2021-12-31 08:08:48 +00:00
}
if ( Properties . Settings . Default . Track_UDP_WinTest )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
udpclient = new UdpClient ( ) ;
udpip = new IPEndPoint ( IPAddress . Broadcast , Properties . Settings . Default . Track_UDP_WinTest_Port ) ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
else if ( Properties . Settings . Default . Track_UDP_AirScout )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
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
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 ,
2023-01-30 06:00:58 +00:00
trackvalues . DXDistance ,
2021-12-31 08:08:48 +00:00
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 ) ;
}
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
else if ( TrackMode = = AIRSCOUTTRACKMODE . SINGLE )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// single shot --> get values from settings and track only once
trackvalues . MyAzimuth = Properties . Settings . Default . Track_SetAz ;
trackvalues . MyElevation = Properties . Settings . Default . Track_SetEl ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
// valid values --> start tracking
if ( ! double . IsNaN ( trackvalues . MyAzimuth ) & &
! double . IsNaN ( trackvalues . MyElevation ) & &
( trackvalues . MyAzimuth > = 0 ) & &
( trackvalues . MyAzimuth < 360 ) )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
}
}
2021-12-31 08:08:48 +00:00
catch ( Exception ex )
{
// leave inner loop
bw_Track . ReportProgress ( 1 , TRACKSTATUS . ERROR ) ;
break ;
}
Thread . Sleep ( 1000 ) ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
Thread . Sleep ( Properties . Settings . Default . Track_Update ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2021-12-31 08:08:48 +00:00
bw_Track . ReportProgress ( - 1 , "Track error: " + ex . Message ) ;
bw_Track . ReportProgress ( 1 , TRACKSTATUS . ERROR ) ;
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
2019-03-19 21:09:03 +00:00
}
while ( ! bw_Track . CancellationPending ) ;
2021-12-31 08:08:48 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
Log . WriteMessage ( "Finished." ) ;
}
private void bw_Track_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
2021-12-31 08:08:48 +00:00
if ( e . ProgressPercentage < = 0 )
2019-03-19 21:09:03 +00:00
{
// report Error
tsl_Status . Text = ( string ) e . UserState ;
}
2021-12-31 08:08:48 +00:00
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 )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 ;
}
2019-03-19 21:09:03 +00:00
}
2021-12-31 08:08:48 +00:00
else if ( e . ProgressPercentage = = 3 )
2019-03-19 21:09:03 +00:00
{
2021-12-31 08:08:48 +00:00
// 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 ;
}
}
2019-03-19 21:09:03 +00:00
}
}
private void bw_Track_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
}
# endregion
#region JSONWriter
private void bw_JSONWriter_DoWork ( object sender , DoWorkEventArgs e )
{
Log . WriteMessage ( "Started." ) ;
int interval = 60 ;
// name the thread for debugging
if ( String . IsNullOrEmpty ( Thread . CurrentThread . Name ) )
Thread . CurrentThread . Name = "bw_JSONWriter" ;
while ( ! bw_JSONWriter . CancellationPending )
{
// get planes each minute
List < PlaneInfo > list = Planes . GetAll ( DateTime . UtcNow , Properties . Settings . Default . Planes_Position_TTL ) ;
2022-08-27 12:13:47 +00:00
if ( list . Count > 0 )
2019-03-19 21:09:03 +00:00
{
2022-08-27 12:13:47 +00:00
// write json file
try
2019-03-19 21:09:03 +00:00
{
2022-08-27 12:13:47 +00:00
using ( StreamWriter sw = new StreamWriter ( TmpDirectory + Path . DirectorySeparatorChar + "planes.json" ) )
2019-03-19 21:09:03 +00:00
{
2022-08-27 12:13:47 +00:00
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 ( "}" ) ;
2019-03-19 21:09:03 +00:00
}
}
2022-08-27 12:13:47 +00:00
catch ( Exception ex )
{
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
// do nothing
}
2019-03-19 21:09:03 +00:00
}
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 )
{
2023-01-30 06:00:58 +00:00
if ( Properties . Settings . Default . NewsFeed_Enabled )
2019-03-19 21:09:03 +00:00
{
2023-01-30 06:00:58 +00:00
try
2019-03-19 21:09:03 +00:00
{
2023-01-30 06:00:58 +00:00
// 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 ) ;
2019-03-19 21:09:03 +00:00
}
}
2023-01-30 06:00:58 +00:00
2019-03-19 21:09:03 +00:00
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
{
2020-03-01 15:12:08 +00:00
// stop background thread
2023-01-30 06:00:58 +00:00
while ( bw_NewsFeed . IsBusy )
{
bw_NewsFeed . CancelAsync ( ) ;
Application . DoEvents ( ) ;
}
2019-03-19 21:09:03 +00:00
// 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 ( ) ;
2020-02-12 10:45:19 +00:00
tc_Map . SelectedTab = tp_News ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
// do nothing if wb_News fails to refresh
}
}
2020-03-01 15:12:08 +00:00
// save time to settings
Properties . Settings . Default . News_LastUpdate = dt ;
2019-03-19 21:09:03 +00:00
}
else
{
2020-03-01 15:12:08 +00:00
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 ;
2019-03-19 21:09:03 +00:00
}
2023-01-30 06:00:58 +00:00
2020-03-01 15:12:08 +00:00
// restart background thread
2023-01-30 06:00:58 +00:00
if ( ! bw_NewsFeed . IsBusy )
bw_NewsFeed . RunWorkerAsync ( ) ;
2019-03-19 21:09:03 +00:00
}
}
private void bw_NewsFeed_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
}
# endregion
#region HistoryDownloader
private void HistoryDownloader_DownloadProgressChanged ( object sender , DownloadProgressChangedEventArgs e )
{
// get byte in GB
double bytesin = double . Parse ( e . BytesReceived . ToString ( ) ) / 1024.0 / 1024.0 / 1024.0 ;
double totalbytes = double . Parse ( e . TotalBytesToReceive . ToString ( ) ) / 1024.0 / 1024.0 / 1024.0 ;
double percentage = bytesin / totalbytes * 100 ;
try
{
if ( bw_HistoryDownloader . IsBusy )
bw_HistoryDownloader . ReportProgress ( 1 , "Downloaded " + bytesin . ToString ( "F2" ) + " GB of " + totalbytes . ToString ( "F2" ) + " GB (" + percentage . ToString ( "F2" ) + "%)." ) ;
}
catch
{
}
}
private string ReadPropertyString ( JObject o , string propertyname )
{
if ( o . Property ( propertyname ) = = null )
return null ;
return o . Property ( propertyname ) . Value . Value < string > ( ) ;
}
private int ReadPropertyDoubleToInt ( JObject o , string propertyname )
{
if ( o . Property ( propertyname ) = = null )
return int . MinValue ;
double d = ReadPropertyDouble ( o , propertyname ) ;
if ( ( d ! = double . MinValue ) & & ( d > = int . MinValue ) & & ( d < = int . MaxValue ) )
return ( int ) d ;
return int . MinValue ;
}
private double ReadPropertyDouble ( JObject o , string propertyname )
{
if ( o . Property ( propertyname ) = = null )
return double . MinValue ;
return o . Property ( propertyname ) . Value . Value < double > ( ) ;
}
private long ReadPropertyLong ( JObject o , string propertyname )
{
if ( o . Property ( propertyname ) = = null )
return long . MinValue ;
return o . Property ( propertyname ) . Value . Value < long > ( ) ;
}
private void HistoryDownloader_DownloadFileCompleted ( object sender , AsyncCompletedEventArgs e )
{
try
{
if ( bw_HistoryDownloader . IsBusy )
bw_HistoryDownloader . ReportProgress ( 1 , "Reading " + Properties . Settings . Default . Analysis_History_ZIPFileName ) ;
// unzip the file
if ( File . Exists ( Properties . Settings . Default . Analysis_History_ZIPFileName ) )
{
string filename = Properties . Settings . Default . Analysis_History_ZIPFileName ;
// unzips a zip file content to the same directory
string downloaddir = Path . GetDirectoryName ( Properties . Settings . Default . Analysis_History_ZIPFileName ) ;
// set path to calling assembly's path if not otherwise specified
if ( String . IsNullOrEmpty ( downloaddir ) )
downloaddir = Assembly . GetCallingAssembly ( ) . Location ;
// open the zip file
using ( ZipFile zip = new ZipFile ( filename ) )
{
zip . ZipErrorAction = ZipErrorAction . Skip ;
// here, we extract every entry, but we could extract conditionally
// based on entry name, size, date, checkbox status, etc.
foreach ( ZipEntry ze in zip )
{
if ( bw_HistoryDownloader . IsBusy )
bw_HistoryDownloader . ReportProgress ( 1 , "Extracting " + ze . FileName ) ;
try
{
/ *
ze . Extract ( downloaddir , ExtractExistingFileAction . OverwriteSilently ) ;
string fname = Path . Combine ( downloaddir , ze . FileName ) ;
File . SetLastWriteTime ( fname , ze . LastModified ) ;
* /
}
catch ( Exception ex )
{
if ( bw_HistoryDownloader . IsBusy )
bw_HistoryDownloader . ReportProgress ( - 1 , ex . Message ) ;
}
}
}
// create csv to load into database
using ( StreamWriter sw = new StreamWriter ( Properties . Settings . Default . Analysis_History_ZIPFileName . ToLower ( ) . Replace ( ".zip" , ".csv" ) ) )
{
sw . WriteLine ( "time;call;reg;hex;lat;lon;track;alt;speed;squawk;radar;type" ) ;
// read all files
for ( int i = 0 ; i < 1440 ; i + = ( int ) Properties . Settings . Default . Analysis_History_Stepwidth )
{
// calculate filename
int hours = i / 60 ;
int minutes = i % 60 ;
string fname = Path . Combine ( Properties . Settings . Default . Analysis_History_Directory , Properties . Settings . Default . Analysis_History_Date . ToString ( "yyyy-MM-dd" ) + "-" + hours . ToString ( "00" ) + minutes . ToString ( "00" ) + "Z.json" ) ;
if ( bw_HistoryDownloader . IsBusy )
bw_HistoryDownloader . ReportProgress ( 1 , "Processing " + fname ) ;
if ( File . Exists ( fname ) )
{
string json = "" ;
using ( StreamReader sr = new StreamReader ( fname ) )
json = sr . ReadToEnd ( ) ;
// analyze json string for planes data
JObject root = ( JObject ) JsonConvert . DeserializeObject ( json ) ;
foreach ( JProperty proot in root . Children < JProperty > ( ) )
{
// get the planes position list
if ( proot . Name = = "acList" )
{
foreach ( JArray a in proot . Children < JArray > ( ) )
{
foreach ( JObject o in a . Values < JObject > ( ) )
{
PlaneInfo info = new PlaneInfo ( ) ;
try
{
info . Call = ReadPropertyString ( o , "Call" ) ;
info . Lat = ReadPropertyDouble ( o , "Lat" ) ;
info . Lon = ReadPropertyDouble ( o , "Long" ) ;
info . Track = ReadPropertyDoubleToInt ( o , "Trak" ) ;
// 2017-07-23: take "GAlt" (corrected altitude by air pressure) rather than "Alt"
info . Alt = ReadPropertyDoubleToInt ( o , "GAlt" ) ;
// info.Alt = ReadPropertyDoubleToInt(o, "Alt");
info . Speed = ReadPropertyDoubleToInt ( o , "Spd" ) ;
info . Reg = ReadPropertyString ( o , "Reg" ) ;
try
{
string squawk = ReadPropertyString ( o , "Sqk" ) ;
}
catch
{
}
info . Hex = ReadPropertyString ( o , "Icao" ) ;
info . Type = ReadPropertyString ( o , "Type" ) ;
// complete type info
AircraftTypeDesignator td = AircraftData . Database . AircraftTypeFindByICAO ( info . Type ) ;
if ( td ! = null )
{
info . Manufacturer = td . Manufacturer ;
info . Model = td . Model ;
info . Category = td . Category ;
}
else
{
info . Manufacturer = "[unknown]" ;
info . Model = "[unknown]" ;
info . Category = PLANECATEGORY . NONE ;
}
// CAUTION!! time is UNIX time in milliseconds
long l = ReadPropertyLong ( o , "PosTime" ) ;
if ( l ! = long . MinValue )
{
DateTime timestamp = new System . DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 ) ;
timestamp = timestamp . AddMilliseconds ( l ) ;
info . Time = timestamp ;
}
else
{
info . Time = DateTime . MinValue ;
}
2019-03-21 11:25:33 +00:00
if ( PlaneInfoChecker . Check ( info ) & &
2019-03-19 21:09:03 +00:00
( 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
}
}
}
}
}
}
}
}
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 ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( msg , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 )
2020-04-10 15:36:18 +00:00
Splash ( "Preparing database for first run: " + msg + " (please wait)" , Color . Yellow ) ;
2019-03-19 21:09:03 +00:00
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 ;
}
2020-04-25 06:00:15 +00:00
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 ;
}
2019-03-19 21:09:03 +00:00
}
2020-02-12 10:45:19 +00:00
if ( ! this . Disposing & & ( ss_Main ! = null ) )
ss_Main . Update ( ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
# 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 ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( msg , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 )
2020-04-10 15:36:18 +00:00
Splash ( "Preparing database for first run: " + msg + " (please wait)" , Color . Yellow ) ;
2019-03-19 21:09:03 +00:00
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 ;
}
2020-02-12 10:45:19 +00:00
if ( ! this . Disposing & & ( ss_Main ! = null ) )
ss_Main . Update ( ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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 ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( msg , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 )
2020-04-10 15:36:18 +00:00
Splash ( "Preparing database for first run: " + msg + " (please wait)" , Color . Yellow ) ;
2019-03-19 21:09:03 +00:00
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 ;
}
2020-02-12 10:45:19 +00:00
if ( ! this . Disposing & & ( ss_Main ! = null ) )
ss_Main . Update ( ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
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
2020-02-12 10:45:19 +00:00
// UpdateAirports();
2019-03-19 21:09:03 +00:00
}
}
# 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 ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( msg , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
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 )
2020-04-10 15:36:18 +00:00
Splash ( "Preparing database for first run: " + msg + " (please wait)" , Color . Yellow ) ;
2019-03-19 21:09:03 +00:00
else
{
SayDatabase ( msg ) ;
}
}
2020-02-12 10:45:19 +00:00
if ( ! this . Disposing & & ( ss_Main ! = null ) )
ss_Main . Update ( ) ;
2019-03-19 21:09:03 +00:00
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
}
}
private void bw_AircraftDatabaseMaintainer_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
}
2020-04-10 15:36:18 +00:00
# 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 ( ) ;
}
}
2021-12-31 08:08:48 +00:00
# endregion
#region CATUpdater
private void bw_CATUpdater_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
2023-01-30 06:00:58 +00:00
try
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
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 ) ;
2021-12-31 08:08:48 +00:00
}
}
# endregion
#region CAT
private void bw_CAT_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
2023-01-30 06:00:58 +00:00
try
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
if ( e . ProgressPercentage < = 0 )
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
Say ( ( string ) e . UserState ) ;
2021-12-31 08:08:48 +00:00
}
2023-01-30 06:00:58 +00:00
else if ( e . ProgressPercentage = = 1 )
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
// new rig status received
RIGSTATUS status = ( RIGSTATUS ) e . UserState ;
switch ( status )
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
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 ;
2021-12-31 08:08:48 +00:00
}
2023-01-30 06:00:58 +00:00
RigStatus = status ;
2021-12-31 08:08:48 +00:00
}
2023-01-30 06:00:58 +00:00
else if ( e . ProgressPercentage = = 2 )
{
// new rig info received
IRig rig = ( IRig ) e . UserState ;
2021-12-31 08:08:48 +00:00
2023-01-30 06:00:58 +00:00
// 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 ( ) ;
}
}
2021-12-31 08:08:48 +00:00
2023-01-30 06:00:58 +00:00
// 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 ( ) ;
2021-12-31 08:08:48 +00:00
}
2023-01-30 06:00:58 +00:00
catch ( Exception ex )
2021-12-31 08:08:48 +00:00
{
2023-01-30 06:00:58 +00:00
RigStatus = RIGSTATUS . ERROR ;
tsl_CAT . ToolTipText = "CAT error: " + ex . Message ;
2021-12-31 08:08:48 +00:00
}
}
2019-03-19 21:09:03 +00:00
# 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 )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
bw_Analysis_FileSaver . ReportProgress ( - 1 , ex . Message ) ;
}
if ( bw_Analysis_FileSaver . CancellationPending )
e . Cancel = true ;
}
private void bw_Analysis_FileSaver_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
if ( e . ProgressPercentage < = 0 )
SayAnalysis ( ( string ) e . UserState ) ;
}
private void bw_Analysis_FileSaver_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
if ( e . Cancelled )
SayAnalysis ( "Cancelled." ) ;
else
{
btn_Analysis_Planes_Save . Enabled = true ;
SayAnalysis ( "Ready." ) ;
}
}
# endregion
#region Analysis_FileLoader
private void Analysis_Planes_Load_JSON ( string filename )
{
JsonSerializerSettings settings = new JsonSerializerSettings ( ) ;
settings . DateTimeZoneHandling = DateTimeZoneHandling . Utc ;
settings . FloatFormatHandling = FloatFormatHandling . String ;
settings . Formatting = Newtonsoft . Json . Formatting . Indented ;
settings . Culture = CultureInfo . InvariantCulture ;
List < AircraftPositionDesignator > aps = new List < AircraftPositionDesignator > ( ) ;
bw_Analysis_FileLoader . ReportProgress ( 0 , "Opening file..." ) ;
using ( StreamReader sr = new StreamReader ( File . Open ( filename , FileMode . Open ) ) )
{
// check for starting bracket of array
char c = ( char ) sr . Read ( ) ;
if ( c ! = '[' )
return ;
// read 1000 positions and update database
int count = 0 ;
int updated = 0 ;
while ( ! sr . EndOfStream )
{
aps . Clear ( ) ;
int j = 0 ;
while ( ( j < 1000 ) & & ! sr . EndOfStream )
{
char nextChar ;
StringBuilder line = new StringBuilder ( ) ;
while ( ( j < 1000 ) & & sr . Peek ( ) > 0 )
{
nextChar = ( char ) sr . Read ( ) ;
line . Append ( nextChar ) ;
if ( line [ 0 ] ! = '{' )
line . Clear ( ) ;
if ( nextChar = = '}' )
{
AircraftPositionDesignator ap = JsonConvert . DeserializeObject < AircraftPositionDesignator > ( line . ToString ( ) , settings ) ;
line . Clear ( ) ;
aps . Add ( ap ) ;
j + + ;
}
}
if ( bw_Analysis_FileLoader . CancellationPending )
return ;
}
count = count + j ;
updated = updated + AircraftPositionData . Database . AircraftPositionBulkInsertOrUpdateIfNewer ( aps ) ;
bw_Analysis_FileLoader . ReportProgress ( 0 , "Updating position " + count . ToString ( ) + ", " + updated . ToString ( ) + " updated so far..." ) ;
}
}
}
private void Analysis_Planes_Load_CSV ( string filename )
{
List < AircraftPositionDesignator > aps = new List < AircraftPositionDesignator > ( ) ;
bw_Analysis_FileLoader . ReportProgress ( 0 , "Opening file..." ) ;
using ( StreamReader sr = new StreamReader ( File . Open ( filename , FileMode . Open ) ) )
{
// read header
string header = sr . ReadLine ( ) ;
// split header
string [ ] a = header . Split ( ';' ) ;
// remove unit brackets and lower all
for ( int i = 0 ; i < a . Length ; i + + )
{
a [ i ] = a [ i ] . ToLower ( ) ;
if ( a [ i ] . IndexOf ( '[' ) > = 0 )
a [ i ] = a [ i ] . Substring ( 0 , a [ i ] . IndexOf ( '[' ) ) ;
}
int lastupdated_index = Array . IndexOf ( a , "time" ) ;
int hex_index = Array . IndexOf ( a , "hex" ) ;
int call_index = Array . IndexOf ( a , "call" ) ;
int lat_index = Array . IndexOf ( a , "lat" ) ;
int lon_index = Array . IndexOf ( a , "lon" ) ;
int alt_index = Array . IndexOf ( a , "alt" ) ;
int track_index = Array . IndexOf ( a , "track" ) ;
int speed_index = Array . IndexOf ( a , "speed" ) ;
bw_Analysis_FileLoader . ReportProgress ( 0 , "Creating position list..." ) ;
// read 1000 positions and update database
int count = 0 ;
int updated = 0 ;
while ( ! sr . EndOfStream )
{
aps . Clear ( ) ;
int j = 0 ;
while ( ( j < 1000 ) & & ! sr . EndOfStream )
{
string s = sr . ReadLine ( ) ;
if ( ! s . Contains ( ";" ) )
continue ;
a = s . Split ( ';' ) ;
DateTime lastupdated = System . Convert . ToDateTime ( a [ lastupdated_index ] ) . ToUniversalTime ( ) ;
string hex = a [ hex_index ] . ToUpper ( ) ;
string call = a [ call_index ] . ToUpper ( ) ;
double lat = System . Convert . ToDouble ( a [ lat_index ] , CultureInfo . InvariantCulture ) ;
double lon = System . Convert . ToDouble ( a [ lon_index ] , CultureInfo . InvariantCulture ) ;
double alt = System . Convert . ToDouble ( a [ alt_index ] , CultureInfo . InvariantCulture ) ;
double track = System . Convert . ToDouble ( a [ track_index ] , CultureInfo . InvariantCulture ) ;
double speed = System . Convert . ToDouble ( a [ speed_index ] , CultureInfo . InvariantCulture ) ;
AircraftPositionDesignator ap = new AircraftPositionDesignator ( hex , call , lat , lon , alt , track , speed , lastupdated ) ;
aps . Add ( ap ) ;
j + + ;
if ( bw_Analysis_FileLoader . CancellationPending )
return ;
}
count = count + j ;
updated = updated + AircraftPositionData . Database . AircraftPositionBulkInsertOrUpdateIfNewer ( aps ) ;
bw_Analysis_FileLoader . ReportProgress ( 0 , "Updating position " + count . ToString ( ) + ", " + updated . ToString ( ) + " updated so far..." ) ;
}
}
}
private void bw_Analysis_FileLoader_DoWork ( object sender , DoWorkEventArgs e )
{
string filename = ( string ) e . Argument ;
// name the thread for debugging
if ( String . IsNullOrEmpty ( Thread . CurrentThread . Name ) )
Thread . CurrentThread . Name = "bw_Analysis_FileLoader" ;
try
{
if ( filename . ToLower ( ) . EndsWith ( ".json" ) )
Analysis_Planes_Load_JSON ( filename ) ;
else if ( filename . ToLower ( ) . EndsWith ( ".csv" ) )
Analysis_Planes_Load_CSV ( filename ) ;
}
catch ( Exception ex )
{
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( ex . ToString ( ) , LogLevel . Error ) ;
2019-03-19 21:09:03 +00:00
bw_Analysis_FileLoader . ReportProgress ( - 1 , ex . Message ) ;
}
if ( bw_Analysis_FileLoader . CancellationPending )
e . Cancel = true ;
}
private void bw_Analysis_FileLoader_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
if ( e . ProgressPercentage < = 0 )
SayAnalysis ( ( string ) e . UserState ) ;
}
private void bw_Analysis_FileLoader_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
if ( e . Cancelled )
SayAnalysis ( "Cancelled." ) ;
else
{
btn_Analysis_Planes_Load . Enabled = true ;
SayAnalysis ( "Ready." ) ;
}
}
# endregion
#region AirportMapper
private void bw_AirportMapper_DoWork ( object sender , DoWorkEventArgs e )
{
bw_AirportMapper . ReportProgress ( 0 , "Getting airports from database..." ) ;
Stopwatch st = new Stopwatch ( ) ;
st . Start ( ) ;
// fill the airports layer of maps
// return if switched off
if ( ! Properties . Settings . Default . Airports_Activate )
return ;
List < AirportDesignator > airports = new List < AirportDesignator > ( ) ;
airports = AircraftData . Database . AirportGetAll ( bw_AirportMapper ) ;
if ( airports ! = null )
bw_AirportMapper . ReportProgress ( 100 , airports ) ;
st . Stop ( ) ;
bw_AirportMapper . ReportProgress ( 0 , airports . Count . ToString ( ) + " airports updated, " + st . ElapsedMilliseconds . ToString ( ) + " ms." ) ;
}
private void bw_AirportMapper_ProgressChanged ( object sender , ProgressChangedEventArgs e )
{
2020-04-10 15:36:18 +00:00
if ( e . ProgressPercentage = = 0 )
2019-03-19 21:09:03 +00:00
{
2020-02-12 10:45:19 +00:00
// log error message
2019-03-19 21:09:03 +00:00
string msg = ( string ) e . UserState ;
Say ( msg ) ;
2020-02-12 10:45:19 +00:00
Log . WriteMessage ( msg , LogLevel . Error ) ;
}
2019-03-19 21:09:03 +00:00
else if ( e . ProgressPercentage = = 100 )
{
2020-02-12 10:45:19 +00:00
// add aiports to overlay
2019-03-19 21:09:03 +00:00
lock ( Airports )
{
Airports = ( List < AirportDesignator > ) e . UserState ;
}
UpdateAirports ( ) ;
}
}
private void bw_AirportMapper_RunWorkerCompleted ( object sender , RunWorkerCompletedEventArgs e )
{
}
# endregion
private void gm_Main_Load ( object sender , EventArgs e )
{
}
2020-03-01 15:12:08 +00:00
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 ;
}
2019-03-19 21:09:03 +00:00
}
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 ;
}
}
}