zhang
2025-05-20 1313906bb1eb983d3beece810035e7fc28d6a92f
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/astart/AStarNavigateService.java
@@ -1,19 +1,16 @@
package com.zy.acs.manager.core.service.astart;
import com.zy.acs.common.constant.RedisConstant;
import com.zy.acs.common.utils.RedisSupport;
import com.zy.acs.framework.common.Cools;
import com.zy.acs.manager.common.utils.MapDataUtils;
import com.zy.acs.manager.core.domain.Lane;
import com.zy.acs.manager.core.service.LaneService;
import com.zy.acs.manager.core.service.astart.domain.AStarNavigateNode;
import com.zy.acs.manager.core.service.astart.domain.DynamicNode;
import com.zy.acs.manager.core.utils.RouteGenerator;
import com.zy.acs.manager.manager.entity.Route;
import com.zy.acs.manager.manager.entity.Segment;
import com.zy.acs.manager.manager.service.CodeService;
import com.zy.acs.manager.manager.service.JamService;
import com.zy.acs.manager.manager.service.RouteService;
import com.zy.acs.manager.system.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -22,6 +19,7 @@
/**
 * Created by vincent on 6/12/2024
 */
@Slf4j
@Service
public class AStarNavigateService {
@@ -31,10 +29,9 @@
    public static final int WEIGHT_CALC_FACTOR = 1;
    @Autowired
    private CodeService codeService;
    @Autowired
    private RouteService routeService;
    // right left up down
    private final static int[][] DIRECTIONS = {{0,1},{0,-1},{-1,0},{1,0}};
    @Autowired
    private MapDataDispatcher mapDataDispatcher;
    @Autowired
@@ -44,29 +41,50 @@
    @Autowired
    private ConfigService configService;
    public synchronized NavigateNode execute(String agvNo, NavigateNode start, NavigateNode end
    public synchronized AStarNavigateNode execute(String agvNo, AStarNavigateNode start, AStarNavigateNode end
            , Boolean lock, List<String> blackList, Segment segment) {
        if (start.getX() == end.getX() && start.getY() == end.getY()) {
            return end;
        }
        Integer maxAgvCountInLane = configService.getVal("maxAgvCountInLane", Integer.class);
        PriorityQueue<NavigateNode> openQueue = new PriorityQueue<>();
        Set<NavigateNode> existNodes = new HashSet<>();
        PriorityQueue<AStarNavigateNode> openQueue = new PriorityQueue<>();
        Set<AStarNavigateNode> existNodes = new HashSet<>();
        Map<String, Integer> bestGMap = new HashMap<>();
        start.setG(0);
        start.setH(calcNodeCost(start, end));
        start.setF(start.getG() + start.getH());
        String startKey = start.getX() + "_" + start.getY();
        bestGMap.put(startKey, start.getG());
        openQueue.add(start);
        existNodes.add(start);
        int[][] mapMatrix = mapDataDispatcher.getMapMatrix(null, null);
        String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null);
        DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(null);
        String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(null);
        long getNeighborNodesTime = 0;
        int getNeighborNodesCount = 0;
        while (!openQueue.isEmpty()) {
            // 取优先队列顶部元素并且把这个元素从Open表中删除,取F值最小的节点
            NavigateNode currentNode = openQueue.poll();
            AStarNavigateNode currentNode = openQueue.poll();
            ArrayList<NavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes);
            for (NavigateNode node : neighbourNodes) {
            // 终点
            if (currentNode.getX() == end.getX() && currentNode.getY() == end.getY()) {
//                System.out.println("getNeighborNodes spend time: " + getNeighborNodesTime +", count: " + getNeighborNodesCount);
                return currentNode;
            }
            long currentTime = System.currentTimeMillis();
            List<AStarNavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes);
            getNeighborNodesTime += System.currentTimeMillis() - currentTime;
            getNeighborNodesCount ++;
            for (AStarNavigateNode node : neighbourNodes) {
                node.setCodeData(codeMatrix[node.getX()][node.getY()]);
                boolean isEndNode = node.getX() == end.getX() && node.getY() == end.getY();
                int weight = 0;
@@ -89,6 +107,9 @@
                assert !vehicle.equals(DynamicNodeType.BLOCK.val);
                if (!vehicle.equals(DynamicNodeType.ACCESS.val)) {
                    if (!vehicle.equals(agvNo)) {
                        if (lock) {
                            continue;
                        }
                        // 如果存在车辆,则增加权重 2 或者 3,因为拐点会增加权重 1
                        // vehicle已经为当前segment做过了避让,且避让任务已完成,则权重值增加
@@ -99,10 +120,6 @@
                                weight += (WEIGHT_CALC_FACTOR * 2);
                            }
                        }
                        if (lock) {
                            continue;
                        }
                    }
                }
@@ -112,7 +129,6 @@
                if (!waveNode.equals(WaveNodeType.ENABLE.val)) {
                    List<String> waveNodeList = MapDataUtils.parseWaveNode(waveNode);
                    List<String> otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo);
                    if (!Cools.isEmpty(otherWaveList)) {
                        if (lock) {
@@ -122,100 +138,102 @@
                }
                // 单巷道车辆容载数量
                Lane lane = laneService.search(node.getCodeData());
                if (null != lane) {
                List<int[]> laneCodeIdxList = laneService.getLaneCodeIdxList(node.getCodeData());
                if (!Cools.isEmpty(laneCodeIdxList)) {
                    Set<String> lanVehicleSet = new HashSet<>();
                    List<String> laneCodes = lane.getCodes();
                    for (String laneCodeData : laneCodes) {
                        int[] laneCodeMatrixIdx = mapDataDispatcher.getCodeMatrixIdx(null, laneCodeData);
                        // scan dynamicMatrix or WaveMatrix
                        DynamicNode laneDynamicNode = dynamicMatrix[laneCodeMatrixIdx[0]][laneCodeMatrixIdx[1]];
                    for (int[] codeMatrixIdx : laneCodeIdxList) {
                        DynamicNode laneDynamicNode = dynamicMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]];
                        String laneVehicle = laneDynamicNode.getVehicle();
                        assert !laneVehicle.equals(DynamicNodeType.BLOCK.val);
                        if (!laneVehicle.equals(DynamicNodeType.ACCESS.val)) {
                            if (!laneVehicle.equals(agvNo)) {
                                lanVehicleSet.add(laneVehicle);
//                                redis.setObject(RedisConstant.AGV_TO_STANDBY_FLAG, laneVehicle, true, 30);
                            }
                        }
                    }
                    if (lanVehicleSet.size() + 1 > maxAgvCountInLane) {
                        continue;
                    }
                }
                //找到目标结点就返回
                if (isEndNode) {
                    //并且计算出G, F, H等值
                    node.initNode(currentNode, end);
                    return node;
                }
                // G + H + T (对启发函数增加去拐点方案calcNodeTurnCost)
                int gCost = calcNodeCost(currentNode, node);
                if (OPEN_TURN_COST_WEIGHT) {
                    gCost += calcNodeTurnCost(currentNode, node, end);
                    if (this.isTurning(currentNode, node)) {
                        weight += WEIGHT_CALC_FACTOR;
                        node.setTurnCount(currentNode.getTurnCount() + 1);
                    } else {
                        // 方向没变
                        node.setTurnCount(currentNode.getTurnCount());
                    }
                }
                //进行计算对 G, F, H 等值
                node.setWeight(weight);
                node.setLastDistance(gCost);
                node.setLastDistance(calcNodeCost(currentNode, node));
                node.initNode(currentNode, end);
                node.setH(calcNodeCost(node, end));
                node.setF(node.getG() + node.getH());
                openQueue.add(node);
                existNodes.add(node);
                String key = node.getX() + "_" + node.getY();
                Integer recordedG = bestGMap.get(key);
                if (recordedG == null || node.getG() <= recordedG) {
                    bestGMap.put(key, node.getG());
                    openQueue.add(node);
                }
//                openQueue.add(node);
//                existNodes.add(node);
            }
        }
        //如果遍历完所有出现的结点都没有找到最终的结点,返回null
//        System.out.println("getNeighborNodes spend time: " + getNeighborNodesTime +", count: " + getNeighborNodesCount);
        return null;
    }
    // 获取四周节点
    private ArrayList<NavigateNode> getNeighborNodes(NavigateNode currentNode, int[][] mapMatrix, Set<NavigateNode> existNodes) {
        //获取当前结点的x, y
    private List<AStarNavigateNode> getNeighborNodes(AStarNavigateNode currentNode, int[][] mapMatrix, Set<AStarNavigateNode> existNodes) {
        int x = currentNode.getX();
        int y = currentNode.getY();
        //如果当前结点的邻结点合法,就加入到neighbour_node
        ArrayList<NavigateNode> neighbourNodes = new ArrayList<>();
        AStarNavigateNode parent = currentNode.getParent();
        NavigateNode rightNode = extendNeighborNodes(currentNode, new NavigateNode(x, y + 1), mapMatrix, existNodes, null, null);
        if (is_valid(currentNode, rightNode)) {
            neighbourNodes.add(rightNode);
//        List<AStarNavigateNode> neighbourNodes = new CopyOnWriteArrayList<>();
        List<AStarNavigateNode> neighbourNodes = new ArrayList<>();
        List<AStarNavigateNode> possibleNodes = new ArrayList<>();
        for (int[] d: DIRECTIONS) {
            int nx = x + d[0];
            int ny = y + d[1];
            // 如果父节点不为空,并且 (nx,ny) 等于父节点坐标,则跳过
            if (parent != null && nx == parent.getX() && ny == parent.getY()) {
                continue;
            }
            possibleNodes.add(new AStarNavigateNode(nx, ny));
        }
        NavigateNode leftNode = extendNeighborNodes(currentNode, new NavigateNode(x, y - 1), mapMatrix, existNodes, null, null);
        if (is_valid(currentNode, leftNode)) {
            neighbourNodes.add(leftNode);
        }
//        possibleNodes.parallelStream()
//                .map(extendNode -> extendNeighborNodes(currentNode, extendNode, mapMatrix, existNodes, null, null))
//                .filter(Objects::nonNull)
//                .forEach(neighbourNodes::add);
        NavigateNode topNode = extendNeighborNodes(currentNode, new NavigateNode(x - 1, y), mapMatrix, existNodes, null, null);
        if (is_valid(currentNode, topNode)) {
            neighbourNodes.add(topNode);
        }
        NavigateNode bottomNode = extendNeighborNodes(currentNode, new NavigateNode(x + 1, y), mapMatrix, existNodes, null, null);
        if (is_valid(currentNode, bottomNode)) {
            neighbourNodes.add(bottomNode);
        for (AStarNavigateNode pn : possibleNodes) {
            AStarNavigateNode next = extendNeighborNodes(currentNode, pn, mapMatrix, existNodes, null, null);
            if (next != null) {
                neighbourNodes.add(next);
            }
        }
        return neighbourNodes;
    }
    private NavigateNode extendNeighborNodes(NavigateNode currentNode, NavigateNode extendNode, int[][] mapMatrix, Set<NavigateNode> existNodes, Integer dx, Integer dy) {
        NavigateNode nextNode = null;
    private AStarNavigateNode extendNeighborNodes(AStarNavigateNode currentNode, AStarNavigateNode extendNode, int[][] mapMatrix, Set<AStarNavigateNode> existNodes, Integer dx, Integer dy) {
        AStarNavigateNode nextNode;
        if (null == dx || null == dy) {
            dx = extendNode.getX() - currentNode.getX();
            dy = extendNode.getY() - currentNode.getY();
            nextNode = extendNode;
        } else {
            nextNode = new NavigateNode(extendNode.getX() + dx, extendNode.getY() + dy);
            nextNode = new AStarNavigateNode(extendNode.getX() + dx, extendNode.getY() + dy);
        }
        int x = nextNode.getX();
@@ -229,84 +247,61 @@
        if (mapMatrix[x][y] == MapNodeType.DISABLE.val)  {
            return extendNeighborNodes(currentNode, nextNode, mapMatrix, existNodes, dx, dy);
        } else {
            if (existNodes.contains(nextNode)) {
                return null;
            }
            // 节点是否可用
            if (mapMatrix[x][y] != MapNodeType.ENABLE.val) {
                return null;
            }
            String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null);
            String currentNodeCodeData = codeMatrix[currentNode.getX()][currentNode.getY()];
            String nextNodeCodeData = codeMatrix[nextNode.getX()][nextNode.getY()];
            nextNode.setCodeData(nextNodeCodeData);
            // 判断通过性
            String routeKey = RouteGenerator.generateRouteKey(currentNodeCodeData, nextNodeCodeData);
            Object routeVal = redis.getMap(RedisConstant.AGV_MAP_ROUTE_HASH_FLAG, routeKey);
            if (routeVal == null || !(Boolean) routeVal) {
                return null;
            }
            return nextNode;
        }
    }
    private boolean is_valid(NavigateNode currentNode, NavigateNode node) {
        if (null == node) {
            return false;
        }
        return true;
    }
        assert mapMatrix[x][y] == MapNodeType.ENABLE.val;
    private boolean isExist(NavigateNode node, List<NavigateNode> existNodes) {
        for (NavigateNode existNode : existNodes) {
            if (this.isSame(node, existNode)) {
                return true;
            }
        }
        return false;
    }
//        if (existNodes.contains(nextNode)) {
//            return null;
//        }
    private boolean isSame(NavigateNode o1, NavigateNode o2) {
        if (Cools.isEmpty(o1, o2)) {
            return false;
        // 判断通过性
        String routeCdaKey = RouteGenerator.generateRouteCdaKey(new int[]{currentNode.getX(), currentNode.getY()}, new int[]{nextNode.getX(), nextNode.getY()});
        if (!mapDataDispatcher.validRouteCdaKey(routeCdaKey)) {
            return null;
        }
        return o1.getX() == o2.getX() && o1.getY() == o2.getY();
        return nextNode;
    }
    //------------------A*启发函数------------------//
    //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加)
    private int calcNodeCost(NavigateNode node1, NavigateNode node2) {
//        Code code1 = codeService.selectByData(node1.getCodeData());
//        Code code2 = codeService.selectByData(node2.getCodeData());
//        return (int) (Math.abs(code2.getX() - code1.getX()) + Math.abs(code2.getY() - code1.getY()));
    private int calcNodeCost(AStarNavigateNode node1, AStarNavigateNode node2) {
        return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY());
    }
    //去除拐点算法,给直线增加优先级
    private int calcNodeTurnCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) {
        // 第一个点或直线点
        if (currNode.getParent() == null
                || nextNode.getX() == currNode.getParent().getX()
                || nextNode.getY() == currNode.getParent().getY()
        ) {
            return 0;
    // 转弯判断:只允许“垂直或水平”运动
    private boolean isTurning(AStarNavigateNode currNode, AStarNavigateNode nextNode) {
        // 第一个点
        if (currNode.getParent() == null) {
            return false;
        }
        // 拐向终点的点
        if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) {
            return 1;
        }
        // 普通拐点
        return 1;
        AStarNavigateNode parent = currNode.getParent();
        // 如果下一点(nextNode)与 parent 在同一行或同一列 => 没有转弯
        // 注意,这实际上等同于“(curr->next) 的方向 == (parent->curr) 的方向”。
        boolean sameRowOrCol =
                (nextNode.getX() == parent.getX())
                        || (nextNode.getY() == parent.getY());
        return !sameRowOrCol;
    }
    // 转弯判断:如果这两个向量相同(例如都等于 (0,1)),说明方向相同;否则说明转弯。
//    private boolean isTurning(AStarNavigateNode currNode, AStarNavigateNode nextNode) {
//        // 如果 currNode 没有父节点,说明是起点,不算转弯
//        if (currNode.getParent() == null) {
//            return false;
//        }
//        // 取出坐标
//        AStarNavigateNode parent = currNode.getParent();
//        int px = currNode.getX() - parent.getX();  // parent -> curr 的x偏移
//        int py = currNode.getY() - parent.getY();  // parent -> curr 的y偏移
//
//        int nx = nextNode.getX() - currNode.getX(); // curr -> next 的x偏移
//        int ny = nextNode.getY() - currNode.getY(); // curr -> next 的y偏移
//
//        // 如果 (px, py) 与 (nx, ny) 不一样,就说明转弯
//        return (px != nx) || (py != ny);
//    }
}