private MyPath <V> ReturnPath(MyPathfindingData vertexData, MyPathfindingData successor, int remainingVertices) { if (vertexData.Predecessor == null) { MyPath <V> retval = new MyPath <V>(remainingVertices + 1); retval.Add(vertexData.Parent as V, successor != null ? (successor.Parent as V) : null); return(retval); } else { MyPath <V> retval = ReturnPath(vertexData.Predecessor, vertexData, remainingVertices + 1); retval.Add(vertexData.Parent as V, successor != null ? (successor.Parent as V) : null); return(retval); } }
private bool Visited(MyPathfindingData vertexData) { return(vertexData.Timestamp == m_timestamp); }
private void Visit(MyPathfindingData vertexData) { vertexData.Timestamp = m_timestamp; }
// Note: Termination criterion tells the pathfinding system, how much we want to terminate the pathfinding in the given vertex. // // Values can range from 0.0 to positive infinity. Infinity means that the vertex will never be returned as a result. Zero, on the // other hand, is equivalent to classical pathfinding, which means that the pathfinding will terminate when a path has been found // to a vertex with a criterion value of zero and that path's length could not be improved by looking further. // // Non-zero values on vertices tell the pathfinding that these vertices are acceptable as final vertices, but only if no better // vertex is found (i.e. one that would have lower length + heuristic value). // // The termination criterion is not used as weighting for the pathfinding priority queue though, which means that you can separate // termination in a vertex from the searching heuristic public MyPath <V> FindPath(V start, Func <V, float> heuristic, Func <V, float> terminationCriterion, Predicate <V> vertexTraversable = null, bool returnClosest = true) { Debug.Assert(heuristic != null); Debug.Assert(terminationCriterion != null); CalculateNextTimestamp(); MyPathfindingData startData = start.PathfindingData; Visit(startData); startData.Predecessor = null; startData.PathLength = 0.0f; IMyPathVertex <V> retVal = null; float lowestAcceptableWeight = float.PositiveInfinity; IMyPathVertex <V> closest = null; float closestWeight = float.PositiveInfinity; float terminationValue = terminationCriterion(start); if (terminationValue != float.PositiveInfinity) { retVal = start; lowestAcceptableWeight = heuristic(start) + terminationValue; } m_openVertices.Insert(start.PathfindingData, heuristic(start)); while (m_openVertices.Count > 0) { MyPathfindingData currentData = m_openVertices.RemoveMin(); V current = currentData.Parent as V; float currentPathLength = currentData.PathLength; if (retVal != null && currentPathLength + heuristic(current) >= lowestAcceptableWeight) { break; } for (int i = 0; i < current.GetNeighborCount(); ++i) { IMyPathEdge <V> edge = current.GetEdge(i); if (edge == null) { continue; } V neighbor = edge.GetOtherVertex(current); if (neighbor == null || (vertexTraversable != null && !vertexTraversable(neighbor))) { continue; } float newPathLength = currentData.PathLength + edge.GetWeight(); MyPathfindingData neighborData = neighbor.PathfindingData; float neighborWeight = newPathLength + heuristic(neighbor); if (neighborWeight < closestWeight) { closest = neighbor; closestWeight = neighborWeight; } terminationValue = terminationCriterion(neighbor); if (neighborWeight + terminationValue < lowestAcceptableWeight) { retVal = neighbor; lowestAcceptableWeight = neighborWeight + terminationValue; } if (Visited(neighborData)) { if (newPathLength < neighborData.PathLength) { neighborData.PathLength = newPathLength; neighborData.Predecessor = currentData; m_openVertices.ModifyUp(neighborData, neighborWeight); } } else { Visit(neighborData); neighborData.PathLength = newPathLength; neighborData.Predecessor = currentData; m_openVertices.Insert(neighborData, neighborWeight); } } } m_openVertices.Clear(); if (retVal == null) { if (returnClosest == false || closest == null) { return(null); } else { return(ReturnPath(closest.PathfindingData, null, 0)); } } else { return(ReturnPath(retVal.PathfindingData, null, 0)); } }
public MyPath <V> FindPath(V start, V end, Predicate <V> vertexTraversable = null, Predicate <IMyPathEdge <V> > edgeTraversable = null) { // CH: TODO: Make multiple private copies of this method and call the right one // according to what were the arguments to the public interface method CalculateNextTimestamp(); MyPathfindingData startData = start.PathfindingData; Visit(startData); startData.Predecessor = null; startData.PathLength = 0.0f; IMyPathVertex <V> retVal = null; float shortestPathLength = float.PositiveInfinity; m_openVertices.Insert(start.PathfindingData, start.EstimateDistanceTo(end)); while (m_openVertices.Count > 0) { MyPathfindingData currentData = m_openVertices.RemoveMin(); V current = currentData.Parent as V; float currentPathLength = currentData.PathLength; if (retVal != null && currentPathLength >= shortestPathLength) { break; } for (int i = 0; i < current.GetNeighborCount(); ++i) { /*IMyPathVertex<V> neighbor = current.GetNeighbor(i); * if (neighbor == null) continue;*/ IMyPathEdge <V> edge = current.GetEdge(i); if (edge == null || (edgeTraversable != null && !edgeTraversable(edge))) { continue; } V neighbor = edge.GetOtherVertex(current); if (neighbor == null || (vertexTraversable != null && !vertexTraversable(neighbor))) { continue; } float newPathLength = currentData.PathLength + edge.GetWeight(); MyPathfindingData neighborData = neighbor.PathfindingData; if (neighbor == end && newPathLength < shortestPathLength) { retVal = neighbor; shortestPathLength = newPathLength; } if (Visited(neighborData)) { if (newPathLength < neighborData.PathLength) { neighborData.PathLength = newPathLength; neighborData.Predecessor = currentData; m_openVertices.ModifyUp(neighborData, newPathLength + neighbor.EstimateDistanceTo(end)); } } else { Visit(neighborData); neighborData.PathLength = newPathLength; neighborData.Predecessor = currentData; m_openVertices.Insert(neighborData, newPathLength + neighbor.EstimateDistanceTo(end)); } } } m_openVertices.Clear(); if (retVal == null) { return(null); } else { return(ReturnPath(retVal.PathfindingData, null, 0)); } }