From 103ca74d9b67ce4f766b5f77451741a76fa696b9 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期日, 22 三月 2026 09:50:10 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/common/utils/NavigateUtils.java |  177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 165 insertions(+), 12 deletions(-)

diff --git a/src/main/java/com/zy/common/utils/NavigateUtils.java b/src/main/java/com/zy/common/utils/NavigateUtils.java
index 6219dbc..e867aa7 100644
--- a/src/main/java/com/zy/common/utils/NavigateUtils.java
+++ b/src/main/java/com/zy/common/utils/NavigateUtils.java
@@ -73,20 +73,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 +116,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 +147,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 +296,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 +309,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 +382,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 +406,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 +415,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 +686,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 +729,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) {
@@ -1740,6 +1877,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();
     }
@@ -1922,6 +2072,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;
     }

--
Gitblit v1.9.1