package com.zy.common.utils; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import com.zy.core.News; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.SpringUtils; import com.core.exception.CoolException; import com.zy.common.model.NavigateNode; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.service.DeviceConfigService; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.thread.StationThread; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; @Component public class NavigateUtils { public synchronized List calcByStationId(int lev, Integer startStationId, Integer endStationId) { NavigateSolution navigateSolution = new NavigateSolution(); List> stationMap = navigateSolution.getStationMap(lev); NavigateNode startNode = navigateSolution.findStationNavigateNode(stationMap, startStationId); if (startNode == null){ throw new CoolException("未找到该 起点 对应的节点"); } NavigateNode endNode = navigateSolution.findStationNavigateNode(stationMap, endStationId); if (endNode == null){ throw new CoolException("未找到该 终点 对应的节点"); } long startTime = System.currentTimeMillis(); News.info("[WCS Debug] 站点路径开始计算,startStationId={},endStationId={}", startStationId, endStationId); List> allList = navigateSolution.allSimplePaths(stationMap, startNode, endNode, 120, 500, 300); if (allList.isEmpty()) { throw new CoolException("未找到该路径"); } News.info("[WCS Debug] 站点路径计算完成,耗时:{}ms", System.currentTimeMillis() - startTime); if (allList.size() > 1) { System.out.println(JSON.toJSONString(allList)); } News.info("[WCS Debug] 站点路径权重开始分析,startStationId={},endStationId={}", startStationId, endStationId); List list = findStationBestPath(allList); News.info("[WCS Debug] 站点路径权重分析结束,startStationId={},endStationId={}", startStationId, endStationId); //去重 HashSet set = new HashSet<>(); List fitlerList = new ArrayList<>(); for(NavigateNode navigateNode : list){ JSONObject valuObject = JSON.parseObject(navigateNode.getNodeValue()); if(set.add(valuObject.getInteger("stationId"))){ fitlerList.add(navigateNode); } } return fitlerList; } public synchronized List calcByTrackSiteNo(int lev, Integer startTrackSiteNo, Integer endTrackSiteNo) { NavigateSolution navigateSolution = new NavigateSolution(); List> rgvTrackMap = navigateSolution.getRgvTrackMap(lev); NavigateNode startNode = navigateSolution.findTrackSiteNoNavigateNode(rgvTrackMap, startTrackSiteNo); if (startNode == null){ throw new CoolException("未找到该 起点 对应的节点"); } NavigateNode endNode = navigateSolution.findTrackSiteNoNavigateNode(rgvTrackMap, endTrackSiteNo); if (endNode == null){ throw new CoolException("未找到该 终点 对应的节点"); } long startTime = System.currentTimeMillis(); News.info("[WCS Debug] RGV路径开始计算,startTrackSiteNo:{},endTrackSiteNo={}", startTrackSiteNo, endTrackSiteNo); NavigateNode res_node = navigateSolution.astarSearchJava(rgvTrackMap, startNode, endNode); if (res_node == null) { throw new CoolException("未找到该路径"); } News.info("[WCS Debug] RGV路径计算完成,耗时:{}ms", System.currentTimeMillis() - startTime); ArrayList list = new ArrayList<>(); // 使用 visited 集合防止父链出现环导致死循环,同时设置安全步数上限 HashSet visited = new HashSet<>(); int maxSteps = rgvTrackMap.size() * rgvTrackMap.get(0).size() + 5; // 安全上限 int steps = 0; while (res_node != null && visited.add(res_node) && steps++ < maxSteps) { list.add(res_node); res_node = res_node.getFather();//迭代操作 } if (steps >= maxSteps) { throw new CoolException("路径回溯超出安全上限,疑似存在父链循环"); } Collections.reverse(list); //将每个节点里面的fatherNode至为null(方便后续计算时父节点过多导致显示的节点太多) for (NavigateNode navigateNode : list) { //父节点设置为null,不影响计算结果,不影响后续操作。 //此操作仅为后续排查处理提供视觉方便。 navigateNode.setFather(null); } //去重 HashSet set = new HashSet<>(); List fitlerList = new ArrayList<>(); for(NavigateNode navigateNode : list){ JSONObject valuObject = JSON.parseObject(navigateNode.getNodeValue()); if(set.add(valuObject.getInteger("trackSiteNo"))){ fitlerList.add(navigateNode); } } return fitlerList; } public synchronized List findLiftStationList(int lev) { NavigateSolution navigateSolution = new NavigateSolution(); List> stationMap = navigateSolution.getStationMap(lev); List liftStationList = new ArrayList<>(); for (List navigateNodes : stationMap) { for (NavigateNode navigateNode : navigateNodes) { String nodeType = navigateNode.getNodeType(); if(nodeType == null){ continue; } if(!nodeType.equals("devp")){ continue; } JSONObject valuObject = JSON.parseObject(navigateNode.getNodeValue()); if(valuObject == null){ continue; } if (valuObject.containsKey("liftNo")) { liftStationList.add(navigateNode); } } } return liftStationList; } public synchronized List findStationBestPath(List> allList) { if (allList == null || allList.isEmpty()) { return new ArrayList<>(); } Map statusMap = new HashMap<>(); try { DeviceConfigService deviceConfigService = SpringUtils.getBean(DeviceConfigService.class); if (deviceConfigService != null) { List devpList = deviceConfigService.selectList(new EntityWrapper() .eq("device_type", String.valueOf(SlaveType.Devp))); for (DeviceConfig deviceConfig : devpList) { StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, deviceConfig.getDeviceNo()); if (stationThread == null) { continue; } Map m = stationThread.getStatusMap(); if (m != null && !m.isEmpty()) { statusMap.putAll(m); } } } } catch (Exception ignore) {} List> candidates = new ArrayList<>(); List lens = new ArrayList<>(); List tasksList = new ArrayList<>(); List congs = new ArrayList<>(); for (List path : allList) { if (path == null || path.isEmpty()) { continue; } int len = path.size(); int tasks = 0; HashSet stationIdSet = new HashSet<>(); for (NavigateNode node : path) { JSONObject value = null; try { value = JSON.parseObject(node.getNodeValue()); } catch (Exception ignore) {} if (value == null) { continue; } Integer stationId = value.getInteger("stationId"); if (stationId == null) { continue; } if (!stationIdSet.add(stationId)) { continue; } StationProtocol protocol = statusMap.get(stationId); if (protocol != null && protocol.getTaskNo() != null && protocol.getTaskNo() > 0) { tasks++; } } double cong = len <= 0 ? 0.0 : (double) tasks / (double) len; candidates.add(path); lens.add(len); tasksList.add(tasks); congs.add(cong); } if (candidates.isEmpty()) { return allList.get(0); } int minLen = Integer.MAX_VALUE; int maxLen = Integer.MIN_VALUE; double minCong = Double.MAX_VALUE; double maxCong = -Double.MAX_VALUE; for (int i = 0; i < candidates.size(); i++) { int l = lens.get(i); double c = congs.get(i); if (l < minLen) minLen = l; if (l > maxLen) maxLen = l; if (c < minCong) minCong = c; if (c > maxCong) maxCong = c; } //长度权重百分比 double lenWeightPercent = 50.0; //拥堵权重百分比 double congWeightPercent = 50.0; try { ConfigService configService = SpringUtils.getBean(ConfigService.class); if (configService != null) { Config cfgLen = configService.selectOne(new EntityWrapper().eq("code", "stationPathLenWeightPercent")); if (cfgLen != null && cfgLen.getValue() != null) { String v = cfgLen.getValue().trim(); if (v.endsWith("%")) v = v.substring(0, v.length() - 1); try { lenWeightPercent = Double.parseDouble(v); } catch (Exception ignore) {} } Config cfgCong = configService.selectOne(new EntityWrapper().eq("code", "stationPathCongWeightPercent")); if (cfgCong != null && cfgCong.getValue() != null) { String v = cfgCong.getValue().trim(); if (v.endsWith("%")) v = v.substring(0, v.length() - 1); try { congWeightPercent = Double.parseDouble(v); } catch (Exception ignore) {} } } } catch (Exception ignore) {} double weightSum = lenWeightPercent + congWeightPercent; double lenW = weightSum <= 0 ? 0.5 : lenWeightPercent / weightSum; double congW = weightSum <= 0 ? 0.5 : congWeightPercent / weightSum; List best = null; double bestCost = Double.MAX_VALUE; int bestTasks = Integer.MAX_VALUE; int bestLen = Integer.MAX_VALUE; for (int i = 0; i < candidates.size(); i++) { int l = lens.get(i); int t = tasksList.get(i); double c = congs.get(i); //归一化 double lenNorm = (maxLen - minLen) <= 0 ? 0.0 : (l - minLen) / (double) (maxLen - minLen); double congNorm = (maxCong - minCong) <= 0 ? 0.0 : (c - minCong) / (double) (maxCong - minCong); //获取权重 double cost = lenNorm * lenW + congNorm * congW; if (cost < bestCost || (cost == bestCost && t < bestTasks) || (cost == bestCost && t == bestTasks && l < bestLen)) { best = candidates.get(i); bestCost = cost; bestTasks = t; bestLen = l; } } if (best == null) { return allList.get(0); } return best; } }