internal static AircraftRelation WhatAmI(this FlightContext context1, FlightContext context2) { var c2Position = context2.GetPositionAt(context1.CurrentPosition.TimeStamp); if (c2Position == null && Math.Abs((context1.Flight.DepartureTime - context2.Flight.DepartureTime)?.TotalSeconds ?? 21) < 30) { return(AircraftRelation.Indeterministic); } else if (c2Position == null || context2.CurrentPosition == null || (context1.CurrentPosition.TimeStamp - context2.CurrentPosition.TimeStamp).TotalSeconds > 30 || context1.CurrentPosition.Location.DistanceTo(c2Position.Location) > 200) { // In this case we conclusively know there's nothing to be found return(AircraftRelation.None); } var bearings = new List <double>(); for (var i = context1.Flight.PositionUpdates.Count - 1; i >= 0; i--) { var p1 = context1.Flight.PositionUpdates[i]; var p2 = context2.GetPositionAt(p1.TimeStamp); // If this statement is true, the changes that our interpolation is right are getting more slim by the tick. if (p1.TimeStamp < context2.Flight.PositionUpdates[0].TimeStamp) { break; } if (Math.Abs(p1.Speed - p2.Speed) > 20 || Math.Abs(p1.Altitude - p2.Altitude) > 100 || p1.Location.DistanceTo(p2.Location) > 200) { return(AircraftRelation.None); } var angle = (p1.Location.DegreeBearing(p2.Location) - p1.Heading + 360) % 360; bearings.Add(angle); } var bearing = Geo.MeanAngle(bearings.ToArray()); return(90 < bearing && bearing < 270 ? AircraftRelation.Towplane : AircraftRelation.OnTow); }