【发布时间】:2015-07-07 18:44:16
【问题描述】:
我在地球地图上有一个包含 325 个节点的列表。 这些节点用航运路线绘制出地球。
我的任务是创建一种方法,该方法仅使用节点路径就可以找到从一个节点到另一个节点的最短路径。它需要实时且快速,因为可能会有数百艘船。
我研究过 A* 和 Dijkstras 解决方案,但它们不能很好地处理角点?
我正在考虑使用角度和距离,但我不确定如何实现它。
地图上的每个节点都是objectMap中的以下对象。 Int 为节点号。
节点和计算是在加载应用程序时完成的。所以我们拥有所有这些。
下面的类包含在 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;
}
【问题讨论】:
-
您所描述的是旅行推销员问题 - 维基百科很好地讨论了为什么它很难以及一些快速“足够好”的答案可能是什么。
-
感谢您的提示,正在查找。
-
您正在寻找的“最短路线”是什么?通过所有个节点的最短路径?正如 Sbodd 指出的那样,这将是 TSP。从给定源节点到给定目标节点的最短路径?那将是直接测地线,除非有一些您没有提到的额外限制。正如您的函数签名所暗示的那样,两个给定位置之间的最短路线?那你为什么需要任何节点呢?
-
因为我要避开障碍物,是的,这将是直接测地线。仍然有麻烦。我创建了自己的算法,效果很好,但有时会倒退。
标签: java path geometry nodes path-finding