示例#1
0
    /// <summary>
    /// Determines whether there is a series of edges that continusously connect from the startNode to the endNode.
    /// Optionally accepts a predicate function filtering out edges that do not meet the provided criteria.
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="criteria"></param>
    /// <returns></returns>
    public bool DoesPathExist(Node startNode, Node endNode, NodeEdgePairs.EdgeFilterCriteria criteria = null)
    {
        HashSet <Node> closedSet = new HashSet <Node> {
            startNode
        };

        Queue <Node> queue = new Queue <Node>();

        queue.Enqueue(startNode);

        while (queue.Count > 0)
        {
            Node node = queue.Dequeue();
            foreach (Edge edge in edgesFromNode.GetEdges(node, criteria))
            {
                Node otherNode = edge.GetOtherNode(node);

                if (!closedSet.Contains(otherNode))
                {
                    if (criteria == null || criteria(edge))
                    {
                        if (otherNode == endNode)
                        {
                            return(true);
                        }
                        queue.Enqueue(otherNode);
                        closedSet.Add(otherNode);
                    }
                }
            }
        }

        return(false);
    }
示例#2
0
    /// <summary>
    /// Finds the shortest series of edges that continuously connect from the startNode to the endNode.
    /// Optionally accepts a predicate function filtering out edges that do not meet the provided criteria.
    /// If no path exists, the returned list will be empty. This implementation is based on the A* algorithm.
    /// </summary>
    /// <param name="startNode"></param>
    /// <param name="endNode"></param>
    /// <param name="criteria"></param>
    /// <returns></returns>
    public List <Node> GetShortestPath(Node startNode, Node endNode, NodeEdgePairs.EdgeFilterCriteria criteria = null)
    {
        List <Node> shortestPath = new List <Node>();

        HashSet <Node> openNodes   = new HashSet <Node>();                  // set of nodes to be evaluated
        HashSet <Node> closedNodes = new HashSet <Node>();                  // set of nodes already evaluated

        Dictionary <Node, Node>  cameFrom = new Dictionary <Node, Node>();  // associates a key node with the node it came from
        Dictionary <Node, float> gScore   = new Dictionary <Node, float>(); // cost of getting to node from the startNode (inf if not included)
        Dictionary <Node, float> fScore   = new Dictionary <Node, float>(); // total cost of getting from start to end via a given node (partly known, partly heuristic)

        openNodes.Add(startNode);
        gScore.Add(startNode, 0f);                                                // cost from start to start is zero
        fScore.Add(startNode, (endNode.GetXYZ() - startNode.GetXYZ()).magnitude); // for start node, total cost is all heuristic (i.e unweighted distance to end)

        while (openNodes.Count > 0)
        {
            // Get the node in the open set that has the current lowest fScore
            Node currentNode = openNodes.First();
            foreach (Node node in openNodes)
            {
                if (fScore.ContainsKey(node) && fScore[node] < fScore[currentNode])
                {
                    currentNode = node;
                }
            }

            // if the current node is the target/goal endNode, then we've reached the end and can return the shortest path
            if (currentNode == endNode)
            {
                shortestPath.Add(currentNode);
                while (cameFrom.ContainsKey(currentNode))
                {
                    currentNode = cameFrom[currentNode];
                    shortestPath.Add(currentNode);                      // adds nodes from finish to start
                }
                return(shortestPath.AsEnumerable().Reverse().ToList()); // reverse nodes to order from start to finish
            }

            openNodes.Remove(currentNode);
            closedNodes.Add(currentNode);

            foreach (Edge edgeFromNode in edgesFromNode.GetEdges(currentNode, criteria))
            {
                Node otherNode = edgeFromNode.GetOtherNode(currentNode);

                if (closedNodes.Contains(otherNode))
                {
                    continue;                                  // ignore if already evaluated
                }
                float tentativeGScore = gScore[currentNode] + edgeFromNode.GetPathLength(true);

                if (!openNodes.Contains(otherNode)) // newly discovered node
                {
                    openNodes.Add(otherNode);
                }
                else if (tentativeGScore >= gScore[otherNode])
                {
                    continue; // This is not a better path
                }

                // Otherwise, this is the best path up til now
                cameFrom[otherNode] = currentNode;
                gScore[otherNode]   = tentativeGScore;
                fScore[otherNode]   = gScore[otherNode] + (endNode.GetXYZ() - otherNode.GetXYZ()).magnitude;
            }
        }

        // If endNode not reached, return empty list
        return(shortestPath);
    }