package com.zy.acs.manager.core.service; 
 | 
  
 | 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 
 | 
import com.zy.acs.common.utils.GsonUtils; 
 | 
import com.zy.acs.common.utils.Utils; 
 | 
import com.zy.acs.framework.common.Cools; 
 | 
import com.zy.acs.framework.common.SnowflakeIdWorker; 
 | 
import com.zy.acs.framework.exception.CoolException; 
 | 
import com.zy.acs.manager.common.utils.MapDataUtils; 
 | 
import com.zy.acs.manager.core.constant.MapDataConstant; 
 | 
import com.zy.acs.manager.core.domain.BlockVehicleDto; 
 | 
import com.zy.acs.manager.core.domain.TaskPosDto; 
 | 
import com.zy.acs.manager.core.domain.type.BlockSeverityType; 
 | 
import com.zy.acs.manager.core.service.astart.MapDataDispatcher; 
 | 
import com.zy.acs.manager.core.service.astart.NavigateNode; 
 | 
import com.zy.acs.manager.core.service.astart.RetreatNavigateNode; 
 | 
import com.zy.acs.manager.core.service.astart.WaveNodeType; 
 | 
import com.zy.acs.manager.manager.entity.*; 
 | 
import com.zy.acs.manager.manager.enums.JamStateType; 
 | 
import com.zy.acs.manager.manager.enums.SegmentStateType; 
 | 
import com.zy.acs.manager.manager.enums.TaskTypeType; 
 | 
import com.zy.acs.manager.manager.service.*; 
 | 
import com.zy.acs.manager.system.service.ConfigService; 
 | 
import lombok.extern.slf4j.Slf4j; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.stereotype.Component; 
 | 
import org.springframework.transaction.annotation.Transactional; 
 | 
import org.springframework.transaction.interceptor.TransactionAspectSupport; 
 | 
  
 | 
import java.util.ArrayList; 
 | 
import java.util.Arrays; 
 | 
import java.util.Date; 
 | 
import java.util.List; 
 | 
import java.util.stream.Collectors; 
 | 
  
 | 
/** 
 | 
 * Wavefront 
 | 
 * Created by vincent on 6/25/2024 
 | 
 */ 
 | 
@Slf4j 
 | 
@Component 
 | 
public class TrafficService { 
 | 
  
 | 
    @Autowired 
 | 
    private AgvService agvService; 
 | 
    @Autowired 
 | 
    private AgvDetailService agvDetailService; 
 | 
    @Autowired 
 | 
    private CodeService codeService; 
 | 
    @Autowired 
 | 
    private TravelService travelService; 
 | 
    @Autowired 
 | 
    private SegmentService segmentService; 
 | 
    @Autowired 
 | 
    private MainService mainService; 
 | 
    @Autowired 
 | 
    private MainLockWrapService mainLockWrapService; 
 | 
    @Autowired 
 | 
    private MapService mapService; 
 | 
    @Autowired 
 | 
    private MapDataDispatcher mapDataDispatcher; 
 | 
    @Autowired 
 | 
    private SnowflakeIdWorker snowflakeIdWorker; 
 | 
    @Autowired 
 | 
    private AgvModelService agvModelService; 
 | 
    @Autowired 
 | 
    private RetreatNavigateService retreatNavigateService; 
 | 
    @Autowired 
 | 
    private ConfigService configService; 
 | 
    @Autowired 
 | 
    private JamService jamService; 
 | 
    @Autowired 
 | 
    private AvoidWaveCalculator avoidWaveCalculator; 
 | 
    @Autowired 
 | 
    private TaskService taskService; 
 | 
    @Autowired 
 | 
    private FuncStaService funcStaService; 
 | 
  
 | 
    @Transactional 
 | 
    public synchronized void trigger(Segment segment) { 
 | 
        try { 
 | 
            Date now = new Date(); 
 | 
  
 | 
            // deprecate jam 
 | 
            if (this.isExpiredJamByAvo(segment.getId())) { 
 | 
                mainService.settleSegmentList(Utils.singletonList(segment), null); 
 | 
                return; 
 | 
            } 
 | 
  
 | 
            // temporary ----------------- 
 | 
            Integer algoExtensionTime = configService.getVal("algoExtensionTime", Integer.class); 
 | 
            if (null != algoExtensionTime && algoExtensionTime > 0) { 
 | 
                Thread.sleep(algoExtensionTime); 
 | 
            } 
 | 
            // --------------------------- 
 | 
  
 | 
            Travel travel = travelService.getById(segment.getTravelId()); 
 | 
            Agv agv = agvService.getById(travel.getAgvId()); 
 | 
            AgvDetail agvDetail = agvDetailService.selectByAgvId(travel.getAgvId()); 
 | 
            long endNode = segment.getEndNode(); 
 | 
  
 | 
            // valid ---------------------------------------------------- 
 | 
            if (!agvService.judgeEnable(agv.getId())) { 
 | 
                return; 
 | 
            } 
 | 
  
 | 
            // resolve deadlock 
 | 
//            if (configService.getVal("unlockSwitch", Boolean.class)) { 
 | 
// 
 | 
//                boolean preSegIsStandbyDeadLock = false; 
 | 
//                Segment previousSeg = segmentService.getPreviousStepOfFinish(segment.getTravelId(), segment.getSerial(), MapDataConstant.RESOLVE_DEADLOCK); 
 | 
//                preSegIsStandbyDeadLock = previousSeg != null; 
 | 
//                if (preSegIsStandbyDeadLock && !jamService.isAvoidSeg(segment.getId())) { 
 | 
//                    if (0 < segmentService.count(new LambdaQueryWrapper<Segment>() 
 | 
//                            .in(Segment::getState, SegmentStateType.WAITING.toString(), SegmentStateType.RUNNING.toString()) 
 | 
//                            .eq(Segment::getMemo, MapDataConstant.RESOLVE_DEADLOCK))) { 
 | 
//                        return; 
 | 
//                    } 
 | 
//                } 
 | 
// 
 | 
//                Jam jam = jamService.getJam(agv.getId(), agvDetail.getRecentCode(), segment.getId()); 
 | 
//                if (!preSegIsStandbyDeadLock && (null != jam && null != jam.getDuration() && jam.getDuration() > (BlockSeverityType.SEVERE.duration - MapDataConstant.MAX_JAM_TIMEOUT) 
 | 
//                        || DateUtils.diffToMilliseconds(segment.getUpdateTime(), now)  > (BlockSeverityType.SEVERE.duration - MapDataConstant.MAX_JAM_TIMEOUT)) 
 | 
//                        && (Cools.isEmpty(segment.getMemo()) || !segment.getMemo().equals(MapDataConstant.RESOLVE_DEADLOCK))) { 
 | 
// 
 | 
//                    Task task = taskService.getById(segment.getTaskId()); 
 | 
//                    if (task.getTaskSts().equals(TaskStsType.PROGRESS.val()) 
 | 
//                            && DateUtils.diffToMilliseconds(task.getUpdateTime(), now) > MapDataConstant.DEADLOCK_TASK_TIMEOUT) { 
 | 
// 
 | 
//                        Code endCode = null; 
 | 
//                        List<FuncSta> idleFunStaList = funcStaService.findInIdleStatus(FuncStaType.STANDBY, segment.getAgvId()); 
 | 
//                        if (!Cools.isEmpty(idleFunStaList)) { 
 | 
//                            idleFunStaList = idleFunStaList.stream().filter(funcSta -> { 
 | 
//                                return 0 == segmentService.count(new LambdaQueryWrapper<Segment>() 
 | 
//                                                .eq(Segment::getEndNode, funcSta.getCode()) 
 | 
//                                                .in(Segment::getState, SegmentStateType.WAITING.toString(), SegmentStateType.RUNNING.toString()) 
 | 
//                                                .eq(Segment::getMemo, MapDataConstant.RESOLVE_DEADLOCK) 
 | 
//                                ); 
 | 
//                            }).collect(Collectors.toList()); 
 | 
//                            FuncSta funcSta = funcStaService.checkoutFurthestFunSta(agvDetailService.getCurrentCode(segment.getAgvId()).getId(), idleFunStaList); 
 | 
//                            if (null != funcSta) { 
 | 
//                                endCode = codeService.getCacheById(funcSta.getCode()); 
 | 
//                            } 
 | 
//                        } 
 | 
//                        if (null == endCode) { 
 | 
//                            log.warn("AGV[{}] failed to search destination,there hadn't any idle funSta,TaskTypeType:{}", segment.getAgvId(), FuncStaType.STANDBY); 
 | 
//                            return; 
 | 
//                        } 
 | 
// 
 | 
//                        segment.setState(SegmentStateType.INIT.toString()); 
 | 
//                        segment.setUpdateTime(now); 
 | 
//                        if (!segmentService.updateById(segment)) { 
 | 
//                            log.error("Segment [{}] failed to update !!!", segment.getGroupId() + " - " + segment.getSerial()); 
 | 
//                            return; 
 | 
//                        } 
 | 
// 
 | 
//                        // new move seg 
 | 
//                        Segment insertSeg = new Segment(); 
 | 
//                        insertSeg.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); 
 | 
//                        insertSeg.setTravelId(segment.getTravelId()); 
 | 
//                        insertSeg.setAgvId(segment.getAgvId()); 
 | 
//                        insertSeg.setTaskId(segment.getTaskId()); 
 | 
//                        insertSeg.setSerial(segment.getSerial() - 1); 
 | 
//                        insertSeg.setEndNode(endCode.getId()); 
 | 
//                        insertSeg.setPosType(TaskPosDto.PosType.MOVE.toString()); 
 | 
//                        insertSeg.setState(SegmentStateType.WAITING.toString()); 
 | 
//                        insertSeg.setMemo(MapDataConstant.RESOLVE_DEADLOCK); 
 | 
//                        if (!segmentService.save(insertSeg)) { 
 | 
//                            log.error("Segment [{}] failed to save !!!", segment.getTravelId() + " - " + segment.getSerial()); 
 | 
//                            return; 
 | 
//                        } 
 | 
//                        return; 
 | 
//                    } 
 | 
//                } 
 | 
//            } 
 | 
  
 | 
            if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { 
 | 
                return; 
 | 
            } 
 | 
            List<Segment> waitingSegList = segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString()); 
 | 
            if (!Cools.isEmpty(waitingSegList)) { 
 | 
                for (Segment waitingSeg : waitingSegList) { 
 | 
                    if (!waitingSeg.getId().equals(segment.getId())) { 
 | 
//                        log.error("AGV[{}] 任务异常,服务器错误!!!", agv.getUuid()); 
 | 
                        return; 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
  
 | 
            // dead lane 
 | 
            if (jamService.count(new LambdaQueryWrapper<Jam>() 
 | 
                    .eq(Jam::getJamAgv, agv.getId()) 
 | 
                    .eq(Jam::getJamSeg, segment.getId()) 
 | 
                    .eq(Jam::getCycleAvo, 1) 
 | 
                    .eq(Jam::getCycleCode, endNode) 
 | 
                    .eq(Jam::getState, JamStateType.RUNNING.toString()) 
 | 
            ) > 0) { 
 | 
                return; 
 | 
            } 
 | 
  
 | 
            // execute ----------------------------------------------- 
 | 
            //        ArrayList<List<TaskPosDto>> list = JSON.parseObject(travel.getTaskContent(), new TypeReference<ArrayList<List<TaskPosDto>>>() {}); 
 | 
  
 | 
            // * sync wave scope 
 | 
            if (!avoidWaveCalculator.calcWaveScope()) { 
 | 
                log.error("failed to calculate avoid wave matrix ..."); 
 | 
                return; 
 | 
            } 
 | 
  
 | 
            // checkout path 
 | 
            Code startCode = codeService.getCacheById(agvDetail.getRecentCode()); 
 | 
            Code endCode = codeService.getCacheById(endNode); 
 | 
            long startTime = System.currentTimeMillis(); 
 | 
            List<String> pathList = this.checkoutPath(agv, startCode, endCode, segment); 
 | 
//            System.out.println("checkoutPath: " + (System.currentTimeMillis() - startTime)); 
 | 
            if (Cools.isEmpty(pathList)) { 
 | 
                return; 
 | 
            } 
 | 
  
 | 
            List<Segment> segmentList = new ArrayList<>(); 
 | 
            segmentList.add(segment); 
 | 
  
 | 
            String lastCodeData = pathList.get(pathList.size() - 1); 
 | 
            if (!endCode.getData().equals(lastCodeData)) { 
 | 
                // slice 
 | 
                Code lastCode = codeService.getCacheByData(lastCodeData); 
 | 
  
 | 
//                if (pathList.size() <= MIN_SLICE_PATH_LENGTH) { 
 | 
//                    return; 
 | 
//                } 
 | 
  
 | 
                // revert 
 | 
                segment.setState(SegmentStateType.INIT.toString()); 
 | 
                segment.setUpdateTime(now); 
 | 
                if (!segmentService.updateById(segment)) { 
 | 
                    log.error("Segment [{}] failed to update !!!", segment.getGroupId() + " - " + segment.getSerial()); 
 | 
                } 
 | 
                segmentList.clear(); 
 | 
  
 | 
                // new move seg 
 | 
                Segment insertSeg = new Segment(); 
 | 
                insertSeg.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); 
 | 
                insertSeg.setTravelId(travel.getId()); 
 | 
                insertSeg.setAgvId(agv.getId()); 
 | 
                insertSeg.setTaskId(segment.getTaskId()); 
 | 
                insertSeg.setSerial(segment.getSerial() - 1); 
 | 
                insertSeg.setEndNode(lastCode.getId()); 
 | 
                insertSeg.setPosType(TaskPosDto.PosType.MOVE.toString()); 
 | 
                insertSeg.setState(SegmentStateType.WAITING.toString()); 
 | 
                if (!segmentService.save(insertSeg)) { 
 | 
                    log.error("Segment [{}] failed to save !!!", segment.getTravelId() + " - " + segment.getSerial()); 
 | 
                } 
 | 
                segmentList.add(insertSeg); 
 | 
  
 | 
            } else { 
 | 
  
 | 
                // complete first segment then merge behind segment 
 | 
                int serial = segment.getSerial(); 
 | 
                boolean interrupt = false; 
 | 
                while (!interrupt) { 
 | 
  
 | 
                    Segment nextStep = segmentService.getNextStepOfInit(travel.getId(), serial); 
 | 
                    serial ++; 
 | 
                    if (null == nextStep) { 
 | 
                        interrupt = true; 
 | 
                    } else { 
 | 
                        if (nextStep.getEndNode() == endNode) { 
 | 
  
 | 
                            segmentList.add(nextStep); 
 | 
                        } else { 
 | 
                            interrupt = true; 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                } 
 | 
            } 
 | 
  
 | 
            mapService.lockPath(null, pathList, agv.getUuid()); 
 | 
  
 | 
            startTime = System.currentTimeMillis(); 
 | 
            mainService.generateAction(segment.getAgvId(), segmentList, pathList, now); 
 | 
//            System.out.println("generateAction: " + (System.currentTimeMillis() - startTime)); 
 | 
  
 | 
        } catch (Exception e) { 
 | 
            log.error("TrafficService.trigger", e); 
 | 
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    private List<String> checkoutPath(Agv agv, Code startCode, Code endCode, Segment segment) { 
 | 
        Integer lev = null; 
 | 
        String agvNo = agv.getUuid(); 
 | 
        Date now = new Date(); 
 | 
        Jam jam = jamService.getJam(agv.getId(), startCode.getId(), segment.getId()); 
 | 
        BlockSeverityType blockSeverity = BlockSeverityType.query(null == jam ? null : jam.getDuration()); 
 | 
        // judge avoid of jam 如果已经在避让点(因为当前车执行了避让任务),那么则不能再去检索之前的阻塞路径 
 | 
        List<Jam> unfinishedOriginJamByCurrAgv = jamService.getUnfinishedOriginJamByAvo(agv.getId(), startCode.getId(), segment.getId()); 
 | 
        List<String> blackPath = this.getBlackPathList(unfinishedOriginJamByCurrAgv); 
 | 
  
 | 
        // 结果集 
 | 
        List<String> pathList = new ArrayList<>(); 
 | 
  
 | 
        // 无障碍解 
 | 
        List<String> unlockPathList = mapService.checkoutPath(agvNo, startCode, endCode, false, blackPath, segment); 
 | 
        // 避让解 
 | 
        List<String> lockPathList = mapService.checkoutPath(agvNo, startCode, endCode, true, blackPath, segment); 
 | 
  
 | 
        if (!Cools.isEmpty(lockPathList) && // 存在避让解 
 | 
            Math.abs(lockPathList.size() - unlockPathList.size()) <= Arrays.stream(mapDataDispatcher.getCodeMatrix(lev)).mapToInt(row -> row.length).sum() / 10 
 | 
        ) { 
 | 
  
 | 
            pathList = lockPathList; 
 | 
        } else { 
 | 
  
 | 
            // preview path 
 | 
            List<String> draftPath = new ArrayList<>(unlockPathList); 
 | 
            if (blockSeverity.equals(BlockSeverityType.SEVERE)) { 
 | 
                unlockPathList.remove(endCode.getData()); 
 | 
                blackPath.addAll(unlockPathList); 
 | 
                List<String> newUnlockPathList = mapService.checkoutPath(agvNo, startCode, endCode, false, blackPath, segment); 
 | 
                if (!Cools.isEmpty(newUnlockPathList)) { 
 | 
                    draftPath = newUnlockPathList; 
 | 
                } 
 | 
            } 
 | 
            // 可走行路径集合计算 
 | 
            List<BlockVehicleDto> blockVehicleList = this.slicePathAndReturnBlockVehicleList(lev, draftPath, agvNo, pathList);    // jamAgvNo may was wave 
 | 
  
 | 
            if (!Cools.isEmpty(pathList)) { 
 | 
  
 | 
                if (!pathList.get(pathList.size() - 1).equals(endCode.getData())) { 
 | 
                    assert !Cools.isEmpty(blockVehicleList); 
 | 
  
 | 
                    boolean hasUnavoidableBlocks = blockVehicleList.stream().anyMatch(blockVehicleDto -> !blockVehicleDto.isAvoidable()); 
 | 
                    if (hasUnavoidableBlocks && pathList.size() <= MapDataConstant.MIN_SLICE_PATH_LENGTH) { 
 | 
                        log.info("AGV[{}] waiting in place, because the path list is too short...", agvNo); 
 | 
                        pathList.clear(); 
 | 
                    } 
 | 
  
 | 
                    boolean hasCycleJam = blockVehicleList.stream().anyMatch( 
 | 
                            blockVehicleDto -> null != jamService.getCycleJam(agv.getId(), segment.getId(), blockVehicleDto.getVehicle()) 
 | 
                    ); 
 | 
                    if (hasCycleJam) { 
 | 
                        log.info("AGV[{}] waiting in place, because has cycle jam...", agvNo); 
 | 
                        pathList.clear(); 
 | 
                    } 
 | 
                } 
 | 
  
 | 
            // 无可走行路径 
 | 
            } else { 
 | 
  
 | 
                if (Cools.isEmpty(blockVehicleList)) { 
 | 
                    log.warn("AGV[{}] can't reach to code: {}, because there is too many vehicle in the lane...", agvNo, endCode.getData()); 
 | 
                } else { 
 | 
  
 | 
                    assert !Cools.isEmpty(blockVehicleList); 
 | 
                    Integer maxJamTimeoutFactor = null; 
 | 
  
 | 
                    // persist jam data 
 | 
                    jam = this.createOrUpdateJam(agv, startCode, segment, jam, draftPath); 
 | 
  
 | 
                    // ? has unAvoidable block vehicles 
 | 
                    if (blockVehicleList.stream().anyMatch(blockVehicleDto -> !blockVehicleDto.isAvoidable())) { 
 | 
  
 | 
                        // set factor of jam timeout 
 | 
                        maxJamTimeoutFactor = 1; 
 | 
                    } else { 
 | 
  
 | 
                        // ? already do notify to avoid 
 | 
                        if (!Cools.isEmpty(jam.getAvoAgv()) 
 | 
                                && BlockVehicleDto.customContain(blockVehicleList, agvService.getById(jam.getAvoAgv()).getUuid())) { 
 | 
  
 | 
                            maxJamTimeoutFactor = 4; 
 | 
  
 | 
                        } else { 
 | 
  
 | 
                            // select optimal block vehicle 
 | 
                            String blockAgvNo = this.checkoutBestSolutionOfBlocks(blockVehicleList, segment); 
 | 
                            if (Cools.isEmpty(blockAgvNo)) { 
 | 
  
 | 
                                maxJamTimeoutFactor = 2; 
 | 
  
 | 
                            } else { 
 | 
  
 | 
                                // block vehicle info 
 | 
                                Long blockAgvId = agvService.getAgvId(blockAgvNo); 
 | 
                                String blockAgvCode = codeService.getCacheById(agvDetailService.selectMajorByAgvId(blockAgvId).getRecentCode()).getData(); 
 | 
  
 | 
                                // create new jam if already notify the avoid vehicle 
 | 
                                if (!Cools.isEmpty(jam.getAvoAgv(), jam.getAvoSeg()) && !blockAgvId.equals(jam.getAvoAgv())) { 
 | 
                                    jam = this.setupNewJam(jam, agv, startCode, segment, draftPath); 
 | 
                                } 
 | 
  
 | 
                                do { 
 | 
  
 | 
                                    // 阻塞车辆正在原地作业,等待 ===>> 超过等待时间,绕路 
 | 
                                    List<Segment> runningSegList = segmentService.getByAgvAndState(blockAgvId, SegmentStateType.RUNNING.toString()); 
 | 
                                    if (!Cools.isEmpty(runningSegList)) { 
 | 
                                        maxJamTimeoutFactor = 1; 
 | 
                                        break; 
 | 
                                    } 
 | 
  
 | 
                                    // 判断下个任务是否为原地任务,如果是则等待 ===>> 超过等待时间,绕路;如果不是,让阻塞车辆避让 
 | 
                                    List<Segment> waitingSegList = segmentService.getJustWaitingSeg(blockAgvId); 
 | 
                                    if (null != waitingSegList 
 | 
                                            && waitingSegList.stream().anyMatch( 
 | 
                                            waitingSeg -> waitingSeg.getEndNode().equals(codeService.getCacheByData(blockAgvCode).getId()) 
 | 
                                    )) { 
 | 
                                        maxJamTimeoutFactor = 1; 
 | 
                                        break; 
 | 
                                    } 
 | 
  
 | 
                                    // notify block vehicle to avoid 
 | 
                                    if (this.notifyVehicleAvoid(blockAgvNo, blockAgvCode, draftPath, agvNo, jam)) { 
 | 
                                        if (jam.getCycleAvo() == 1) { 
 | 
                                            jam.setCycleCode(endCode.getId()); 
 | 
                                        } 
 | 
                                        jam.setAvoAgv(blockAgvId); 
 | 
                                        jam.setNotifyTime(new Date()); 
 | 
                                        if (!jamService.updateById(jam)) { 
 | 
                                            throw new CoolException(jam.getUuid() + "-jam failed to update!!!"); 
 | 
                                        } 
 | 
                                    } else { 
 | 
  
 | 
                                        maxJamTimeoutFactor = 1; 
 | 
                                    } 
 | 
  
 | 
                                } while (false); 
 | 
                            } 
 | 
  
 | 
                        } 
 | 
  
 | 
                    } 
 | 
  
 | 
                    // handle jam timeout 
 | 
                    if (null != maxJamTimeoutFactor) { 
 | 
                        if (System.currentTimeMillis() - jam.getStartTime().getTime() > (long) MapDataConstant.MAX_JAM_TIMEOUT * maxJamTimeoutFactor) { 
 | 
  
 | 
                            if (!Cools.isEmpty(lockPathList)) { 
 | 
  
 | 
                                pathList = lockPathList; 
 | 
                            } else { 
 | 
                                log.error("{}号车辆检索[{}] ===>> [{}]路径失败,原因:{}" 
 | 
                                        , agvNo, startCode.getData(), endCode.getData(), "路径阻塞超时"); 
 | 
                            } 
 | 
                        } else { 
 | 
                            log.warn("{}号车辆正在等待交通堵塞,阻塞车辆:【{}】" 
 | 
                                    , agvNo 
 | 
                                    , blockVehicleList.stream().map(BlockVehicleDto::getVehicle).collect(Collectors.toList()).toString() 
 | 
                            ); 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                } 
 | 
  
 | 
            } 
 | 
        } 
 | 
  
 | 
        if (!Cools.isEmpty(pathList)) { 
 | 
  
 | 
            if (null != jam) { 
 | 
                boolean beDeprecate = false; 
 | 
                if (blockSeverity.equals(BlockSeverityType.SEVERE) && !Cools.isEmpty(jam.getJamPath())) { 
 | 
                    List<String> jamPath = GsonUtils.fromJsonToList(jam.getJamPath(), String.class); 
 | 
                    if (!this.comparePathLists(jamPath, pathList)) {    // jamPath >= pathList 
 | 
                        beDeprecate = true; 
 | 
                    } 
 | 
                } 
 | 
                jam.setEndTime(now); 
 | 
                jam.setUpdateTime(now); 
 | 
                jam.setState(beDeprecate ? JamStateType.DEPRECATED.toString() : JamStateType.FINISH.toString()); 
 | 
                if (jamService.updateById(jam)) { 
 | 
                    if (beDeprecate) { 
 | 
                        // search previous jam that jamSeg from this segment 
 | 
                        List<Jam> previousJams = jamService.list(new LambdaQueryWrapper<Jam>() 
 | 
                                .eq(Jam::getJamSeg, segment.getId()) 
 | 
                                .eq(Jam::getState, JamStateType.FINISH.toString()) 
 | 
                        ); 
 | 
                        for (Jam previousJam : previousJams) { 
 | 
                            previousJam.setState(JamStateType.DEPRECATED.toString()); 
 | 
                            previousJam.setUpdateTime(now); 
 | 
                            if (!jamService.updateById(previousJam)) { 
 | 
                                log.error("Jam[{}] failed to update!!!", previousJam.getUuid()); 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                } else { 
 | 
                    log.error("Jam[{}] failed to update!!!", jam.getUuid()); 
 | 
                } 
 | 
            } 
 | 
            // deal expired jam 
 | 
            for (Jam expiredJam : jamService.list(new LambdaQueryWrapper<Jam>() 
 | 
                    .eq(Jam::getJamAgv, agv.getId()) 
 | 
                    .eq(Jam::getState, JamStateType.RUNNING.toString()))) { 
 | 
                expiredJam.setEndTime(now); 
 | 
                expiredJam.setUpdateTime(now); 
 | 
                expiredJam.setState(JamStateType.DEPRECATED.toString()); 
 | 
                if (!jamService.updateById(expiredJam)) { 
 | 
                    log.error("Jam[{}] failed to update!!!", expiredJam.getUuid()); 
 | 
                } 
 | 
            } 
 | 
  
 | 
        } 
 | 
  
 | 
        return pathList; 
 | 
    } 
 | 
  
 | 
    private List<BlockVehicleDto> slicePathAndReturnBlockVehicleList(Integer lev, List<String> fullPathList, String agvNo, List<String> pathList) { 
 | 
        List<BlockVehicleDto> blockVehicleList = new ArrayList<>(); 
 | 
  
 | 
        String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(lev); 
 | 
        List<int[]> codeMatrixIdxList = mapDataDispatcher.getCodeMatrixIdxList(lev, fullPathList); 
 | 
        for (int i = 0; i < fullPathList.size(); i++) { 
 | 
            String codeData = fullPathList.get(i); 
 | 
            int[] codeMatrixIdx = codeMatrixIdxList.get(i); 
 | 
  
 | 
            String waveNode = waveMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]]; 
 | 
            assert !waveNode.equals(WaveNodeType.DISABLE.val); 
 | 
            if (!waveNode.equals(WaveNodeType.ENABLE.val)) { 
 | 
                List<String> waveNodeList = MapDataUtils.parseWaveNode(waveNode); 
 | 
                List<String> otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo); 
 | 
                if (!Cools.isEmpty(otherWaveList)) { 
 | 
                    for (String otherWave : otherWaveList) { 
 | 
                        if (mapService.isWalkingByVehicle(lev, otherWave)) { 
 | 
                            blockVehicleList.add(new BlockVehicleDto(otherWave, false)); 
 | 
                        } else { 
 | 
                            blockVehicleList.add(new BlockVehicleDto(otherWave, true)); 
 | 
                        } 
 | 
                    } 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            pathList.add(codeData); 
 | 
        } 
 | 
  
 | 
        if (pathList.size() <= 1) { 
 | 
            pathList.clear(); 
 | 
        } 
 | 
  
 | 
        return blockVehicleList.stream().distinct().collect(Collectors.toList()); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * avoidPathList include wave node and dynamic node 
 | 
     */ 
 | 
    private boolean notifyVehicleAvoid(String agvNo, String agvPosCode, List<String> avoidPathList, String sponsor, Jam jam) { 
 | 
        Long agvId = agvService.getAgvId(agvNo); 
 | 
        if (!Cools.isEmpty(segmentService.getByAgvAndState(agvId, SegmentStateType.RUNNING.toString()))) { 
 | 
            log.warn("{}号车辆避让失败,存在进行中任务!!!", agvNo); 
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        int[] startMapIdx = mapDataDispatcher.getCodeMatrixIdx(null, agvPosCode); 
 | 
        RetreatNavigateNode startNode = new RetreatNavigateNode(startMapIdx[0], startMapIdx[1], agvPosCode); 
 | 
  
 | 
        assert avoidPathList.size() >= 2; 
 | 
        RetreatNavigateNode finalNode = retreatNavigateService.execute(agvNo, startNode, avoidPathList, sponsor, jam); 
 | 
        if (null == finalNode) { 
 | 
            log.warn("{}号车辆避让失败,检索避让点失败!!!", agvNo); 
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        String endCodeData = finalNode.getCodeData(); 
 | 
        Code endCode = codeService.getCacheByData(endCodeData); 
 | 
  
 | 
        List<Segment> waitingSegList = segmentService.getByAgvAndState(agvId, SegmentStateType.WAITING.toString()); 
 | 
        if (!Cools.isEmpty(waitingSegList)) { 
 | 
  
 | 
            if (waitingSegList.size() > 1) { 
 | 
                log.error("避让通知失败,{}号车辆存在多个等待中的Segment!!!", agvNo); 
 | 
                return false; 
 | 
            } 
 | 
            // revert 
 | 
            Date now = new Date(); 
 | 
            for (Segment seg : waitingSegList) { 
 | 
                seg.setState(SegmentStateType.INIT.toString()); 
 | 
                seg.setUpdateTime(now); 
 | 
                if (!segmentService.updateById(seg)) { 
 | 
                    log.error("Segment [{}] 更新失败 !!!", seg.getTravelId() + " - " + seg.getSerial()); 
 | 
                } 
 | 
            } 
 | 
            Segment segment = waitingSegList.get(0); 
 | 
  
 | 
            Segment insertSeg = new Segment(); 
 | 
            insertSeg.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); 
 | 
            insertSeg.setTravelId(segment.getTravelId()); 
 | 
            insertSeg.setAgvId(agvId); 
 | 
            insertSeg.setTaskId(segment.getTaskId()); 
 | 
            insertSeg.setSerial(segment.getSerial() - 1); 
 | 
            insertSeg.setEndNode(endCode.getId()); 
 | 
            insertSeg.setPosType(TaskPosDto.PosType.MOVE.toString()); 
 | 
            insertSeg.setState(SegmentStateType.WAITING.toString()); 
 | 
            if (!segmentService.save(insertSeg)) { 
 | 
                log.error("Segment [{}] 保存失败 !!!", segment.getTravelId() + " - " + segment.getSerial()); 
 | 
                return false; 
 | 
            } else { 
 | 
                jam.setAvoSeg(insertSeg.getId()); 
 | 
                jam.setAvoCode(endCode.getId()); 
 | 
            } 
 | 
  
 | 
        } else { 
 | 
  
 | 
            return mainLockWrapService.buildMinorTask(agvId, TaskTypeType.MOVE, endCodeData, jam); 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    private Jam createOrUpdateJam(Agv agv, Code startCode, Segment segment, Jam jam, List<String> jamPath) { 
 | 
        if (jam == null) { 
 | 
            jam = new Jam(); 
 | 
            jam.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); 
 | 
            jam.setJamAgv(agv.getId()); 
 | 
            jam.setJamCode(startCode.getId()); 
 | 
            jam.setJamSeg(segment.getId()); 
 | 
            jam.setJamPath(GsonUtils.toJson(jamPath)); 
 | 
            jam.setStartTime(new Date()); 
 | 
            jam.setState(JamStateType.RUNNING.toString()); 
 | 
            if (!jamService.save(jam)) { 
 | 
                log.error("AGV[{}] failed to save jam", agv.getUuid()); 
 | 
                throw new CoolException("failed to save jam"); 
 | 
            } 
 | 
        } else { 
 | 
            jam.setDuration(System.currentTimeMillis() - jam.getStartTime().getTime()); 
 | 
            if (!jamService.updateById(jam)) { 
 | 
                log.error("AGV[{}] failed to update jam", agv.getUuid()); 
 | 
            } 
 | 
        } 
 | 
        return jam; 
 | 
    } 
 | 
  
 | 
    private Jam setupNewJam(Jam originJam, Agv agv, Code startCode, Segment segment, List<String> draftPath) { 
 | 
        originJam.setUpdateTime(new Date()); 
 | 
        originJam.setState(JamStateType.FINISH.toString()); 
 | 
        if (!jamService.updateById(originJam)) { 
 | 
            log.error("Jam[{}] failed to update", originJam.getUuid()); 
 | 
            return originJam; 
 | 
        } else { 
 | 
            return this.createOrUpdateJam( 
 | 
                    agv 
 | 
                    , startCode 
 | 
                    , segment 
 | 
                    , null 
 | 
                    , draftPath 
 | 
            ); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    private List<String> getBlackPathList(List<Jam> unfinishedOriginJamByCurrAgv) { 
 | 
        List<String> blackPathList = new ArrayList<>(); 
 | 
        Integer lev = MapDataDispatcher.MAP_DEFAULT_LEV; 
 | 
        if (!Cools.isEmpty(unfinishedOriginJamByCurrAgv)) { 
 | 
            for (Jam jam : unfinishedOriginJamByCurrAgv) { 
 | 
                if (!Cools.isEmpty(jam.getJamPath())) { 
 | 
  
 | 
                    List<String> list = GsonUtils.fromJsonToList(jam.getJamPath(), String.class); 
 | 
  
 | 
                    Agv jamAgv = agvService.getById(jam.getJamAgv()); 
 | 
                    List<String> jamDynamicNodes = mapService.queryCodeListFromDynamicNode(lev, jamAgv.getUuid()); 
 | 
                    // jamDynamicNodes has sorted 
 | 
                    String firstCodeNode = jamDynamicNodes.stream().findFirst().orElse(null); 
 | 
  
 | 
                    if (!Cools.isEmpty(firstCodeNode)) { 
 | 
                        int idx = list.indexOf(firstCodeNode); 
 | 
                        if (idx != -1) { 
 | 
                            list = new ArrayList<>(list.subList(idx, list.size())); 
 | 
  
 | 
                            // the wave of first node 
 | 
                            Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance( 
 | 
                                    agvModelService.getById(jamAgv.getAgvModel()).getDiameter(), 
 | 
                                    MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR 
 | 
                            ); 
 | 
                            List<String> waveCodeList = mapService.getWaveScopeByCode(lev, firstCodeNode, avoidDistance) 
 | 
                                    .stream().map(NavigateNode::getCodeData).distinct().collect(Collectors.toList()); 
 | 
                            list.addAll(waveCodeList); 
 | 
                        } else { 
 | 
                            // 如果被阻塞车辆已经不在原来的阻塞路径中,考虑避让车走行时不需要把之前的阻塞路径加入黑名单 
 | 
                            list = new ArrayList<>(); 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    blackPathList.addAll(list); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        return blackPathList.stream().distinct().collect(Collectors.toList()); 
 | 
    } 
 | 
  
 | 
    private String checkoutBestSolutionOfBlocks(List<BlockVehicleDto> blockVehicleList, Segment segment) { 
 | 
        assert !Cools.isEmpty(blockVehicleList); 
 | 
        for (BlockVehicleDto blockVehicleDto : blockVehicleList) { 
 | 
            if (!blockVehicleDto.isAvoidable()) { 
 | 
                continue; 
 | 
            } 
 | 
            // 当前vehicle正在进行避让作业 
 | 
            if (!Cools.isEmpty(jamService.getUnfinishedAvoSegByAvo(blockVehicleDto.getVehicle(), null))) { 
 | 
                continue; 
 | 
            } 
 | 
            return blockVehicleDto.getVehicle(); 
 | 
        } 
 | 
        return null; 
 | 
    } 
 | 
  
 | 
    public boolean comparePathLists(List<String> list1, List<String> list2) { 
 | 
        if (list1.equals(list2)) { 
 | 
            return true; 
 | 
        } 
 | 
        if (list1.containsAll(list2)) { 
 | 
            return true; 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 1. the jam was deprecated 
 | 
     * 2. the jam segment is finished 
 | 
     * 
 | 
     * all these by avoid segment 
 | 
     */ 
 | 
    private boolean isExpiredJamByAvo(Long avoSeg) { 
 | 
        List<Jam> jamList = jamService.list(new LambdaQueryWrapper<Jam>() 
 | 
//                .eq(Jam::getAvoAgv, avoAgv) 
 | 
                .eq(Jam::getAvoSeg, avoSeg)); 
 | 
        if (Cools.isEmpty(jamList)) { 
 | 
            return false; 
 | 
        } 
 | 
        if (jamList.size() > 1) { 
 | 
            log.error("AvoSeg[id = {}] seg data has exception, result in two jams", avoSeg); 
 | 
        } 
 | 
        Jam jam = jamList.get(0); 
 | 
        if (jam.getState().equals(JamStateType.DEPRECATED.toString())) { 
 | 
            return true; 
 | 
        } 
 | 
        Segment jamSegment = segmentService.getById(jam.getJamSeg()); 
 | 
        if (jamSegment.getState().equals(SegmentStateType.FINISH.toString())) { 
 | 
            return true; 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
} 
 |