AirScout/AirScout.Aircrafts/PlaneInfoCache.cs

327 wiersze
13 KiB
C#

using ScoutBase.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AirScout.Core;
using System.IO;
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))
{
// not found --> add plane
this.Add(plane.Hex, plane);
i = 1;
}
else
{
// plane already in cache --> check time and update if newer
if (plane.Time > oldplane.Time)
{
// 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
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);
// 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
// change speed to km/h
speed_kmh = info.Speed_kmh;
// calculate distance after timespan
dist = speed_kmh * (at - info.Time).TotalHours;
// estimate new position
newpos = LatLon.DestinationPoint(info.Lat, info.Lon, info.Track, dist);
info.Lat = newpos.Lat;
info.Lon = newpos.Lon;
info.Time = at;
// return calculated info
return info;
}
public List<PlaneInfo> GetAll(DateTime at, int ttl)
{
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);
// 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;
/*
string filename = "positions.csv";
string call = "CSN464";
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);
}
*/
// 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
/*
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);
}
*/
}
}
else
{
// do nothing
/*
if (plane.Call == call)
{
File.AppendAllText(filename, oldtimediff.ToString() + ";" + newtimediff.ToString() + "invalid timediff!" + Environment.NewLine);
}
*/
}
}
else
{
// no stored values available
}
// --> estimate new position using speed and track
// 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;
}
}
}