private ShortestPathNode? findShortestPath(Vector start, IReadOnlyList<IGoal> wayPoints, double stepSize) { var open = new BinaryHeapOpenSet<GridKey, GridSearchNode>(); var closed = new ClosedSet<GridKey>(); open.Add( new GridSearchNode( key: new GridKey(start, wayPoints.Count), start, previous: null, distanceFromStart: 0.0, estimatedCost: 0.0, wayPoints, targetWayPoint: 0)); while (!open.IsEmpty) { var nodeToExpand = open.DequeueMostPromissing(); if (nodeToExpand.RemainingWayPoints.Count == 0) { var head = new ShortestPathNode( wayPoints.Last().Position, // use the goal position directly targetWayPoint: wayPoints.Count - 1); // the goal way point should be kept here var backtrackingNode = nodeToExpand.Previous; while (backtrackingNode != null) { var node = new ShortestPathNode(backtrackingNode.Position, backtrackingNode.TargetWayPoint); node.CostToNext = TimeSpan.FromSeconds(Distance.Between(node.Position, head.Position) / maxSpeed); node.Next = head; head = node; backtrackingNode = backtrackingNode.Previous; } return head; } closed.Add(nodeToExpand.Key); for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; var nextPoint = new Vector( nodeToExpand.Position.X + dx * stepSize, nodeToExpand.Position.Y + dy * stepSize); var reachedWayPoint = nodeToExpand.RemainingWayPoints[0].ReachedGoal(nextPoint); var remainingWayPoints = reachedWayPoint ? nodeToExpand.RemainingWayPoints.Skip(1).ToList().AsReadOnly() : nodeToExpand.RemainingWayPoints; var targetWayPoint = wayPoints.Count - nodeToExpand.RemainingWayPoints.Count; // I want to keep the ID of the waypoint in the node which reaches the waypoint and only increase it for its childer var key = new GridKey(nextPoint, remainingWayPoints.Count); if (closed.Contains(key)) { continue; } if (collisionDetector.IsCollision(nextPoint)) { closed.Add(key); continue; } var distance = nodeToExpand.DistanceFromStart + (nextPoint - nodeToExpand.Position).CalculateLength(); var node = new GridSearchNode(key, nextPoint, nodeToExpand, distance, distance + 0, remainingWayPoints, targetWayPoint); if (open.Contains(node.Key)) { if (node.DistanceFromStart < open.Get(node.Key).DistanceFromStart) { open.ReplaceExistingWithTheSameKey(node); } } else { open.Add(node); } } } } return null; }
public IPlan?FindOptimalPlanFor(VehicleState initialState) { var heuristic = createShortestPathHeuristic(initialState); var open = new BinaryHeapOpenSet <DiscreteState, SearchNode>(); var closed = new ClosedSet <DiscreteState>(); open.Add( new SearchNode( discreteState: discretizer.Discretize(initialState, wayPoints.Count), state: initialState, actionFromPreviousState: null, previousState: null, costToCome: 0, estimatedTotalCost: 0, // we don't need estimate for the initial node targetWayPoint: 0)); while (!open.IsEmpty) { var node = open.DequeueMostPromissing(); if (node.TargetWayPoint == wayPoints.Count) { return(node.ReconstructPlan()); } closed.Add(node.Key); exploredStates.OnNext(node.State); foreach (var action in actions.AllPossibleActions) { var predictedStates = motionModel.CalculateNextState(node.State, action, timeStep); var elapsedTime = predictedStates.Last().relativeTime; var nextVehicleState = predictedStates.Last().state; var reachedWayPoint = false; var collided = false; foreach (var(simulationTime, state) in predictedStates) { if (collisionDetector.IsCollision(state)) { elapsedTime = simulationTime; nextVehicleState = state; reachedWayPoint = false; collided = true; break; } if (wayPoints[node.TargetWayPoint].ReachedGoal(state.Position)) { reachedWayPoint = true; } } var nextTargetWayPoint = reachedWayPoint ? node.TargetWayPoint + 1 : node.TargetWayPoint; var nextDiscreteState = discretizer.Discretize(nextVehicleState, nextTargetWayPoint); if (closed.Contains(nextDiscreteState)) { continue; } if (collided) { closed.Add(nextDiscreteState); continue; } var costToCome = node.CostToCome + timeStep.TotalSeconds; var reachedLastWayPoint = nextTargetWayPoint != wayPoints.Count; var costToGo = reachedLastWayPoint ? heuristic.EstimateTimeToGoal(nextVehicleState, nextTargetWayPoint).TotalSeconds : 0; var discoveredNode = new SearchNode( discreteState: nextDiscreteState, state: nextVehicleState, actionFromPreviousState: action, previousState: node, costToCome: costToCome, estimatedTotalCost: costToCome + costToGo, nextTargetWayPoint); if (greedy && reachedLastWayPoint) { return(discoveredNode.ReconstructPlan()); } if (!open.Contains(discoveredNode.Key)) { open.Add(discoveredNode); } else if (discoveredNode.CostToCome < open.Get(discoveredNode.Key).CostToCome) { open.ReplaceExistingWithTheSameKey(discoveredNode); } } } return(null); }