private TaxiInstructions GetTaxiInstructionsWhenMultipleRunways(TaxiPoint source, List <Runway> runways) { var tryGetPaths = _airfield.NavigationGraph.ShortestPathsDijkstra(_airfield.NavigationCostFunction, source); var cheapestPathCost = double.PositiveInfinity; IEnumerable <TaggedEdge <NavigationPoint, string> > cheapestPath = new List <TaggedEdge <NavigationPoint, string> >(); Runway closestRunway = null; foreach (var runway in runways) { if (!tryGetPaths(runway, out var path)) { continue; } var taggedEdges = path.ToList(); var pathCost = PathCost(taggedEdges); if (!(pathCost < cheapestPathCost)) { continue; } closestRunway = runway; cheapestPath = taggedEdges; cheapestPathCost = pathCost; } return(CompileInstructions(closestRunway, cheapestPath)); }
private TaxiInstructions GetTaxiInstructionsWhenSingleRunway(TaxiPoint source, Runway target) { var tryGetPaths = _airfield.NavigationGraph.ShortestPathsDijkstra(_airfield.NavigationCostFunction, source); if (tryGetPaths(target, out var path)) { return(CompileInstructions(target, path)); } throw new TaxiPathNotFoundException($"No taxi path found from {source.Name} to {target.Name}"); }
private static TaxiInstructions CompileInstructions(TaxiPoint target, IEnumerable <TaggedEdge <TaxiPoint, string> > path) { var taggedEdges = path.ToList(); var taxiInstructions = new TaxiInstructions() { DestinationName = target.Name, TaxiPoints = taggedEdges.Select(edge => edge.Source).ToList(), Comments = new List <string>() }; // Include the final TaxiPoint taxiInstructions.TaxiPoints.Add(taggedEdges.Last().Target); foreach (var edge in taggedEdges) { taxiInstructions.TaxiwayNames.Add(edge.Tag); } taxiInstructions.TaxiwayNames = RemoveRepeating(taxiInstructions.TaxiwayNames); Logger.Debug(taxiInstructions); return(taxiInstructions); }
private async Task CheckAsync() { try { Logger.Debug($"Peforming Taxi Progress check for {_sender.Id}"); var previousId = _sender.Id; await GameQuerier.PopulatePilotData(_sender); // If the caller does not exist any more or the ID has been reused for a different object then cancel the check. if (_sender.Id == null || _sender.Id != previousId) { _sender.Id = "DELETED"; Logger.Debug( $"Stopping Taxi Progress Check. CallerId changed, New: {_sender.Id} , Old: {previousId}."); Stop(); return; } var closestPoint = _taxiPoints.OrderBy(taxiPoint => taxiPoint.DistanceTo(_sender.Position.Coordinate)) .First(); // If the player is more than 5 miles from the closest TaxiPoint they they are long gone and should not longer // be monitored if (closestPoint.DistanceTo(_sender.Position.Coordinate) > 5) { Stop(); return; } // If this is true then we don't need to say the same commands again etc. if (_currentTaxiPoint == closestPoint) { return; } // We want to get rid of all the previous TaxiPoints in the list. We do this instead of just getting rid of the first in case // somehow the pilot manage to skip a TaxiPoint by going fast enough that they passed it before the check. var index = _taxiPoints.IndexOf(_currentTaxiPoint); if (index > 1) { Logger.Trace($" {_sender.Id} skipped at least one taxi point"); } for (var i = _taxiPoints.Count - 1; i >= 0; i--) { if (i > index) { continue; } Logger.Trace($"Removing {_taxiPoints[i].Name} from route of {_sender.Id}"); _taxiPoints.RemoveAt(i); } _currentTaxiPoint = closestPoint; Logger.Debug($"New closest TaxiPoint to {_sender.Id} is {_currentTaxiPoint.Name}"); if (_currentTaxiPoint is Runway) { using (var activity = Constants.ActivitySource.StartActivity("TaxiProgressChecker.SendTaxiInstruction", ActivityKind.Consumer)) { if (_taxiPoints.Count == 1) { Logger.Debug( $"Stopping Taxi Progress Check. {_sender.Id} has reached the end of the taxi route at {_currentTaxiPoint.Name}"); activity?.AddTag("Response", "RunwayTakeOff"); await SendMessage($"Take-off {_currentTaxiPoint.Name} at your discretion"); } else { activity?.AddTag("Response", "RunwayCrossing"); // If we have reached this bit in the code then the current taxi point is a runway that is not the terminus of the route // so tell the player they are good to cross. await SendMessage($"cross {_currentTaxiPoint.Name} at your discretion"); } } } else if (_taxiPoints.Count == 1) { Logger.Error( $"{_currentTaxiPoint.Name} is the last point in the taxi path but is not a runway"); } } catch (Exception ex) { Logger.Error(ex, "Error checking taxi progress"); } }
static void Main(string[] args) { var graph = new UndirectedGraph <TaxiPoint, TaggedEdge <TaxiPoint, string> >(); // Krymsk Airfield TaxiPoint runwayFour = new TaxiPoint("Runway 4"); TaxiPoint adJunction = new TaxiPoint("Alpha / Delta Junction"); TaxiPoint acJunction = new TaxiPoint("Alpha / Charlie Junction"); TaxiPoint bdJunction = new TaxiPoint("Bravo / Delta Junction"); TaxiPoint padsFourteenThroughTwenty = new TaxiPoint("Pads 14 to 20"); graph.AddVertex(runwayFour); graph.AddVertex(adJunction); graph.AddVertex(acJunction); graph.AddVertex(bdJunction); graph.AddVertex(padsFourteenThroughTwenty); TaggedEdge <TaxiPoint, string> runwayFourToAdJunction = new TaggedEdge <TaxiPoint, string>(runwayFour, adJunction, "Alpha"); TaggedEdge <TaxiPoint, string> adJunctionToAcJunction = new TaggedEdge <TaxiPoint, string>(adJunction, acJunction, "Alpha"); TaggedEdge <TaxiPoint, string> adJunctionToBdJunction = new TaggedEdge <TaxiPoint, string>(adJunction, bdJunction, "Delta"); TaggedEdge <TaxiPoint, string> acJunctionToPadsFourteenThroughTwenty = new TaggedEdge <TaxiPoint, string>(acJunction, padsFourteenThroughTwenty, "Charlie"); graph.AddEdge(runwayFourToAdJunction); graph.AddEdge(adJunctionToAcJunction); graph.AddEdge(adJunctionToBdJunction); graph.AddEdge(acJunctionToPadsFourteenThroughTwenty); Dictionary <TaggedEdge <TaxiPoint, string>, double> edgeCostDictionary = new Dictionary <TaggedEdge <TaxiPoint, string>, double>(graph.EdgeCount) { { runwayFourToAdJunction, 1 }, { adJunctionToAcJunction, 1 }, { adJunctionToBdJunction, 1 }, { acJunctionToPadsFourteenThroughTwenty, 1 } }; string dotGraph = graph.ToGraphviz(algorithm => { // Custom init example algorithm.FormatVertex += (sender, vertexArgs) => { vertexArgs.VertexFormat.Label = $"{vertexArgs.Vertex.Name}"; }; algorithm.FormatEdge += (sender, edgeArgs) => { var label = new QuikGraph.Graphviz.Dot.GraphvizEdgeLabel { Value = $"Taxiway {edgeArgs.Edge.Tag} : Cost {edgeCostDictionary[edgeArgs.Edge]}" }; edgeArgs.EdgeFormat.Label = label; }; }); Console.WriteLine("Graph Definition"); Console.WriteLine("-------------------------------------"); Console.WriteLine(dotGraph); Console.WriteLine("-------------------------------------"); Console.WriteLine("Shortest Path Test"); TaxiPoint root = padsFourteenThroughTwenty; Func <TaggedEdge <TaxiPoint, string>, double> edgeCost = AlgorithmExtensions.GetIndexer(edgeCostDictionary); TryFunc <TaxiPoint, IEnumerable <TaggedEdge <TaxiPoint, string> > > tryGetPaths = graph.ShortestPathsDijkstra(edgeCost, root); // Query path for given vertices TaxiPoint target = runwayFour; Console.WriteLine("Getting Path"); if (tryGetPaths(target, out IEnumerable <TaggedEdge <TaxiPoint, string> > path)) { List <string> taxiways = new List <string>(); foreach (TaggedEdge <TaxiPoint, string> edge in path) { taxiways.Add(edge.Tag); } Console.WriteLine("{0} to {1} via taxiways {2}", root.Name, target.Name, string.Join(", ", RemoveRepeating(taxiways))); } else { Console.WriteLine("Path was null"); } Console.WriteLine("Press Enter to close"); Console.ReadLine(); }