#
Junjie
23 小时以前 aa710969e00e9d7e56a276066a239f74d5c49310
src/main/java/com/zy/common/utils/NavigateUtils.java
@@ -32,6 +32,7 @@
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.common.SpringUtils;
@@ -73,20 +74,40 @@
    private StationTaskTraceRegistry stationTaskTraceRegistry;
    public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) {
        return calcByStationId(startStationId, endStationId, null, false);
        return calcByStationId(startStationId, endStationId, null, null, false);
    }
    public synchronized List<NavigateNode> calcByStationId(Integer startStationId,
                                                           Integer endStationId,
                                                           Double pathLenFactor) {
        return calcByStationId(startStationId, endStationId, null, pathLenFactor, false);
    }
    public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId, Integer currentTaskNo) {
        return calcByStationId(startStationId, endStationId, currentTaskNo, false);
        return calcByStationId(startStationId, endStationId, currentTaskNo, null, false);
    }
    public synchronized List<NavigateNode> calcByStationId(Integer startStationId,
                                                           Integer endStationId,
                                                           Integer currentTaskNo,
                                                           Double pathLenFactor) {
        return calcByStationId(startStationId, endStationId, currentTaskNo, pathLenFactor, false);
    }
    public synchronized List<NavigateNode> calcReachablePathByStationId(Integer startStationId, Integer endStationId) {
        return calcByStationId(startStationId, endStationId, null, true);
        return calcByStationId(startStationId, endStationId, null, null, true);
    }
    public synchronized List<List<NavigateNode>> calcCandidatePathByStationId(Integer startStationId,
                                                                              Integer endStationId,
                                                                              Integer currentTaskNo) {
        return calcCandidatePathByStationId(startStationId, endStationId, currentTaskNo, null);
    }
    public synchronized List<List<NavigateNode>> calcCandidatePathByStationId(Integer startStationId,
                                                                              Integer endStationId,
                                                                              Integer currentTaskNo,
                                                                              Double pathLenFactor) {
        StationPathSearchContext context = buildStationPathSearchContext(startStationId, endStationId);
        if (context.allList.isEmpty()) {
            return new ArrayList<>();
@@ -96,15 +117,30 @@
                context.allList,
                context.resolvedPolicy,
                currentTaskNo,
                pathLenFactor,
                startStationId,
                endStationId
        );
        return normalizeCandidatePaths(orderedPathList);
    }
    public synchronized Map<Integer, Set<Integer>> loadUndirectedStationGraphSnapshot() {
        Map<Integer, Set<Integer>> graph = loadUndirectedStationGraph();
        Map<Integer, Set<Integer>> snapshot = new HashMap<>();
        for (Map.Entry<Integer, Set<Integer>> entry : graph.entrySet()) {
            Integer stationId = entry.getKey();
            if (stationId == null) {
                continue;
            }
            snapshot.put(stationId, new LinkedHashSet<>(entry.getValue() == null ? Collections.emptySet() : entry.getValue()));
        }
        return snapshot;
    }
    private synchronized List<NavigateNode> calcByStationId(Integer startStationId,
                                                            Integer endStationId,
                                                            Integer currentTaskNo,
                                                            Double pathLenFactor,
                                                            boolean reachabilityOnly) {
        StationPathSearchContext context = buildStationPathSearchContext(startStationId, endStationId);
        if (context.allList.isEmpty()) {
@@ -112,7 +148,7 @@
        }
        List<NavigateNode> list = reachabilityOnly
                ? findStationReachablePath(context.allList, context.resolvedPolicy, startStationId, endStationId)
                : findStationBestPathTwoStage(context.allList, context.resolvedPolicy, currentTaskNo, startStationId, endStationId);
                : findStationBestPathTwoStage(context.allList, context.resolvedPolicy, currentTaskNo, pathLenFactor, startStationId, endStationId);
        return normalizeStationPath(list);
    }
@@ -261,9 +297,10 @@
    private List<NavigateNode> findStationBestPathTwoStage(List<List<NavigateNode>> allList,
                                                           StationPathResolvedPolicy resolvedPolicy,
                                                           Integer currentTaskNo,
                                                           Double pathLenFactor,
                                                           Integer startStationId,
                                                           Integer endStationId) {
        List<List<NavigateNode>> orderedPathList = orderStationPathCandidates(allList, resolvedPolicy, currentTaskNo, startStationId, endStationId);
        List<List<NavigateNode>> orderedPathList = orderStationPathCandidates(allList, resolvedPolicy, currentTaskNo, pathLenFactor, startStationId, endStationId);
        if (orderedPathList.isEmpty()) {
            return new ArrayList<>();
        }
@@ -273,6 +310,7 @@
    private List<List<NavigateNode>> orderStationPathCandidates(List<List<NavigateNode>> allList,
                                                                StationPathResolvedPolicy resolvedPolicy,
                                                                Integer currentTaskNo,
                                                                Double pathLenFactor,
                                                                Integer startStationId,
                                                                Integer endStationId) {
        if (allList == null || allList.isEmpty()) {
@@ -345,7 +383,8 @@
            return new ArrayList<>();
        }
        metricsList.sort((a, b) -> compareDouble(a.staticCost, b.staticCost, a.turnCount, b.turnCount, a.pathLen, b.pathLen));
        applyPathLengthPreference(metricsList, profileConfig, globalPolicy, pathLenFactor);
        metricsList.sort((a, b) -> compareStaticCandidateMetrics(a, b, pathLenFactor));
        PathCandidateMetrics preferred = metricsList.get(0);
        int maxLen = (int) Math.ceil(preferred.pathLen * safeDouble(profileConfig.getS1MaxLenRatio(), 1.15d));
        int maxTurns = preferred.turnCount + safeInt(profileConfig.getS1MaxTurnDiff(), 1);
@@ -368,8 +407,8 @@
            primaryMetrics = new ArrayList<>(primaryMetrics.subList(0, topK));
        }
        primaryMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount));
        secondaryMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount));
        primaryMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor));
        secondaryMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor));
        List<PathCandidateMetrics> remainingMetrics = new ArrayList<>();
        for (PathCandidateMetrics metrics : metricsList) {
@@ -377,7 +416,7 @@
                remainingMetrics.add(metrics);
            }
        }
        remainingMetrics.sort((a, b) -> compareDouble(a.dynamicCost, b.dynamicCost, a.pathLen, b.pathLen, a.turnCount, b.turnCount));
        remainingMetrics.sort((a, b) -> compareDynamicCandidateMetrics(a, b, pathLenFactor));
        List<List<NavigateNode>> orderedPathList = new ArrayList<>();
        appendCandidatePathList(orderedPathList, primaryMetrics);
@@ -648,9 +687,9 @@
        double congWeightFactor = globalPolicy == null ? 1.0d : globalPolicy.congWeightFactor;
        double passOtherOutStationPenaltyWeight = globalPolicy == null ? 0.0d : globalPolicy.passOtherOutStationPenaltyWeight;
        metrics.staticCost =
                safeDouble(profileConfig.getS1LenWeight(), 1.0d) * lenWeightFactor * metrics.pathLen
                        + safeDouble(profileConfig.getS1TurnWeight(), 3.0d) * metrics.turnCount
        metrics.baseLengthWeight = safeDouble(profileConfig.getS1LenWeight(), 1.0d) * lenWeightFactor;
        metrics.otherStaticCost =
                safeDouble(profileConfig.getS1TurnWeight(), 3.0d) * metrics.turnCount
                        + safeDouble(profileConfig.getS1LiftWeight(), 8.0d) * metrics.liftTransferCount
                        + passOtherOutStationPenaltyWeight * metrics.passOtherOutStationCount
                        + softDeviationWeight * metrics.softDeviationCount;
@@ -691,6 +730,105 @@
        int leftLiftCount = countLiftTransferCount(left);
        int rightLiftCount = countLiftTransferCount(right);
        return compareDouble(leftLen, rightLen, leftTurnCount, rightTurnCount, leftLiftCount, rightLiftCount);
    }
    private void applyPathLengthPreference(List<PathCandidateMetrics> metricsList,
                                           StationPathProfileConfig profileConfig,
                                           PathGlobalPolicy globalPolicy,
                                           Double pathLenFactor) {
        if (metricsList == null || metricsList.isEmpty()) {
            return;
        }
        double normalizedFactor = normalizePathLenFactor(pathLenFactor);
        int minPathLen = Integer.MAX_VALUE;
        int maxPathLen = Integer.MIN_VALUE;
        for (PathCandidateMetrics metrics : metricsList) {
            if (metrics == null) {
                continue;
            }
            minPathLen = Math.min(minPathLen, metrics.pathLen);
            maxPathLen = Math.max(maxPathLen, metrics.pathLen);
        }
        if (minPathLen == Integer.MAX_VALUE || maxPathLen == Integer.MIN_VALUE) {
            return;
        }
        double targetPathLen = normalizedFactor <= 0.0d || maxPathLen <= minPathLen
                ? minPathLen
                : minPathLen + normalizedFactor * (maxPathLen - minPathLen);
        for (PathCandidateMetrics metrics : metricsList) {
            if (metrics == null) {
                continue;
            }
            metrics.pathLenPreferenceDistance = normalizedFactor <= 0.0d
                    ? metrics.pathLen
                    : Math.abs(metrics.pathLen - targetPathLen);
            metrics.staticCost = metrics.baseLengthWeight * metrics.pathLenPreferenceDistance + metrics.otherStaticCost;
        }
    }
    private int compareStaticCandidateMetrics(PathCandidateMetrics left,
                                              PathCandidateMetrics right,
                                              Double pathLenFactor) {
        if (left == right) {
            return 0;
        }
        if (left == null) {
            return 1;
        }
        if (right == null) {
            return -1;
        }
        int result = Double.compare(left.staticCost, right.staticCost);
        if (result != 0) {
            return result;
        }
        result = Double.compare(left.pathLenPreferenceDistance, right.pathLenPreferenceDistance);
        if (result != 0) {
            return result;
        }
        result = Integer.compare(left.turnCount, right.turnCount);
        if (result != 0) {
            return result;
        }
        return comparePathLenTie(left.pathLen, right.pathLen, pathLenFactor);
    }
    private int compareDynamicCandidateMetrics(PathCandidateMetrics left,
                                               PathCandidateMetrics right,
                                               Double pathLenFactor) {
        if (left == right) {
            return 0;
        }
        if (left == null) {
            return 1;
        }
        if (right == null) {
            return -1;
        }
        int result = Double.compare(left.dynamicCost, right.dynamicCost);
        if (result != 0) {
            return result;
        }
        result = Double.compare(left.pathLenPreferenceDistance, right.pathLenPreferenceDistance);
        if (result != 0) {
            return result;
        }
        result = comparePathLenTie(left.pathLen, right.pathLen, pathLenFactor);
        if (result != 0) {
            return result;
        }
        return Integer.compare(left.turnCount, right.turnCount);
    }
    private int comparePathLenTie(int leftPathLen, int rightPathLen, Double pathLenFactor) {
        double normalizedFactor = normalizePathLenFactor(pathLenFactor);
        if (normalizedFactor <= 0.0d) {
            return Integer.compare(leftPathLen, rightPathLen);
        }
        if (normalizedFactor >= 0.5d) {
            return Integer.compare(rightPathLen, leftPathLen);
        }
        return Integer.compare(leftPathLen, rightPathLen);
    }
    private int countLiftTransferCount(List<NavigateNode> path) {
@@ -1087,18 +1225,46 @@
                    graph.computeIfAbsent(stationId, key -> new LinkedHashSet<>());
                    List<NavigateNode> nextNodeList = navigateSolution.extend_current_node(stationMap, node);
                    for (NavigateNode nextNode : safeList(nextNodeList)) {
                        Integer nextStationId = extractStationId(nextNode);
                        if (nextStationId == null || stationId.equals(nextStationId)) {
                            continue;
                        for (Integer nextStationId : resolveConnectedStationIds(stationId, nextNode)) {
                            if (nextStationId == null || stationId.equals(nextStationId)) {
                                continue;
                            }
                            graph.computeIfAbsent(nextStationId, key -> new LinkedHashSet<>());
                            graph.get(stationId).add(nextStationId);
                            graph.get(nextStationId).add(stationId);
                        }
                        graph.computeIfAbsent(nextStationId, key -> new LinkedHashSet<>());
                        graph.get(stationId).add(nextStationId);
                        graph.get(nextStationId).add(stationId);
                    }
                }
            }
        }
        return graph;
    }
    private Set<Integer> resolveConnectedStationIds(Integer currentStationId, NavigateNode nextNode) {
        Set<Integer> stationIdSet = new LinkedHashSet<>();
        if (nextNode == null || nextNode.getNodeValue() == null) {
            return stationIdSet;
        }
        try {
            JSONObject value = JSON.parseObject(nextNode.getNodeValue());
            if (value == null) {
                return stationIdSet;
            }
            Integer directStationId = value.getInteger("stationId");
            if (directStationId != null && !directStationId.equals(currentStationId)) {
                stationIdSet.add(directStationId);
            }
            JSONArray bridgeStationIds = value.getJSONArray("bridgeStationIds");
            if (bridgeStationIds != null) {
                for (Integer bridgeStationId : bridgeStationIds.toJavaList(Integer.class)) {
                    if (bridgeStationId != null && !bridgeStationId.equals(currentStationId)) {
                        stationIdSet.add(bridgeStationId);
                    }
                }
            }
        } catch (Exception ignore) {
        }
        return stationIdSet;
    }
    private List<Integer> loadStationLevList() {
@@ -1740,6 +1906,19 @@
        return value == null ? defaultValue : value;
    }
    private double normalizePathLenFactor(Double pathLenFactor) {
        if (pathLenFactor == null) {
            return 0.0d;
        }
        if (pathLenFactor < 0.0d) {
            return 0.0d;
        }
        if (pathLenFactor > 1.0d) {
            return 1.0d;
        }
        return pathLenFactor;
    }
    private boolean notBlank(String text) {
        return text != null && !text.trim().isEmpty();
    }
@@ -1815,8 +1994,8 @@
    }
    private List<NavigateNode> normalizeStationPath(List<NavigateNode> path) {
        HashSet<Integer> stationIdSet = new HashSet<>();
        List<NavigateNode> filterList = new ArrayList<>();
        Integer lastStationId = null;
        for (NavigateNode navigateNode : safeList(path)) {
            if (navigateNode == null) {
                continue;
@@ -1831,9 +2010,14 @@
                continue;
            }
            Integer stationId = valueObject.getInteger("stationId");
            if (stationId == null || !stationIdSet.add(stationId)) {
            if (stationId == null) {
                continue;
            }
            // 仅压缩连续重复站点,保留环线重算场景下后续再次经过的同一站点。
            if (lastStationId != null && lastStationId.equals(stationId)) {
                continue;
            }
            lastStationId = stationId;
            NavigateNode clonedNode = navigateNode.clone();
            if (clonedNode == null) {
                continue;
@@ -1922,6 +2106,9 @@
        private int runBlockCount;
        private int softDeviationCount;
        private double loopPenalty;
        private double baseLengthWeight;
        private double otherStaticCost;
        private double pathLenPreferenceDistance;
        private double staticCost;
        private double dynamicCost;
    }