Exemple #1
0
        /// <summary>
        /// Finds the shortest or otherwise least costly path from the specified source face to
        /// the specified target face, using the A* algorithm and the supplied heuristic and cost
        /// delegates to measure costs between faces and over face edges.
        /// </summary>
        /// <param name="source">The source face from which the path should start.</param>
        /// <param name="target">The target face that the path should attempt to reach.</param>
        /// <param name="costHeuristic">Delegate for estimating the cost of the path from the specified source face to the specified target face.</param>
        /// <param name="cost">Delegate for determining the actual cost of the path along the specified face edge, from its near vertex to its far face.</param>
        /// <param name="path">An optional existing path created by an earlier call to one of the <seealso cref="O:MakeIt.Tile.PathFinder.FindPath"/> functions, which will be overwritten with the new path data.</param>
        /// <returns>A face edge path instance describing the path found from source to target, or an incomplete object if no path was found.</returns>
        /// <remarks><para>The optional <paramref name="path"/> parameter is useful for reducing allocation activity
        /// and pressure on the garbage collector.  Reusing an existing path object will not require an additional
        /// allocation to store the path as long as the new path fits inside the capacity already available in the
        /// existing path.</para></remarks>
        public IFaceEdgePath FindPath(Topology.Face source, Topology.Face target, FaceCostHeuristicDelegate costHeuristic, FaceCostDelegate cost, IFaceEdgePath path = null)
        {
            if (!source)
            {
                throw new ArgumentException("The source face must be a valid face.", "source");
            }
            if (!target)
            {
                throw new ArgumentException("The target face must be a valid face.", "target");
            }
            if (source.topology != target.topology)
            {
                throw new ArgumentException("The target face must belong to the same topology as the source face.", "target");
            }

            var concretePath = path as FaceEdgePath;

            if (concretePath == null)
            {
                if (path != null)
                {
                    throw new ArgumentException("The provided pre-allocated path was not an instance of the necessary underlying type recognized by this path finder.", "path");
                }
                concretePath = new FaceEdgePath();
            }

            var topology = source.topology;

            if (source == target)
            {
                return(concretePath.Rebuild(source, target));
            }

            if (_queue == null)
            {
                _queue     = new DelegateOrderedPriorityQueue <Node>(Node.AreOrdered, Mathf.CeilToInt(Mathf.Sqrt(source.topology.faces.Count)));
                _openSet   = new Dictionary <int, Node>();
                _closedSet = new Dictionary <int, Node>();
            }
            else
            {
                _queue.Clear();
                _openSet.Clear();
                _closedSet.Clear();
            }

            _queue.Push(new Node(0f, 0f, costHeuristic(source, target, 0), source.index, -1, -1, 0));
            _openSet.Add(source.index, _queue.front);

            while (_queue.Count > 0)
            {
                var node = _queue.front;
                _queue.Pop();

                if (node._elementIndex == target.index)
                {
                    return(concretePath.Rebuild(source, target, node, _closedSet));
                }

                _closedSet.Add(node._elementIndex, node);
                var face = new Topology.Face(topology, node._elementIndex);

                foreach (var edge in face.edges)
                {
                    if (_closedSet.ContainsKey(edge.face.index))
                    {
                        continue;
                    }

                    var g = node._g + cost(edge, node._length);

                    if (!float.IsPositiveInfinity(g))
                    {
                        Node neighborNode;
                        if (!_openSet.TryGetValue(edge.face.index, out neighborNode))
                        {
                            var h = costHeuristic(edge.face, target, node._length);
                            neighborNode = new Node(g + h, g, h, edge.face.index, edge.index, node._elementIndex, node._length + 1);
                            _queue.Push(neighborNode);
                            _openSet.Add(edge.face.index, neighborNode);
                        }
                        else if (g < neighborNode._g)
                        {
                            var h = costHeuristic(edge.face, target, node._length);
                            neighborNode = new Node(g + h, g, h, edge.face.index, edge.index, node._elementIndex, node._length + 1);
                            _openSet[edge.face.index] = neighborNode;
                            _queue.Reprioritize(neighborNode);
                        }
                    }
                }
            }

            return(concretePath.Rebuild(source, target));
        }
Exemple #2
0
 public FacePathAdapter(FaceEdgePath faceEdgePath)
 {
     _faceEdgePath = faceEdgePath;
 }