通过向量列表查找路径

时间:2015-07-07 18:44:16

标签: java path geometry nodes path-finding

我在地球地图上有325个节点的列表。 这些节点通过航运路线绘制出地球。

我的任务是创建一种方法,只需使用节点路径即可找到从一个节点到另一个节点的最短路径。它需要实时和快速,因为可能有数百艘船。

我已经研究过A *和Dijkstras解决方案,但他们没有很好地处理角落?

我正在考虑使用角度和距离,但我不确定如何实现它。

Map of nodes on earth example - real image has more detail

地图上的每个节点都是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;
}

1 个答案:

答案 0 :(得分:0)

你所描述的是A *和Dijkstras的众所周知的问题---解决方案是不使用它们中的任何一个。

你需要的是一个“任意角度”的算法 - 所以你应该使用一种叫做Theta *的算法。这种方法适当地切割角落附近,同时避开障碍物。

事实上,它与您已经提出的方法非常相似!我建议在这里阅读优秀的文章,这是一个非常好的解释:做什么: Theta*: Any-Angle Path Planning for Smoother Trajectories in Continuous Environments