package com.zy.acs.manager.core.service.astart; 
 | 
  
 | 
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.DynamicNode; 
 | 
import com.zy.acs.manager.manager.entity.Route; 
 | 
import com.zy.acs.manager.manager.service.AgvService; 
 | 
import com.zy.acs.manager.manager.service.CodeService; 
 | 
import com.zy.acs.manager.manager.service.RouteService; 
 | 
import com.zy.acs.manager.system.service.ConfigService; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.stereotype.Service; 
 | 
  
 | 
import java.util.*; 
 | 
  
 | 
/** 
 | 
 * Created by vincent on 6/12/2024 
 | 
 */ 
 | 
@Service 
 | 
public class AStarNavigateService { 
 | 
  
 | 
    private final RedisSupport redis = RedisSupport.defaultRedisSupport; 
 | 
  
 | 
    public static final boolean OPEN_TURN_COST_WEIGHT = Boolean.FALSE; 
 | 
  
 | 
    @Autowired 
 | 
    private CodeService codeService; 
 | 
    @Autowired 
 | 
    private RouteService routeService; 
 | 
    @Autowired 
 | 
    private MapDataDispatcher mapDataDispatcher; 
 | 
    @Autowired 
 | 
    private AgvService agvService; 
 | 
    @Autowired 
 | 
    private LaneService laneService; 
 | 
    @Autowired 
 | 
    private ConfigService configService; 
 | 
  
 | 
    public synchronized NavigateNode execute(String agvNo, NavigateNode start, NavigateNode end 
 | 
            , Boolean lock, List<String> blackList) { 
 | 
        if (start.getX() == end.getX() && start.getY() == end.getY()) { 
 | 
            return end; 
 | 
        } 
 | 
        Integer maxAgvCountInLane = configService.getVal("maxAgvCountInLane", Integer.class); 
 | 
  
 | 
        PriorityQueue<NavigateNode> openQueue = new PriorityQueue<>(); 
 | 
        ArrayList<NavigateNode> existNodes = new ArrayList<>(); 
 | 
  
 | 
        openQueue.add(start); 
 | 
        existNodes.add(start); 
 | 
  
 | 
        int[][] mapMatrix = mapDataDispatcher.getMapMatrix(null, null); 
 | 
        DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(null); 
 | 
        String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(null); 
 | 
  
 | 
//        List<String> included = new ArrayList<>(); 
 | 
//        if (!Cools.isEmpty(whiteList)) { 
 | 
//            included.addAll(whiteList); 
 | 
//        } 
 | 
//        included.add(agvNo); 
 | 
//        List<VehicleDto> vehicleDtoList = agvService.getVehicleDtoList(included); 
 | 
  
 | 
        while (openQueue.size() > 0) { 
 | 
            // 取优先队列顶部元素并且把这个元素从Open表中删除,取F值最小的节点 
 | 
            NavigateNode currentNode = openQueue.poll(); 
 | 
            // 对当前结点进行扩展,得到一个四周结点的数组 
 | 
            ArrayList<NavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes); 
 | 
            // 对这个结点遍历,看是否有目标结点出现 
 | 
            label: for (NavigateNode node : neighbourNodes) { 
 | 
  
 | 
                // 节点存在其他车辆 
 | 
//                for (VehicleDto vehicleDto : vehicleDtoList) { 
 | 
//                    if (node.getCodeData().equals(vehicleDto.getPosCode())) { 
 | 
//                        if (!Cools.isEmpty(blackList) && blackList.contains(vehicleDto.getVehicle())) { 
 | 
//                            continue label; 
 | 
//                        } 
 | 
//                        if (lock) { 
 | 
//                            continue label; 
 | 
//                        } 
 | 
//                    } 
 | 
//                } 
 | 
  
 | 
                // 节点被占用 
 | 
                DynamicNode dynamicNode = dynamicMatrix[node.getX()][node.getY()]; 
 | 
                String vehicle = dynamicNode.getVehicle(); 
 | 
                assert !vehicle.equals(DynamicNodeType.BLOCK.val); 
 | 
                if (!vehicle.equals(DynamicNodeType.ACCESS.val)) { 
 | 
                    if (!vehicle.equals(agvNo)) { 
 | 
  
 | 
                        if (!Cools.isEmpty(blackList) && blackList.contains(vehicle)) { 
 | 
                            continue; 
 | 
                        } 
 | 
                        if (lock) { 
 | 
                            continue; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                // 避障波 
 | 
                String waveNode = waveMatrix[node.getX()][node.getY()]; 
 | 
                assert !waveNode.equals(WaveNodeType.DISABLE.val); 
 | 
                if (!waveNode.equals(WaveNodeType.ENABLE.val)) { 
 | 
                    List<String> waveNodeList = MapDataUtils.parseWaveNode(waveNode); 
 | 
                    List<String> otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo); 
 | 
  
 | 
                    if (!Cools.isEmpty(otherWaveList)) { 
 | 
                        if (!Cools.isEmpty(blackList) && 0 < Cools.getIntersection(otherWaveList, blackList).size()) { 
 | 
                            continue; 
 | 
                        } 
 | 
  
 | 
                        if (lock) { 
 | 
                            continue; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
  
 | 
                // 单巷道车辆容载数量 
 | 
                Lane lane = laneService.search(node.getCodeData()); 
 | 
                if (null != lane) { 
 | 
                    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]]; 
 | 
                        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) { 
 | 
                        if (lock) { 
 | 
                            continue; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
  
 | 
  
 | 
                //找到目标结点就返回 
 | 
                if (node.getX() == end.getX() && node.getY() == end.getY()) { 
 | 
                    //并且计算出G, F, H等值 
 | 
                    node.initNode(currentNode, end); 
 | 
                    return node; 
 | 
                } 
 | 
  
 | 
                // G + H + T (对启发函数增加去拐点方案calcNodeTurnCost) 
 | 
                int gCost = calcNodeCost(currentNode, node) * (OPEN_TURN_COST_WEIGHT ? calcNodeTurnCost(currentNode, node, end) : 1); 
 | 
  
 | 
                //进行计算对 G, F, H 等值 
 | 
                node.setLastDistance(gCost); 
 | 
                node.initNode(currentNode, end); 
 | 
                node.setH(calcNodeCost(node, end)); 
 | 
                node.setF(node.getG() + node.getH()); 
 | 
  
 | 
                openQueue.add(node); 
 | 
                existNodes.add(node); 
 | 
            } 
 | 
        } 
 | 
        //如果遍历完所有出现的结点都没有找到最终的结点,返回null 
 | 
        return null; 
 | 
    } 
 | 
  
 | 
    // 获取四周节点 
 | 
    private ArrayList<NavigateNode> getNeighborNodes(NavigateNode currentNode, int[][] mapMatrix, List<NavigateNode> existNodes) { 
 | 
        //获取当前结点的x, y 
 | 
        int x = currentNode.getX(); 
 | 
        int y = currentNode.getY(); 
 | 
        //如果当前结点的邻结点合法,就加入到neighbour_node 
 | 
        ArrayList<NavigateNode> neighbourNodes = new ArrayList<>(); 
 | 
  
 | 
        NavigateNode rightNode = extendNeighborNodes(currentNode, new NavigateNode(x, y + 1), mapMatrix, existNodes, null, null); 
 | 
        if (is_valid(currentNode, rightNode, mapMatrix, existNodes)) { 
 | 
            neighbourNodes.add(rightNode); 
 | 
        } 
 | 
  
 | 
        NavigateNode leftNode = extendNeighborNodes(currentNode, new NavigateNode(x, y - 1), mapMatrix, existNodes, null, null); 
 | 
        if (is_valid(currentNode, leftNode, mapMatrix, existNodes)) { 
 | 
            neighbourNodes.add(leftNode); 
 | 
        } 
 | 
  
 | 
        NavigateNode topNode = extendNeighborNodes(currentNode, new NavigateNode(x - 1, y), mapMatrix, existNodes, null, null); 
 | 
        if (is_valid(currentNode, topNode, mapMatrix, existNodes)) { 
 | 
            neighbourNodes.add(topNode); 
 | 
        } 
 | 
  
 | 
        NavigateNode bottomNode = extendNeighborNodes(currentNode, new NavigateNode(x + 1, y), mapMatrix, existNodes, null, null); 
 | 
        if (is_valid(currentNode, bottomNode, mapMatrix, existNodes)) { 
 | 
            neighbourNodes.add(bottomNode); 
 | 
        } 
 | 
  
 | 
        return neighbourNodes; 
 | 
    } 
 | 
  
 | 
    private NavigateNode extendNeighborNodes(NavigateNode currentNode, NavigateNode extendNode, int[][] mapMatrix, List<NavigateNode> existNodes, Integer dx, Integer dy) { 
 | 
        NavigateNode nextNode = null; 
 | 
  
 | 
        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); 
 | 
        } 
 | 
  
 | 
        int x = nextNode.getX(); 
 | 
        int y = nextNode.getY(); 
 | 
        // 数组越界 
 | 
        if (x < 0 || x >= mapMatrix.length 
 | 
                || y < 0 || y >= mapMatrix[0].length) { 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        if (mapMatrix[x][y] == MapNodeType.DISABLE.val)  { 
 | 
  
 | 
            return extendNeighborNodes(currentNode, nextNode, mapMatrix, existNodes, dx, dy); 
 | 
  
 | 
        } else { 
 | 
  
 | 
            if (isExist(nextNode, existNodes)) { 
 | 
                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); 
 | 
  
 | 
            // 判断通过性 
 | 
            Route route = routeService.findByCodeOfBoth( 
 | 
                    codeService.selectByData(currentNodeCodeData).getId(), 
 | 
                    codeService.selectByData(nextNodeCodeData).getId() 
 | 
            ); 
 | 
            if (null == route) { 
 | 
                return null; 
 | 
            } 
 | 
  
 | 
            return nextNode; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private boolean is_valid(NavigateNode currentNode, NavigateNode node, int[][] mapMatrix, List<NavigateNode> existNodes) { 
 | 
        if (null == node) { 
 | 
            return false; 
 | 
        } 
 | 
//        int x = node.getX(); 
 | 
//        int y = node.getY(); 
 | 
//        if (x < 0 || x >= mapMatrix.length 
 | 
//                || y < 0 || y >= mapMatrix[0].length) { 
 | 
//            return false; 
 | 
//        } 
 | 
// 
 | 
//        // 如果结点的位置小于0,则不合法 
 | 
//        if (mapMatrix[x][y] < 0) return false; 
 | 
// 
 | 
//        if (is_exist(node, existNodes)) { 
 | 
//            return false; 
 | 
//        } 
 | 
// 
 | 
//        // 判断通过性 
 | 
//        String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null); 
 | 
//        String currentNodeCodeData = codeMatrix[currentNode.getX()][currentNode.getY()]; 
 | 
//        String nextNodeCodeData = codeMatrix[node.getX()][node.getY()]; 
 | 
//        node.setCodeData(nextNodeCodeData); 
 | 
// 
 | 
//        Route route = routeService.findByCodeOfBoth( 
 | 
//                codeService.selectByData(currentNodeCodeData).getId(), 
 | 
//                codeService.selectByData(nextNodeCodeData).getId() 
 | 
//        ); 
 | 
//        if (null == route) { 
 | 
//            return false; 
 | 
//        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
//    private boolean is_exist(NavigateNode node, List<NavigateNode> existNodes) { 
 | 
//        for (NavigateNode exist_node : existNodes) { 
 | 
//            if (node.getX() == exist_node.getX() && node.getY() == exist_node.getY()) { 
 | 
//                return true; 
 | 
//            } 
 | 
//        } 
 | 
//        return false; 
 | 
//    } 
 | 
  
 | 
    private boolean isExist(NavigateNode node, List<NavigateNode> existNodes) { 
 | 
        for (NavigateNode existNode : existNodes) { 
 | 
            if (this.isSame(node, existNode)) { 
 | 
                return true; 
 | 
            } 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    private boolean isSame(NavigateNode o1, NavigateNode o2) { 
 | 
        if (Cools.isEmpty(o1, o2)) { 
 | 
            return false; 
 | 
        } 
 | 
        return o1.getX() == o2.getX() && o1.getY() == o2.getY(); 
 | 
    } 
 | 
  
 | 
    //------------------A*启发函数------------------// 
 | 
  
 | 
    //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) 
 | 
    private int calcNodeCost(NavigateNode node1, NavigateNode 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 1; 
 | 
        } 
 | 
  
 | 
        // 拐向终点的点 
 | 
        if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { 
 | 
            return 2; 
 | 
        } 
 | 
  
 | 
        // 普通拐点 
 | 
        /* 
 | 
        拐点判断逻辑 
 | 
        拿到父节点和下一节点 
 | 
        通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 
 | 
         */ 
 | 
        return 3; 
 | 
    } 
 | 
  
 | 
} 
 |