Example #1
0
        internal static void TrackAerotow(this FlightContext context)
        {
            // ToDo: Think about the possibility of a paired landing.

            if (context.Options.AircraftAccessor == null)
            {
                throw new Exception($"Unable to track tow without {nameof(FlightContextFactory)}");
            }

            var target = context.Flight.Encounters
                         .FirstOrDefault(q => q.Type == Models.EncounterType.Tow ||
                                         q.Type == Models.EncounterType.Tug);

            if (target == null)
            {
                // Note of caution; this situation should ideally never happen. If it does it would be a design flaw in the state machine?
                context.StateMachine.Fire(FlightContext.Trigger.LaunchCompleted);
                return;
            }

            var otherContext = context.Options.AircraftAccessor(target.Aircraft);

            var iAm = context.WhatAmI(otherContext);

            if (iAm == null)
            {
                return;              // (I'm nothing. Try again next time)
            }
            if (iAm == Internal.Geo.AircraftRelation.None ||
                (target.Type == Models.EncounterType.Tow && iAm != Internal.Geo.AircraftRelation.Towplane) ||
                (target.Type == Models.EncounterType.Tug && iAm != Internal.Geo.AircraftRelation.OnTow))
            {
                target.End = context.CurrentPosition.TimeStamp;
                context.StateMachine.Fire(FlightContext.Trigger.LaunchCompleted);
                context.InvokeOnLaunchCompletedEvent();
                return;
            }
        }
Example #2
0
        internal static void Departing(this FlightContext context)
        {
            /*
             * First check plausible scenarios. The easiest to track is an aerotow.
             *
             * If not, wait until the launch is completed.
             */

            if (context.Flight.LaunchMethod == LaunchMethods.None)
            {
                var departure = context.Flight.PositionUpdates
                                .Where(q => q.Heading != 0 && !double.IsNaN(q.Heading))
                                .OrderBy(q => q.TimeStamp)
                                .Take(5)
                                .ToList();

                if (departure.Count > 4)
                {
                    context.Flight.DepartureHeading = Convert.ToInt16(departure.Average(q => q.Heading));

                    if (context.Flight.DepartureHeading == 0)
                    {
                        context.Flight.DepartureHeading = 360;
                    }

                    // Only start method recognition after the heading has been determined
                    context.Flight.LaunchMethod = LaunchMethods.Unknown | LaunchMethods.Aerotow | LaunchMethods.Winch | LaunchMethods.Self;
                }
                else
                {
                    return;
                }
            }

            if (context.Flight.DepartureTime != null &&
                (context.CurrentPosition.TimeStamp - (context.Flight.PositionUpdates.FirstOrDefault(q => q.Speed > 30)?.TimeStamp ?? context.CurrentPosition.TimeStamp)).TotalSeconds < 10)
            {
                return;
            }

            // We can safely try to extract the correct path

            if (context.Flight.LaunchMethod.HasFlag(LaunchMethods.Unknown | LaunchMethods.Aerotow))
            {
                var encounters = context.TowEncounter().ToList();

                if (encounters.Count(q => q?.Type == EncounterType.Tug || q?.Type == EncounterType.Tow) > 1)
                {
                    return;
                }

                var encounter = encounters.SingleOrDefault(q => q?.Type == EncounterType.Tug || q?.Type == EncounterType.Tow);

                if (encounter != null)
                {
                    context.Flight.LaunchMethod = LaunchMethods.Aerotow
                                                  | (encounter.Type == EncounterType.Tug
                            ? LaunchMethods.OnTow
                            : LaunchMethods.TowPlane
                                                     );

                    context.Flight.Encounters.Add(encounter);

                    context.StateMachine.Fire(FlightContext.Trigger.TrackAerotow);

                    return;
                }
                else if (encounters.Any(q => q == null))
                {
                    return;
                }

                context.Flight.LaunchMethod &= ~LaunchMethods.Aerotow;
            }

            if (context.Flight.LaunchMethod.HasFlag(LaunchMethods.Unknown))
            {
                var x = new DenseVector(context.Flight.PositionUpdates.Select(w => (w.TimeStamp - context.Flight.DepartureTime.Value).TotalSeconds).ToArray());
                var y = new DenseVector(context.Flight.PositionUpdates.Select(w => w.Altitude).ToArray());

                var interpolation = CubicSpline.InterpolateNatural(x, y);

                var r  = new List <double>();
                var r2 = new List <double>();

                for (var i = 0; i < (context.CurrentPosition.TimeStamp - context.Flight.DepartureTime.Value).TotalSeconds; i++)
                {
                    r.Add(interpolation.Differentiate(i));
                    r2.Add(interpolation.Differentiate2(i));
                }

                // When the initial climb has completed
                if (interpolation.Differentiate((context.CurrentPosition.TimeStamp - context.Flight.DepartureTime.Value).TotalSeconds) < 0)
                {
                    // Skip the first element because heading is 0 when in rest
                    var averageHeading = context.Flight.PositionUpdates.Skip(1).Average(q => q.Heading);

                    // ToDo: Add check to see whether there is another aircraft nearby
                    if (context.Flight.PositionUpdates
                        .Skip(1)
                        .Where(q => interpolation.Differentiate((context.CurrentPosition.TimeStamp - context.Flight.DepartureTime.Value).TotalSeconds) > 0)
                        .Select(q => Geo.GetHeadingError(averageHeading, q.Heading))
                        .Any(q => q > 20) ||
                        Geo.DistanceTo(
                            context.Flight.PositionUpdates.First().Location,
                            context.CurrentPosition.Location) > 3000)
                    {
                        context.Flight.LaunchMethod = LaunchMethods.Self;
                    }
                    else
                    {
                        context.Flight.LaunchMethod = LaunchMethods.Winch;
                    }

                    context.Flight.LaunchFinished = context.CurrentPosition.TimeStamp;
                    context.InvokeOnLaunchCompletedEvent();
                    context.StateMachine.Fire(FlightContext.Trigger.LaunchCompleted);
                }
            }
        }