package com.zy.common.utils; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.SpringUtils; import com.core.exception.CoolException; import com.zy.common.model.NavigateNode; import com.zy.core.enums.MapNodeType; import com.zy.core.model.PythonResult; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; /** * 四向库核心 * A*算法实现类 */ public class NavigateSolution { // -1 -> 墙壁, 0 -> 货位, 1 -> 起点 2 -> 终点 3-> 母轨 4->输送站点 5->充电桩 6->小车可走输送站点 66->小车 67->提升机 int[][] map = {{}}; public NavigateSolution(Integer mapType, Integer lev, List whitePoints, List shuttlePoints) { //载入地图指定层高地图 NavigateMapData mapData = SpringUtils.getBean(NavigateMapData.class); int[][] data = mapData.getDataFromRedis(lev, mapType, whitePoints, shuttlePoints); if (data == null) { throw new CoolException("地图未载入!"); } this.map = data; } public NavigateSolution(int[][] data) { this.map = data; } // Open表用优先队列 public PriorityQueue Open = new PriorityQueue(); //Close表用普通的数组 public ArrayList Close = new ArrayList(); //用来存放已经出现过的结点。 Map bestGMap = new HashMap<>(); public String astarSearchPython(NavigateNode start, NavigateNode end, String pythonScriptPath) { String maps = JSON.toJSONString(map); String startStr = start.getX() + "-" + start.getY(); String targetStr = end.getX() + "-" + end.getY(); //默认地图母轨方向x String mapDirection = "x"; ConfigService configService = SpringUtils.getBean(ConfigService.class); if (configService != null) { Config config = configService.selectOne(new EntityWrapper() .eq("code", "direction_map") .eq("status", 1)); if (config != null) { mapDirection = config.getValue(); } } ProcessBuilder processBuilder = new ProcessBuilder("python", pythonScriptPath, maps, startStr, targetStr, mapDirection); processBuilder.redirectErrorStream(true); try { Process process = processBuilder.start(); // 读取Python脚本的输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null) { builder.append(line); } // 等待Python脚本执行完成 int exitCode = process.waitFor(); if (exitCode != 0) { System.out.println("Python script exited with error code: " + exitCode); return null; } reader.close(); if (builder.length() <= 0) { return null; } PythonResult result = JSON.parseObject(builder.toString(), PythonResult.class); if (result.getCalcResult() != 200) { return null; } String path = result.getPath(); return path; } catch (IOException | InterruptedException e) { e.printStackTrace(); } return null; } public NavigateNode astarSearchJava(NavigateNode start, NavigateNode end) { //把第一个开始的结点加入到Open表中 this.Open.add(start); //主循环 while (Open.size() > 0) { //取优先队列顶部元素并且把这个元素从Open表中删除 NavigateNode current_node = Open.poll(); if (current_node.getX() == end.getX() && current_node.getY() == end.getY()) {//找到目标结点就返回 return current_node; } //将这个结点加入到Close表中 Close.add(current_node); //对当前结点进行扩展,得到一个四周结点的数组 ArrayList neighbour_node = extend_current_node(current_node); //对这个结点遍历,看是否有目标结点出现 for (NavigateNode node : neighbour_node) { // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) int gCost = calcNodeExtraCost(current_node, node, end); //进行计算对G, F, H 等值 node.setG(1 + gCost); node.init_node(current_node, end); node.setH(calcNodeCost(node, end)); node.setF(node.getG() + node.getH()); String key = node.getX() + "_" + node.getY(); Integer recordedG = bestGMap.get(key); if (recordedG == null || node.getG() <= recordedG) { bestGMap.put(key, node.getG()); Open.add(node); } } } //如果遍历完所有出现的结点都没有找到最终的结点,返回null return null; } public ArrayList extend_current_node(NavigateNode current_node) { //默认地图母轨方向x String mapDirection = "x"; ConfigService configService = SpringUtils.getBean(ConfigService.class); if (configService != null) { Config config = configService.selectOne(new EntityWrapper() .eq("code", "direction_map") .eq("status", 1)); if (config != null) { mapDirection = config.getValue(); } } //获取当前结点的x, y int x = current_node.getX(); int y = current_node.getY(); //如果当前结点的邻结点合法,就加入到neighbour_node ArrayList neighbour_node = new ArrayList(); // if (map[x][y] == 0 || map[x][y] == 3) { // //只有子轨和母轨才能进行左右移动 // if (is_valid(x, y + 1)) // { // Node node = new Node(x, y + 1); // neighbour_node.add(node); // } // if (is_valid(x, y - 1)) // { // Node node = new Node(x, y - 1); // neighbour_node.add(node); // } // } // // if (map[x][y] == 3) { // //只有母轨才能进行上下移动 // if (is_valid(x + 1, y)) // { // Node node = new Node(x + 1, y); // neighbour_node.add(node); // } // if (is_valid(x - 1, y)) // { // Node node = new Node(x -1, y); // neighbour_node.add(node); // } // } if (mapDirection.equals("x")) {//母轨x方向 if (map[x][y] == MapNodeType.MAIN_PATH.id) { //母轨才能进行上下移动 if (is_valid(x + 1, y)) { NavigateNode node = new NavigateNode(x + 1, y); node.setNodeValue(map[x + 1][y]); neighbour_node.add(node); } if (is_valid(x - 1, y)) { NavigateNode node = new NavigateNode(x - 1, y); node.setNodeValue(map[x - 1][y]); neighbour_node.add(node); } } if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) { //子轨和母轨、小车可走输送线、充电桩、提升机才能进行左右移动 if (is_valid(x, y + 1)) { NavigateNode node = new NavigateNode(x, y + 1); node.setNodeValue(map[x][y + 1]); neighbour_node.add(node); } if (is_valid(x, y - 1)) { NavigateNode node = new NavigateNode(x, y - 1); node.setNodeValue(map[x][y - 1]); neighbour_node.add(node); } } }else if (mapDirection.equals("y")) {//母轨y方向 if (map[x][y] == MapNodeType.MAIN_PATH.id) { //母轨才能进行左右移动 if (is_valid(x, y + 1)) { NavigateNode node = new NavigateNode(x, y + 1); node.setNodeValue(map[x][y + 1]); neighbour_node.add(node); } if (is_valid(x, y - 1)) { NavigateNode node = new NavigateNode(x, y - 1); node.setNodeValue(map[x][y - 1]); neighbour_node.add(node); } } if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) { //子轨和母轨、小车可走输送线、充电桩、提升机才能进行上下移动 if (is_valid(x + 1, y)) { NavigateNode node = new NavigateNode(x + 1, y); node.setNodeValue(map[x + 1][y]); neighbour_node.add(node); } if (is_valid(x - 1, y)) { NavigateNode node = new NavigateNode(x - 1, y); node.setNodeValue(map[x - 1][y]); neighbour_node.add(node); } } } return neighbour_node; } public boolean is_valid(int x, int y) { if (x < 0 || x >= this.map.length || y < 0 || y >= this.map[0].length) { return false; } // 如果结点的位置小于0,则不合法 if (map[x][y] < 0) { return false; } if (map[x][y] == MapNodeType.CAR.id) {//节点是小车 return false; } //以上情况都没有则合法 return true; } //------------------A*启发函数------------------// //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) private int calcNodeCost(NavigateNode node1, NavigateNode node2) { return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); } //去除拐点算法,给直线增加优先级 private int calcNodeExtraCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { // 第一个点或直线点 if (currNode.getFather() == null || nextNode.getX() == currNode.getFather().getX() || nextNode.getY() == currNode.getFather().getY()) { return 0; } // 拐向终点的点 if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { return 1; } // 普通拐点 /* 拐点判断逻辑 拿到父节点和下一节点 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 */ return 1; } //------------------A*启发函数-end------------------// }