/// <summary> /// Create a random IFR flight /// </summary> /// <param name="awyTableRef">The airway table to chose from</param> /// <param name="acftNo">The aircraft regNo</param> /// <param name="acftType">The aircraft type</param> /// <param name="airline">The airline operator ICAO code</param> /// <returns></returns> public static CmdList GetRandomFlight(awyTable awyTableRef, int acftNo, string acftType, string airline) { var route = new CmdList( ); var visited = new List <string>( ); // visited Navs and Fixes, we don't want to run circles var awy = GetRandomAwy(awyTableRef); if (awy == null) { return(route); // no airways available ?? } // add Aircraft Descriptor first route.Enqueue(new CmdA(acftType, CmdA.FlightT.Airway, airline)); // some random altitude and complete start of the route var altMsl = m_random.Next(MinLevel(awy.baseFt), MaxLevel(awy.topFt)); altMsl = (int)Math.Round(altMsl / 100.0) * 100; // get 100 ft increments route.Descriptor.InitFromAirway(acftNo, awy, altMsl, GetSpeed(awy.layer)); // set start conditions (assumes MslBase=0) // add segment length command route.Enqueue(new CmdD(awy.Distance_nm)); visited.Add(awy.startID); // we add all startIDs // do we have an airway to go from here? var newleg = awyTableRef.GetNextSegment(awy); while (newleg != null) { if (visited.Contains(newleg.startID)) { break; // this would create a circle (endless loop) } awy = newleg; // random speed change if (m_random.Next(10) == 0) // one out of 10 // add S command { route.Enqueue(new CmdS(GetSpeed(awy.layer))); } // random alt change if (m_random.Next(20) == 0) // one out of 20 // add V command { altMsl = GetNewAlt(altMsl, awy.baseFt, awy.topFt); route.Enqueue(new CmdV(1200, altMsl)); } // add Goto command route.Enqueue(new CmdG(awy.end_latlon)); visited.Add(awy.startID); // we add all startIDs to avoid loops above // try next one newleg = awyTableRef.GetNextSegment(awy); } route.Descriptor.FinishFromAirway(awy); // set end location ID from last segment // add mandatory end segment route.Enqueue(new CmdE( )); return(route); }
/// <summary> /// Converts from a list of AITraffic messages to a route /// returns null if something was wrong /// </summary> /// <param name="aitStream">A list of AITraffic messages as strings</param> /// <returns>A created route or null</returns> private CmdList RouteFromAIT(List <string> aitStream, bool absoluteTrack, bool ignoreAirborne) { if (aitStream.Count < 2) { Error = "# messages 2"; return(null); } ; // we don't handle below 3 reports var vac = RealTraffic.FromAITrafficString(aitStream[0]); if (vac == null) { Error = "AIT message conversion error"; return(null); } ; // converter error long cTs = vac.TStamp; // start time, var cPos = new LatLon(vac.LatLon); double cAlt = vac.Alt_ft; double cGs = vac.GS; double cVsi = vac.VSI; double cTrack = vac.TRK; if (cGs == 0) { //Initial Speed is Zero - we may not have GS at all so try to calculate some.. // try to calculate a GS var vac1 = RealTraffic.FromAITrafficString(aitStream[1]); if (vac1 == null) { return(null); // ERROR Exit, this one is not usable at all } cGs = cPos.DistanceTo(vac1.LatLon, ConvConsts.EarthRadiusNm) * 3600.0 / (vac1.TStamp - vac.TStamp); // let's try the calculated one.. } ; if (cGs == 0) { //Still Speed is Zero - we may not have GS at all so try to calculate some.. Error = "Speed is not available, cannot continue"; return(null); } double maxGS = cGs; // track Max Speed to adjust for the AcftType later var route = new CmdList( ); CmdA a = null; if (absoluteTrack) { a = new CmdA(vac.AcftType, CmdA.FlightT.MsgAbsolute); a.CreateForMsgAbsolute(cPos, cTrack, cAlt, cGs); } else { a = new CmdA(vac.AcftType, CmdA.FlightT.MsgRelative); a.CreateForMsgRelative(cAlt, cGs); } route.Enqueue(a); // walk through route for (int i = 1; i < aitStream.Count; i++) { if (string.IsNullOrEmpty(aitStream[i])) { continue; // empty CRLFs ?? } vac = RealTraffic.FromAITrafficString(aitStream[i]); if (vac == null) { Error = "AIT message conversion error"; return(null); } ; // converter error if ((!ignoreAirborne) && (!vac.Airborne)) { continue; // catch some incomplete ones } // see what delta we have long dT = vac.TStamp - cTs; cTs = vac.TStamp; // update time if (vac.GS == 0) { // try to calculate a GS ( but this does not account for turns - so it is likely too low vac.GS = cPos.DistanceTo(vac.LatLon, ConvConsts.EarthRadiusNm) * 3600.0 / dT; // let's try the calculated one.. } if (vac.GS < 5) { continue; // plane is not moving } double dAlt = vac.Alt_ft - cAlt; double dGs = vac.GS - cGs; double dTrk = vac.TRK - cTrack; double dVsi = vac.VSI - cVsi; maxGS = (vac.GS > cGs) ? vac.GS : cGs; // change speed if delta is large enough // don't collect speeds under 5 else the model does not move anymore.. if ((vac.GS >= 5) && Math.Abs(dGs) > 4) { route.Enqueue(new CmdS(vac.GS)); cGs = vac.GS; // update if used } // change Alt if delta is large enough if (Math.Abs(dAlt) > 25) { if (dAlt > 0 && cVsi < 0) { cVsi = 1200; // wrong sign, just apply a VSI } if (dAlt < 0 && cVsi > 0) { cVsi = 1200; // wrong sign, just apply a VSI } route.Enqueue(new CmdV(cVsi, vac.Alt_ft)); // we change at old VSI as this was the start to get to the new alt cAlt = vac.Alt_ft; // update if used cVsi = vac.VSI; // update if used } // Goto Pos if (absoluteTrack) { //just goto absolute location (let the model do the flying..) route.Enqueue(new CmdG(vac.LatLon)); } else { // OR calc Direction and Distance for relative flying.. route.Enqueue(new CmdH(cPos.BearingTo(vac.LatLon))); route.Enqueue(new CmdD(cPos.DistanceTo(vac.LatLon, ConvConsts.EarthRadiusNm))); } cPos = new LatLon(vac.LatLon); // move position cTrack = vac.TRK; // update track } route.Enqueue(new CmdE( )); // mandatory end command // we don't know the real acft type (no lookup in the converter) // so take a jet for above 180 and a GA one below if (maxGS > 180) { route.Descriptor.UpdateAcftType(Aircrafts.AircraftSelection.GetRandomAcftTypeOp( ).AcftType); } else { route.Descriptor.UpdateAcftType(Aircrafts.AircraftSelection.GetRandomGAAcftTypeOp( ).AcftType); } return(route); }