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.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<String, Integer> deviceMap = null;
|
private HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = null;
|
|
|
private HashMap<Integer,Long> applyRecordsMap = new HashMap<>();
|
private HashMap<String, List<NavigateNode>> taskNodesMap = new HashMap<>();
|
private List<TrafficControlDataModel> 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<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;
|
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) {
|
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;
|
}
|
}
|
|
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) {
|
//更新交管信息
|
redisUtil.set(RedisKeyType.TRAFFIC_CONTROL_MAP.key, trafficControlDataList);
|
|
NavigateNode startNode = totalNodeList.get(0);
|
List<int[]> 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<String> 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<String> 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)) {
|
return false;//node has shuttle
|
}
|
}
|
|
//检测节点是否被使用
|
for (TrafficControlDataModel controlDataModel : trafficControlDataList) {
|
List<NavigateNode> 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<NavigateNode> 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<NavigateNode> newTotalNodeList = new ArrayList<>();
|
List<NavigateNode> totalNodeList = controlDataModel.getTotalNodeList();
|
|
List<String> 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);
|
return true;
|
}
|
}
|
}
|
return false;
|
}
|
|
@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<TrafficControlDataModel> getAllTrafficControl() {
|
return trafficControlDataList;
|
}
|
|
@Override
|
public boolean connect() {
|
return false;
|
}
|
|
@Override
|
public void close() {
|
|
}
|
|
}
|