#
luxiaotao1123
2024-12-31 fe2d752b1f20cabead2620a3081ad77bc67526ae
#
2个文件已修改
1个文件已添加
224 ■■■■ 已修改文件
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/astart/AStarNavigateService.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/astart/domain/AStarNavigateNode.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java
@@ -6,6 +6,7 @@
import com.zy.acs.manager.common.utils.MapDataUtils;
import com.zy.acs.manager.core.constant.MapDataConstant;
import com.zy.acs.manager.core.service.astart.*;
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.core.service.floyd.FloydNavigateService;
import com.zy.acs.manager.manager.entity.Code;
@@ -54,15 +55,15 @@
        int[] startMapIdx = mapDataDispatcher.getCodeMatrixIdx(null, startCode.getData());
        int[] endMapIdx = mapDataDispatcher.getCodeMatrixIdx(null, endCode.getData());
        NavigateNode startNode = new NavigateNode(startMapIdx[0], startMapIdx[1], startCode.getData());
        NavigateNode endNode = new NavigateNode(endMapIdx[0], endMapIdx[1], endCode.getData());
        AStarNavigateNode startNode = new AStarNavigateNode(startMapIdx[0], startMapIdx[1], startCode.getData());
        AStarNavigateNode endNode = new AStarNavigateNode(endMapIdx[0], endMapIdx[1], endCode.getData());
        NavigateNode finishNode = aStarNavigateService.execute(agvNo, startNode, endNode, lock, blackList, segment);
        AStarNavigateNode finishNode = aStarNavigateService.execute(agvNo, startNode, endNode, lock, blackList, segment);
        if (null == finishNode) {
            return new ArrayList<>();
        }
        ArrayList<NavigateNode> navigateNodes = new ArrayList<>();
        ArrayList<AStarNavigateNode> navigateNodes = new ArrayList<>();
        while (finishNode != null) {
            navigateNodes.add(finishNode);
@@ -71,7 +72,7 @@
        Collections.reverse(navigateNodes);
        List<String> navigatePath = navigateNodes.stream().map(NavigateNode::getCodeData).collect(Collectors.toList());
        List<String> navigatePath = navigateNodes.stream().map(AStarNavigateNode::getCodeData).collect(Collectors.toList());
        // max count of steps
        if (navigatePath.size() > MapDataConstant.MAX_STEPS_SINGLE) {
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/astart/AStarNavigateService.java
@@ -1,12 +1,10 @@
package com.zy.acs.manager.core.service.astart;
import com.zy.acs.common.constant.RedisConstant;
import com.zy.acs.common.utils.GsonUtils;
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.core.utils.RouteGenerator;
import com.zy.acs.manager.manager.entity.Segment;
@@ -41,15 +39,15 @@
    @Autowired
    private ConfigService configService;
    public synchronized NavigateNode execute(String agvNo, NavigateNode start, NavigateNode end
    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<>();
        Set<NavigateNode> existNodes = new HashSet<>();
        PriorityQueue<AStarNavigateNode> openQueue = new PriorityQueue<>();
        Set<AStarNavigateNode> existNodes = new HashSet<>();
        openQueue.add(start);
        existNodes.add(start);
@@ -60,10 +58,14 @@
        String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(null);
        while (!openQueue.isEmpty()) {
            // 取优先队列顶部元素并且把这个元素从Open表中删除,取F值最小的节点
            NavigateNode currentNode = openQueue.poll();
            AStarNavigateNode currentNode = openQueue.poll();
            List<NavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes);
            for (NavigateNode node : neighbourNodes) {
            // 终点
            if (currentNode.getX() == end.getX() && currentNode.getY() == end.getY()) {
                return currentNode;
            }
            List<AStarNavigateNode> neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes);
            for (AStarNavigateNode node : neighbourNodes) {
                node.setCodeData(codeMatrix[node.getX()][node.getY()]);
                boolean isEndNode = node.getX() == end.getX() && node.getY() == end.getY();
@@ -140,23 +142,19 @@
                    }
                }
                //找到目标结点就返回
                if (isEndNode) {
                    //并且计算出G, F, H等值
                    node.initNode(currentNode, end);
                    return node;
                }
                // G + H + T (对启发函数增加去拐点方案calcNodeTurnCost)
                int gCost = calcNodeCost(currentNode, node);
                if (OPEN_TURN_COST_WEIGHT) {
                    gCost += calcNodeTurnCost(currentNode, node, end);
                    if (this.isTurning(currentNode, node)) {
                        weight += WEIGHT_CALC_FACTOR;
                        node.setTurnCount(currentNode.getTurnCount() + 1);
                    } else {
                        // 方向没变
                        node.setTurnCount(currentNode.getTurnCount());
                    }
                }
                //进行计算对 G, F, H 等值
                node.setWeight(weight);
                node.setLastDistance(gCost);
                node.setLastDistance(calcNodeCost(currentNode, node));
                node.initNode(currentNode, end);
                node.setH(calcNodeCost(node, end));
                node.setF(node.getG() + node.getH());
@@ -165,22 +163,22 @@
                existNodes.add(node);
            }
        }
        //如果遍历完所有出现的结点都没有找到最终的结点,返回null
        return null;
    }
    // 获取四周节点
    private List<NavigateNode> getNeighborNodes(NavigateNode currentNode, int[][] mapMatrix, Set<NavigateNode> existNodes) {
    private List<AStarNavigateNode> getNeighborNodes(AStarNavigateNode currentNode, int[][] mapMatrix, Set<AStarNavigateNode> existNodes) {
        int x = currentNode.getX();
        int y = currentNode.getY();
        List<NavigateNode> neighbourNodes = new CopyOnWriteArrayList<>();
        List<AStarNavigateNode> neighbourNodes = new CopyOnWriteArrayList<>();
        List<NavigateNode> possibleNodes = Arrays.asList(
                new NavigateNode(x, y + 1), // right
                new NavigateNode(x, y - 1), // left
                new NavigateNode(x - 1, y), // up
                new NavigateNode(x + 1, y)  // down
        List<AStarNavigateNode> possibleNodes = Arrays.asList(
                new AStarNavigateNode(x, y + 1), // right
                new AStarNavigateNode(x, y - 1), // left
                new AStarNavigateNode(x - 1, y), // up
                new AStarNavigateNode(x + 1, y)  // down
        );
        possibleNodes.parallelStream()
@@ -191,15 +189,15 @@
        return neighbourNodes;
    }
    private NavigateNode extendNeighborNodes(NavigateNode currentNode, NavigateNode extendNode, int[][] mapMatrix, Set<NavigateNode> existNodes, Integer dx, Integer dy) {
        NavigateNode nextNode;
    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();
@@ -233,27 +231,41 @@
    //------------------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 0;
    // 转弯判断:只允许“垂直或水平”运动
    private boolean isTurning(AStarNavigateNode currNode, AStarNavigateNode nextNode) {
        // 第一个点
        if (currNode.getParent() == null) {
            return false;
        }
        // 拐向终点的点
        if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) {
            return 1;
        }
        // 普通拐点
        return 1;
        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);
//    }
}
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/astart/domain/AStarNavigateNode.java
New file
@@ -0,0 +1,103 @@
package com.zy.acs.manager.core.service.astart.domain;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;
/**
 * A*寻路算法Node节点
 */
@Slf4j
@Data
public class AStarNavigateNode implements Comparable<AStarNavigateNode>, Cloneable, Serializable {
    private static final long serialVersionUID = 1L;
    private int x;  //坐标x
    private int y;  //坐标y
    private int turnCount;  //转弯次数
    private int G;  //已经花费的步数
    private int H;  //将要花费的步数
    private int F;  //综合花费的步数
    private AStarNavigateNode parent;    //父节点
    private Integer lastDistance;   // 距离上个节点距离
    private Integer weight;        // G 权重
//    private boolean turningPoint;   //是否为拐点
//    private Integer moveDistance;   // 总行走距离
//    private String direction;   //行走方向
    private String codeData;
    public AStarNavigateNode(int x, int y) {
        this.x = x;
        this.y = y;
        this.turnCount = 0;
    }
    public AStarNavigateNode(int x, int y, String codeData) {
        this.x = x;
        this.y = y;
        this.turnCount = 0;
        this.codeData = codeData;
    }
    //通过结点的坐标和目标结点的坐标可以计算出F, G, H三个属性
    //需要传入这个节点的上一个节点和最终的结点
    public void initNode(AStarNavigateNode father, AStarNavigateNode end) {
        this.parent = father;
        if (this.parent != null) {
            //走过的步数等于父节点走过的步数加一
            this.G = this.parent.G
                    + Optional.ofNullable(this.lastDistance).orElse(0)
                    + Optional.ofNullable(this.weight).orElse(0);
        } else { //父节点为空代表它是第一个结点
            this.G = 0;
        }
        //以下计算方案为算法原始方案,没有去拐点方案。已被Solution计算时自动覆盖。
        //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加)
        this.H = Math.abs(this.x - end.x) + Math.abs(this.y - end.y);
        this.F = this.G + this.H;
    }
    @Override
    public int compareTo(AStarNavigateNode o) {
        return Integer.compare(this.F, o.F);
    }
    @Override
    public AStarNavigateNode clone() {
        try {
            return (AStarNavigateNode) super.clone();
        } catch (CloneNotSupportedException e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof AStarNavigateNode)) return false;
        AStarNavigateNode that = (AStarNavigateNode) obj;
        return this.x == that.x
                && this.y == that.y
//                && this.turnCount == that.turnCount   // ** 转弯优化,严重影响性能
                ;
    }
    @Override
    public int hashCode() {
        return Objects.hash(
                this.x
                , this.y
//                , this.turnCount  // ** 转弯优化,严重影响性能
        );
    }
}