| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.zy.acs.common.utils.Utils; |
| | | import com.zy.acs.framework.common.Cools; |
| | | import com.zy.acs.framework.exception.CoolException; |
| | | import com.zy.acs.manager.common.config.RedisProperties; |
| | | import com.zy.acs.manager.common.utils.MapDataUtils; |
| | | import com.zy.acs.manager.core.constant.MapDataConstant; |
| | | import com.zy.acs.manager.core.domain.VehicleFootprint; |
| | | import com.zy.acs.manager.core.service.astart.CodeNodeType; |
| | | import com.zy.acs.manager.core.service.astart.DynamicNodeType; |
| | | import com.zy.acs.manager.core.service.astart.MapDataDispatcher; |
| | | import com.zy.acs.manager.core.service.astart.NavigateNode; |
| | |
| | | import java.io.InputStreamReader; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.StandardCopyOption; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.TimeUnit; |
| | |
| | | } |
| | | |
| | | private boolean calcWaveScopeByJava(Integer lev, AgvModel agvModel) throws Exception { |
| | | if (null == agvModel.getDiameter() || agvModel.getDiameter() <= 0) { |
| | | log.warn("There is no diameter or diameter value was wrong..."); |
| | | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(lev); |
| | | Double[][][] cdaMatrix = mapDataDispatcher.getCdaMatrix(lev); |
| | | String[][] waveMatrix = mapDataDispatcher.initWaveMatrix(lev); |
| | | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); |
| | | |
| | | // è®°å½æ¯å°è½¦çå®å
¨åå¾ï¼é¡ºå¸¦æ è®°å·²æç©å½¢æ¹å¼ç»å¶çå°ç |
| | | Map<String, Double> vehicleAvoidDistance = new HashMap<>(); |
| | | Set<String> preciseNodes = new HashSet<>(); |
| | | |
| | | // å
æ ¹æ®å®æ¶ä½ç½®+è§åº¦ç»å¶å®é
ç©å½¢å ä½ |
| | | List<Agv> agvList = agvService.list(new LambdaQueryWrapper<>()); |
| | | for (Agv agv : agvList) { |
| | | // æ¯æ¬¡æè°åº¦åè¡¨å·æ°è½¦è¾å½åå°ç ä¸è§åº¦ |
| | | AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); |
| | | if (null == agvDetail) { continue; } |
| | | Long recentCodeId = agvDetail.getRecentCode(); |
| | | if (null == recentCodeId) { continue; } |
| | | Code centerCode = codeService.getCacheById(recentCodeId); |
| | | if (null == centerCode) { continue; } |
| | | |
| | | AgvModel model = agvModelService.getByAgvId(agv.getId()); |
| | | if (null == model) { |
| | | model = agvModel; |
| | | } |
| | | double avoidDistance = resolveAvoidDistance(model, agvModel); |
| | | vehicleAvoidDistance.put(agv.getUuid(), avoidDistance); |
| | | |
| | | // å°æè½¬ç©å½¢æ å°å°ç½æ ¼ï¼å¾å°éè¦å ç¨çèç¹éå |
| | | List<NavigateNode> footprintNodes = calcFootprintNodes(lev, centerCode, agvDetail, model, codeMatrix, cdaMatrix); |
| | | if (Cools.isEmpty(footprintNodes)) { |
| | | continue; |
| | | } |
| | | preciseNodes.add(centerCode.getData()); |
| | | for (NavigateNode navigateNode : footprintNodes) { |
| | | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; |
| | | waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, agv.getUuid()); |
| | | } |
| | | } |
| | | |
| | | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | |
| | | // java |
| | | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(lev); |
| | | String[][] waveMatrix = mapDataDispatcher.initWaveMatrix(lev); |
| | | |
| | | // lock path |
| | | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); |
| | | // åç¨åæ¥çå形波纹补ä¸å©ä½çè·¯å¾éå®èç¹ |
| | | for (int i = 0; i < dynamicMatrix.length; i++) { |
| | | for (int j = 0; j < dynamicMatrix[i].length; j++) { |
| | | DynamicNode dynamicNode = dynamicMatrix[i][j]; |
| | | String vehicle = dynamicNode.getVehicle(); |
| | | if (!DynamicNodeType.ACCESS.val.equals(vehicle) && !DynamicNodeType.BLOCK.val.equals(vehicle)) { |
| | | |
| | | List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, codeMatrix[i][j], avoidDistance); |
| | | |
| | | String codeData = codeMatrix[i][j]; |
| | | if (preciseNodes.contains(codeData)) { |
| | | // å·²ç»æçå®ç©å½¢åè¿ä¸æ¬¡ï¼é¿å
éå¤å ç¨ |
| | | continue; |
| | | } |
| | | double avoidDistance = vehicleAvoidDistance.getOrDefault(vehicle, resolveAvoidDistance(null, agvModel)); |
| | | if (avoidDistance <= 0) { |
| | | continue; |
| | | } |
| | | List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, codeData, avoidDistance); |
| | | for (NavigateNode navigateNode : includeList) { |
| | | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; // overlay |
| | | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; |
| | | waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, vehicle); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // mapDataDispatcher.printMatrix(waveMatrix); |
| | | // ææè½¦è¾åæ¥å®æååç»ä¸åå redisï¼åå°é¢ç¹å·æ° |
| | | mapDataDispatcher.setWaveMatrix(lev, waveMatrix); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | // ä¸å车åå¯è½ç´å¾ä¸åï¼ç¼ºå¤±æ¶éåè°ç¨æ¹ä¼ å
¥çé»è®¤æ¨¡åï¼æååéå 0 |
| | | private double resolveAvoidDistance(AgvModel agvModel, AgvModel fallback) { |
| | | Integer diameter = null; |
| | | if (null != agvModel && null != agvModel.getDiameter() && agvModel.getDiameter() > 0) { |
| | | diameter = agvModel.getDiameter(); |
| | | } else if (null != fallback) { |
| | | diameter = fallback.getDiameter(); |
| | | } |
| | | return MapDataUtils.getVehicleWaveSafeDistance(diameter, MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | } |
| | | |
| | | /** |
| | | * 计ç®ç»å®è½¦è¾å¨å½åè§åº¦ä¸çå®è¦ççç½æ ¼èç¹ |
| | | */ |
| | | private List<NavigateNode> calcFootprintNodes(Integer lev, Code centerCode, AgvDetail agvDetail, AgvModel agvModel |
| | | , String[][] codeMatrix, Double[][][] cdaMatrix) { |
| | | if (null == centerCode || null == agvDetail || null == agvModel) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | int[] codeMatrixIdx = mapDataDispatcher.getCodeMatrixIdx(lev, centerCode.getData()); |
| | | if (null == codeMatrixIdx) { |
| | | return new ArrayList<>(); |
| | | } |
| | | Double centerX = cdaMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]][0]; |
| | | Double centerY = cdaMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]][1]; |
| | | if (centerX == null || centerY == null) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | VehicleFootprint footprint = this.buildFootprint(agvModel); |
| | | if (null == footprint) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | double direction = Optional.ofNullable(agvDetail.getAgvAngle()).orElse(0D); |
| | | // ç°åºè§åº¦æ¯ä»¥æ£å为 0ï¼ ç»ä¸è½¬æ¢æå¼§åº¦æ¹ä¾¿ä¸è§å½æ° |
| | | double headingRad = Math.toRadians(90 - direction); |
| | | |
| | | // æè½¬ç©å½¢å
æ±åºä¸çåæ å
å´çï¼åå°éå |
| | | double[][] corners = this.buildRectangleCorners(centerX, centerY, footprint, headingRad); |
| | | double minX = Arrays.stream(corners).mapToDouble(point -> point[0]).min().orElse(centerX); |
| | | double maxX = Arrays.stream(corners).mapToDouble(point -> point[0]).max().orElse(centerX); |
| | | double minY = Arrays.stream(corners).mapToDouble(point -> point[1]).min().orElse(centerY); |
| | | double maxY = Arrays.stream(corners).mapToDouble(point -> point[1]).max().orElse(centerY); |
| | | |
| | | List<NavigateNode> nodeList = new ArrayList<>(); |
| | | for (int i = 0; i < codeMatrix.length; i++) { |
| | | for (int j = 0; j < codeMatrix[i].length; j++) { |
| | | String codeData = codeMatrix[i][j]; |
| | | if (CodeNodeType.NONE.val.equals(codeData)) { |
| | | continue; |
| | | } |
| | | Double px = cdaMatrix[i][j][0]; |
| | | Double py = cdaMatrix[i][j][1]; |
| | | if (px == null || py == null) { |
| | | continue; |
| | | } |
| | | // å
å©ç¨ AABB å䏿¬¡ç²æ»¤ï¼åå精确çç¹å
æ£æµ |
| | | if (px < minX || px > maxX || py < minY || py > maxY) { |
| | | continue; |
| | | } |
| | | // æ¯å¦å½ä¸ å½¢ç¶ç©éµèå´ |
| | | if (this.isInsideFootprint(px, py, centerX, centerY, footprint, headingRad)) { |
| | | nodeList.add(new NavigateNode(i, j, codeData)); |
| | | } |
| | | } |
| | | } |
| | | return nodeList; |
| | | } |
| | | |
| | | /** |
| | | * æ ¹æ®è½¦ååæ°ï¼å« head/tail/widthï¼æå»ºæå½±ç¨çç©å½¢ï¼å¿
è¦æ¶éçº§ä½¿ç¨ length |
| | | */ |
| | | private VehicleFootprint buildFootprint(AgvModel agvModel) { |
| | | if (null == agvModel) { |
| | | return null; |
| | | } |
| | | // double baseLength = Optional.ofNullable(agvModel.getLength()).filter(len -> len > 0).map(Double::valueOf).orElse(0D); |
| | | // double defaultHalfLength = baseLength > 0 ? baseLength / 2.0 : 0; |
| | | |
| | | if (null == agvModel.getHeadOffset() || agvModel.getHeadOffset() <= 0) { |
| | | throw new CoolException(agvModel.getName() + "æªè®¾ç½® 车头é¿åº¦ã"); |
| | | } |
| | | if (null == agvModel.getTailOffset() || agvModel.getTailOffset() <= 0) { |
| | | throw new CoolException(agvModel.getName() + "æªè®¾ç½® 车尾é¿åº¦ã"); |
| | | } |
| | | if (null == agvModel.getWidth() || agvModel.getWidth() <= 0) { |
| | | throw new CoolException(agvModel.getName() + "æªè®¾ç½® 车身宽度ã"); |
| | | } |
| | | double head = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getHeadOffset(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | double tail = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getTailOffset(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | double halfWidth = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getWidth() / 2, MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); |
| | | |
| | | // padding ç´æ¥æ²¿å个æ¹åçæ¯ä¾å¤æ©ï¼çä»·äºç»è½¦èº«é¢çå®å
¨è·ç¦» |
| | | // double padding = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR) / 2.0; |
| | | // if (padding > 0) { |
| | | // head += padding; |
| | | // tail += padding; |
| | | // halfWidth += padding; |
| | | // } |
| | | |
| | | // head = head <= 0 ? Math.max(tail, halfWidth) : head; |
| | | // tail = tail <= 0 ? head : tail; |
| | | // halfWidth = halfWidth <= 0 ? Math.max(head, tail) / 2.0 : halfWidth; |
| | | // |
| | | // if (head <= 0 || tail <= 0 || halfWidth <= 0) { |
| | | // return null; |
| | | // } |
| | | return new VehicleFootprint(head, tail, halfWidth); |
| | | } |
| | | |
| | | /** |
| | | * æè½¬ç©å½¢çå个è§åæ ï¼ç¨æ¥å¿«éçæå
å´ç |
| | | */ |
| | | private double[][] buildRectangleCorners(double centerX, double centerY, VehicleFootprint footprint, double headingRad) { |
| | | double cos = Math.cos(headingRad); |
| | | double sin = Math.sin(headingRad); |
| | | |
| | | double[][] localPoints = new double[][]{ |
| | | {footprint.head, footprint.halfWidth}, |
| | | {footprint.head, -footprint.halfWidth}, |
| | | {-footprint.tail, footprint.halfWidth}, |
| | | {-footprint.tail, -footprint.halfWidth} |
| | | }; |
| | | |
| | | double[][] corners = new double[4][2]; |
| | | for (int idx = 0; idx < localPoints.length; idx++) { |
| | | double lx = localPoints[idx][0]; |
| | | double ly = localPoints[idx][1]; |
| | | double gx = centerX + lx * cos - ly * sin; |
| | | double gy = centerY + lx * sin + ly * cos; |
| | | corners[idx][0] = gx; |
| | | corners[idx][1] = gy; |
| | | } |
| | | return corners; |
| | | } |
| | | |
| | | private boolean isInsideFootprint(double px, double py, double centerX, double centerY, VehicleFootprint footprint, double headingRad) { |
| | | double dx = px - centerX; |
| | | double dy = py - centerY; |
| | | |
| | | // æç¹ç»åè½¦è¾æ¬ä½çå±é¨åæ ï¼ååç®åç©å½¢å¤æ |
| | | double localX = dx * Math.cos(headingRad) + dy * Math.sin(headingRad); |
| | | double localY = -dx * Math.sin(headingRad) + dy * Math.cos(headingRad); |
| | | |
| | | return localX >= -footprint.tail && localX <= footprint.head |
| | | && localY >= -footprint.halfWidth && localY <= footprint.halfWidth; |
| | | } |
| | | |
| | | private File loadPythonFile() { |
| | | File scriptFile = null; |
| | | try { |