package com.algo.model; import java.util.List; import java.util.Objects; /** * AGV状态信息 * 包含AGV的完整状态数据,包括剩余路径和CTU物理参数 */ public class AGVStatus { /** * AGV编号 */ private String agvId; /** * AGV状态 */ private int status; /** * AGV当前位置 */ private String position; /** * 空背篓数量 */ private String empty; /** * AGV方向角度 */ private String direction; /** * 电压电量值 */ private int vol; /** * 异常码,0表示正常 */ private int error; /** * 背篓数据列表 */ private List backpack; /** * 低电量设定阈值,低于该值可以去自动充电也可以继续做任务 */ private int autoCharge; /** * 最低电量,电量低于该值必须去充电 */ private int lowVol; /** * CTU剩余未完成的路径,格式与输出路径相同 */ private PlannedPath remainingPath; /** * CTU物理参数配置 */ private CTUPhysicalConfig physicalConfig; /** * 当前执行路径中的位置索引(从剩余路径开始计算) */ private int currentPathIndex; /** * 预计到达下一个路径点的时间戳(毫秒) */ private long nextPointArrivalTime; // 构造函数 public AGVStatus() { this.physicalConfig = new CTUPhysicalConfig(); // 使用默认配置 this.currentPathIndex = 0; this.nextPointArrivalTime = System.currentTimeMillis(); } public AGVStatus(String agvId, int status, String position, String empty, String direction, int vol, int error, List backpack, int autoCharge, int lowVol) { this.agvId = agvId; this.status = status; this.position = position; this.empty = empty; this.direction = direction; this.vol = vol; this.error = error; this.backpack = backpack; this.autoCharge = autoCharge; this.lowVol = lowVol; this.physicalConfig = new CTUPhysicalConfig(); // 使用默认配置 this.currentPathIndex = 0; this.nextPointArrivalTime = System.currentTimeMillis(); } // 原有的Getter和Setter方法 public String getAgvId() { return agvId; } public void setAgvId(String agvId) { this.agvId = agvId; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public String getEmpty() { return empty; } public void setEmpty(String empty) { this.empty = empty; } public String getDirection() { return direction; } public void setDirection(String direction) { this.direction = direction; } public int getVol() { return vol; } public void setVol(int vol) { this.vol = vol; } public int getError() { return error; } public void setError(int error) { this.error = error; } public List getBackpack() { return backpack; } public void setBackpack(List backpack) { this.backpack = backpack; } public int getAutoCharge() { return autoCharge; } public void setAutoCharge(int autoCharge) { this.autoCharge = autoCharge; } public int getLowVol() { return lowVol; } public void setLowVol(int lowVol) { this.lowVol = lowVol; } // 新增的剩余路径和物理参数相关的Getter和Setter方法 public PlannedPath getRemainingPath() { return remainingPath; } public void setRemainingPath(PlannedPath remainingPath) { this.remainingPath = remainingPath; } public CTUPhysicalConfig getPhysicalConfig() { return physicalConfig; } public void setPhysicalConfig(CTUPhysicalConfig physicalConfig) { this.physicalConfig = physicalConfig; } public int getCurrentPathIndex() { return currentPathIndex; } public void setCurrentPathIndex(int currentPathIndex) { this.currentPathIndex = currentPathIndex; } public long getNextPointArrivalTime() { return nextPointArrivalTime; } public void setNextPointArrivalTime(long nextPointArrivalTime) { this.nextPointArrivalTime = nextPointArrivalTime; } /** * 检查CTU是否有剩余未完成的路径 * * @return true如果有剩余路径 */ public boolean hasRemainingPath() { return remainingPath != null && remainingPath.getCodeList() != null && !remainingPath.getCodeList().isEmpty() && currentPathIndex < remainingPath.getCodeList().size(); } /** * 获取剩余路径的长度(从当前位置开始) * * @return 剩余路径点数量 */ public int getRemainingPathLength() { if (!hasRemainingPath()) { return 0; } return remainingPath.getCodeList().size() - currentPathIndex; } /** * 获取当前正在执行的路径点 * * @return 当前路径点,如果没有则返回null */ public PathCode getCurrentPathCode() { if (!hasRemainingPath()) { return null; } return remainingPath.getCodeList().get(currentPathIndex); } /** * 获取下一个要到达的路径点 * * @return 下一个路径点,如果没有则返回null */ public PathCode getNextPathCode() { if (!hasRemainingPath() || currentPathIndex + 1 >= remainingPath.getCodeList().size()) { return null; } return remainingPath.getCodeList().get(currentPathIndex + 1); } /** * 检查AGV是否可用(空闲且非故障状态) * * @return true如果AGV可用 */ public boolean isAvailable() { return error == 0 && status == 0 && vol > lowVol; } /** * 检查CTU是否可以接受新任务(考虑剩余路径) * * @return true如果可以接受新任务 */ public boolean canAcceptNewTask() { // 如果有剩余路径,需要等待完成后才能接受新任务 // 除非剩余路径很短(比如只有1个点) if (hasRemainingPath()) { int remainingLength = getRemainingPathLength(); return remainingLength <= 1; // 允许在即将完成当前路径时接受新任务 } return isAvailable(); } /** * 获取可用的背篓数量 * * @return 可用背篓数量 */ public int getAvailableBackpackCount() { if (backpack == null || backpack.isEmpty()) { return 0; } int count = 0; for (BackpackData bp : backpack) { if (!bp.isLoaded() && bp.getTaskId() == null) { count++; } } return count; } /** * 查找可用的背篓位置 * * @return 可用背篓的索引,如果没有可用则返回-1 */ public int findAvailableBackpackIndex() { if (backpack == null || backpack.isEmpty()) { return -1; } for (BackpackData bp : backpack) { if (!bp.isLoaded() && bp.getTaskId() == null) { return bp.getIndex(); } } return -1; } /** * 检查AGV是否需要充电 * * @return true如果需要充电 */ public boolean needsCharging() { return vol <= autoCharge; } /** * 检查AGV是否必须充电 * * @return true如果必须充电 */ public boolean mustCharge() { return vol <= lowVol; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AGVStatus agvStatus = (AGVStatus) o; return Objects.equals(agvId, agvStatus.agvId); } @Override public int hashCode() { return Objects.hash(agvId); } @Override public String toString() { return "AGVStatus{" + "agvId='" + agvId + '\'' + ", status=" + status + ", position='" + position + '\'' + ", empty='" + empty + '\'' + ", direction='" + direction + '\'' + ", vol=" + vol + ", error=" + error + ", backpack=" + (backpack != null ? backpack.size() : 0) + ", autoCharge=" + autoCharge + ", lowVol=" + lowVol + ", hasRemainingPath=" + hasRemainingPath() + ", remainingPathLength=" + getRemainingPathLength() + ", physicalConfig=" + physicalConfig + '}'; } }