package com.zy.core.thread.impl; import com.alibaba.fastjson.JSON; import com.core.common.SpringUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.zy.asrs.utils.Utils; import com.zy.common.model.NavigateNode; import com.zy.common.model.enums.NavigationMapType; import com.zy.common.utils.NavigatePositionConvert; import com.zy.common.utils.NavigateUtils; import com.zy.common.utils.RedisUtil; import com.zy.common.utils.ShuttleOperaUtils; import com.zy.core.News; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.model.TrafficControlDataModel; import com.zy.core.model.command.ShuttleAssignCommand; import com.zy.core.model.command.ShuttleRedisCommand; import com.zy.core.model.protocol.ShuttleProtocol; import com.zy.core.thread.ShuttleThread; import com.zy.core.thread.TrafficControlThread; import com.zy.core.utils.TrafficControlUtils; import java.io.IOException; import java.util.*; import java.util.function.Function; public class TrafficControlImplThread implements TrafficControlThread { private RedisUtil redisUtil; private boolean detecting = false; private boolean updateDetect = false; private Long detectTime = System.currentTimeMillis(); private HashMap deviceMap = null; private HashMap>> levNodesMap = null; private HashMap shuttleReportErrorMap = new HashMap<>(); private HashMap pathIdleShuttleMap = new HashMap<>(); private HashMap applyRecordsMap = new HashMap<>(); private HashMap> taskNodesMap = new HashMap<>(); private List trafficControlDataList = new ArrayList<>(); public TrafficControlImplThread(RedisUtil redisUtil) { this.redisUtil = redisUtil; } @Override public void run() { //从缓存恢复交管信息 Object object = redisUtil.get(RedisKeyType.TRAFFIC_CONTROL_MAP.key); if(object != null) { trafficControlDataList = (List) object; } // List shuttleNoList = new ArrayList<>(); // while (true) { // try { // DeviceConfigService deviceConfigService = null; // try { // deviceConfigService = SpringUtils.getBean(DeviceConfigService.class); // }catch (Exception e){} // // if(deviceConfigService == null){ // continue; // } // // if(shuttleNoList.isEmpty()){ // List shuttleList = deviceConfigService.selectList(new EntityWrapper() // .eq("device_type", String.valueOf(SlaveType.Shuttle))); // for (DeviceConfig deviceConfig : shuttleList) { // shuttleNoList.add(deviceConfig.getDeviceNo()); // } // } // // if((updateDetect) || ((System.currentTimeMillis() - detectTime) > 1000 * 2)) { // detect(shuttleNoList); // } // }catch (Exception e){ // e.printStackTrace(); // } // } } public synchronized void detect(List shuttleNoList) { detecting = true; updateDetect = false; ObjectMapper objectMapper = null; try { objectMapper = SpringUtils.getBean(ObjectMapper.class); }catch (Exception e){} if(objectMapper == null){ return; } HashMap> tmpTaskNodesMap = new HashMap<>(); for (Integer shuttleNo : shuttleNoList) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { continue; } ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); if (shuttleProtocol == null) { continue; } if (shuttleProtocol.getTaskNo() == 0) { continue; } if (shuttleProtocol.getCurrentLocNo() == null) { continue; } int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo()); Object obj = redisUtil.get(RedisKeyType.SHUTTLE_WORK_FLAG.key + shuttleProtocol.getTaskNo()); if (obj == null) { continue; } ShuttleRedisCommand redisCommand = null; try { redisCommand = objectMapper.readValue(String.valueOf(obj), ShuttleRedisCommand.class); } catch (IOException e) { throw new RuntimeException(e); } if (redisCommand == null) { continue; } ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand(); if (assignCommand == null) { continue; } List nodeList = assignCommand.getNodesDeepCopy(); if (nodeList == null || nodeList.isEmpty()) { continue; } tmpTaskNodesMap.put(shuttleProtocol.getTaskNo() + "-" + shuttleNo, nodeList); } this.taskNodesMap = tmpTaskNodesMap; HashMap>> levNodesMap = calcNodeList(); HashMap>> levBlockMap = new HashMap<>(); //过滤不需要管制节点 for (Map.Entry>> entry : levNodesMap.entrySet()) { Integer lev = entry.getKey(); HashMap> value = entry.getValue(); HashMap> blockMap = new HashMap<>(); for (Map.Entry> listEntry : value.entrySet()) { String locNo = listEntry.getKey(); List shuttleNos = listEntry.getValue(); if (shuttleNos.size() <= 1) { continue; } blockMap.put(locNo, shuttleNos); } levBlockMap.put(lev, blockMap); } //计算堵塞范围 List> allLocList = new ArrayList<>(); List> allDeviceNodes = new ArrayList<>(); for (Map.Entry>> entry : levBlockMap.entrySet()) { Integer lev = entry.getKey(); HashMap> nodes = entry.getValue(); Set sets = new HashSet<>(); for (Map.Entry> val : nodes.entrySet()) { String locNo = val.getKey(); sets.add(locNo); } List> locList = TrafficControlUtils.groupNodes(sets); List> deviceNodes = new ArrayList<>(); //get devices for (List list : locList) { List> tmpDeviceNodes = new ArrayList<>(); for (String loc : list) { List shuttleNos = nodes.get(loc); if(!tmpDeviceNodes.contains(shuttleNos)) { tmpDeviceNodes.add(shuttleNos); } } //节点并集-获取堵塞设备编号 List> deviceList = mergeConnectedComponents(tmpDeviceNodes); deviceNodes.addAll(deviceList); } allLocList.addAll(locList); allDeviceNodes.addAll(deviceNodes); } System.out.println(JSON.toJSONString(allLocList)); System.out.println(JSON.toJSONString(allDeviceNodes)); // //分配堵塞节点可执行设备 // findDeviceByBlockList(allLocList, allDeviceNodes); detecting = false; detectTime = System.currentTimeMillis(); // //发布堵塞节点可用设备编号 // redisUtil.set(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key, trafficControlDataList); } // //分配堵塞节点可执行设备 // public void findDeviceByBlockList(List> allLocList, List> blockNodes) { // HashMap map = new HashMap<>(); // if (deviceMap == null) { // Object object = redisUtil.get(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key); // if (object != null) { // map = (HashMap) object; // } // } else { // map = deviceMap; // } // // HashMap newMap = new HashMap<>(); // // for (int i = 0; i < blockNodes.size(); i++) { // List blockNode = blockNodes.get(i); // List locs = allLocList.get(i); // // String key = JSON.toJSONString(locs); // // Integer value = -1; // if (map.containsKey(key)) { // value = map.get(key); // map.remove(key); // // if (value > 0) { // ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, value); // if (shuttleThread == null) { // continue; // } // // ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); // if (shuttleProtocol == null) { // continue; // } // // if (shuttleProtocol.getTaskNo() == 0) { // value = searchDevice(locs, blockNode, newMap); // } // // if (!shuttleProtocol.getTrafficControl()) { // value = searchDevice(locs, blockNode, newMap); // } // }else { // value = searchDevice(locs, blockNode, newMap); // } // } else { // value = searchDevice(locs, blockNode, newMap); // } // newMap.put(key, value); // } // // deviceMap = newMap; // //发布堵塞节点可用设备编号 // redisUtil.set(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key, newMap); // } public Integer searchDevice(List locs, List blockNode, HashMap deviceMap) { NavigateUtils navigateUtils = null; try { navigateUtils = SpringUtils.getBean(NavigateUtils.class); }catch (Exception e){} if(navigateUtils == null){ return -1; } Integer value = -1; for (Integer shuttleNo : blockNode) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { continue; } ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); if (shuttleProtocol == null) { continue; } if (!shuttleThread.isDeviceIdle()) { continue; } if (shuttleProtocol.getTaskNo() == 0) { continue; } if (!shuttleProtocol.getTrafficControl()) { continue;//小车未申请交通管制 } //检测小车是否已经分配 if (deviceMap.containsValue(shuttleNo)) { continue; } List trafficControlNodes = shuttleProtocol.getTrafficControlNodes(); List trafficControlLocs = new ArrayList<>(); for (NavigateNode node : trafficControlNodes) { trafficControlLocs.add(Utils.getLocNo(node.getX(), node.getY(), node.getZ())); } //检测当前小车节点是否匹配交通管制节点 boolean result = false; for (String loc : locs) { if (trafficControlLocs.contains(loc)) { result = true; break; } } if (!result) { continue; } //check path String currentLocNo = shuttleProtocol.getCurrentLocNo(); for (String loc : locs) { if (loc.equals(currentLocNo)) { continue; } List nodeList = navigateUtils.calc(currentLocNo, loc, NavigationMapType.getNormalWithDevice(), Utils.getShuttlePoints(shuttleNo, Utils.getLev(loc)), null); if (nodeList == null) { break; } } value = shuttleNo; break; } return value; } //节点并集 public List> mergeConnectedComponents(List> lists) { // 1. 收集所有唯一元素 Set allElements = new HashSet<>(); for (List list : lists) { allElements.addAll(list); } // 2. 初始化并查集 Map parent = new HashMap<>(); for (Integer element : allElements) { parent.put(element, element); } // 3. 定义查找根节点的函数(带路径压缩) Function find = x -> { int root = x; while (parent.get(root) != root) { root = parent.get(root); } // 路径压缩 int current = x; while (parent.get(current) != root) { int next = parent.get(current); parent.put(current, root); current = next; } return root; }; // 4. 遍历每个列表并合并元素 for (List list : lists) { if (list.isEmpty()) continue; int first = list.get(0); for (int i = 1; i < list.size(); i++) { int a = first; int b = list.get(i); int rootA = find.apply(a); int rootB = find.apply(b); if (rootA != rootB) { parent.put(rootB, rootA); // 合并集合 } } } // 5. 按根节点分组 Map> components = new HashMap<>(); for (Integer element : allElements) { int root = find.apply(element); components.computeIfAbsent(root, k -> new TreeSet<>()).add(element); } // 6. 转换为有序列表 List> result = new ArrayList<>(); for (Set set : components.values()) { result.add(new ArrayList<>(set)); } return result; } private HashMap>> calcNodeList() { HashMap>> levNodesMap = new HashMap<>(); for (Map.Entry> entry : taskNodesMap.entrySet()) { String key = entry.getKey(); String[] split = key.split("-"); Integer taskNo = Integer.parseInt(split[0]); Integer shuttleNo = Integer.parseInt(split[1]); List nodeList = entry.getValue(); NavigateNode node1 = nodeList.get(0); int lev = node1.getZ(); HashMap> nodeMap = new HashMap<>(); if(levNodesMap.containsKey(lev)) { nodeMap = levNodesMap.get(lev); } for (NavigateNode node : nodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), lev); List shuttleNos = new ArrayList<>(); if (nodeMap.containsKey(locNo)) { shuttleNos = nodeMap.get(locNo); } if (!shuttleNos.contains(shuttleNo)) { shuttleNos.add(shuttleNo); } nodeMap.put(locNo, shuttleNos); } levNodesMap.put(lev, nodeMap); } this.levNodesMap = levNodesMap; return levNodesMap; } @Override public synchronized boolean applyTrafficControl(List totalNodeList, List nodeList, Integer shuttleNo, Integer taskNo) { ShuttleOperaUtils shuttleOperaUtils = SpringUtils.getBean(ShuttleOperaUtils.class); if (shuttleOperaUtils == null) { return false; } //更新交管信息 redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_MAP.key, trafficControlDataList); NavigateNode startNode = totalNodeList.get(0); List shuttlePoints = Utils.getShuttlePoints(shuttleNo, startNode.getZ()); int[] currentShuttlePoint = Utils.getShuttlePoint(shuttleNo); if(currentShuttlePoint == null) { return false; } String currentShuttleLoc = Utils.getLocNo(currentShuttlePoint[0], currentShuttlePoint[1], startNode.getZ()); List shuttleLocList = new ArrayList<>(); for (int[] shuttlePoint : shuttlePoints) { String locNo = Utils.getLocNo(shuttlePoint[0], shuttlePoint[1], startNode.getZ()); shuttleLocList.add(locNo); } //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { //存在管制 if(!controlDataModel.getTaskNo().equals(taskNo)) { return false; } for (NavigateNode node : nodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); if(shuttleLocList.contains(locNo)) { ShuttleThread shuttleThread = Utils.searchShuttle(locNo); if(shuttleThread != null) { shuttleThread.restartCalcPath(); } } } News.info("traffic running {},{}", shuttleNo, taskNo); return true;//已经管制允许执行 } } ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { return false; } if (!applyRecordsMap.containsKey(shuttleNo)) { applyRecordsMap.put(shuttleNo, System.currentTimeMillis()); } Long applyRecordTime = applyRecordsMap.get(shuttleNo); if ((System.currentTimeMillis() - applyRecordTime) > 1000 * 10) { shuttleThread.restartCalcPath(); } List totalLocList = new ArrayList<>(); for (NavigateNode node : totalNodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); totalLocList.add(locNo); } //检测路径是否有小车 for (String loc : totalLocList) { if(shuttleLocList.contains(loc)) { ShuttleThread pathShuttleThread = Utils.searchShuttle(loc); if (pathShuttleThread == null) { return false; } ShuttleProtocol shuttleProtocol = pathShuttleThread.getStatus(); if(shuttleProtocol == null) { return false; } if (pathShuttleThread.isIdle()) { if(pathIdleShuttleMap.containsKey(shuttleProtocol.getShuttleNo())) { Long idleTime = pathIdleShuttleMap.get(shuttleProtocol.getShuttleNo()); if((System.currentTimeMillis() - idleTime) > 1000 * 10) { //检测障碍物车 boolean checkObstacle = shuttleOperaUtils.checkObstacle(shuttleProtocol.getCurrentLocNo(), new ArrayList() {{ add(shuttleNo); }}); pathIdleShuttleMap.remove(shuttleProtocol.getShuttleNo()); } }else { pathIdleShuttleMap.put(shuttleProtocol.getShuttleNo(), System.currentTimeMillis()); } } return false;//node has shuttle } } //检测节点是否被使用 for (TrafficControlDataModel controlDataModel : trafficControlDataList) { List list = controlDataModel.getTotalNodeList(); for (int i = 0; i < list.size(); i++) { NavigateNode node = list.get(i); String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); if (i == 0 && currentShuttleLoc.equals(locNo)) { continue;//..todo wait watch problem } if(totalLocList.contains(locNo)) { return false; } } } //交管接收 TrafficControlDataModel model = new TrafficControlDataModel(); model.setShuttleNo(shuttleNo); model.setTaskNo(taskNo); model.setNodeList(nodeList); model.setTotalNodeList(totalNodeList); trafficControlDataList.add(model); applyRecordsMap.remove(shuttleNo); News.info("receipt traffic {},{}", shuttleNo, taskNo); return true; } @Override public synchronized boolean trafficReport(List nodeList, Integer shuttleNo, Integer taskNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { List newTotalNodeList = new ArrayList<>(); List totalNodeList = controlDataModel.getTotalNodeList(); List reportList = new ArrayList<>(); for (NavigateNode node : nodeList) { reportList.add(Utils.getLocNo(node.getX(), node.getY(), node.getZ())); } for (NavigateNode node : totalNodeList) { String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ()); if(reportList.contains(locNo)) { continue; } newTotalNodeList.add(node); } controlDataModel.setTotalNodeList(newTotalNodeList); trafficControlDataList.set(i, controlDataModel); shuttleReportErrorMap.remove(shuttleNo); return true; } } } return false; } @Override public boolean trafficReportError(Integer shuttleNo, Integer taskNo) { ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); if (shuttleThread == null) { return false; } if(shuttleReportErrorMap.containsKey(shuttleNo)) { Long errorTime = shuttleReportErrorMap.get(shuttleNo); if((System.currentTimeMillis() - errorTime) > 1000 * 10) { shuttleReportErrorMap.remove(shuttleNo); shuttleThread.restartCalcPath(); } }else { shuttleReportErrorMap.put(shuttleNo, System.currentTimeMillis()); } return true; } @Override public synchronized boolean cancelTrafficControl(Integer shuttleNo, Integer taskNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { if(controlDataModel.getTaskNo().equals(taskNo)) { trafficControlDataList.remove(i);//取消管制 return true; } } } return false; } @Override public boolean forceCancelTrafficControl(Integer shuttleNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { trafficControlDataList.remove(i);//取消管制 return true; } } return false; } @Override public TrafficControlDataModel queryTrafficControl(Integer shuttleNo) { //检测车子是否存在管制 for (int i = 0; i < trafficControlDataList.size(); i++) { TrafficControlDataModel controlDataModel = trafficControlDataList.get(i); if(shuttleNo.equals(controlDataModel.getShuttleNo())) { return controlDataModel; } } return null; } @Override public List getAllTrafficControl() { return trafficControlDataList; } @Override public boolean connect() { return false; } @Override public void close() { } }