| | |
| | | package com.zy.acs.manager.core.service; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.zy.acs.common.utils.RedisSupport; |
| | | import com.zy.acs.common.utils.Utils; |
| | | import com.zy.acs.framework.common.Cools; |
| | | import com.zy.acs.manager.common.utils.MapDataUtils; |
| | | import com.zy.acs.manager.core.constant.MapDataConstant; |
| | | import com.zy.acs.manager.core.domain.Lane; |
| | | import com.zy.acs.manager.core.service.astart.*; |
| | | import com.zy.acs.manager.core.service.astart.domain.DynamicNode; |
| | | import com.zy.acs.manager.core.utils.RouteGenerator; |
| | | import com.zy.acs.manager.manager.entity.Code; |
| | | import com.zy.acs.manager.manager.entity.Jam; |
| | | import com.zy.acs.manager.manager.entity.Route; |
| | | import com.zy.acs.manager.manager.service.AgvModelService; |
| | | import com.zy.acs.manager.manager.service.AgvService; |
| | | import com.zy.acs.manager.manager.service.CodeService; |
| | | import com.zy.acs.manager.manager.service.RouteService; |
| | | import com.zy.acs.manager.manager.entity.Segment; |
| | | import com.zy.acs.manager.manager.enums.JamStateType; |
| | | 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.Service; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.CopyOnWriteArrayList; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | |
| | | private final RedisSupport redis = RedisSupport.defaultRedisSupport; |
| | | |
| | | public static final int WEIGHT_CALC_COEFFICIENT = 10000; |
| | | public static final int WEIGHT_CALC_FACTOR = 10000; |
| | | |
| | | @Autowired |
| | | private CodeService codeService; |
| | | @Autowired |
| | | private RouteService routeService; |
| | | @Autowired |
| | | private MapDataDispatcher mapDataDispatcher; |
| | | @Autowired |
| | |
| | | private LaneService laneService; |
| | | @Autowired |
| | | private ConfigService configService; |
| | | @Autowired |
| | | private SegmentService segmentService; |
| | | @Autowired |
| | | private JamService jamService; |
| | | |
| | | /** |
| | | * avoidPathList ===>> [ minor vehicle ] [wave] [ curr vehicle ] [ code2 ] [ code3 ] ...... |
| | |
| | | String breakPoint = avoidPathList.stream().findFirst().orElse(null); |
| | | List<String> blackList = Utils.singletonList(sponsor); |
| | | |
| | | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModelService.getById(agvService.selectByUuid(sponsor).getAgvModel()).getDiameter() |
| | | , MapDataConstant.IDLE_DISTANCE_COE); |
| | | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModelService.getByAgvNo(sponsor).getDiameter() |
| | | , MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | List<String> avoidPathListWave = mapService.getWaveScopeByCodeList(lev, avoidPathList, avoidDistance); |
| | | |
| | | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(lev); |
| | | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); |
| | | String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(lev); |
| | | |
| | |
| | | RetreatNavigateNode finialNode = null; |
| | | |
| | | PriorityQueue<RetreatNavigateNode> openQueue = new PriorityQueue<>(); |
| | | ArrayList<RetreatNavigateNode> existNodes = new ArrayList<>(); |
| | | Set<RetreatNavigateNode> existNodes = new HashSet<>(); |
| | | |
| | | openQueue.add(start); |
| | | existNodes.add(start); |
| | | boolean phaseSecond = true; |
| | | |
| | | while (openQueue.size() > 0 && null == finialNode) { |
| | | while (!openQueue.isEmpty() && null == finialNode) { |
| | | |
| | | RetreatNavigateNode currentNode = openQueue.poll(); |
| | | |
| | | List<RetreatNavigateNode> enableNodes = new ArrayList<>(); |
| | | |
| | | ArrayList<RetreatNavigateNode> neighborNodes = this.getNeighborNodes(currentNode, existNodes); |
| | | List<RetreatNavigateNode> neighborNodes = this.getNeighborNodes(currentNode, existNodes, codeMatrix); |
| | | boolean pointOfTurn = neighborNodes.size() >= 2; |
| | | label: for (RetreatNavigateNode node : neighborNodes) { |
| | | if (node.getCodeData().equals(breakPoint)) { continue; } |
| | | |
| | |
| | | if (!Cools.isEmpty(blackList) && blackList.contains(otherWave)) { |
| | | continue label; |
| | | } |
| | | if (1 < mapDataDispatcher.queryCodeListFromDynamicNode(lev, otherWave).size()) { |
| | | if (mapService.isWalkingByVehicle(lev, otherWave)) { |
| | | phaseSecond = false; // there is a running way |
| | | continue label; |
| | | } else { |
| | | weight += WEIGHT_CALC_COEFFICIENT; |
| | | weight += WEIGHT_CALC_FACTOR; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // lane |
| | | Lane lane = laneService.search(node.getCodeData()); |
| | | if (null != lane) { |
| | | Set<String> lanVehicleSet = new HashSet<>(); |
| | | if (pointOfTurn) { |
| | | List<int[]> laneCodeIdxList = laneService.getLaneCodeIdxList(node.getCodeData()); |
| | | if (!Cools.isEmpty(laneCodeIdxList)) { |
| | | Set<String> lanVehicleSet = new HashSet<>(); |
| | | |
| | | List<String> laneCodes = lane.getCodes(); |
| | | for (String laneCodeData : laneCodes) { |
| | | int[] laneCodeMatrixIdx = mapDataDispatcher.getCodeMatrixIdx(null, laneCodeData); |
| | | // scan dynamicMatrix or WaveMatrix |
| | | DynamicNode laneDynamicNode = dynamicMatrix[laneCodeMatrixIdx[0]][laneCodeMatrixIdx[1]]; |
| | | String laneVehicle = laneDynamicNode.getVehicle(); |
| | | assert !laneVehicle.equals(DynamicNodeType.BLOCK.val); |
| | | if (!laneVehicle.equals(DynamicNodeType.ACCESS.val)) { |
| | | if (!laneVehicle.equals(agvNo)) { |
| | | lanVehicleSet.add(laneVehicle); |
| | | // redis.setObject(RedisConstant.AGV_TO_STANDBY_FLAG, laneVehicle, true, 30); |
| | | for (int[] codeMatrixIdx : laneCodeIdxList) { |
| | | // overlap with sponsor |
| | | String laneCodeData = codeMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]]; |
| | | if (avoidPathList.contains(laneCodeData)) { |
| | | lanVehicleSet.add(sponsor); |
| | | } |
| | | |
| | | DynamicNode laneDynamicNode = dynamicMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]]; |
| | | String laneVehicle = laneDynamicNode.getVehicle(); |
| | | assert !laneVehicle.equals(DynamicNodeType.BLOCK.val); |
| | | if (!laneVehicle.equals(DynamicNodeType.ACCESS.val)) { |
| | | if (!laneVehicle.equals(agvNo)) { |
| | | lanVehicleSet.add(laneVehicle); |
| | | } |
| | | } |
| | | } |
| | | if (lanVehicleSet.size() + 1 > maxAgvCountInLane) { |
| | | phaseSecond = false; // there is a running way |
| | | continue; |
| | | } |
| | | if (lanVehicleSet.contains(sponsor)) { |
| | | weight += WEIGHT_CALC_FACTOR * 2; |
| | | } |
| | | } |
| | | |
| | | if (lanVehicleSet.size() + 1 > maxAgvCountInLane) { |
| | | continue; |
| | | } |
| | | |
| | | Code code = codeService.getCacheByData(node.getCodeData()); |
| | | |
| | | // judge whether the node has already been marked as a retreat node? |
| | | // This is a very troublesome matter, if the node be repeatedly mark as a retreat node |
| | | List<Segment> runningSegments = segmentService.getRunningByEndCode(code.getId()); |
| | | for (Segment runningSeg : runningSegments) { |
| | | if (0 < jamService.count(new LambdaQueryWrapper<Jam>() |
| | | .eq(Jam::getAvoSeg, runningSeg.getId()) |
| | | .ne(Jam::getState, JamStateType.DEPRECATED.toString()))) { |
| | | weight += WEIGHT_CALC_FACTOR * 3; |
| | | } else { |
| | | weight += WEIGHT_CALC_FACTOR; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | if (null == finialNode) { |
| | | if (null == finialNode && phaseSecond) { |
| | | // assert openQueue.size() == 0; |
| | | |
| | | existNodes.clear(); |
| | |
| | | int actualLanesOfTurn = 0; |
| | | int filterPointOfTurnTimes = 0; |
| | | |
| | | while (openQueue.size() > 0 && null == finialNode) { |
| | | while (!openQueue.isEmpty() && null == finialNode) { |
| | | |
| | | RetreatNavigateNode currentNode = openQueue.poll(); |
| | | List<RetreatNavigateNode> enableNodes = new ArrayList<>(); |
| | | |
| | | ArrayList<RetreatNavigateNode> neighborNodes = this.getNeighborNodes(currentNode, existNodes); |
| | | List<RetreatNavigateNode> neighborNodes = this.getNeighborNodes(currentNode, existNodes, codeMatrix); |
| | | |
| | | // 第一步:获取有效转弯点 |
| | | if (null == availablePointOfTurn) { |
| | |
| | | |
| | | for (RetreatNavigateNode node : neighborNodes) { |
| | | // lane |
| | | Lane lane = laneService.search(node.getCodeData()); |
| | | if (null != lane) { |
| | | List<int[]> laneCodeIdxList = laneService.getLaneCodeIdxList(node.getCodeData()); |
| | | if (!Cools.isEmpty(laneCodeIdxList)) { |
| | | Set<String> lanVehicleSet = new HashSet<>(); |
| | | |
| | | for (String laneCodeData : lane.getCodes()) { |
| | | int[] laneCodeMatrixIdx = mapDataDispatcher.getCodeMatrixIdx(null, laneCodeData); |
| | | // scan dynamicMatrix or WaveMatrix |
| | | DynamicNode laneDynamicNode = dynamicMatrix[laneCodeMatrixIdx[0]][laneCodeMatrixIdx[1]]; |
| | | for (int[] codeMatrixIdx : laneCodeIdxList) { |
| | | DynamicNode laneDynamicNode = dynamicMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]]; |
| | | String laneVehicle = laneDynamicNode.getVehicle(); |
| | | assert !laneVehicle.equals(DynamicNodeType.BLOCK.val); |
| | | if (!laneVehicle.equals(DynamicNodeType.ACCESS.val)) { |
| | | if (!laneVehicle.equals(agvNo)) { |
| | | lanVehicleSet.add(laneVehicle); |
| | | // redis.setObject(RedisConstant.AGV_TO_STANDBY_FLAG, laneVehicle, true, 30); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (lanVehicleSet.size() + 1 > maxAgvCountInLane) { |
| | | continue; |
| | | } |
| | |
| | | availablePointOfTurn = currentNode; |
| | | availablePointWaveScopeOfTurn = mapService.getWaveScopeByCode(lev, availablePointOfTurn.getCodeData(), avoidDistance) |
| | | .stream().map(NavigateNode::getCodeData).distinct().collect(Collectors.toList()); |
| | | } else { |
| | | actualLanesOfTurn = 0; |
| | | } |
| | | } |
| | | } |
| | |
| | | if (!Cools.isEmpty(blackList) && blackList.contains(otherWave)) { |
| | | continue; |
| | | } |
| | | if (1 < mapDataDispatcher.queryCodeListFromDynamicNode(lev, otherWave).size()) { |
| | | if (mapService.isWalkingByVehicle(lev, otherWave)) { |
| | | |
| | | if (null != availablePointOfTurn && actualLanesOfTurn > 0) { |
| | | actualLanesOfTurn --; |
| | | } |
| | | continue label; |
| | | } else { |
| | | weight += WEIGHT_CALC_COEFFICIENT; |
| | | weight += WEIGHT_CALC_FACTOR; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | // 获取四周节点 |
| | | private ArrayList<RetreatNavigateNode> getNeighborNodes(RetreatNavigateNode currentNode, List<RetreatNavigateNode> existNodes) { |
| | | private List<RetreatNavigateNode> getNeighborNodes(RetreatNavigateNode currentNode, Set<RetreatNavigateNode> existNodes, String[][] codeMatrix) { |
| | | |
| | | int x = currentNode.getX(); |
| | | int y = currentNode.getY(); |
| | | |
| | | ArrayList<RetreatNavigateNode> neighbourNodes = new ArrayList<>(); |
| | | List<RetreatNavigateNode> neighbourNodes = new CopyOnWriteArrayList<>(); |
| | | |
| | | RetreatNavigateNode rightNode = extendNeighborNodes(currentNode, new RetreatNavigateNode(x, y + 1), existNodes, null, null); |
| | | if (null != rightNode) { |
| | | neighbourNodes.add(rightNode); |
| | | } |
| | | List<RetreatNavigateNode> possibleNodes = Arrays.asList( |
| | | new RetreatNavigateNode(x, y + 1), // right |
| | | new RetreatNavigateNode(x, y - 1), // left |
| | | new RetreatNavigateNode(x - 1, y), // up |
| | | new RetreatNavigateNode(x + 1, y) // down |
| | | ); |
| | | |
| | | RetreatNavigateNode leftNode = extendNeighborNodes(currentNode, new RetreatNavigateNode(x, y - 1), existNodes, null, null); |
| | | if (null != leftNode) { |
| | | neighbourNodes.add(leftNode); |
| | | } |
| | | |
| | | RetreatNavigateNode topNode = extendNeighborNodes(currentNode, new RetreatNavigateNode(x - 1, y), existNodes, null, null); |
| | | if (null != topNode) { |
| | | neighbourNodes.add(topNode); |
| | | } |
| | | |
| | | RetreatNavigateNode bottomNode = extendNeighborNodes(currentNode, new RetreatNavigateNode(x + 1, y), existNodes, null, null); |
| | | if (null != bottomNode) { |
| | | neighbourNodes.add(bottomNode); |
| | | } |
| | | possibleNodes.parallelStream() |
| | | .map(extendNode -> extendNeighborNodes(currentNode, extendNode, existNodes, null, null)) |
| | | .filter(Objects::nonNull) |
| | | .peek(node -> node.setCodeData(codeMatrix[node.getX()][node.getY()])) |
| | | .forEach(neighbourNodes::add); |
| | | |
| | | return neighbourNodes; |
| | | } |
| | | |
| | | private RetreatNavigateNode extendNeighborNodes(RetreatNavigateNode currentNode, RetreatNavigateNode extendNode, List<RetreatNavigateNode> existNodes, Integer dx, Integer dy) { |
| | | private RetreatNavigateNode extendNeighborNodes(RetreatNavigateNode currentNode, RetreatNavigateNode extendNode, Set<RetreatNavigateNode> existNodes, Integer dx, Integer dy) { |
| | | RetreatNavigateNode nextNode; |
| | | |
| | | if (null == dx || null == dy) { |
| | |
| | | if (mapMatrix[x][y] == MapNodeType.DISABLE.val) { |
| | | |
| | | return extendNeighborNodes(currentNode, nextNode, existNodes, dx, dy); |
| | | } |
| | | |
| | | } else { |
| | | if (this.isExist(nextNode, existNodes)) { |
| | | return null; |
| | | } |
| | | assert mapMatrix[x][y] == MapNodeType.ENABLE.val; |
| | | |
| | | // 节点是否可用 |
| | | if (mapMatrix[x][y] != MapNodeType.ENABLE.val) { |
| | | return null; |
| | | } |
| | | if (existNodes.contains(nextNode)) { |
| | | return null; |
| | | } |
| | | |
| | | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null); |
| | | String currentNodeCodeData = codeMatrix[currentNode.getX()][currentNode.getY()]; |
| | | String nextNodeCodeData = codeMatrix[nextNode.getX()][nextNode.getY()]; |
| | | nextNode.setCodeData(nextNodeCodeData); |
| | | |
| | | // 判断通过性 |
| | | Route route = routeService.findByCodeOfBoth( |
| | | codeService.selectByData(currentNodeCodeData).getId(), |
| | | codeService.selectByData(nextNodeCodeData).getId() |
| | | ); |
| | | if (null == route) { |
| | | return null; |
| | | } |
| | | |
| | | // 判断通过性 |
| | | String routeCdaKey = RouteGenerator.generateRouteCdaKey(new int[]{currentNode.getX(), currentNode.getY()}, new int[]{nextNode.getX(), nextNode.getY()}); |
| | | if (!mapDataDispatcher.validRouteCdaKey(routeCdaKey)) { |
| | | return null; |
| | | } |
| | | |
| | | return nextNode; |
| | | } |
| | | |
| | | private boolean isExist(RetreatNavigateNode node, List<RetreatNavigateNode> existNodes) { |
| | | for (RetreatNavigateNode existNode : existNodes) { |
| | | if (this.isSame(node, existNode)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private boolean isSame(RetreatNavigateNode o1, RetreatNavigateNode o2) { |