jianghaiyue
16 小时以前 d808837cd368c3772962be591aa6532bcc0cf3e4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
package com.algo.util;
 
import com.algo.model.CTUPhysicalConfig;
import com.algo.model.PathCode;
import com.algo.model.PlannedPath;
 
import java.util.List;
import java.util.Map;
 
/**
 * 路径时间计算器
 * 统一处理路径中每个点的时间计算,确保在各个模块中计算的一致性
 * 考虑加减速、转向、停留等所有时间因素
 */
public class PathTimeCalculator {
 
    /**
     * 路径映射表(网格坐标)
     */
    private final Map<String, Map<String, Integer>> pathMapping;
    
    /**
     * 实际坐标映射表(物理坐标,毫米)
     */
    private final Map<String, double[]> realCoordinateMapping;
 
    public PathTimeCalculator(Map<String, Map<String, Integer>> pathMapping, 
                             Map<String, double[]> realCoordinateMapping) {
        this.pathMapping = pathMapping;
        this.realCoordinateMapping = realCoordinateMapping;
    }
 
    /**
     * 为路径计算时间信息
     *
     * @param path         规划路径
     * @param startTime    起始时间(毫秒时间戳)
     * @param config       CTU物理配置
     * @param initialSpeed 初始速度(米/秒)
     */
    public void calculatePathTiming(PlannedPath path, long startTime, 
                                   CTUPhysicalConfig config, double initialSpeed) {
        List<PathCode> codeList = path.getCodeList();
        if (codeList == null || codeList.isEmpty()) {
            return;
        }
 
        long currentTime = startTime;
        double currentSpeed = initialSpeed;
        
        for (int i = 0; i < codeList.size(); i++) {
            PathCode currentCode = codeList.get(i);
            
            // 设置到达时间
            currentCode.setArrivalTime(currentTime);
            
            // 计算在当前位置的停留时间
            double stayDuration = calculateStayDuration(currentCode, config);
            
            // 如果不是最后一个点,计算转向时间
            if (i < codeList.size() - 1) {
                PathCode nextCode = codeList.get(i + 1);
                double turnTime = calculateTurnTime(currentCode, nextCode, config);
                stayDuration += turnTime;
            }
            
            // 设置离开时间
            long departureTime = currentTime + (long)(stayDuration * 1000);
            currentCode.setDepartureTime(departureTime);
            
            // 计算累计时间
            currentCode.setCumulativeTime(departureTime - startTime);
            
            // 如果有下一个点,计算移动时间和速度变化
            if (i < codeList.size() - 1) {
                PathCode nextCode = codeList.get(i + 1);
                
                // 计算精确的移动时间(考虑加减速)
                MovementTimeResult movement = calculatePreciseMovementTime(
                    currentCode, nextCode, currentSpeed, config
                );
                
                currentTime = departureTime + movement.travelTime;
                currentSpeed = movement.endSpeed;
            }
        }
    }
 
    /**
     * 计算两点间移动时间
     */
    private MovementTimeResult calculatePreciseMovementTime(PathCode fromCode, PathCode toCode, 
                                                          double startSpeed, CTUPhysicalConfig config) {
        // 获取实际距离
        double realDistance = getRealDistance(fromCode.getCode(), toCode.getCode());
        
        if (realDistance <= 0) {
            // 备用:使用网格距离
            realDistance = getGridDistance(fromCode.getCode(), toCode.getCode()) 
                         * config.getStandardPointDistance();
        }
        
        // 确定目标速度(考虑是否为目标点)
        double targetSpeed = toCode.isTargetPoint() ? 0.0 : config.getNormalSpeed();
        
        // 使用物理配置的精确计算方法
        double movementTime = config.calculatePreciseMovementTime(
            realDistance, startSpeed, targetSpeed, config.getNormalSpeed()
        );
        
        return new MovementTimeResult((long)(movementTime * 1000), targetSpeed);
    }
 
    /**
     * 计算在路径点的停留时间
     */
    private double calculateStayDuration(PathCode pathCode, CTUPhysicalConfig config) {
        double stayTime = 0.1; // 基础停留时间100ms
        
        // 根据动作类型增加停留时间
        if (pathCode.getActionType() != null) {
            switch (pathCode.getActionType()) {
                case "1": // 取货
                    stayTime += 10.0;
                    break;
                case "2": // 放货
                    stayTime += 10.0;
                    break;
                case "3": // 充电
                    stayTime += 600.0;
                    break;
                default:
                    stayTime += 0.5;
                    break;
            }
        } else if (pathCode.isTargetPoint()) {
            // 目标点停留时间
            if ("1".equals(pathCode.getPosType())) {
                stayTime += 10.0; // 取货
            } else if ("2".equals(pathCode.getPosType())) {
                stayTime += 10.0; // 放货
            } else {
                stayTime += 10.0; // 其他目标点
            }
        }
        
        return stayTime;
    }
 
    /**
     * 计算转向时间
     */
    private double calculateTurnTime(PathCode fromCode, PathCode toCode, CTUPhysicalConfig config) {
        if (fromCode.getDirection().equals(toCode.getDirection())) {
            return 0.0;
        }
        
        // 使用配置的转向时间计算方法
        return config.getTurnTime(fromCode.getDirection(), toCode.getDirection());
    }
 
    /**
     * 获取实际物理距离
     */
    private double getRealDistance(String fromCode, String toCode) {
        if (realCoordinateMapping == null) {
            return 0.0;
        }
        
        double[] fromCoord = realCoordinateMapping.get(fromCode);
        double[] toCoord = realCoordinateMapping.get(toCode);
        
        if (fromCoord != null && toCoord != null) {
            return CTUPhysicalConfig.calculateRealDistance(fromCoord, toCoord);
        }
        
        return 0.0;
    }
 
    /**
     * 获取网格距离
     */
    private double getGridDistance(String fromCode, String toCode) {
        int[] fromCoord = JsonUtils.getCoordinate(fromCode, pathMapping);
        int[] toCoord = JsonUtils.getCoordinate(toCode, pathMapping);
        
        if (fromCoord != null && toCoord != null) {
            return JsonUtils.calculateEuclideanDistance(fromCoord, toCoord);
        }
        
        return 1.0; // 默认距离
    }
 
    /**
     * 计算路径中指定位置之后的时间(用于冲突解决)
     *
     * @param path      路径
     * @param fromIndex 开始重新计算的索引
     * @param config    物理配置
     */
    public void recalculatePathTimingFromIndex(PlannedPath path, int fromIndex, CTUPhysicalConfig config) {
        List<PathCode> codeList = path.getCodeList();
        if (codeList == null || fromIndex >= codeList.size()) {
            return;
        }
        
        // 获取重新计算起点的时间和速度
        PathCode startCode = codeList.get(fromIndex);
        long startTime = startCode.getDepartureTime() != null ? 
                        startCode.getDepartureTime() : startCode.getArrivalTime();
        
        // 估算当前速度
        double currentSpeed = config.getNormalSpeed();
        
        // 从指定位置开始重新计算
        long currentTime = startTime;
        
        for (int i = fromIndex + 1; i < codeList.size(); i++) {
            PathCode currentCode = codeList.get(i);
            PathCode previousCode = codeList.get(i - 1);
            
            // 计算移动时间
            MovementTimeResult movement = calculatePreciseMovementTime(
                previousCode, currentCode, currentSpeed, config
            );
            
            currentTime += movement.travelTime;
            currentSpeed = movement.endSpeed;
            
            // 设置到达时间
            currentCode.setArrivalTime(currentTime);
            
            // 计算停留时间
            double stayDuration = calculateStayDuration(currentCode, config);
            
            // 如果不是最后一个点,增加转向时间
            if (i < codeList.size() - 1) {
                PathCode nextCode = codeList.get(i + 1);
                double turnTime = calculateTurnTime(currentCode, nextCode, config);
                stayDuration += turnTime;
            }
            
            // 设置离开时间
            long departureTime = currentTime + (long)(stayDuration * 1000);
            currentCode.setDepartureTime(departureTime);
            
            // 更新累计时间
            long pathStartTime = codeList.get(0).getArrivalTime();
            currentCode.setCumulativeTime(departureTime - pathStartTime);
            
            currentTime = departureTime;
        }
    }
 
    /**
     * 计算路径的总执行时间
     */
    public long calculateTotalPathTime(PlannedPath path) {
        List<PathCode> codeList = path.getCodeList();
        if (codeList == null || codeList.isEmpty()) {
            return 0;
        }
        
        PathCode firstCode = codeList.get(0);
        PathCode lastCode = codeList.get(codeList.size() - 1);
        
        if (firstCode.getArrivalTime() != null && lastCode.getDepartureTime() != null) {
            return lastCode.getDepartureTime() - firstCode.getArrivalTime();
        }
        
        return 0;
    }
 
    /**
     * 检查路径在指定时间窗口是否与占用表冲突
     */
    public boolean isPathTimeConflictFree(PlannedPath path, Map<String, String> occupancyMap) {
        List<PathCode> codeList = path.getCodeList();
        if (codeList == null || codeList.isEmpty()) {
            return true;
        }
        
        for (PathCode pathCode : codeList) {
            if (pathCode.getArrivalTime() == null || pathCode.getDepartureTime() == null) {
                continue;
            }
            
            int[] coord = JsonUtils.getCoordinate(pathCode.getCode(), pathMapping);
            if (coord == null) continue;
            
            // 检查整个停留时间段
            long startTimeSlot = pathCode.getArrivalTime() / 1000;
            long endTimeSlot = pathCode.getDepartureTime() / 1000;
            
            for (long timeSlot = startTimeSlot; timeSlot <= endTimeSlot; timeSlot++) {
                String spaceTimeKey = coord[0] + "," + coord[1] + "," + timeSlot;
                if (occupancyMap.containsKey(spaceTimeKey)) {
                    return false;
                }
            }
        }
        
        return true;
    }
 
    /**
     * 移动时间计算结果
     */
    private static class MovementTimeResult {
        final long travelTime; // 移动时间(毫秒)
        final double endSpeed; // 结束速度(米/秒)
        
        public MovementTimeResult(long travelTime, double endSpeed) {
            this.travelTime = travelTime;
            this.endSpeed = endSpeed;
        }
    }
}