|
|
@ -13,7 +13,7 @@ public class AStarPathPlanner { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 路径规划状态
|
|
|
// 路径规划状态
|
|
|
public List<Node> findPath(String startId, float startDirectionAngle, String endId, float endDirectionAngle) { |
|
|
public List<Node> findPath(String startId, LCCDirection startDirectionAngle, String endId, LCCDirection endDirectionAngle) { |
|
|
Node start = graph.getNode(startId); |
|
|
Node start = graph.getNode(startId); |
|
|
Node goal = graph.getNode(endId); |
|
|
Node goal = graph.getNode(endId); |
|
|
if (start == null || goal == null) return Collections.emptyList(); |
|
|
if (start == null || goal == null) return Collections.emptyList(); |
|
|
@ -39,12 +39,14 @@ public class AStarPathPlanner { |
|
|
// 处理邻居移动
|
|
|
// 处理邻居移动
|
|
|
for (Node neighbor : graph.getNeighbors(current.node())) { |
|
|
for (Node neighbor : graph.getNeighbors(current.node())) { |
|
|
// 计算可能的两种方向(前进/后退)
|
|
|
// 计算可能的两种方向(前进/后退)
|
|
|
float[] possibleHeadings = { |
|
|
LCCDirection[] possibleHeadings; |
|
|
current.directionAngle(), // 前进方向不变
|
|
|
if (current.directionAngle() == LCCDirection.UP || current.directionAngle() == LCCDirection.DOWN) { |
|
|
(current.directionAngle() + 180) % 360 // 后退方向反转
|
|
|
possibleHeadings = new LCCDirection[]{LCCDirection.UP, LCCDirection.DOWN}; |
|
|
}; |
|
|
} else { |
|
|
|
|
|
possibleHeadings = new LCCDirection[]{LCCDirection.LEFT, LCCDirection.RIGHT}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (float nextHeading : possibleHeadings) { |
|
|
for (LCCDirection nextHeading : possibleHeadings) { |
|
|
float moveCost = graph.distance(current.node(), neighbor); |
|
|
float moveCost = graph.distance(current.node(), neighbor); |
|
|
considerState(current, neighbor, nextHeading, moveCost, open, visited, goal); |
|
|
considerState(current, neighbor, nextHeading, moveCost, open, visited, goal); |
|
|
} |
|
|
} |
|
|
@ -52,24 +54,35 @@ public class AStarPathPlanner { |
|
|
|
|
|
|
|
|
// 处理旋转(仅在可旋转节点)
|
|
|
// 处理旋转(仅在可旋转节点)
|
|
|
if (current.node().rotatable()) { |
|
|
if (current.node().rotatable()) { |
|
|
for (float rotation : new float[]{0, 90, 180, 270}) { |
|
|
for (LCCDirection rotation : new LCCDirection[]{LCCDirection.UP, LCCDirection.DOWN, LCCDirection.LEFT, LCCDirection.RIGHT}) { |
|
|
if (rotation == current.directionAngle()) continue; |
|
|
if (rotation == current.directionAngle()) continue; |
|
|
|
|
|
|
|
|
float angleDiff = Math.min( |
|
|
// 计算旋转代价
|
|
|
Math.abs(rotation - current.directionAngle()), |
|
|
int angleDiff = 0; |
|
|
360 - Math.abs(rotation - current.directionAngle()) |
|
|
if (current.directionAngle() == LCCDirection.UP && rotation == LCCDirection.RIGHT) { |
|
|
); |
|
|
angleDiff = 90; |
|
|
|
|
|
} else if (current.directionAngle() == LCCDirection.RIGHT && rotation == LCCDirection.DOWN) { |
|
|
|
|
|
angleDiff = 90; |
|
|
|
|
|
} else if (current.directionAngle() == LCCDirection.DOWN && rotation == LCCDirection.LEFT) { |
|
|
|
|
|
angleDiff = 90; |
|
|
|
|
|
} else if (current.directionAngle() == LCCDirection.LEFT && rotation == LCCDirection.UP) { |
|
|
|
|
|
angleDiff = 90; |
|
|
|
|
|
} else if (current.directionAngle() == rotation) { |
|
|
|
|
|
// 无需旋转
|
|
|
|
|
|
continue; |
|
|
|
|
|
} else { |
|
|
|
|
|
angleDiff = 180; // 反向旋转
|
|
|
|
|
|
} |
|
|
float rotationCost = angleDiff * ROTATION_COST_PER_DEGREE; |
|
|
float rotationCost = angleDiff * ROTATION_COST_PER_DEGREE; |
|
|
|
|
|
|
|
|
considerState(current, current.node(), rotation, |
|
|
considerState(current, current.node(), rotation, rotationCost, open, visited, goal); |
|
|
rotationCost, open, visited, goal); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return Collections.emptyList(); |
|
|
return Collections.emptyList(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void considerState(State current, Node nextNode, float nextHeading, |
|
|
private void considerState(State current, Node nextNode, LCCDirection nextHeading, |
|
|
float cost, PriorityQueue<State> open, |
|
|
float cost, PriorityQueue<State> open, |
|
|
Map<String, State> visited, Node goal) { |
|
|
Map<String, State> visited, Node goal) { |
|
|
String key = stateKey(nextNode.id(), nextHeading); |
|
|
String key = stateKey(nextNode.id(), nextHeading); |
|
|
@ -96,7 +109,7 @@ public class AStarPathPlanner { |
|
|
return graph.distance(a, b); |
|
|
return graph.distance(a, b); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private String stateKey(String nodeId, float directionAngle) { |
|
|
private String stateKey(String nodeId, LCCDirection directionAngle) { |
|
|
return nodeId + "|" + directionAngle; |
|
|
return nodeId + "|" + directionAngle; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|