|  |  |  | 
|---|
|  |  |  | import com.zy.acs.common.utils.RedisSupport; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.manager.common.utils.MapDataUtils; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.Lane; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.LaneService; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.astart.domain.AStarNavigateNode; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.astart.domain.DynamicNode; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.entity.Route; | 
|---|
|  |  |  | 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.core.utils.RouteGenerator; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.entity.Segment; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.service.JamService; | 
|---|
|  |  |  | 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; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * Created by vincent on 6/12/2024 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Service | 
|---|
|  |  |  | public class AStarNavigateService { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final RedisSupport redis = RedisSupport.defaultRedisSupport; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static final boolean OPEN_TURN_COST_WEIGHT = Boolean.FALSE; | 
|---|
|  |  |  | public static final boolean OPEN_TURN_COST_WEIGHT = Boolean.TRUE; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private CodeService codeService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private RouteService routeService; | 
|---|
|  |  |  | public static final int WEIGHT_CALC_FACTOR = 1; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // right left up down | 
|---|
|  |  |  | private final static int[][] DIRECTIONS = {{0,1},{0,-1},{-1,0},{1,0}}; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private MapDataDispatcher mapDataDispatcher; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private AgvService agvService; | 
|---|
|  |  |  | private JamService jamService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private LaneService laneService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private ConfigService configService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public synchronized NavigateNode execute(String agvNo, NavigateNode start, NavigateNode end | 
|---|
|  |  |  | , Boolean lock, List<String> blackList) { | 
|---|
|  |  |  | public synchronized AStarNavigateNode execute(String agvNo, AStarNavigateNode start, AStarNavigateNode end | 
|---|
|  |  |  | , Boolean lock, List<String> blackList, Segment segment) { | 
|---|
|  |  |  | if (start.getX() == end.getX() && start.getY() == end.getY()) { | 
|---|
|  |  |  | return end; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | Integer maxAgvCountInLane = configService.getVal("maxAgvCountInLane", Integer.class); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | PriorityQueue<NavigateNode> openQueue = new PriorityQueue<>(); | 
|---|
|  |  |  | ArrayList<NavigateNode> existNodes = new ArrayList<>(); | 
|---|
|  |  |  | PriorityQueue<AStarNavigateNode> openQueue = new PriorityQueue<>(); | 
|---|
|  |  |  | Set<AStarNavigateNode> existNodes = new HashSet<>(); | 
|---|
|  |  |  | Map<String, Integer> bestGMap = new HashMap<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | start.setG(0); | 
|---|
|  |  |  | start.setH(calcNodeCost(start, end)); | 
|---|
|  |  |  | start.setF(start.getG() + start.getH()); | 
|---|
|  |  |  | String startKey = start.getX() + "_" + start.getY(); | 
|---|
|  |  |  | bestGMap.put(startKey, start.getG()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | openQueue.add(start); | 
|---|
|  |  |  | existNodes.add(start); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int[][] mapMatrix = mapDataDispatcher.getMapMatrix(null, null); | 
|---|
|  |  |  | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null); | 
|---|
|  |  |  | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(null); | 
|---|
|  |  |  | String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(null); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //        List<String> included = new ArrayList<>(); | 
|---|
|  |  |  | //        if (!Cools.isEmpty(whiteList)) { | 
|---|
|  |  |  | //            included.addAll(whiteList); | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | //        included.add(agvNo); | 
|---|
|  |  |  | //        List<VehicleDto> vehicleDtoList = agvService.getVehicleDtoList(included); | 
|---|
|  |  |  | long getNeighborNodesTime = 0; | 
|---|
|  |  |  | int getNeighborNodesCount = 0; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | while (openQueue.size() > 0) { | 
|---|
|  |  |  | while (!openQueue.isEmpty()) { | 
|---|
|  |  |  | // 取优先队列顶部元素并且把这个元素从Open表中删除,取F值最小的节点 | 
|---|
|  |  |  | NavigateNode currentNode = openQueue.poll(); | 
|---|
|  |  |  | // 对当前结点进行扩展,得到一个四周结点的数组 | 
|---|
|  |  |  | ArrayList<NavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes); | 
|---|
|  |  |  | // 对这个结点遍历,看是否有目标结点出现 | 
|---|
|  |  |  | label: for (NavigateNode node : neighbourNodes) { | 
|---|
|  |  |  | AStarNavigateNode currentNode = openQueue.poll(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 节点存在其他车辆 | 
|---|
|  |  |  | //                for (VehicleDto vehicleDto : vehicleDtoList) { | 
|---|
|  |  |  | //                    if (node.getCodeData().equals(vehicleDto.getPosCode())) { | 
|---|
|  |  |  | //                        if (!Cools.isEmpty(blackList) && blackList.contains(vehicleDto.getVehicle())) { | 
|---|
|  |  |  | //                            continue label; | 
|---|
|  |  |  | //                        } | 
|---|
|  |  |  | //                        if (lock) { | 
|---|
|  |  |  | //                            continue label; | 
|---|
|  |  |  | //                        } | 
|---|
|  |  |  | //                    } | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | // 终点 | 
|---|
|  |  |  | if (currentNode.getX() == end.getX() && currentNode.getY() == end.getY()) { | 
|---|
|  |  |  | //                System.out.println("getNeighborNodes spend time: " + getNeighborNodesTime +", count: " + getNeighborNodesCount); | 
|---|
|  |  |  | return currentNode; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | long currentTime = System.currentTimeMillis(); | 
|---|
|  |  |  | List<AStarNavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes); | 
|---|
|  |  |  | getNeighborNodesTime += System.currentTimeMillis() - currentTime; | 
|---|
|  |  |  | getNeighborNodesCount ++; | 
|---|
|  |  |  | for (AStarNavigateNode node : neighbourNodes) { | 
|---|
|  |  |  | node.setCodeData(codeMatrix[node.getX()][node.getY()]); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | boolean isEndNode = node.getX() == end.getX() && node.getY() == end.getY(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int weight = 0; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!Cools.isEmpty(blackList) && blackList.contains(node.getCodeData())) { | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | // 特殊情况,当blackList有且只有一个元素且为startNode时 | 
|---|
|  |  |  | // 说明blackList已经知道当前导航起始点和目标点为相邻节点 | 
|---|
|  |  |  | // 但是当前blackList的任务是不让系统走相邻的最短路径,所以才会有下面的判断和continue | 
|---|
|  |  |  | if (blackList.size() == 1 && blackList.get(0).equals(start.getCodeData())) { | 
|---|
|  |  |  | if (isEndNode && currentNode.getCodeData().equals(start.getCodeData())) { | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 节点被占用 | 
|---|
|  |  |  | 
|---|
|  |  |  | assert !vehicle.equals(DynamicNodeType.BLOCK.val); | 
|---|
|  |  |  | if (!vehicle.equals(DynamicNodeType.ACCESS.val)) { | 
|---|
|  |  |  | if (!vehicle.equals(agvNo)) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lock) { | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 如果存在车辆,则增加权重 2 或者 3,因为拐点会增加权重 1 | 
|---|
|  |  |  | // vehicle已经为当前segment做过了避让,且避让任务已完成,则权重值增加 | 
|---|
|  |  |  | if (null != segment) { | 
|---|
|  |  |  | if (!Cools.isEmpty(jamService.getJamFromSegmentByAvo(segment, vehicle))) { | 
|---|
|  |  |  | weight += (WEIGHT_CALC_FACTOR * 3); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | weight += (WEIGHT_CALC_FACTOR * 2); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  | if (!waveNode.equals(WaveNodeType.ENABLE.val)) { | 
|---|
|  |  |  | List<String> waveNodeList = MapDataUtils.parseWaveNode(waveNode); | 
|---|
|  |  |  | List<String> otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!Cools.isEmpty(otherWaveList)) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lock) { | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 单巷道车辆容载数量 | 
|---|
|  |  |  | 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<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 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]]; | 
|---|
|  |  |  | 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) { | 
|---|
|  |  |  | //                        if (lock) { | 
|---|
|  |  |  | //                            continue; | 
|---|
|  |  |  | //                        } | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //找到目标结点就返回 | 
|---|
|  |  |  | if (node.getX() == end.getX() && node.getY() == end.getY()) { | 
|---|
|  |  |  | //并且计算出G, F, H等值 | 
|---|
|  |  |  | node.initNode(currentNode, end); | 
|---|
|  |  |  | return node; | 
|---|
|  |  |  | if (OPEN_TURN_COST_WEIGHT) { | 
|---|
|  |  |  | if (this.isTurning(currentNode, node)) { | 
|---|
|  |  |  | weight += WEIGHT_CALC_FACTOR; | 
|---|
|  |  |  | node.setTurnCount(currentNode.getTurnCount() + 1); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | // 方向没变 | 
|---|
|  |  |  | node.setTurnCount(currentNode.getTurnCount()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // G + H + T (对启发函数增加去拐点方案calcNodeTurnCost) | 
|---|
|  |  |  | int gCost = calcNodeCost(currentNode, node) * (OPEN_TURN_COST_WEIGHT ? calcNodeTurnCost(currentNode, node, end) : 1); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //进行计算对 G, F, H 等值 | 
|---|
|  |  |  | node.setLastDistance(gCost); | 
|---|
|  |  |  | node.setWeight(weight); | 
|---|
|  |  |  | node.setLastDistance(calcNodeCost(currentNode, node)); | 
|---|
|  |  |  | node.initNode(currentNode, end); | 
|---|
|  |  |  | node.setH(calcNodeCost(node, end)); | 
|---|
|  |  |  | node.setF(node.getG() + node.getH()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | openQueue.add(node); | 
|---|
|  |  |  | existNodes.add(node); | 
|---|
|  |  |  | String key = node.getX() + "_" + node.getY(); | 
|---|
|  |  |  | Integer recordedG = bestGMap.get(key); | 
|---|
|  |  |  | if (recordedG == null || node.getG() <= recordedG) { | 
|---|
|  |  |  | bestGMap.put(key, node.getG()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | openQueue.add(node); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //                openQueue.add(node); | 
|---|
|  |  |  | //                existNodes.add(node); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | //如果遍历完所有出现的结点都没有找到最终的结点,返回null | 
|---|
|  |  |  | //        System.out.println("getNeighborNodes spend time: " + getNeighborNodesTime +", count: " + getNeighborNodesCount); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 获取四周节点 | 
|---|
|  |  |  | private ArrayList<NavigateNode> getNeighborNodes(NavigateNode currentNode, int[][] mapMatrix, List<NavigateNode> existNodes) { | 
|---|
|  |  |  | //获取当前结点的x, y | 
|---|
|  |  |  | private List<AStarNavigateNode> getNeighborNodes(AStarNavigateNode currentNode, int[][] mapMatrix, Set<AStarNavigateNode> existNodes) { | 
|---|
|  |  |  | int x = currentNode.getX(); | 
|---|
|  |  |  | int y = currentNode.getY(); | 
|---|
|  |  |  | //如果当前结点的邻结点合法,就加入到neighbour_node | 
|---|
|  |  |  | ArrayList<NavigateNode> neighbourNodes = new ArrayList<>(); | 
|---|
|  |  |  | AStarNavigateNode parent = currentNode.getParent(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode rightNode = extendNeighborNodes(currentNode, new NavigateNode(x, y + 1), mapMatrix, existNodes, null, null); | 
|---|
|  |  |  | if (is_valid(currentNode, rightNode, mapMatrix, existNodes)) { | 
|---|
|  |  |  | neighbourNodes.add(rightNode); | 
|---|
|  |  |  | //        List<AStarNavigateNode> neighbourNodes = new CopyOnWriteArrayList<>(); | 
|---|
|  |  |  | List<AStarNavigateNode> neighbourNodes = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<AStarNavigateNode> possibleNodes = new ArrayList<>(); | 
|---|
|  |  |  | for (int[] d: DIRECTIONS) { | 
|---|
|  |  |  | int nx = x + d[0]; | 
|---|
|  |  |  | int ny = y + d[1]; | 
|---|
|  |  |  | // 如果父节点不为空,并且 (nx,ny) 等于父节点坐标,则跳过 | 
|---|
|  |  |  | if (parent != null && nx == parent.getX() && ny == parent.getY()) { | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | possibleNodes.add(new AStarNavigateNode(nx, ny)); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode leftNode = extendNeighborNodes(currentNode, new NavigateNode(x, y - 1), mapMatrix, existNodes, null, null); | 
|---|
|  |  |  | if (is_valid(currentNode, leftNode, mapMatrix, existNodes)) { | 
|---|
|  |  |  | neighbourNodes.add(leftNode); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | //        possibleNodes.parallelStream() | 
|---|
|  |  |  | //                .map(extendNode -> extendNeighborNodes(currentNode, extendNode, mapMatrix, existNodes, null, null)) | 
|---|
|  |  |  | //                .filter(Objects::nonNull) | 
|---|
|  |  |  | //                .forEach(neighbourNodes::add); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode topNode = extendNeighborNodes(currentNode, new NavigateNode(x - 1, y), mapMatrix, existNodes, null, null); | 
|---|
|  |  |  | if (is_valid(currentNode, topNode, mapMatrix, existNodes)) { | 
|---|
|  |  |  | neighbourNodes.add(topNode); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | NavigateNode bottomNode = extendNeighborNodes(currentNode, new NavigateNode(x + 1, y), mapMatrix, existNodes, null, null); | 
|---|
|  |  |  | if (is_valid(currentNode, bottomNode, mapMatrix, existNodes)) { | 
|---|
|  |  |  | neighbourNodes.add(bottomNode); | 
|---|
|  |  |  | for (AStarNavigateNode pn : possibleNodes) { | 
|---|
|  |  |  | AStarNavigateNode next = extendNeighborNodes(currentNode, pn, mapMatrix, existNodes, null, null); | 
|---|
|  |  |  | if (next != null) { | 
|---|
|  |  |  | neighbourNodes.add(next); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return neighbourNodes; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private NavigateNode extendNeighborNodes(NavigateNode currentNode, NavigateNode extendNode, int[][] mapMatrix, List<NavigateNode> existNodes, Integer dx, Integer dy) { | 
|---|
|  |  |  | NavigateNode nextNode = null; | 
|---|
|  |  |  | private AStarNavigateNode extendNeighborNodes(AStarNavigateNode currentNode, AStarNavigateNode extendNode, int[][] mapMatrix, Set<AStarNavigateNode> existNodes, Integer dx, Integer dy) { | 
|---|
|  |  |  | AStarNavigateNode nextNode; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (null == dx || null == dy) { | 
|---|
|  |  |  | dx = extendNode.getX() - currentNode.getX(); | 
|---|
|  |  |  | dy = extendNode.getY() - currentNode.getY(); | 
|---|
|  |  |  | nextNode = extendNode; | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | nextNode = new NavigateNode(extendNode.getX() + dx, extendNode.getY() + dy); | 
|---|
|  |  |  | nextNode = new AStarNavigateNode(extendNode.getX() + dx, extendNode.getY() + dy); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int x = nextNode.getX(); | 
|---|
|  |  |  | 
|---|
|  |  |  | if (mapMatrix[x][y] == MapNodeType.DISABLE.val)  { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return extendNeighborNodes(currentNode, nextNode, mapMatrix, existNodes, dx, dy); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (isExist(nextNode, existNodes)) { | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 节点是否可用 | 
|---|
|  |  |  | if (mapMatrix[x][y] != MapNodeType.ENABLE.val) { | 
|---|
|  |  |  | 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; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return nextNode; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private boolean is_valid(NavigateNode currentNode, NavigateNode node, int[][] mapMatrix, List<NavigateNode> existNodes) { | 
|---|
|  |  |  | if (null == node) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | //        int x = node.getX(); | 
|---|
|  |  |  | //        int y = node.getY(); | 
|---|
|  |  |  | //        if (x < 0 || x >= mapMatrix.length | 
|---|
|  |  |  | //                || y < 0 || y >= mapMatrix[0].length) { | 
|---|
|  |  |  | //            return false; | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        // 如果结点的位置小于0,则不合法 | 
|---|
|  |  |  | //        if (mapMatrix[x][y] < 0) return false; | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        if (is_exist(node, existNodes)) { | 
|---|
|  |  |  | //            return false; | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        // 判断通过性 | 
|---|
|  |  |  | //        String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null); | 
|---|
|  |  |  | //        String currentNodeCodeData = codeMatrix[currentNode.getX()][currentNode.getY()]; | 
|---|
|  |  |  | //        String nextNodeCodeData = codeMatrix[node.getX()][node.getY()]; | 
|---|
|  |  |  | //        node.setCodeData(nextNodeCodeData); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        Route route = routeService.findByCodeOfBoth( | 
|---|
|  |  |  | //                codeService.selectByData(currentNodeCodeData).getId(), | 
|---|
|  |  |  | //                codeService.selectByData(nextNodeCodeData).getId() | 
|---|
|  |  |  | //        ); | 
|---|
|  |  |  | //        if (null == route) { | 
|---|
|  |  |  | //            return false; | 
|---|
|  |  |  | assert mapMatrix[x][y] == MapNodeType.ENABLE.val; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //        if (existNodes.contains(nextNode)) { | 
|---|
|  |  |  | //            return null; | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //    private boolean is_exist(NavigateNode node, List<NavigateNode> existNodes) { | 
|---|
|  |  |  | //        for (NavigateNode exist_node : existNodes) { | 
|---|
|  |  |  | //            if (node.getX() == exist_node.getX() && node.getY() == exist_node.getY()) { | 
|---|
|  |  |  | //                return true; | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | //        return false; | 
|---|
|  |  |  | //    } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private boolean isExist(NavigateNode node, List<NavigateNode> existNodes) { | 
|---|
|  |  |  | for (NavigateNode existNode : existNodes) { | 
|---|
|  |  |  | if (this.isSame(node, existNode)) { | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | // 判断通过性 | 
|---|
|  |  |  | String routeCdaKey = RouteGenerator.generateRouteCdaKey(new int[]{currentNode.getX(), currentNode.getY()}, new int[]{nextNode.getX(), nextNode.getY()}); | 
|---|
|  |  |  | if (!mapDataDispatcher.validRouteCdaKey(routeCdaKey)) { | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private boolean isSame(NavigateNode o1, NavigateNode o2) { | 
|---|
|  |  |  | if (Cools.isEmpty(o1, o2)) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return o1.getX() == o2.getX() && o1.getY() == o2.getY(); | 
|---|
|  |  |  | return nextNode; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //------------------A*启发函数------------------// | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) | 
|---|
|  |  |  | private int calcNodeCost(NavigateNode node1, NavigateNode node2) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private int calcNodeCost(AStarNavigateNode node1, AStarNavigateNode node2) { | 
|---|
|  |  |  | return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //去除拐点算法,给直线增加优先级 | 
|---|
|  |  |  | private int calcNodeTurnCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { | 
|---|
|  |  |  | // 第一个点或直线点 | 
|---|
|  |  |  | if (currNode.getParent() == null | 
|---|
|  |  |  | || nextNode.getX() == currNode.getParent().getX() | 
|---|
|  |  |  | || nextNode.getY() == currNode.getParent().getY() | 
|---|
|  |  |  | ) { | 
|---|
|  |  |  | return 1; | 
|---|
|  |  |  | // 转弯判断:只允许“垂直或水平”运动 | 
|---|
|  |  |  | private boolean isTurning(AStarNavigateNode currNode, AStarNavigateNode nextNode) { | 
|---|
|  |  |  | // 第一个点 | 
|---|
|  |  |  | if (currNode.getParent() == null) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 拐向终点的点 | 
|---|
|  |  |  | if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { | 
|---|
|  |  |  | return 2; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 普通拐点 | 
|---|
|  |  |  | /* | 
|---|
|  |  |  | 拐点判断逻辑 | 
|---|
|  |  |  | 拿到父节点和下一节点 | 
|---|
|  |  |  | 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | return 3; | 
|---|
|  |  |  | AStarNavigateNode parent = currNode.getParent(); | 
|---|
|  |  |  | // 如果下一点(nextNode)与 parent 在同一行或同一列 => 没有转弯 | 
|---|
|  |  |  | // 注意,这实际上等同于“(curr->next) 的方向 == (parent->curr) 的方向”。 | 
|---|
|  |  |  | boolean sameRowOrCol = | 
|---|
|  |  |  | (nextNode.getX() == parent.getX()) | 
|---|
|  |  |  | || (nextNode.getY() == parent.getY()); | 
|---|
|  |  |  | return !sameRowOrCol; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 转弯判断:如果这两个向量相同(例如都等于 (0,1)),说明方向相同;否则说明转弯。 | 
|---|
|  |  |  | //    private boolean isTurning(AStarNavigateNode currNode, AStarNavigateNode nextNode) { | 
|---|
|  |  |  | //        // 如果 currNode 没有父节点,说明是起点,不算转弯 | 
|---|
|  |  |  | //        if (currNode.getParent() == null) { | 
|---|
|  |  |  | //            return false; | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | //        // 取出坐标 | 
|---|
|  |  |  | //        AStarNavigateNode parent = currNode.getParent(); | 
|---|
|  |  |  | //        int px = currNode.getX() - parent.getX();  // parent -> curr 的x偏移 | 
|---|
|  |  |  | //        int py = currNode.getY() - parent.getY();  // parent -> curr 的y偏移 | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        int nx = nextNode.getX() - currNode.getX(); // curr -> next 的x偏移 | 
|---|
|  |  |  | //        int ny = nextNode.getY() - currNode.getY(); // curr -> next 的y偏移 | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //        // 如果 (px, py) 与 (nx, ny) 不一样,就说明转弯 | 
|---|
|  |  |  | //        return (px != nx) || (py != ny); | 
|---|
|  |  |  | //    } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|