2019-03-19 21:09:03 +00:00
|
|
|
|
using ScoutBase.Core;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
2019-03-21 11:25:33 +00:00
|
|
|
|
using AirScout.Core;
|
2021-12-31 08:08:48 +00:00
|
|
|
|
using System.IO;
|
2019-03-19 21:09:03 +00:00
|
|
|
|
|
|
|
|
|
namespace AirScout.Aircrafts
|
|
|
|
|
{
|
|
|
|
|
public class PlaneInfoCache : SortedDictionary<string, PlaneInfo>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public int InsertOrUpdateIfNewer (PlaneInfo plane)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
if (plane == null)
|
|
|
|
|
return i;
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
PlaneInfo oldplane = null;
|
|
|
|
|
if (!this.TryGetValue(plane.Hex, out oldplane))
|
|
|
|
|
{
|
2021-12-31 08:08:48 +00:00
|
|
|
|
// not found --> add plane
|
2019-03-19 21:09:03 +00:00
|
|
|
|
this.Add(plane.Hex, plane);
|
|
|
|
|
i = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// plane already in cache --> check time and update if newer
|
|
|
|
|
if (plane.Time > oldplane.Time)
|
|
|
|
|
{
|
2023-01-30 06:00:58 +00:00
|
|
|
|
|
2021-12-31 08:08:48 +00:00
|
|
|
|
// keep old values
|
|
|
|
|
oldplane.OldTime = oldplane.Time;
|
|
|
|
|
oldplane.OldLat = oldplane.Lat;
|
|
|
|
|
oldplane.OldLon = oldplane.Lon;
|
|
|
|
|
oldplane.OldAlt = oldplane.Alt;
|
|
|
|
|
oldplane.OldSpeed = oldplane.Speed;
|
|
|
|
|
oldplane.OldTrack = oldplane.Track;
|
|
|
|
|
|
|
|
|
|
// update values
|
2019-03-19 21:09:03 +00:00
|
|
|
|
oldplane.Alt = plane.Alt;
|
|
|
|
|
oldplane.AltDiff = plane.AltDiff;
|
|
|
|
|
oldplane.Angle = plane.Angle;
|
|
|
|
|
oldplane.Call = plane.Call;
|
|
|
|
|
oldplane.Category = plane.Category;
|
|
|
|
|
oldplane.Comment = plane.Comment;
|
|
|
|
|
oldplane.Eps1 = plane.Eps1;
|
|
|
|
|
oldplane.Eps2 = plane.Eps2;
|
|
|
|
|
oldplane.Theta1 = plane.Theta1;
|
|
|
|
|
oldplane.Theta2 = plane.Theta2;
|
|
|
|
|
oldplane.IntPoint = plane.IntPoint;
|
|
|
|
|
oldplane.IntQRB = plane.IntQRB;
|
|
|
|
|
oldplane.Lat = plane.Lat;
|
|
|
|
|
oldplane.Lon = plane.Lon;
|
|
|
|
|
oldplane.Manufacturer = plane.Manufacturer;
|
|
|
|
|
oldplane.Model = plane.Model;
|
|
|
|
|
oldplane.Potential = plane.Potential;
|
|
|
|
|
oldplane.Reg = plane.Reg;
|
|
|
|
|
oldplane.SignalStrength = plane.SignalStrength;
|
|
|
|
|
oldplane.Speed = plane.Speed;
|
|
|
|
|
oldplane.Squint = plane.Squint;
|
|
|
|
|
oldplane.Time = plane.Time;
|
|
|
|
|
oldplane.Track = plane.Track;
|
|
|
|
|
oldplane.Type = plane.Type;
|
|
|
|
|
i = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int BulkInsertOrUpdateIfNewer (List<PlaneInfo> planes)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
if (planes == null)
|
|
|
|
|
return i;
|
|
|
|
|
if (planes.Count == 0)
|
|
|
|
|
return i;
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
foreach (PlaneInfo plane in planes)
|
|
|
|
|
{
|
|
|
|
|
int j = InsertOrUpdateIfNewer(plane);
|
|
|
|
|
i = i + j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Delete (PlaneInfo plane)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
PlaneInfo oldplane = null;
|
|
|
|
|
if (this.TryGetValue(plane.Hex, out oldplane))
|
|
|
|
|
{
|
|
|
|
|
this.Remove(plane.Hex);
|
|
|
|
|
i = 1;
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int BulkDelete (List<PlaneInfo> planes)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
if (planes == null)
|
|
|
|
|
return i;
|
|
|
|
|
if (planes.Count == 0)
|
|
|
|
|
return i;
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
foreach (PlaneInfo plane in planes)
|
|
|
|
|
{
|
|
|
|
|
int j = Delete(plane);
|
|
|
|
|
i = i + j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PlaneInfo Get(string hex, DateTime at, int ttl)
|
|
|
|
|
{
|
|
|
|
|
PlaneInfo plane = null;
|
|
|
|
|
DateTime to = at;
|
|
|
|
|
DateTime from = to - new TimeSpan(0, ttl, 0);
|
|
|
|
|
// return null if not found
|
|
|
|
|
if (!this.TryGetValue(hex, out plane))
|
|
|
|
|
return null;
|
|
|
|
|
// return null if not in timespan
|
|
|
|
|
if ((plane.Time < from) || (plane.Time > to))
|
|
|
|
|
return null;
|
|
|
|
|
// create new plane info
|
|
|
|
|
PlaneInfo info = new PlaneInfo(plane);
|
2021-12-31 08:08:48 +00:00
|
|
|
|
// estimate new values
|
|
|
|
|
double alt = 0;
|
|
|
|
|
double speed = 0;
|
|
|
|
|
double speed_kmh = 0;
|
|
|
|
|
double track = 0;
|
|
|
|
|
double dist = 0;
|
|
|
|
|
LatLon.GPoint newpos;
|
|
|
|
|
// use stored old values if available
|
|
|
|
|
if (plane.OldTime != DateTime.MinValue)
|
|
|
|
|
{
|
|
|
|
|
double oldtimediff = (plane.Time - plane.OldTime).TotalSeconds;
|
|
|
|
|
double newtimediff = (at - plane.Time).TotalSeconds;
|
|
|
|
|
|
|
|
|
|
// adjust values if there is a valid timespan in history
|
|
|
|
|
if ((oldtimediff > 0) && (newtimediff > 0))
|
|
|
|
|
{
|
|
|
|
|
alt = (plane.Alt - plane.OldAlt) / oldtimediff * newtimediff + plane.Alt;
|
|
|
|
|
track = (plane.Track - plane.OldTrack) / oldtimediff * newtimediff + plane.Track;
|
|
|
|
|
speed = (plane.Speed - plane.OldSpeed) / oldtimediff * newtimediff + plane.Speed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// do nothing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// no stored values available
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --> estimate new position using speed and track
|
|
|
|
|
|
|
|
|
|
// do plausibility check of calculated new absolute values
|
|
|
|
|
if ((alt > 0) && (alt <= 50000) &&
|
|
|
|
|
(track > 0) && (track <= 360) &&
|
|
|
|
|
(speed > 0) && (speed <= 700))
|
|
|
|
|
{
|
|
|
|
|
// change speed to km/h
|
|
|
|
|
speed_kmh = UnitConverter.kts_kmh(speed);
|
|
|
|
|
// calculate distance after timespan
|
|
|
|
|
dist = speed_kmh * (at - info.Time).TotalHours;
|
|
|
|
|
// estimate new position
|
|
|
|
|
newpos = LatLon.DestinationPoint(info.Lat, info.Lon, track, dist);
|
|
|
|
|
|
|
|
|
|
// check resulting motion vector against last reported track
|
|
|
|
|
// should be well inside the bounds
|
|
|
|
|
// a plane cannot move to a position to where it is not pointing to
|
|
|
|
|
double calctrack = LatLon.Bearing(info.Lat, info.Lon, newpos.Lat, newpos.Lon);
|
|
|
|
|
if (Math.Abs(info.Track - calctrack) < 45)
|
|
|
|
|
{
|
|
|
|
|
// valid --> use the calculated values
|
|
|
|
|
info.Lat = newpos.Lat;
|
|
|
|
|
info.Lon = newpos.Lon;
|
|
|
|
|
info.Alt = alt;
|
|
|
|
|
info.Track = track;
|
|
|
|
|
info.Speed = speed;
|
|
|
|
|
info.Time = at;
|
|
|
|
|
|
|
|
|
|
// return calculated info
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// one of plausibility checks failed --> use last reported constant values for estimation
|
2019-03-19 21:09:03 +00:00
|
|
|
|
// change speed to km/h
|
2021-12-31 08:08:48 +00:00
|
|
|
|
speed_kmh = info.Speed_kmh;
|
2019-03-19 21:09:03 +00:00
|
|
|
|
// calculate distance after timespan
|
2021-12-31 08:08:48 +00:00
|
|
|
|
dist = speed_kmh * (at - info.Time).TotalHours;
|
2019-03-19 21:09:03 +00:00
|
|
|
|
// estimate new position
|
2021-12-31 08:08:48 +00:00
|
|
|
|
newpos = LatLon.DestinationPoint(info.Lat, info.Lon, info.Track, dist);
|
2019-03-19 21:09:03 +00:00
|
|
|
|
info.Lat = newpos.Lat;
|
|
|
|
|
info.Lon = newpos.Lon;
|
|
|
|
|
info.Time = at;
|
2021-12-31 08:08:48 +00:00
|
|
|
|
|
|
|
|
|
// return calculated info
|
2019-03-19 21:09:03 +00:00
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<PlaneInfo> GetAll(DateTime at, int ttl)
|
|
|
|
|
{
|
2021-12-31 08:08:48 +00:00
|
|
|
|
|
2019-03-19 21:09:03 +00:00
|
|
|
|
List<PlaneInfo> l = new List<PlaneInfo>();
|
|
|
|
|
DateTime to = at;
|
|
|
|
|
DateTime from = to - new TimeSpan(0, ttl, 0);
|
|
|
|
|
lock (this)
|
|
|
|
|
{
|
|
|
|
|
foreach (PlaneInfo plane in this.Values)
|
|
|
|
|
{
|
|
|
|
|
if ((plane.Time < from) || (plane.Time > to))
|
|
|
|
|
continue;
|
|
|
|
|
// create new plane info
|
|
|
|
|
PlaneInfo info = new PlaneInfo(plane);
|
2021-12-31 08:08:48 +00:00
|
|
|
|
// estimate new values
|
|
|
|
|
// use stored old values if available
|
|
|
|
|
if (plane.OldTime != DateTime.MinValue)
|
|
|
|
|
{
|
|
|
|
|
double oldtimediff = (plane.Time - plane.OldTime).TotalSeconds;
|
|
|
|
|
double newtimediff = (at - plane.Time).TotalSeconds;
|
|
|
|
|
|
|
|
|
|
// adjust values if there is a valid timespan in history
|
|
|
|
|
if ((oldtimediff > 0) && (newtimediff > 0))
|
|
|
|
|
{
|
|
|
|
|
double newalt = (plane.Alt - plane.OldAlt) / oldtimediff * newtimediff + plane.Alt;
|
|
|
|
|
double newtrack = (plane.Track - plane.OldTrack) / oldtimediff * newtimediff + plane.Track;
|
|
|
|
|
double newspeed = (plane.Speed - plane.OldSpeed) / oldtimediff * newtimediff + plane.Speed;
|
|
|
|
|
|
2023-01-30 06:00:58 +00:00
|
|
|
|
/*
|
|
|
|
|
string filename = "positions.csv";
|
|
|
|
|
string call = "CSN464";
|
|
|
|
|
|
2021-12-31 08:08:48 +00:00
|
|
|
|
if (plane.Call == call)
|
|
|
|
|
{
|
|
|
|
|
File.AppendAllText(filename, oldtimediff.ToString() + ";" +
|
|
|
|
|
newtimediff.ToString() + ";" +
|
|
|
|
|
plane.OldAlt.ToString("F8") + ";" +
|
|
|
|
|
plane.Alt.ToString("F8") + ";" +
|
|
|
|
|
newalt.ToString("F8") + ";" +
|
|
|
|
|
plane.OldTrack.ToString("F8") + ";" +
|
|
|
|
|
plane.Track.ToString("F8") + ";" +
|
|
|
|
|
newtrack.ToString("F8") + ";" +
|
|
|
|
|
plane.OldSpeed.ToString("F8") + ";" +
|
|
|
|
|
plane.Speed.ToString("F8") + ";" +
|
|
|
|
|
newspeed.ToString("F8") + ";" +
|
|
|
|
|
Environment.NewLine);
|
|
|
|
|
}
|
2023-01-30 06:00:58 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2021-12-31 08:08:48 +00:00
|
|
|
|
// do plausibility check of calculated values
|
|
|
|
|
if ((newalt > 0) && (newalt < 50000) &&
|
|
|
|
|
(newtrack > 0) && (newtrack < 360) &&
|
|
|
|
|
(newspeed > 0) && (newspeed < 700))
|
|
|
|
|
{
|
|
|
|
|
info.Alt = newalt;
|
|
|
|
|
info.Track = newtrack;
|
|
|
|
|
info.Speed = newspeed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// do nothing
|
2023-01-30 06:00:58 +00:00
|
|
|
|
/*
|
2021-12-31 08:08:48 +00:00
|
|
|
|
if (plane.Call == call)
|
|
|
|
|
{
|
|
|
|
|
File.AppendAllText(filename, oldtimediff.ToString() + ";" +
|
|
|
|
|
newtimediff.ToString() + ";" +
|
|
|
|
|
plane.OldAlt.ToString("F8") + ";" +
|
|
|
|
|
plane.Alt.ToString("F8") + ";" +
|
|
|
|
|
newalt.ToString("F8") + ";" +
|
|
|
|
|
plane.OldTrack.ToString("F8") + ";" +
|
|
|
|
|
plane.Track.ToString("F8") + ";" +
|
|
|
|
|
newtrack.ToString("F8") + ";" +
|
|
|
|
|
plane.OldSpeed.ToString("F8") + ";" +
|
|
|
|
|
plane.Speed.ToString("F8") + ";" +
|
|
|
|
|
newspeed.ToString("F8") + ":" +
|
|
|
|
|
"invalid values!" +
|
|
|
|
|
Environment.NewLine);
|
|
|
|
|
}
|
2023-01-30 06:00:58 +00:00
|
|
|
|
*/
|
2021-12-31 08:08:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// do nothing
|
2023-01-30 06:00:58 +00:00
|
|
|
|
/*
|
2021-12-31 08:08:48 +00:00
|
|
|
|
if (plane.Call == call)
|
|
|
|
|
{
|
|
|
|
|
File.AppendAllText(filename, oldtimediff.ToString() + ";" + newtimediff.ToString() + "invalid timediff!" + Environment.NewLine);
|
|
|
|
|
}
|
2023-01-30 06:00:58 +00:00
|
|
|
|
*/
|
2021-12-31 08:08:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// no stored values available
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --> estimate new position using speed and track
|
2019-03-19 21:09:03 +00:00
|
|
|
|
// change speed to km/h
|
|
|
|
|
double speed = info.Speed_kmh;
|
|
|
|
|
// calculate distance after timespan
|
|
|
|
|
double dist = speed * (at - info.Time).TotalHours;
|
|
|
|
|
// estimate new position
|
|
|
|
|
LatLon.GPoint newpos = LatLon.DestinationPoint(info.Lat, info.Lon, info.Track, dist);
|
|
|
|
|
info.Lat = newpos.Lat;
|
|
|
|
|
info.Lon = newpos.Lon;
|
|
|
|
|
info.Time = at;
|
|
|
|
|
l.Add(info);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|