예제 #1
0
 private void bw_JSONWriter_DoWork(object sender, DoWorkEventArgs e)
 {
     while (!bw_JSONWriter.CancellationPending)
     {
         Thread.Sleep(60000);
         DataTable dt = new DataTable();
         // DataTable dt = FlightRadar.GetPlanePositions((int)Properties.Settings.Default.Planes_Lifetime);
         // get planes each minute
         // write json file
         try
         {
             using (StreamWriter sw = new StreamWriter(TmpDirectory + Path.DirectorySeparatorChar + "planes.json"))
             {
                 int major = Assembly.GetExecutingAssembly().GetName().Version.Major;
                 sw.Write("{\"full_count\":" + dt.Rows.Count.ToString() + ",\"version\":" + major.ToString());
                 for (int i = 0; i < dt.Rows.Count; i++)
                 {
                     string             index  = "\"" + i.ToString("x8") + "\"";
                     string             hex    = "\"" + dt.Rows[i]["Hex"].ToString() + "\"";
                     string             lat    = ((double)dt.Rows[i]["Lat"]).ToString("F4", CultureInfo.InvariantCulture);
                     string             lon    = ((double)dt.Rows[i]["Lon"]).ToString("F4", CultureInfo.InvariantCulture);
                     string             track  = dt.Rows[i]["Track"].ToString();
                     string             alt    = UnitConverter.m_ft((double)dt.Rows[i]["Alt"]).ToString("F0");
                     string             speed  = UnitConverter.kmh_kts((double)dt.Rows[i]["Speed"]).ToString("F0");
                     string             squawk = "\"" + dt.Rows[i]["Squawk"].ToString() + "\"";
                     string             radar  = "\"" + dt.Rows[i]["Radar"].ToString() + "\"";
                     AircraftDesignator d      = AircraftDatabase_old.AircraftFindByHex(dt.Rows[i]["Hex"].ToString());
                     string             type;
                     if (d != null)
                     {
                         type = "\"" + d.TypeCode + "\"";
                     }
                     else
                     {
                         type = "\"" + "\"";
                     }
                     string   reg   = "\"" + dt.Rows[i]["Reg"].ToString() + "\"";
                     DateTime rtime = System.Convert.ToDateTime(dt.Rows[i]["Time"].ToString());
                     rtime = rtime.ToUniversalTime();
                     DateTime sTime  = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                     string   time   = ((long)(rtime - sTime).TotalSeconds).ToString();
                     string   dep    = "\"\"";
                     string   dest   = "\"\"";
                     string   flight = "\"\"";
                     string   dummy0 = "\"\"";
                     string   dummy1 = "0";
                     string   dummy2 = "0";
                     string   call   = "\"" + dt.Rows[i]["Call"].ToString() + "\"";
                     string   dummy3 = "0";
                     sw.WriteLine("," + index + ":[" +
                                  hex + "," +
                                  lat + "," +
                                  lon + "," +
                                  track + "," +
                                  alt + "," +
                                  speed + "," +
                                  squawk + "," +
                                  radar + "," +
                                  type + "," +
                                  reg + "," +
                                  time + "," +
                                  dep + "," +
                                  dest + "," +
                                  flight + "," +
                                  dummy1 + "," +
                                  dummy2 + "," +
                                  call + "," +
                                  dummy3 +
                                  "]");
                 }
                 sw.WriteLine("}");
             }
         }
         catch
         {
             // do nothing
         }
     }
 }
예제 #2
0
        protected override void OnDoWork(DoWorkEventArgs e)
        {
            Log.WriteMessage("Started.");
            Arguments = (PlaneFeedWorkEventArgs)e.Argument;
            if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
            {
                Thread.CurrentThread.Name = this.GetType().Name;
            }

            // use PlaneInfoConverter for plausibility check
            PlaneInfoConverter C = new PlaneInfoConverter();

            // check boundaries
            if ((Arguments.MaxLat <= Arguments.MinLat) || (Arguments.MaxLon <= Arguments.MinLon))
            {
                Status = STATUS.ERROR;
                this.ReportProgress((int)PROGRESS.ERROR, "Area boundaries mismatch. Check your Covered Area parameters!");
                Log.WriteMessage("Area boundaries mismatch. Check your Covered Area parameters!", LogLevel.Error);
            }
            else
            {
                if (Arguments.Feed == null)
                {
                    Status = STATUS.ERROR;
                    this.ReportProgress((int)PROGRESS.ERROR, "Plane feed plugin not found. Check your settings!");
                    Log.WriteMessage("Plane feed plugin not found. Check your settings!", LogLevel.Error);
                }
                else
                {
                    do
                    {
                        try
                        {
                            Status = STATUS.OK;
                            int interval = Arguments.Interval;
                            // build arguments
                            PlaneFeedPluginArgs feedargs = new PlaneFeedPluginArgs();
                            feedargs.AppDirectory      = Arguments.AppDirectory;
                            feedargs.AppDataDirectory  = Arguments.AppDataDirectory;
                            feedargs.LogDirectory      = Arguments.LogDirectory;
                            feedargs.TmpDirectory      = Arguments.TmpDirectory;
                            feedargs.DatabaseDirectory = Arguments.DatabaseDirectory;
                            feedargs.MaxLat            = Arguments.MaxLat;
                            feedargs.MinLon            = Arguments.MinLon;
                            feedargs.MinLat            = Arguments.MinLat;
                            feedargs.MaxLon            = Arguments.MaxLon;
                            feedargs.MyLat             = Arguments.MyLat;
                            feedargs.MyLon             = Arguments.MyLon;
                            feedargs.DXLat             = Arguments.DXLat;
                            feedargs.DXLon             = Arguments.DXLon;
                            feedargs.MinAlt            = Arguments.MinAlt;
                            feedargs.MaxAlt            = Arguments.MaxAlt;
                            feedargs.KeepHistory       = Arguments.KeepHistory;
                            feedargs.InstanceID        = Arguments.InstanceID;
                            feedargs.SessionKey        = Arguments.SessionKey;
                            feedargs.GetKeyURL         = Arguments.GetKeyURL;

                            // do start procedure
                            Arguments.Feed.Start(feedargs);
                            // run inner loop
                            do
                            {
                                // call plugin's interface to get the planes
                                try
                                {
                                    Stopwatch st = new Stopwatch();
                                    st.Start();
                                    // get plane raw data and do addtional checks
                                    PlaneFeedPluginPlaneInfoList acs = Arguments.Feed.GetPlanes(feedargs);
                                    PlaneInfoList planes             = new PlaneInfoList();
                                    int           total  = acs.Count;
                                    int           count  = 0;
                                    int           errors = 0;
                                    foreach (PlaneFeedPluginPlaneInfo ac in acs)
                                    {
                                        // skip without error when on ground
                                        if (ac.Ground)
                                        {
                                            continue;
                                        }
                                        // copy raw data to new PlaneInfo object
                                        PlaneInfo plane = new PlaneInfo();
                                        plane.Hex    = ac.Hex;
                                        plane.Lat    = ac.Lat;
                                        plane.Lon    = ac.Lon;
                                        plane.Alt    = ac.Alt;
                                        plane.Call   = ac.Call;
                                        plane.Reg    = ac.Reg;
                                        plane.Track  = ac.Track;
                                        plane.Speed  = ac.Speed;
                                        plane.Time   = ac.Time;
                                        plane.From   = ac.From;
                                        plane.To     = ac.To;
                                        plane.VSpeed = ac.VSpeed;
                                        try
                                        {
                                            plane.Category = (PLANECATEGORY)ac.Category;
                                        }
                                        catch
                                        {
                                            plane.Category = PLANECATEGORY.NONE;
                                        }
                                        plane.Type         = ac.Type;
                                        plane.Model        = ac.Model;
                                        plane.Manufacturer = ac.Manufacturer;
                                        // start checks
                                        // assuming that at least a timestamp is set!
                                        // do basic check on hex --> is strictly needed as identifier
                                        if (!PlaneInfoChecker.Check_Hex(plane.Hex))
                                        {
                                            // try to fill hex from reg
                                            if (!PlaneInfoChecker.Check_Reg(plane.Reg))
                                            {
                                                if (Arguments.LogErrors)
                                                {
                                                    Log.WriteMessage("Incorrect aircraft data received [Hex]: " + plane.Hex, LogLevel.Warning);
                                                }
                                                errors++;
                                                continue;
                                            }
                                            AircraftDesignator ad = AircraftData.Database.AircraftFindByReg(plane.Reg);
                                            if (ad == null)
                                            {
                                                if (Arguments.LogErrors)
                                                {
                                                    Log.WriteMessage("Incorrect aircraft data received [Hex]: " + plane.Hex, LogLevel.Warning);
                                                }
                                                errors++;
                                                continue;
                                            }
                                            plane.Hex = ad.Hex;
                                        }
                                        // check latitude
                                        if (!PlaneInfoChecker.Check_Lat(plane.Lat))
                                        {
                                            if (Arguments.LogErrors)
                                            {
                                                Log.WriteMessage("Incorrect aircraft data received [Lat]: " + plane.Lat.ToString("F8", CultureInfo.InvariantCulture), LogLevel.Warning);
                                            }
                                            errors++;
                                            continue;
                                        }
                                        // skip without error when latitude is out of scope
                                        if ((plane.Lat < Arguments.MinLat) || (plane.Lat > Arguments.MaxLat))
                                        {
                                            continue;
                                        }
                                        // check longitude
                                        if (!PlaneInfoChecker.Check_Lon(plane.Lon))
                                        {
                                            if (Arguments.LogErrors)
                                            {
                                                Log.WriteMessage("Incorrect aircraft data received [Lon]: " + plane.Lon.ToString("F8", CultureInfo.InvariantCulture), LogLevel.Warning);
                                            }
                                            errors++;
                                            continue;
                                        }
                                        // skip without error when longitude is out of scope
                                        if ((plane.Lon < Arguments.MinLon) || (plane.Lon > Arguments.MaxLon))
                                        {
                                            continue;
                                        }
                                        // check altitude
                                        if (!PlaneInfoChecker.Check_Alt(plane.Alt))
                                        {
                                            // try to recover altitude from previuos messages
                                            PlaneInfo info = null;
                                            if (PlanePositions.TryGetValue(plane.Hex, out info))
                                            {
                                                plane.Alt = info.Alt;
                                            }
                                            else
                                            {
                                                if (Arguments.LogErrors)
                                                {
                                                    Log.WriteMessage("Incorrect aircraft data received [Alt]: " + plane.Alt.ToString("F8", CultureInfo.InvariantCulture), LogLevel.Warning);
                                                }
                                                errors++;
                                                continue;
                                            }
                                        }
                                        // skip without error when altitude_ is out of bounds
                                        if ((plane.Alt_m < Arguments.MinAlt) || (plane.Alt_m > Arguments.MaxAlt))
                                        {
                                            continue;
                                        }
                                        // check call
                                        if (!PlaneInfoChecker.Check_Call(plane.Call))
                                        {
                                            // try to recover from cache if check fails or set it to [unknown]
                                            PlaneInfo info = null;
                                            if (PlanePositions.TryGetValue(plane.Hex, out info))
                                            {
                                                plane.Call = info.Call;
                                            }
                                            else
                                            {
                                                plane.Call = "[unknown]";
                                            }
                                        }
                                        // still unknown call --> try to recover last known call from database
                                        if (!PlaneInfoChecker.Check_Call(plane.Call))
                                        {
                                            AircraftDesignator ad = AircraftData.Database.AircraftFindByHex(plane.Hex);
                                            if (ad != null)
                                            {
                                                plane.Call = ad.Call;
                                            }
                                            else
                                            {
                                                plane.Call = "[unknown]";
                                            }
                                        }
                                        // check registration
                                        if (!PlaneInfoChecker.Check_Reg(plane.Reg))
                                        {
                                            // try to recover from cache if check fails or set it to [unknown]
                                            PlaneInfo info = null;
                                            if (PlanePositions.TryGetValue(plane.Hex, out info))
                                            {
                                                plane.Reg = info.Reg;
                                            }
                                            else
                                            {
                                                plane.Reg = "[unknown]";
                                            }
                                        }
                                        // still unknown --> try to recover last known reg from database
                                        if (!PlaneInfoChecker.Check_Reg(plane.Reg))
                                        {
                                            AircraftDesignator ad = AircraftData.Database.AircraftFindByHex(plane.Hex);
                                            if (ad != null)
                                            {
                                                plane.Reg = ad.Reg;
                                            }
                                            else
                                            {
                                                plane.Reg = "[unknown]";
                                            }
                                        }
                                        // check speed
                                        if (!PlaneInfoChecker.Check_Track(plane.Track))
                                        {
                                            if (Arguments.LogErrors)
                                            {
                                                Log.WriteMessage("Incorrect aircraft data received [Track]: " + plane.Track.ToString("F8", CultureInfo.InvariantCulture), LogLevel.Warning);
                                            }
                                            errors++;
                                            continue;
                                        }
                                        // check speed
                                        if (!PlaneInfoChecker.Check_Speed(plane.Speed))
                                        {
                                            // try to recover speed from previous messages
                                            PlaneInfo info = null;
                                            if (PlanePositions.TryGetValue(plane.Hex, out info))
                                            {
                                                plane.Speed = info.Speed;
                                            }
                                            else
                                            {
                                                if (Arguments.LogErrors)
                                                {
                                                    Log.WriteMessage("Incorrect aircraft data received [Speed]: " + plane.Speed.ToString("F8", CultureInfo.InvariantCulture), LogLevel.Warning);
                                                }
                                                errors++;
                                                continue;
                                            }
                                        }
                                        // check type
                                        if (!PlaneInfoChecker.Check_Type(plane.Type))
                                        {
                                            AircraftDesignator ad = AircraftData.Database.AircraftFindByHex(plane.Hex);
                                            if (ad != null)
                                            {
                                                plane.Type = ad.TypeCode;
                                                // getrest of info later later
                                            }
                                            else
                                            {
                                                // set all type info to unknown
                                                plane.Type         = "[unknown]";
                                                plane.Model        = "[unknown]";
                                                plane.Manufacturer = "[unknown]";
                                                plane.Category     = PLANECATEGORY.NONE;
                                            }
                                        }
                                        // try to recover type info from database if check fails or unknown
                                        if (!PlaneInfoChecker.Check_Manufacturer(plane.Manufacturer) || !PlaneInfoChecker.Check_Model(plane.Model) ||
                                            (plane.Manufacturer == "[unkonwn]") || (plane.Model == "[unknown]"))
                                        {
                                            AircraftTypeDesignator td = AircraftData.Database.AircraftTypeFindByICAO(plane.Type);
                                            if (td != null)
                                            {
                                                plane.Manufacturer = td.Manufacturer;
                                                plane.Model        = td.Model;
                                                plane.Category     = td.Category;
                                            }
                                            else
                                            {
                                                plane.Manufacturer = "[unknown]";
                                                plane.Model        = "[unknown]";
                                                plane.Category     = PLANECATEGORY.NONE;
                                            }
                                        }
                                        // remove manufacturer info if part of model description
                                        if (plane.Model.StartsWith(plane.Manufacturer))
                                        {
                                            plane.Model = plane.Model.Remove(0, plane.Manufacturer.Length).Trim();
                                        }
                                        // check position against estimated position from last konwn if possible
                                        PlaneInfo oldplane = PlanePositions.Get(plane.Hex, plane.Time, 5);
                                        double    dist     = 0;
                                        if (Arguments.ExtendedPlausibilityCheck_Enable && (oldplane != null) && ((dist = LatLon.Distance(oldplane.Lat, oldplane.Lon, plane.Lat, plane.Lon)) > Arguments.ExtendedPlausiblityCheck_MaxErrorDist))
                                        {
                                            // report error
                                            if (Arguments.LogErrors)
                                            {
                                                Log.WriteMessage("Incorrect aircraft position received [(" + oldplane.Lat.ToString("F8") + "," + oldplane.Lon.ToString("F8") + ")<" + dist.ToString("F0") + "km>(" + plane.Lat.ToString("F8") + "," + plane.Lon.ToString("F8") + ")]: " + plane.ToString(), LogLevel.Warning);
                                            }
                                            errors++;
                                            continue;
                                        }
                                        // all checks successfully done --> add plane to list
                                        planes.Add(plane);
                                        count++;
                                        // cancel thread if requested
                                        if (this.CancellationPending)
                                        {
                                            return;
                                        }
                                    }
                                    // update local cache
                                    this.PlanePositions.BulkInsertOrUpdateIfNewer(planes);
                                    // report planes to main program
                                    this.ReportProgress((int)PROGRESS.PLANES, planes);
                                    // update global database
                                    AircraftData.Database.PlaneInfoBulkInsertOrUpdateIfNewer(this, planes);
                                    // update position database if enabled
                                    if (Arguments.KeepHistory)
                                    {
                                        AircraftPositionData.Database.PlaneInfoBulkInsertOrUpdateIfNewer(planes);
                                    }
                                    st.Stop();
                                    string msg = "[" + DateTime.UtcNow.ToString("HH:mm:ss") + "] " +
                                                 total.ToString() + " Positions updated from " + Arguments.Feed.Name + ", " +
                                                 st.ElapsedMilliseconds.ToString() + " ms. OK: " + count.ToString() + ", Errors: " + errors.ToString();
                                    this.ReportProgress((int)PROGRESS.STATUS, msg);
                                    // write all planes to file
                                    try
                                    {
                                        using (StreamWriter sw = new StreamWriter(Path.Combine(Arguments.TmpDirectory, "planes.csv")))
                                        {
                                            sw.WriteLine("Time;Hex;Lat;Lon;Alt;Track;Speed;Call;Reg;From;To;VSpeed");
                                            foreach (PlaneInfo plane in planes)
                                            {
                                                sw.WriteLine(plane.Time + ";" +
                                                             plane.Hex + ";" +
                                                             plane.Lat + ";" +
                                                             plane.Lon + ";" +
                                                             plane.Alt + ";" +
                                                             plane.Track + ";" +
                                                             plane.Speed + ";" +
                                                             plane.Call + ";" +
                                                             plane.Reg + ";" +
                                                             plane.From + ";" +
                                                             plane.To + ";" +
                                                             plane.VSpeed);
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        // do nothing
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Status = STATUS.ERROR;
                                    this.ReportProgress((int)PROGRESS.ERROR, "Plane Feed Execption: " + ex.Message);
                                    Log.WriteMessage(ex.ToString(), LogLevel.Error);
                                }
                                // wait for next execution
                                int i = 0;
                                while (!CancellationPending && (i < interval))
                                {
                                    Thread.Sleep(1000);
                                    i++;
                                }
                            }while (!CancellationPending);
                            // do stop procedure
                            Arguments.Feed.Stop(feedargs);
                        }
                        catch (Exception ex)
                        {
                            Status = STATUS.ERROR;
                            this.ReportProgress((int)PROGRESS.ERROR, "Plane Feed Execption: " + ex.Message);
                            Log.WriteMessage(ex.ToString(), LogLevel.Error);
                            Console.WriteLine("Plane Feed Execption: " + ex.ToString(), LogLevel.Error);
                        }
                    }while (!this.CancellationPending);
                }
            }
            this.ReportProgress((int)PROGRESS.FINISHED);
            Log.WriteMessage("Finished.");
        }
예제 #3
0
        private void bw_History_DoWork(object sender, DoWorkEventArgs e)
        {
            // check that Stepwidth ist positive in any case
            if (Properties.Settings.Default.Path_History_StepWidth <= 0)
            {
                Properties.Settings.Default.Path_History_StepWidth = 1;
            }
            bw_History.ReportProgress(0, "Calculating Path....");
            LocationDesignator mycall = StationData.Database.LocationFindOrCreate(Properties.Settings.Default.MyCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.MyLat, Properties.Settings.Default.MyLon, false, 3));
            QRVDesignator      myqrv  = StationData.Database.QRVFindOrCreateDefault(mycall.Call, mycall.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);
            }
            if (Properties.Settings.Default.Path_BestCaseElevation)
            {
                if (!MaidenheadLocator.IsPrecise(mycall.Lat, mycall.Lon, 3))
                {
                    ElvMinMaxInfo maxinfo = ElevationData.Database.ElevationTileFindMinMaxInfo(mycall.Loc, Properties.Settings.Default.ElevationModel);
                    if (maxinfo != null)
                    {
                        mycall.Lat = maxinfo.MaxLat;
                        mycall.Lon = maxinfo.MaxLon;
                    }
                }
            }
            LocationDesignator dxcall = StationData.Database.LocationFindOrCreate(Properties.Settings.Default.DXCall, MaidenheadLocator.LocFromLatLon(Properties.Settings.Default.DXLat, Properties.Settings.Default.DXLon, false, 3));
            QRVDesignator      dxqrv  = StationData.Database.QRVFindOrCreateDefault(dxcall.Call, dxcall.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);
            }
            if (Properties.Settings.Default.Path_BestCaseElevation)
            {
                if (!MaidenheadLocator.IsPrecise(dxcall.Lat, dxcall.Lon, 3))
                {
                    ElvMinMaxInfo maxinfo = ElevationData.Database.ElevationTileFindMinMaxInfo(dxcall.Loc, Properties.Settings.Default.ElevationModel);
                    if (maxinfo != null)
                    {
                        dxcall.Lat = maxinfo.MaxLat;
                        dxcall.Lon = maxinfo.MaxLon;
                    }
                }
            }

            // find local obstruction, if any
            LocalObstructionDesignator o = ElevationData.Database.LocalObstructionFind(mycall.Lat, mycall.Lon, Properties.Settings.Default.ElevationModel);
            double mybearing             = LatLon.Bearing(mycall.Lat, mycall.Lon, dxcall.Lat, dxcall.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
            PPath = PropagationData.Database.PropagationPathFindOrCreateFromLatLon(
                bw_History,
                mycall.Lat,
                mycall.Lon,
                ElevationData.Database[mycall.Lat, mycall.Lon, Properties.Settings.Default.ElevationModel] + myqrv.AntennaHeight,
                dxcall.Lat,
                dxcall.Lon,
                ElevationData.Database[dxcall.Lat, dxcall.Lon, Properties.Settings.Default.ElevationModel] + 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);
            DateTime time = From;

            lock (Crossings)
            {
                Crossings.Clear();
            }
            lock (NearestPositions)
            {
                NearestPositions.Clear();
            }
            // pre-select nearest positions only
            bw_History.ReportProgress(0, "Pre-selecting nearest positions...");
            LatLon.GPoint midpoint = PPath.GetMidPoint();
            double        maxdist  = PPath.Distance / 2;

            foreach (AircraftPositionDesignator ap in AllPositions)
            {
                if ((ap.LastUpdated >= From) && (ap.LastUpdated <= To) && (LatLon.Distance(ap.Lat, ap.Lon, midpoint.Lat, midpoint.Lon) <= maxdist))
                {
                    AircraftDesignator     ac = null;
                    AircraftTypeDesignator at = null;
                    ac = AircraftData.Database.AircraftFindByHex(ap.Hex);
                    if (ac != null)
                    {
                        at = AircraftData.Database.AircraftTypeFindByICAO(ac.TypeCode);
                    }
                    PlaneInfo plane = new PlaneInfo(ap.LastUpdated, ap.Call, ((ac != null) && (!String.IsNullOrEmpty(ac.TypeCode)))? ac.Reg : "[unknown]", ap.Hex, ap.Lat, ap.Lon, ap.Track, ap.Alt, ap.Speed, (ac != null) && (!String.IsNullOrEmpty(ac.TypeCode)) ? ac.TypeCode : "[unkomwn]", ((at != null) && (!String.IsNullOrEmpty(at.Manufacturer))) ? at.Manufacturer : "[unknown]", ((at != null) && (!String.IsNullOrEmpty(at.Model))) ? at.Model : "[unknown]", (at != null) ? at.Category : PLANECATEGORY.NONE);
                    lock (NearestPositions)
                    {
                        NearestPositions.Add(plane);
                    }
                    if (NearestPositions.Count % 1000 == 0)
                    {
                        bw_History.ReportProgress(0, "Pre-selecting nearest positions..." + "[" + NearestPositions.Count.ToString() + "]");
                    }
                }
                if (bw_History.CancellationPending)
                {
                    break;
                }
            }
            bw_History.ReportProgress(0, "Pre-selecting nearest positions finished, " + NearestPositions.Count.ToString() + " positions.");
            // return if no positions left over
            if (NearestPositions.Count == 0)
            {
                return;
            }
            int startindex = 0;

            // set timeline to first reported position
            time = NearestPositions[0].Time;
            while ((!bw_History.CancellationPending) && (time <= To))
            {
                if (Crossings.Count % 1000 == 0)
                {
                    bw_History.ReportProgress(0, "Calculating at " + time.ToString("yyyy-MM-dd HH:mm:ss") + ", " + Crossings.Count.ToString() + " crossings so far.");
                }
                // calculate from timestamp
                DateTime from = time.AddMinutes(-Properties.Settings.Default.Planes_Position_TTL);
                // fill plane position cache
                PlaneInfoCache ac = new PlaneInfoCache();
                int            i  = startindex;
                startindex = -1;
                while ((!bw_History.CancellationPending) && (i < NearestPositions.Count))
                {
                    // update ap in cache if relevant
                    if (NearestPositions[i].Time >= from)
                    {
                        // store first index as startindex for next iteration
                        if (startindex == -1)
                        {
                            startindex = i;
                        }
                        lock (ac)
                        {
                            ac.InsertOrUpdateIfNewer(NearestPositions[i]);
                        }
                    }
                    // stop if position is newer than current time
                    if (NearestPositions[i].Time > time)
                    {
                        break;
                    }
                    i++;
                }
                List <PlaneInfo> allplanes = ac.GetAll(time, Properties.Settings.Default.Planes_Position_TTL);
                // get nearest planes
                List <PlaneInfo> nearestplanes = AircraftData.Database.GetNearestPlanes(time, 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);
                if ((nearestplanes != null) && (nearestplanes.Count() > 0))
                {
                    // get all planes crossing the path
                    foreach (PlaneInfo plane in nearestplanes)
                    {
                        if (plane.IntQRB <= Properties.Settings.Default.Path_Band_Settings[Properties.Settings.Default.Band].MaxDistance)
                        {
                            // check if level value is available
                            SignalLevelDesignator ad = SignalData.Database.SignalLevelFind(plane.Time);
                            if (ad != null)
                            {
                                plane.SignalStrength = ad.Level;
                            }
                            else
                            {
                                plane.SignalStrength = double.MinValue;
                            }
                            lock (Crossings)
                            {
                                if (!Properties.Settings.Default.Analysis_CrossingHistory_WithSignalLevel || (ad != null))
                                {
                                    Crossings.Add(plane);
                                }
                            }
                        }
                        bw_History.ReportProgress(0, "Calculating at " + time.ToString("yyyy-MM-dd HH:mm:ss") + ", " + Crossings.Count.ToString() + " crossings so far.");
                    }
                }
                time = time.AddSeconds(Stepwidth);
            }
            bw_History.ReportProgress(100, "Calculation done.");
        }