| | |
| | | public class TrafficControlImplThread implements TrafficControlThread { |
| | | |
| | | private RedisUtil redisUtil; |
| | | private boolean detecting = false; |
| | | private boolean updateDetect = false; |
| | | private Long detectTime = System.currentTimeMillis(); |
| | | private HashMap<String, Integer> deviceMap = null; |
| | | private HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = null; |
| | | |
| | | |
| | | private List<TrafficControlDataModel> applyList = new ArrayList<>(); |
| | | private HashMap<Integer,Long> shuttleReportErrorMap = new HashMap<>(); |
| | | private HashMap<Integer,Long> pathIdleShuttleMap = new HashMap<>(); |
| | | private HashMap<Integer,Long> applyRecordsMap = new HashMap<>(); |
| | |
| | | trafficControlDataList = (List<TrafficControlDataModel>) object; |
| | | } |
| | | |
| | | // List<Integer> 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<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() |
| | | // .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<Integer> shuttleNoList) { |
| | | detecting = true; |
| | | updateDetect = false; |
| | | ObjectMapper objectMapper = null; |
| | | while (true) { |
| | | try { |
| | | objectMapper = SpringUtils.getBean(ObjectMapper.class); |
| | | }catch (Exception e){} |
| | | |
| | | if(objectMapper == null){ |
| | | return; |
| | | } |
| | | |
| | | HashMap<String, List<NavigateNode>> tmpTaskNodesMap = new HashMap<>(); |
| | | for (Integer shuttleNo : shuttleNoList) { |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo); |
| | | if (shuttleThread == null) { |
| | | if (applyList.isEmpty()) { |
| | | 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<NavigateNode> nodeList = assignCommand.getNodesDeepCopy(); |
| | | if (nodeList == null || nodeList.isEmpty()) { |
| | | continue; |
| | | } |
| | | |
| | | tmpTaskNodesMap.put(shuttleProtocol.getTaskNo() + "-" + shuttleNo, nodeList); |
| | | } |
| | | this.taskNodesMap = tmpTaskNodesMap; |
| | | HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = calcNodeList(); |
| | | |
| | | HashMap<Integer, HashMap<String, List<Integer>>> levBlockMap = new HashMap<>(); |
| | | //过滤不需要管制节点 |
| | | for (Map.Entry<Integer, HashMap<String, List<Integer>>> entry : levNodesMap.entrySet()) { |
| | | Integer lev = entry.getKey(); |
| | | HashMap<String, List<Integer>> value = entry.getValue(); |
| | | |
| | | HashMap<String, List<Integer>> blockMap = new HashMap<>(); |
| | | for (Map.Entry<String, List<Integer>> listEntry : value.entrySet()) { |
| | | String locNo = listEntry.getKey(); |
| | | List<Integer> shuttleNos = listEntry.getValue(); |
| | | if (shuttleNos.size() <= 1) { |
| | | continue; |
| | | } |
| | | blockMap.put(locNo, shuttleNos); |
| | | } |
| | | |
| | | levBlockMap.put(lev, blockMap); |
| | | } |
| | | |
| | | //计算堵塞范围 |
| | | List<List<String>> allLocList = new ArrayList<>(); |
| | | List<List<Integer>> allDeviceNodes = new ArrayList<>(); |
| | | for (Map.Entry<Integer, HashMap<String, List<Integer>>> entry : levBlockMap.entrySet()) { |
| | | Integer lev = entry.getKey(); |
| | | HashMap<String, List<Integer>> nodes = entry.getValue(); |
| | | |
| | | Set<String> sets = new HashSet<>(); |
| | | for (Map.Entry<String, List<Integer>> val : nodes.entrySet()) { |
| | | String locNo = val.getKey(); |
| | | sets.add(locNo); |
| | | } |
| | | |
| | | List<List<String>> locList = TrafficControlUtils.groupNodes(sets); |
| | | List<List<Integer>> deviceNodes = new ArrayList<>(); |
| | | |
| | | //get devices |
| | | for (List<String> list : locList) { |
| | | List<List<Integer>> tmpDeviceNodes = new ArrayList<>(); |
| | | for (String loc : list) { |
| | | List<Integer> shuttleNos = nodes.get(loc); |
| | | if(!tmpDeviceNodes.contains(shuttleNos)) { |
| | | tmpDeviceNodes.add(shuttleNos); |
| | | } |
| | | } |
| | | //节点并集-获取堵塞设备编号 |
| | | List<List<Integer>> 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<List<String>> allLocList, List<List<Integer>> blockNodes) { |
| | | // HashMap<String, Integer> map = new HashMap<>(); |
| | | // if (deviceMap == null) { |
| | | // Object object = redisUtil.get(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key); |
| | | // if (object != null) { |
| | | // map = (HashMap<String, Integer>) object; |
| | | // } |
| | | // } else { |
| | | // map = deviceMap; |
| | | // } |
| | | // |
| | | // HashMap<String, Integer> newMap = new HashMap<>(); |
| | | // |
| | | // for (int i = 0; i < blockNodes.size(); i++) { |
| | | // List<Integer> blockNode = blockNodes.get(i); |
| | | // List<String> 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<String> locs, List<Integer> blockNode, HashMap<String, Integer> 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<NavigateNode> trafficControlNodes = shuttleProtocol.getTrafficControlNodes(); |
| | | List<String> 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; |
| | | TrafficControlDataModel dataModel = applyList.get(0); |
| | | processApply(dataModel); |
| | | applyList.remove(0); |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | if (!result) { |
| | | continue; |
| | | } |
| | | |
| | | //check path |
| | | String currentLocNo = shuttleProtocol.getCurrentLocNo(); |
| | | for (String loc : locs) { |
| | | if (loc.equals(currentLocNo)) { |
| | | continue; |
| | | } |
| | | List<NavigateNode> 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<List<Integer>> mergeConnectedComponents(List<List<Integer>> lists) { |
| | | // 1. 收集所有唯一元素 |
| | | Set<Integer> allElements = new HashSet<>(); |
| | | for (List<Integer> list : lists) { |
| | | allElements.addAll(list); |
| | | } |
| | | |
| | | // 2. 初始化并查集 |
| | | Map<Integer, Integer> parent = new HashMap<>(); |
| | | for (Integer element : allElements) { |
| | | parent.put(element, element); |
| | | } |
| | | |
| | | // 3. 定义查找根节点的函数(带路径压缩) |
| | | Function<Integer, Integer> 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<Integer> 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<Integer, Set<Integer>> components = new HashMap<>(); |
| | | for (Integer element : allElements) { |
| | | int root = find.apply(element); |
| | | components.computeIfAbsent(root, k -> new TreeSet<>()).add(element); |
| | | } |
| | | |
| | | // 6. 转换为有序列表 |
| | | List<List<Integer>> result = new ArrayList<>(); |
| | | for (Set<Integer> set : components.values()) { |
| | | result.add(new ArrayList<>(set)); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private HashMap<Integer, HashMap<String, List<Integer>>> calcNodeList() { |
| | | HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = new HashMap<>(); |
| | | for (Map.Entry<String, List<NavigateNode>> entry : taskNodesMap.entrySet()) { |
| | | String key = entry.getKey(); |
| | | String[] split = key.split("-"); |
| | | Integer taskNo = Integer.parseInt(split[0]); |
| | | Integer shuttleNo = Integer.parseInt(split[1]); |
| | | |
| | | List<NavigateNode> nodeList = entry.getValue(); |
| | | NavigateNode node1 = nodeList.get(0); |
| | | int lev = node1.getZ(); |
| | | |
| | | HashMap<String, List<Integer>> 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<Integer> 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<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { |
| | | public synchronized boolean processApply(TrafficControlDataModel applyData) { |
| | | ShuttleOperaUtils shuttleOperaUtils = SpringUtils.getBean(ShuttleOperaUtils.class); |
| | | if (shuttleOperaUtils == null) { |
| | | return false; |
| | | } |
| | | |
| | | if (applyData == null) { |
| | | return false; |
| | | } |
| | | |
| | | if (applyData.getShuttleNo() == null || applyData.getTaskNo() == null || applyData.getNodeList() == null || applyData.getTotalNodeList() == null) { |
| | | return false; |
| | | } |
| | | |
| | | Integer shuttleNo = applyData.getShuttleNo(); |
| | | Integer taskNo = applyData.getTaskNo(); |
| | | List<NavigateNode> nodeList = applyData.getNodeList(); |
| | | List<NavigateNode> totalNodeList = applyData.getTotalNodeList(); |
| | | |
| | | //更新交管信息 |
| | | redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_MAP.key, trafficControlDataList); |
| | |
| | | } |
| | | } |
| | | |
| | | News.info("traffic running {},{}", shuttleNo, taskNo); |
| | | // News.info("traffic running {},{}", shuttleNo, taskNo); |
| | | return true;//已经管制允许执行 |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | //交管接收 |
| | | trafficControlDataList.add(applyData); |
| | | |
| | | applyRecordsMap.remove(shuttleNo); |
| | | News.info("receipt traffic {},{}", shuttleNo, taskNo); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public synchronized boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) { |
| | | boolean add = true; |
| | | for (TrafficControlDataModel controlDataModel : applyList) { |
| | | if(controlDataModel.getShuttleNo().equals(shuttleNo)) { |
| | | add = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (add) { |
| | | TrafficControlDataModel model = new TrafficControlDataModel(); |
| | | model.setShuttleNo(shuttleNo); |
| | | model.setTaskNo(taskNo); |
| | | model.setNodeList(nodeList); |
| | | model.setTotalNodeList(totalNodeList); |
| | | trafficControlDataList.add(model); |
| | | applyList.add(model); |
| | | }else { |
| | | return false; |
| | | } |
| | | |
| | | applyRecordsMap.remove(shuttleNo); |
| | | News.info("receipt traffic {},{}", shuttleNo, taskNo); |
| | | return true; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public TrafficControlDataModel queryTrafficControl(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)) { |
| | | return controlDataModel; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public TrafficControlDataModel queryTrafficControl(Integer shuttleNo) { |
| | | //检测车子是否存在管制 |
| | | for (int i = 0; i < trafficControlDataList.size(); i++) { |