コード例 #1
0
ファイル: Runway.cs プロジェクト: jmpEA31/GroundRouteFinder
        /// <summary>
        /// Find the chain of TaxiNodes that represent this runway
        /// </summary>
        /// <param name="taxiNodes"></param>
        /// <param name="taxiEdges"></param>
        /// <returns></returns>
        private List <TaxiNode> FindNodeChain(IEnumerable <TaxiNode> taxiNodes, IEnumerable <TaxiEdge> taxiEdges)
        {
            List <TaxiNode> nodes = new List <TaxiNode>();

            // Start with the node nearest to the runway lat/lon
            TaxiNode currentNode = NearestNode;

            nodes.Add(currentNode);
            ulong previousNodeId = 0;

            do
            {
                // Now find an edge that is marked as 'runway' and that starts at the current node, but does not lead to the previous node
                IEnumerable <TaxiEdge> edgesToNext = taxiEdges.Where(e => e.IsRunway && (e.StartNode.Id == currentNode.Id && e.EndNode.Id != previousNodeId));
                if (edgesToNext.Count() == 0)
                {
                    break;
                }

                TaxiEdge edgeToNext = edgesToNext.First();
                if (edgesToNext.Count() > 1)
                {
                    double maxDeviation = double.MaxValue;

                    foreach (TaxiEdge candidate in edgesToNext)
                    {
                        double deviation = VortexMath.TurnAngle(this.Bearing, VortexMath.BearingRadians(currentNode, candidate.EndNode));
                        if (deviation < maxDeviation)
                        {
                            edgeToNext   = candidate;
                            maxDeviation = deviation;
                        }
                    }
                }

                // Keep the current Id as the previous Id
                previousNodeId = currentNode.Id;

                // And get the new current node
                currentNode = taxiNodes.Single(n => n.Id == edgeToNext.EndNode.Id);
                if (currentNode != null)
                {
                    nodes.Add(currentNode);
                }
            }while (currentNode != null);

            return(nodes);
        }
コード例 #2
0
ファイル: Runway.cs プロジェクト: jmpEA31/GroundRouteFinder
        private void FindExits()
        {
            ExitGroups.Clear();
            TaxiNode groupStartNode = null;

            // First, group all nodes
            foreach (TaxiNode node in RunwayNodes)
            {
                foreach (TaxiEdge edge in node.IncomingEdges)
                {
                    if (edge.IsRunway)
                    {
                        continue;
                    }

                    if (edge.ReverseEdge == null)
                    {
                        continue;
                    }

                    TaxiEdge actualEdge = edge.ReverseEdge;
                    double   exitAngle  = VortexMath.TurnAngle(actualEdge.Bearing, Bearing);

                    if (Math.Abs(exitAngle) > VortexMath.Deg135Rad)
                    {
                        continue;
                    }

                    if (groupStartNode == null)
                    {
                        groupStartNode = node;
                        ExitGroups.Add(node, new List <ExitPoint>());
                    }

                    double landingLengthUsed = VortexMath.DistanceKM(DisplacedNode, node);  // 'distance used' actually

                    if (VortexMath.DistanceKM(groupStartNode, node) < 0.200)
                    {
                        ExitGroups[groupStartNode].Add(new ExitPoint()
                        {
                            OffRunwayNode = actualEdge.EndNode, OnRunwayNode = node, LandingLengthUsed = landingLengthUsed, TurnAngle = exitAngle
                        });
                    }
                    else
                    {
                        // add to new group
                        groupStartNode = node;
                        ExitGroups.Add(node, new List <ExitPoint>());
                        ExitGroups[groupStartNode].Add(new ExitPoint()
                        {
                            OffRunwayNode = actualEdge.EndNode, OnRunwayNode = node, LandingLengthUsed = landingLengthUsed, TurnAngle = exitAngle
                        });
                    }
                }
            }

            if (ExitGroups.Count == 0)
            {
                return; // todo: add warning
            }
            // Then pick groups based upon distance
            List <ExitPoint> minimumExit = null;
            List <ExitPoint> mediumExit  = null;
            List <ExitPoint> longExit    = null;
            List <ExitPoint> maxExit     = null;

            foreach (KeyValuePair <TaxiNode, List <ExitPoint> > exitGroup in ExitGroups.OrderBy(eg => eg.Value.First().LandingLengthUsed))
            {
                if (minimumExit == null || minimumExit.First().LandingLengthUsed < VortexMath.Feet4000Km)
                {
                    minimumExit = exitGroup.Value;
                }
                else if (mediumExit == null || mediumExit.First().LandingLengthUsed < VortexMath.Feet5000Km)
                {
                    mediumExit = exitGroup.Value;
                }
                else if (longExit == null || longExit.First().LandingLengthUsed < VortexMath.Feet6500Km)
                {
                    longExit = exitGroup.Value;
                }
                else
                {
                    maxExit = exitGroup.Value;
                }
            }

            ExitGroups.Clear();
            if (minimumExit != null)
            {
                ExitGroups.Add(minimumExit.First().OnRunwayNode, minimumExit);
            }
            if (mediumExit != null)
            {
                ExitGroups.Add(mediumExit.First().OnRunwayNode, mediumExit);
            }
            if (longExit != null)
            {
                ExitGroups.Add(longExit.First().OnRunwayNode, longExit);
            }
            if (maxExit != null)
            {
                ExitGroups.Add(maxExit.First().OnRunwayNode, maxExit);
            }

            foreach (var result in ExitGroups)
            {
                Logger.Log($"{Designator} Group: {result.Key.Id}");

                ExitPoint right = result.Value.Where(ep => ep.TurnAngle > 0).OrderBy(ep => ep.TurnAngle).FirstOrDefault();
                ExitPoint left  = result.Value.Where(ep => ep.TurnAngle < 0).OrderByDescending(ep => ep.TurnAngle).FirstOrDefault();
                ExitGroups[result.Key].Clear();

                if (right != null)
                {
                    Logger.Log($" Right Exit: {right.OnRunwayNode.Id}->{right.OffRunwayNode.Id} {right.TurnAngle * VortexMath.Rad2Deg:0.0} {right.LandingLengthUsed * VortexMath.KmToFoot:0}ft");
                    ExitGroups[result.Key].Add(right);
                }

                if (left != null)
                {
                    Logger.Log($" Left  Exit: {left.OnRunwayNode.Id}->{left.OffRunwayNode.Id} {left.TurnAngle * VortexMath.Rad2Deg:0.0} {left.LandingLengthUsed * VortexMath.KmToFoot:0}ft");
                    ExitGroups[result.Key].Add(left);
                }
            }
        }
コード例 #3
0
ファイル: Runway.cs プロジェクト: jmpEA31/GroundRouteFinder
        private void FindEntries()
        {
            EntryGroups.Clear();

            TaxiNode groupStartNode = null;
            bool     foundGroups    = false;

            // Nodes are ordered, longest remaining runway to runway end
            foreach (TaxiNode node in RunwayNodes)
            {
                double takeoffLengthRemaining = VortexMath.DistanceKM(node, OppositeEnd);
                if (takeoffLengthRemaining < VortexMath.Feet4000Km)
                {
                    break;
                }

                foreach (TaxiEdge edge in node.IncomingEdges)
                {
                    if (edge.IsRunway)
                    {
                        continue;
                    }

                    double entryAngle = VortexMath.TurnAngle(edge.Bearing, Bearing);
                    if (Math.Abs(entryAngle) > VortexMath.Deg120Rad)
                    {
                        continue;
                    }

                    if (groupStartNode == null)
                    {
                        groupStartNode = node;
                        EntryGroups.Add(node, new List <EntryPoint>());
                    }

                    // Next can be simplified to 1 if (>= 0.250) / else with the actual add after the if else
                    // for now this shows better what is going on
                    if (VortexMath.DistanceKM(groupStartNode, node) < 0.200)
                    {
                        EntryGroups[groupStartNode].Add(new EntryPoint()
                        {
                            OffRunwayNode = edge.StartNode, OnRunwayNode = node, TakeoffLengthRemaining = takeoffLengthRemaining, TurnAngle = entryAngle
                        });
                    }
                    else if (EntryGroups.Count < 2)
                    {
                        // add to new group
                        groupStartNode = node;
                        EntryGroups.Add(node, new List <EntryPoint>());
                        EntryGroups[groupStartNode].Add(new EntryPoint()
                        {
                            OffRunwayNode = edge.StartNode, OnRunwayNode = node, TakeoffLengthRemaining = takeoffLengthRemaining, TurnAngle = entryAngle
                        });
                    }
                    else
                    {
                        foundGroups = true;
                        break;
                    }
                }
                if (foundGroups)
                {
                    break;
                }
            }

            bool   gotLeft          = false;
            bool   gotRight         = false;
            bool   useIntersections = Settings.UseIntersectionTakeOffs;
            double maxShiftKm       = (double)Settings.MaxIntersectionShift * VortexMath.Foot2Km;

            // Find at least one enrty from the left and one from the right
            // If using intersections is allowed, add the intersections as option
            // as long as they are not too far from the runway start
            foreach (var result in EntryGroups)
            {
                Logger.Log($"{Designator} Group: {result.Key.Id}");

                EntryPoint right = result.Value.Where(ep => ep.TurnAngle < 0).OrderByDescending(ep => ep.TurnAngle).FirstOrDefault();
                EntryPoint left  = result.Value.Where(ep => ep.TurnAngle > 0).OrderBy(ep => ep.TurnAngle).FirstOrDefault();
                EntryGroups[result.Key].Clear();

                if (right != null)
                {
                    // No entry from the right, or using intersections is allowed
                    if (!gotRight || useIntersections)
                    {
                        // No entry from the right, or current intersections is not too far from runway start
                        if (!gotRight || (this.Length - maxShiftKm) < right.TakeoffLengthRemaining)
                        {
                            Logger.Log($" Right Entry: {right.OffRunwayNode.Id}->{right.OnRunwayNode.Id} {right.TurnAngle * VortexMath.Rad2Deg:0.0} {right.TakeoffLengthRemaining * VortexMath.KmToFoot:0}ft");
                            EntryGroups[result.Key].Add(right);
                            gotRight = true;
                        }
                    }
                }

                if (left != null)
                {
                    // No entry from the left, or using intersections is allowed
                    if (!gotLeft || useIntersections)
                    {
                        // No entry from the left, or current intersections is not too far from runway start
                        if (!gotLeft || (this.Length - maxShiftKm) < left.TakeoffLengthRemaining)
                        {
                            Logger.Log($" Left  Entry: {left.OffRunwayNode.Id}->{left.OnRunwayNode.Id} {left.TurnAngle * VortexMath.Rad2Deg:0.0} {left.TakeoffLengthRemaining * VortexMath.KmToFoot:0}ft");
                            EntryGroups[result.Key].Add(left);
                            gotLeft = true;
                        }
                    }
                }
            }
        }