package com.zy.acs.manager.core.service;
|
|
import com.zy.acs.framework.common.Cools;
|
import com.zy.acs.manager.core.domain.ReservedTimeWindow;
|
import com.zy.acs.manager.core.domain.TimeWindow;
|
import org.springframework.stereotype.Service;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* dynamic time window
|
* Created by vincent on 11/1/2024
|
*/
|
@Service
|
public class TimeWindowService {
|
|
public static final Map<String, List<TimeWindow>> TIME_WINDOW_MAP = new ConcurrentHashMap<>();
|
|
// reserve --------------------------------------------------------------------
|
|
public synchronized boolean reserveTimeWindows(String agvNo, List<String> pathList) {
|
if (Cools.isEmpty(agvNo, pathList)) {
|
return false;
|
}
|
|
long estimatedTime = System.currentTimeMillis();
|
|
List<ReservedTimeWindow> reservedWindows = new ArrayList<>();
|
|
for (int i = 0; i < pathList.size() - 1; i++) {
|
String fromCode = pathList.get(i);
|
String toCode = pathList.get(i + 1);
|
String twKey = fromCode + "_" + toCode;
|
|
long twStartTime = estimatedTime;
|
long twEndTime = estimatedTime + estimateTravelTime(fromCode, toCode, agvNo);
|
|
TimeWindow timeWindow = new TimeWindow(twStartTime, twEndTime, agvNo);
|
|
boolean success = reserveTimeWindow(twKey, timeWindow);
|
if (!success) {
|
// 预定失败,释放已预定的时间窗口
|
releaseReservedTimeWindows(reservedWindows);
|
return false;
|
}
|
|
reservedWindows.add(new ReservedTimeWindow(twKey, timeWindow));
|
|
estimatedTime = twEndTime;
|
}
|
|
return true;
|
}
|
|
// 预定时间窗口
|
public synchronized boolean reserveTimeWindow(String twKey, TimeWindow window) {
|
|
List<TimeWindow> windows = TIME_WINDOW_MAP.getOrDefault(twKey, new ArrayList<>());
|
|
for (TimeWindow reservedWindow : windows) {
|
if (reservedWindow.isConflict(window)) {
|
return false;
|
}
|
}
|
|
windows.add(window);
|
TIME_WINDOW_MAP.put(twKey, windows);
|
return true;
|
}
|
|
|
// release ------------------------------------------------------------------
|
|
public synchronized void releasePathTimeWindows(String agvNo, List<String> pathList) {
|
for (int i = 0; i < pathList.size() - 1; i++) {
|
String fromCode = pathList.get(i);
|
String toCode = pathList.get(i + 1);
|
String twKey = fromCode + "_" + toCode;
|
|
// 查找并释放时间窗口
|
releaseTimeWindow(twKey, agvNo);
|
}
|
}
|
|
public synchronized void releaseTimeWindow(String twKey, String agvNo) {
|
List<TimeWindow> windows = TIME_WINDOW_MAP.get(twKey);
|
if (windows != null) {
|
windows.removeIf(window -> window.getAgvNo().equals(agvNo));
|
if (windows.isEmpty()) {
|
TIME_WINDOW_MAP.remove(twKey);
|
}
|
}
|
}
|
|
private void releaseReservedTimeWindows(List<ReservedTimeWindow> reservedWindows) {
|
for (ReservedTimeWindow reserved : reservedWindows) {
|
releaseTimeWindow(reserved.getTwKey(), reserved.getTimeWindow().getAgvNo());
|
}
|
}
|
|
// util --------------------------------------------------------------------------------------
|
|
private long estimateTravelTime(String fromCode, String toCode, String agvNo) {
|
// 根据距离和AGV速度估算行驶时间
|
double distance = 1000;
|
double speed = 2; // 获取AGV速度,单位:米/秒
|
return (long) (distance / speed * 1000); // 转换为毫秒
|
}
|
|
}
|