package com.zy.asrs.wcs.core.utils; 
 | 
  
 | 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 
 | 
import com.zy.asrs.framework.common.SpringUtils; 
 | 
import com.zy.asrs.framework.exception.CoolException; 
 | 
import com.zy.asrs.wcs.core.model.NavigateNode; 
 | 
import com.zy.asrs.wcs.core.model.enums.MapNodeType; 
 | 
import com.zy.asrs.wcs.system.entity.Dict; 
 | 
import com.zy.asrs.wcs.system.service.DictService; 
 | 
  
 | 
import java.util.ArrayList; 
 | 
import java.util.List; 
 | 
import java.util.PriorityQueue; 
 | 
  
 | 
/** 
 | 
 * 四向库核心 
 | 
 * A*算法实现类 
 | 
 */ 
 | 
public class NavigateSolution { 
 | 
  
 | 
    // -1 -> 墙壁, 0 -> 货位, 1 -> 起点  2 -> 终点  3-> 母轨  4->输送站点  5->充电桩 6->小车可走输送站点  66->小车  67->提升机 
 | 
  
 | 
    int[][] map = {{}}; 
 | 
  
 | 
    public NavigateSolution() { 
 | 
        //载入地图 
 | 
        NavigateMapData mapData = SpringUtils.getBean(NavigateMapData.class); 
 | 
        mapData.setLev(1); 
 | 
        int[][] data = mapData.getData(); 
 | 
        this.map = data; 
 | 
    } 
 | 
  
 | 
    public NavigateSolution(Integer mapType, Integer lev, List<int[]> whitePoints, List<int[]> shuttlePoints) { 
 | 
        //载入地图指定层高地图 
 | 
        NavigateMapData mapData = SpringUtils.getBean(NavigateMapData.class); 
 | 
        mapData.setLev(lev); 
 | 
        int[][] data = mapData.getDataFromRedis(mapType, whitePoints, shuttlePoints); 
 | 
        if (data == null) { 
 | 
            throw new CoolException("地图未载入!"); 
 | 
        } 
 | 
        this.map = data; 
 | 
    } 
 | 
  
 | 
    public NavigateSolution(int[][] data) { 
 | 
        this.map = data; 
 | 
    } 
 | 
  
 | 
    // Open表用优先队列 
 | 
    public PriorityQueue<NavigateNode> Open = new PriorityQueue<NavigateNode>(); 
 | 
    //Close表用普通的数组 
 | 
    public ArrayList<NavigateNode> Close = new ArrayList<NavigateNode>(); 
 | 
    //Exist表用来存放已经出现过的结点。 
 | 
    public ArrayList<NavigateNode> Exist = new ArrayList<NavigateNode>(); 
 | 
  
 | 
    public NavigateNode astarSearch(NavigateNode start, NavigateNode end) { 
 | 
        //把第一个开始的结点加入到Open表中 
 | 
        this.Open.add(start); 
 | 
        //把出现过的结点加入到Exist表中 
 | 
        this.Exist.add(start); 
 | 
        //主循环 
 | 
        while (Open.size() > 0) { 
 | 
            //取优先队列顶部元素并且把这个元素从Open表中删除 
 | 
            NavigateNode current_node = Open.poll(); 
 | 
            //将这个结点加入到Close表中 
 | 
            Close.add(current_node); 
 | 
            //对当前结点进行扩展,得到一个四周结点的数组 
 | 
            ArrayList<NavigateNode> neighbour_node = extend_current_node(current_node); 
 | 
            //对这个结点遍历,看是否有目标结点出现 
 | 
            for (NavigateNode node : neighbour_node) { 
 | 
                // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) 
 | 
                int gCost = calcNodeCost(current_node, node) * calcNodeExtraCost(current_node, node, end); 
 | 
                if (node.getX() == end.getX() && node.getY() == end.getY()) {//找到目标结点就返回 
 | 
                    //init_node操作把这个邻居结点的父节点设置为当前结点 
 | 
                    //并且计算出G, F, H等值 
 | 
                    node.setLastDistance(gCost); 
 | 
                    node.init_node(current_node, end); 
 | 
                    return node; 
 | 
                } 
 | 
  
 | 
                //进行计算对G, F, H 等值 
 | 
                node.setLastDistance(gCost); 
 | 
                node.init_node(current_node, end); 
 | 
                node.setH(calcNodeCost(node, end)); 
 | 
                node.setF(node.getG() + node.getH()); 
 | 
  
 | 
                Open.add(node); 
 | 
                Exist.add(node); 
 | 
            } 
 | 
        } 
 | 
        //如果遍历完所有出现的结点都没有找到最终的结点,返回null 
 | 
        return null; 
 | 
    } 
 | 
  
 | 
  
 | 
    public ArrayList<NavigateNode> extend_current_node(NavigateNode current_node) { 
 | 
        //默认地图母轨方向x 
 | 
        String mapDirection = "x"; 
 | 
        DictService dictService = SpringUtils.getBean(DictService.class); 
 | 
        if (dictService != null) { 
 | 
            Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>() 
 | 
                    .eq(Dict::getFlag, "direction_map") 
 | 
                    .eq(Dict::getStatus, 1)); 
 | 
            if (dict != null) { 
 | 
                mapDirection = dict.getValue(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        //获取当前结点的x, y 
 | 
        int x = current_node.getX(); 
 | 
        int y = current_node.getY(); 
 | 
        //如果当前结点的邻结点合法,就加入到neighbour_node 
 | 
        ArrayList<NavigateNode> neighbour_node = new ArrayList<NavigateNode>(); 
 | 
//        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); 
 | 
                    neighbour_node.add(node); 
 | 
                } 
 | 
                if (is_valid(x - 1, y)) 
 | 
                { 
 | 
                    NavigateNode node = new NavigateNode(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); 
 | 
                    neighbour_node.add(node); 
 | 
                } 
 | 
                if (is_valid(x, y - 1)) 
 | 
                { 
 | 
                    NavigateNode node = new NavigateNode(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); 
 | 
                    neighbour_node.add(node); 
 | 
                } 
 | 
                if (is_valid(x, y - 1)) 
 | 
                { 
 | 
                    NavigateNode node = new NavigateNode(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); 
 | 
                    neighbour_node.add(node); 
 | 
                } 
 | 
                if (is_valid(x - 1, y)) 
 | 
                { 
 | 
                    NavigateNode node = new NavigateNode(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; 
 | 
        } 
 | 
        NavigateNode navigateNode = new NavigateNode(x, y); 
 | 
        if (is_exist(navigateNode)) { 
 | 
            return false; 
 | 
        } 
 | 
        //以上情况都没有则合法 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    public boolean is_exist(NavigateNode node) 
 | 
    { 
 | 
        for (NavigateNode exist_node : Exist) { 
 | 
            if (node.getX() == exist_node.getX() && node.getY() == exist_node.getY()) { 
 | 
                return true; 
 | 
            } 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    //------------------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 1; 
 | 
        } 
 | 
  
 | 
        // 拐向终点的点 
 | 
        if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { 
 | 
            return 2; 
 | 
        } 
 | 
  
 | 
        // 普通拐点 
 | 
        /* 
 | 
        拐点判断逻辑 
 | 
        拿到父节点和下一节点 
 | 
        通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 
 | 
         */ 
 | 
        return 3; 
 | 
    } 
 | 
  
 | 
    //------------------A*启发函数-end------------------// 
 | 
  
 | 
} 
 |