package com.zy.asrs.wcs.core.utils; 
 | 
  
 | 
import com.alibaba.fastjson.JSON; 
 | 
import com.alibaba.fastjson.JSONArray; 
 | 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 
 | 
import com.zy.asrs.framework.common.Cools; 
 | 
import com.zy.asrs.framework.common.SnowflakeIdWorker; 
 | 
import com.zy.asrs.framework.exception.CoolException; 
 | 
import com.zy.asrs.wcs.core.entity.*; 
 | 
import com.zy.asrs.wcs.core.kernel.AnalyzeService; 
 | 
import com.zy.asrs.wcs.core.model.NavigateNode; 
 | 
import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; 
 | 
import com.zy.asrs.wcs.core.model.enums.NavigationMapType; 
 | 
import com.zy.asrs.wcs.core.model.enums.TaskStsType; 
 | 
import com.zy.asrs.wcs.core.service.*; 
 | 
import com.zy.asrs.wcs.rcs.News; 
 | 
import com.zy.asrs.wcs.rcs.cache.SlaveConnection; 
 | 
import com.zy.asrs.wcs.rcs.entity.Device; 
 | 
import com.zy.asrs.wcs.rcs.model.enums.SlaveType; 
 | 
import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; 
 | 
import com.zy.asrs.wcs.rcs.service.DeviceService; 
 | 
import com.zy.asrs.wcs.rcs.thread.ShuttleThread; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.stereotype.Service; 
 | 
  
 | 
import java.util.*; 
 | 
  
 | 
/** 
 | 
 * Created by vincent on 2023/10/12 
 | 
 */ 
 | 
@Service 
 | 
public class ShuttleDispatcher { 
 | 
  
 | 
    private static final Integer INF = 9999999; 
 | 
    private static final Integer WEIGHT = 1000000; 
 | 
  
 | 
    @Autowired 
 | 
    private TaskService taskService; 
 | 
    @Autowired 
 | 
    private LiftDispatcher liftDispatcher; 
 | 
    @Autowired 
 | 
    private SnowflakeIdWorker snowflakeIdWorker; 
 | 
    @Autowired 
 | 
    private AnalyzeService analyzeService; 
 | 
    @Autowired 
 | 
    private MotionService motionService; 
 | 
    @Autowired 
 | 
    private DeviceService deviceService; 
 | 
    @Autowired 
 | 
    private BasShuttleService basShuttleService; 
 | 
    @Autowired 
 | 
    private TaskCtgService taskCtgService; 
 | 
    @Autowired 
 | 
    private ShuttleStandbyService shuttleStandbyService; 
 | 
  
 | 
    public synchronized ShuttleThread searchIdleShuttle(Task task) { 
 | 
        String locNo = taskService.judgeInbound(task) ? task.getDestLoc() : task.getOriginLoc(); 
 | 
        ShuttleThread resThread = null; 
 | 
        Integer finalDistance = ShuttleDispatcher.INF; 
 | 
  
 | 
        List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() 
 | 
                .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) 
 | 
                .eq(Device::getHostId, task.getHostId()) 
 | 
                .eq(Device::getStatus, 1)); 
 | 
  
 | 
        for (Device device : list) { 
 | 
            if (taskService.hasBusyOutboundByShuttle(Integer.parseInt(device.getDeviceNo()))) { 
 | 
                continue; 
 | 
            } 
 | 
            //获取四向穿梭车线程 
 | 
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); 
 | 
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); 
 | 
            if (shuttleProtocol == null || shuttleProtocol.getShuttleNo() == null) { 
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            if (!shuttleThread.isIdle()) { 
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            //检测是否存在充电任务 
 | 
            Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo())); 
 | 
            if (taskCharge != null) { 
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            // 有没有被其他任务调度 
 | 
            int currentLev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车当前层高 
 | 
            String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车当前库位号 
 | 
  
 | 
            if (currentLocNo.equals(locNo)) { 
 | 
                resThread = shuttleThread; 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            String targetLocNo = null;//默认到提升机待机位 
 | 
            // 同楼层直接计算到目标库位 
 | 
            if (currentLev == Utils.getLev(locNo)) { 
 | 
                targetLocNo = locNo; 
 | 
            }else { 
 | 
                Device recentTransferLift = Utils.getRecentTransferLift(locNo, Integer.parseInt(device.getDeviceNo())); 
 | 
                if (recentTransferLift == null) { 
 | 
                    continue; 
 | 
                } 
 | 
  
 | 
                //获取小车楼层提升机待机位 
 | 
                ShuttleStandby shuttleStandby = shuttleStandbyService.getOne(new LambdaQueryWrapper<ShuttleStandby>() 
 | 
                        .eq(ShuttleStandby::getDeviceId, recentTransferLift.getId()) 
 | 
                        .eq(ShuttleStandby::getDeviceLev, currentLev) 
 | 
                        .eq(ShuttleStandby::getStatus, 1)); 
 | 
                targetLocNo = shuttleStandby.getDeviceLoc(); 
 | 
            } 
 | 
  
 | 
            //当前穿梭车线程到当前车子所在楼层的提升机口距离 
 | 
            List<NavigateNode> currentShuttlePath = NavigateUtils.calc( 
 | 
                    currentLocNo 
 | 
                    , targetLocNo 
 | 
                    , NavigationMapType.NORMAL.id 
 | 
                    , Utils.getShuttlePoints(Integer.parseInt(shuttleThread.getDevice().getDeviceNo()), currentLev) 
 | 
            );//搜索空闲穿梭车,使用正常通道地图 
 | 
            if (currentShuttlePath == null) { 
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            Integer currDistance = NavigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 
 | 
  
 | 
            // 不同楼层权重 
 | 
            if (currentLev != Utils.getLev(locNo)) { 
 | 
                currDistance += WEIGHT; 
 | 
            } 
 | 
  
 | 
            // 挂载任务权重 
 | 
            List<Task> tasks = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo())); 
 | 
            if (!Cools.isEmpty(tasks)) { 
 | 
                currDistance += tasks.size() * WEIGHT; 
 | 
            } 
 | 
  
 | 
            if (currDistance < finalDistance) { 
 | 
                finalDistance = currDistance; 
 | 
                resThread = shuttleThread; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        return resThread; 
 | 
    } 
 | 
  
 | 
    //生成迁移任务 
 | 
    public synchronized Task generateMoveTask(Device device, String locNo) { 
 | 
        // 已有迁移任务 
 | 
        if (taskService.selectMoveWorking(Integer.valueOf(device.getDeviceNo())) != null) { 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        //获取迁移任务类型 
 | 
        TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>() 
 | 
                .eq(TaskCtg::getFlag, "MOVE") 
 | 
                .eq(TaskCtg::getStatus, 1)); 
 | 
        if (taskCtg == null) { 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); 
 | 
        if (shuttleThread == null) { 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        Task task = new Task(); 
 | 
        task.setUuid(String.valueOf(snowflakeIdWorker.nextId())); 
 | 
        task.setTaskNo(String.valueOf(Utils.getTaskNo("MOVE"))); 
 | 
        task.setTaskSts(TaskStsType.NEW_MOVE.sts); 
 | 
        task.setTaskCtg(taskCtg.getId()); 
 | 
        task.setPriority(10); 
 | 
        task.setOriginSite(null); 
 | 
        task.setOriginLoc(null); 
 | 
        task.setDestSite(null); 
 | 
        task.setDestLoc(locNo); // 迁移位置 
 | 
        task.setIoTime(new Date()); 
 | 
        task.setStartTime(new Date()); 
 | 
        task.setHostId(device.getHostId()); 
 | 
        task.setStatus(1); 
 | 
        task.setShuttleNo(Integer.valueOf(device.getDeviceNo())); 
 | 
  
 | 
        // generate motion list 
 | 
        List<Motion> motionList = analyzeService.generateShuttleMoveMotion(task); 
 | 
        if (Cools.isEmpty(motionList)) { 
 | 
            News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo()); 
 | 
            return null; 
 | 
        } 
 | 
        motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), device.getHostId()); 
 | 
  
 | 
        task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts); 
 | 
  
 | 
        if (!taskService.save(task)) { 
 | 
            News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo()); 
 | 
            return null; 
 | 
        } 
 | 
  
 | 
        return task; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 搜索避让库位,通过小车号和目标库位 
 | 
     */ 
 | 
    public String searchStandByLocNo(Integer shuttleNo, Long hostId, String locNo) { 
 | 
        BasShuttle basShuttle = basShuttleService.getOne(new LambdaQueryWrapper<BasShuttle>() 
 | 
                .eq(BasShuttle::getShuttleNo, shuttleNo) 
 | 
                .eq(BasShuttle::getHostId, hostId)); 
 | 
        if (basShuttle == null) { 
 | 
            throw new CoolException("小车基础数据不存在"); 
 | 
        } 
 | 
  
 | 
        String idleLoc = basShuttle.getIdleLoc(); 
 | 
        if (Cools.isEmpty(idleLoc)) { 
 | 
            throw new CoolException("小车避让数据不存在"); 
 | 
        } 
 | 
  
 | 
        int lev = Utils.getLev(locNo);//当前楼层 
 | 
        JSONArray standbyLoc = JSON.parseArray(idleLoc); 
 | 
        if (lev > standbyLoc.size()) { 
 | 
            throw new CoolException("避让数据异常"); 
 | 
        } 
 | 
  
 | 
        Object object = standbyLoc.get(lev - 1); 
 | 
        List<String> locs = JSON.parseArray(object.toString(), String.class); 
 | 
        if (locs.isEmpty()) { 
 | 
            throw new CoolException("避让数据为空"); 
 | 
        } 
 | 
  
 | 
        Integer finalDistance = ShuttleDispatcher.INF; 
 | 
        String recentLoc = null; 
 | 
        for (String loc : locs) { 
 | 
            //当前穿梭车到避让位计算 
 | 
            List<NavigateNode> currentShuttlePath = NavigateUtils.calc( 
 | 
                    locNo 
 | 
                    , loc 
 | 
                    , NavigationMapType.NORMAL.id 
 | 
                    , Utils.getShuttlePoints(shuttleNo, lev) 
 | 
            );//使用正常通道地图 
 | 
            if (currentShuttlePath == null) { 
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            Integer currDistance = NavigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 
 | 
            if (currDistance < finalDistance) { 
 | 
                finalDistance = currDistance; 
 | 
                recentLoc = loc; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        if (recentLoc == null) { 
 | 
            throw new CoolException("搜索避让位置失败"); 
 | 
        } 
 | 
  
 | 
        return recentLoc; 
 | 
    } 
 | 
  
 | 
  
 | 
} 
 |