我在地球地图上有325个节点的列表。 这些节点通过航运路线绘制出地球。
我的任务是创建一种方法,只需使用节点路径即可找到从一个节点到另一个节点的最短路径。它需要实时和快速,因为可能有数百艘船。
我已经研究过A *和Dijkstras解决方案,但他们没有很好地处理角落?
我正在考虑使用角度和距离,但我不确定如何实现它。
地图上的每个节点都是objectMap中的以下对象。 Int是节点号。
节点和计算是在app的加载过程中完成的。所以我们拥有所有这些。
下面的类包含在objectMap中,效果很好。
public static class Node
{
private int nodeNumber;
private Vector2 pos;
private int connectedNodes[];
private ObjectMap<Integer, Node> masterList;
private ObjectMap<Integer, Float> connectedNodeDistances;
private ObjectMap<Integer, Float> connectedNodeDegrees;
public Node(int nodeNumber, float x, float y, int connectedNodes[], ObjectMap<Integer, Node> masterList)
{
this.nodeNumber = nodeNumber;
float areaX = x / MapCreator.WORLD_SCALE;
float areaY = y / MapCreator.WORLD_SCALE;
this.pos = new Vector2(areaX / MapCreator.CURRENT_DOWN_SIZE_X, (PolyUtils.getInstance().getScreenPercentageY(1f) - (areaY / MapCreator.CURRENT_DOWN_SIZE_X)) - MapCreator.TOP_EXTRA);
this.connectedNodes = connectedNodes;
this.masterList = masterList;
this.connectedNodeDistances = new ObjectMap<Integer, Float>();
this.connectedNodeDegrees = new ObjectMap<Integer, Float>();
}
public void calculateDistances()
{
for(int eachConnectedNode : connectedNodes)
{
float angleDegree = new Vector2(this.pos).sub(masterList.get(eachConnectedNode).getPos()).angle();
connectedNodeDistances.put(eachConnectedNode, this.pos.dst(masterList.get(eachConnectedNode).getPos()));
connectedNodeDegrees.put(eachConnectedNode, angleDegree);
}
}
public int getNodeNumber() {
return nodeNumber;
}
public float getDistanceFromNode(int number)
{
return connectedNodeDistances.get(number);
}
public Vector2 getPos() {
return pos;
}
public int[] getConnectedNodes() {
return connectedNodes;
}
}
我被困的地方是:
public Array<Node> getFastestRoute(Vector2 startPos, Vector2 endPos, int numberOfAttempts)
{
Array<Array<Node>> potentialRoutes = new Array<Array<Node>>();
int sizeOfShortestRouteNodes = 999999;
for(int index = 0; index < numberOfAttempts; index++)
{
Array<Node> newRoute = getListOfNodes(startPos, endPos, MathUtils.random(-0.75f, 0.75f));
if(newRoute != null)
{
if(newRoute.size < sizeOfShortestRouteNodes)
{
potentialRoutes.clear();
potentialRoutes.add(newRoute);
sizeOfShortestRouteNodes = potentialRoutes.size;
}
else if(newRoute.size == sizeOfShortestRouteNodes)
{
potentialRoutes.add(newRoute);
}
}
}
return getShortestRouteDistance(potentialRoutes);
}
private Array<Node> getListOfNodes(Vector2 startPos, Vector2 endPos, float randomizationSeed)
{
//TODO Draw as lines as test.
Array<Node> nodeList = new Array<Node>();
Array<Node> deadNodes = new Array<Node>();
int iterations = 0;
final int maxIterations = 100; //Needs to be low so that boat trip isn't too long also helps performance.
nodeList.add(getNearestNode(startPos));
Node lastNode = getNearestNode(endPos);
Node currentNode = nodeList.first();
while(true)
{
float currentNodeToEndAngle = new Vector2(new Vector2(currentNode.getPos())).sub(endPos).angle();
//Find closest direction
Node closestNodeInDirection = null;
float closestDirection = 361;
for(int eachConnectedNode : currentNode.getConnectedNodes())
{
Node potentialNode = boatNodes.get((eachConnectedNode));
if(!deadNodes.contains(potentialNode, true))
{
float angleToEndNodeFromCurrent = (new Vector2(currentNode.getPos()).sub(potentialNode.getPos()).angle());
//Randomize the direction from the seed.
angleToEndNodeFromCurrent = angleToEndNodeFromCurrent * randomizationSeed;
float differenceInDegrees = Math.abs(angleToEndNodeFromCurrent - currentNodeToEndAngle);
if(differenceInDegrees < closestDirection)
{
closestDirection = differenceInDegrees;
closestNodeInDirection = potentialNode;
}
}
}
//No new nodes.
if(closestNodeInDirection == null)
{
//Go back and try another route.
if(nodeList.size > 1)
{
nodeList.pop();
currentNode = nodeList.peek();
}
}
//Adding nodes.
if(closestNodeInDirection != null && lastNode != closestNodeInDirection)
{
nodeList.add(closestNodeInDirection);
deadNodes.add(closestNodeInDirection);
currentNode = closestNodeInDirection;
}
else if(closestNodeInDirection != null)
{
//Last node reached.
nodeList.add(lastNode);
return nodeList;
}
//Iterations too many.
iterations++;
if(iterations >= maxIterations){
return null;
}
}
}
public Array<Node> getShortestRouteDistance(Array<Array<Node>> allNodeRoutes)
{
Array<Node> shortestRoute = null;
float shortestRouteLength = 99999f;
for(int arraysIndex = 0; arraysIndex < allNodeRoutes.size; arraysIndex++)
{
Array<Node> nodeArray = allNodeRoutes.get(arraysIndex);
float lengthOfThisRoute = 0f;
for(int nodesIndex = 0; nodesIndex < nodeArray.size; nodesIndex++)
{
Node nextNode = null;
Node thisNode = nodeArray.get(nodesIndex);
if(nodesIndex + 1 < nodeArray.size)
{
nextNode = nodeArray.get(nodesIndex + 1);
}
if(nextNode != null)
{
lengthOfThisRoute += thisNode.getDistanceFromNode(nextNode.getNodeNumber());
}
}
if(lengthOfThisRoute < shortestRouteLength)
{
shortestRouteLength = lengthOfThisRoute;
shortestRoute = nodeArray;
}
}
return shortestRoute;
}
答案 0 :(得分:0)
你所描述的是A *和Dijkstras的众所周知的问题---解决方案是不使用它们中的任何一个。
你需要的是一个“任意角度”的算法 - 所以你应该使用一种叫做Theta *的算法。这种方法适当地切割角落附近,同时避开障碍物。
事实上,它与您已经提出的方法非常相似!我建议在这里阅读优秀的文章,这是一个非常好的解释:做什么: Theta*: Any-Angle Path Planning for Smoother Trajectories in Continuous Environments