#
Administrator
2 天以前 a03b6ca1541d4351017bdfaf51de03f9fd3d655c
src/main/java/com/zy/common/utils/NavigateUtils.java
@@ -7,6 +7,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.entity.BasDevp;
@@ -15,6 +16,7 @@
import com.zy.asrs.service.BasStationService;
import com.zy.core.News;
import com.zy.core.model.StationObjModel;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -34,6 +36,7 @@
@Component
public class NavigateUtils {
    private static final long STATION_PATH_RUNTIME_SNAPSHOT_TTL_MS = 2000L;
    private static final String CFG_STATION_PATH_LEN_WEIGHT_PERCENT = "stationPathLenWeightPercent";
    private static final String CFG_STATION_PATH_CONG_WEIGHT_PERCENT = "stationPathCongWeightPercent";
@@ -43,7 +46,17 @@
    @Autowired
    private BasStationService basStationService;
    public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) {
    private final AtomicReference<CachedStationPathRuntimeSnapshot> runtimeSnapshotRef = new AtomicReference<>();
    @Scheduled(fixedDelay = 1500, initialDelay = 3000)
    public void refreshStationPathCaches() {
        try {
            runtimeSnapshotRef.set(new CachedStationPathRuntimeSnapshot(System.currentTimeMillis(), buildStationPathRuntimeSnapshot()));
        } catch (Exception ignore) {
        }
    }
    public List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) {
        BasStation startStation = basStationService.selectById(startStationId);
        if (startStation == null) {
            throw new CoolException("未找到该 起点 对应的站点数据");
@@ -121,7 +134,38 @@
        return fitlerList;
    }
    public synchronized List<NavigateNode> calcByTrackSiteNo(int lev, Integer startTrackSiteNo, Integer endTrackSiteNo) {
    public List<NavigateNode> calcReachablePathByStationId(Integer startStationId, Integer endStationId) {
        BasStation startStation = basStationService.selectById(startStationId);
        if (startStation == null) {
            throw new CoolException("未找到该 起点 对应的站点数据");
        }
        Integer lev = startStation.getStationLev();
        NavigateSolution navigateSolution = new NavigateSolution();
        List<List<NavigateNode>> 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);
        NavigateNode resNode = navigateSolution.astarSearchJava(stationMap, startNode, endNode);
        if (resNode == null) {
            return new ArrayList<>();
        }
        News.info("[WCS Debug] 站点快速可达路径计算完成,耗时:{}ms", System.currentTimeMillis() - startTime);
        return buildStationPathFromFatherChain(resNode, stationMap);
    }
    public List<NavigateNode> calcByTrackSiteNo(int lev, Integer startTrackSiteNo, Integer endTrackSiteNo) {
        NavigateSolution navigateSolution = new NavigateSolution();
        List<List<NavigateNode>> rgvTrackMap = navigateSolution.getRgvTrackMap(lev);
@@ -191,7 +235,7 @@
        return fitlerList;
    }
    public synchronized List<NavigateNode> findLiftStationList(int lev) {
    public List<NavigateNode> findLiftStationList(int lev) {
        NavigateSolution navigateSolution = new NavigateSolution();
        List<List<NavigateNode>> stationMap = navigateSolution.getStationMap(lev);
@@ -218,45 +262,76 @@
        return liftStationList;
    }
    public synchronized List<NavigateNode> findStationBestPath(List<List<NavigateNode>> allList) {
    private List<NavigateNode> buildStationPathFromFatherChain(NavigateNode endNode, List<List<NavigateNode>> stationMap) {
        ArrayList<NavigateNode> list = new ArrayList<>();
        HashSet<NavigateNode> visited = new HashSet<>();
        int maxSteps = stationMap.size() * stationMap.get(0).size() + 5;
        int steps = 0;
        NavigateNode fatherNode = null;
        NavigateNode currentNode = endNode;
        while (currentNode != null && visited.add(currentNode) && steps++ < maxSteps) {
            currentNode.setIsInflectionPoint(false);
            currentNode.setIsLiftTransferPoint(false);
            try {
                JSONObject valueObject = JSON.parseObject(currentNode.getNodeValue());
                if (valueObject != null) {
                    Object isLiftTransfer = valueObject.get("isLiftTransfer");
                    if (isLiftTransfer != null) {
                        String isLiftTransferStr = isLiftTransfer.toString();
                        if ("1".equals(isLiftTransferStr) || "true".equalsIgnoreCase(isLiftTransferStr)) {
                            currentNode.setIsLiftTransferPoint(true);
                        }
                    }
                }
            } catch (Exception ignore) {
            }
            HashMap<String, Object> result = searchInflectionPoint(currentNode, fatherNode, currentNode.getFather());
            if (Boolean.parseBoolean(result.get("result").toString())) {
                currentNode.setIsInflectionPoint(true);
                currentNode.setDirection(result.get("direction").toString());
            }
            list.add(currentNode);
            fatherNode = currentNode;
            currentNode = currentNode.getFather();
        }
        if (steps >= maxSteps) {
            throw new CoolException("路径回溯超出安全上限,疑似存在父链循环");
        }
        Collections.reverse(list);
        for (NavigateNode navigateNode : list) {
            navigateNode.setFather(null);
        }
        HashSet<Integer> stationIdSet = new HashSet<>();
        List<NavigateNode> filterList = new ArrayList<>();
        for (NavigateNode navigateNode : list) {
            JSONObject valueObject = JSON.parseObject(navigateNode.getNodeValue());
            if (valueObject.containsKey("rgvCalcFlag")) {
                continue;
            }
            if (stationIdSet.add(valueObject.getInteger("stationId"))) {
                filterList.add(navigateNode);
            }
        }
        return filterList;
    }
    public List<NavigateNode> findStationBestPath(List<List<NavigateNode>> allList) {
        if (allList == null || allList.isEmpty()) {
            return new ArrayList<>();
        }
        Map<Integer, StationProtocol> statusMap = new HashMap<>();
        try {
            DeviceConfigService deviceConfigService = SpringUtils.getBean(DeviceConfigService.class);
            if (deviceConfigService != null) {
                List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                        .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<Integer, StationProtocol> m = stationThread.getStatusMap();
                    if (m != null && !m.isEmpty()) {
                        statusMap.putAll(m);
                    }
                }
            }
        } catch (Exception ignore) {}
        Set<Integer> outStationIdSet = loadAllOutStationIdSet();
        double lenWeightPercent = 50.0;
        double congWeightPercent = 50.0;
        double passOtherOutStationWeightPercent = 100.0;
        boolean forceSkipPassOtherOutStation = false;
        try {
            ConfigService configService = SpringUtils.getBean(ConfigService.class);
            if (configService != null) {
                lenWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_LEN_WEIGHT_PERCENT, lenWeightPercent);
                congWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_CONG_WEIGHT_PERCENT, congWeightPercent);
                passOtherOutStationWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_PASS_OTHER_OUT_STATION_WEIGHT_PERCENT, passOtherOutStationWeightPercent);
                forceSkipPassOtherOutStation = loadBooleanConfig(configService, CFG_STATION_PATH_PASS_OTHER_OUT_STATION_FORCE_SKIP, false);
            }
        } catch (Exception ignore) {}
        StationPathRuntimeSnapshot runtimeSnapshot = loadStationPathRuntimeSnapshot();
        Map<Integer, StationProtocol> statusMap = runtimeSnapshot.statusMap;
        Set<Integer> outStationIdSet = runtimeSnapshot.outStationIdSet;
        double lenWeightPercent = runtimeSnapshot.lenWeightPercent;
        double congWeightPercent = runtimeSnapshot.congWeightPercent;
        double passOtherOutStationWeightPercent = runtimeSnapshot.passOtherOutStationWeightPercent;
        boolean forceSkipPassOtherOutStation = runtimeSnapshot.forceSkipPassOtherOutStation;
        List<List<NavigateNode>> candidates = new ArrayList<>();
        List<Integer> lens = new ArrayList<>();
@@ -472,6 +547,59 @@
                || "on".equalsIgnoreCase(value);
    }
    private StationPathRuntimeSnapshot loadStationPathRuntimeSnapshot() {
        long now = System.currentTimeMillis();
        CachedStationPathRuntimeSnapshot cached = runtimeSnapshotRef.get();
        if (cached != null && now - cached.loadTimeMs < STATION_PATH_RUNTIME_SNAPSHOT_TTL_MS && cached.snapshot != null) {
            return cached.snapshot;
        }
        StationPathRuntimeSnapshot snapshot = buildStationPathRuntimeSnapshot();
        runtimeSnapshotRef.set(new CachedStationPathRuntimeSnapshot(now, snapshot));
        return snapshot;
    }
    private StationPathRuntimeSnapshot buildStationPathRuntimeSnapshot() {
        StationPathRuntimeSnapshot snapshot = new StationPathRuntimeSnapshot();
        snapshot.statusMap = loadAllStationStatusMap();
        snapshot.outStationIdSet = loadAllOutStationIdSet();
        try {
            ConfigService configService = SpringUtils.getBean(ConfigService.class);
            if (configService != null) {
                snapshot.lenWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_LEN_WEIGHT_PERCENT, snapshot.lenWeightPercent);
                snapshot.congWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_CONG_WEIGHT_PERCENT, snapshot.congWeightPercent);
                snapshot.passOtherOutStationWeightPercent = loadDoubleConfig(configService, CFG_STATION_PATH_PASS_OTHER_OUT_STATION_WEIGHT_PERCENT, snapshot.passOtherOutStationWeightPercent);
                snapshot.forceSkipPassOtherOutStation = loadBooleanConfig(configService, CFG_STATION_PATH_PASS_OTHER_OUT_STATION_FORCE_SKIP, false);
            }
        } catch (Exception ignore) {
        }
        return snapshot;
    }
    private Map<Integer, StationProtocol> loadAllStationStatusMap() {
        Map<Integer, StationProtocol> statusMap = new HashMap<>();
        try {
            DeviceConfigService deviceConfigService = SpringUtils.getBean(DeviceConfigService.class);
            if (deviceConfigService == null) {
                return statusMap;
            }
            List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .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<Integer, StationProtocol> m = stationThread.getStatusMap();
                if (m != null && !m.isEmpty()) {
                    statusMap.putAll(m);
                }
            }
        } catch (Exception ignore) {
        }
        return statusMap;
    }
    //判断当前节点到下一个节点是否为拐点
    public HashMap<String,Object> searchInflectionPoint(NavigateNode currentNode, NavigateNode fatherNode, NavigateNode nextNode) {
        HashMap<String, Object> map = new HashMap<>();
@@ -523,4 +651,23 @@
        return direction;
    }
    private static class StationPathRuntimeSnapshot {
        private Map<Integer, StationProtocol> statusMap = new HashMap<>();
        private Set<Integer> outStationIdSet = new HashSet<>();
        private double lenWeightPercent = 50.0;
        private double congWeightPercent = 50.0;
        private double passOtherOutStationWeightPercent = 100.0;
        private boolean forceSkipPassOtherOutStation = false;
    }
    private static class CachedStationPathRuntimeSnapshot {
        private final long loadTimeMs;
        private final StationPathRuntimeSnapshot snapshot;
        private CachedStationPathRuntimeSnapshot(long loadTimeMs, StationPathRuntimeSnapshot snapshot) {
            this.loadTimeMs = loadTimeMs;
            this.snapshot = snapshot;
        }
    }
}