bklLiudl
2025-04-08 a82e815f97b789dc4ca208df09dd96534a023f4a
Wms/WMS.DAL/Common.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.Design;
using System.Data;
using System.Linq;
@@ -8,6 +9,7 @@
using System.Threading.Tasks;
using Model.ModelDto.BllSoDto;
using Model.ModelDto.SysDto;
using Serilog;
using SqlSugar;
using WMS.Entity.BllAsnEntity;
using WMS.Entity.BllCheckEntity;
@@ -17,12 +19,13 @@
using WMS.Entity.LogEntity;
using WMS.Entity.SysEntity;
namespace WMS.DAL
{
    public class Common
    {
        //public static readonly DataContext Db = new DataContext();
        /// <summary>
        /// 获取深度为1的储位号(根据深度为2的储位号)
@@ -477,6 +480,268 @@
            }
        }
        /// <summary>
        /// 获取小车路径
        /// </summary>
        /// <param name="startLocation">起始位置</param>
        /// <param name="endLocation">目标位置</param>
        /// <param name="moveType">移动类型 0:移动 1:取货 2:放货</param>
        /// <param name="isLoad">是否载货0:未载货  1:已载货</param>
        /// <returns></returns>
        public static List<CarModel> GetCarPath(string startLocation, string endLocation, int moveType, string isLoad = "0")
        {
            var _db = DataContext.Db;
            if (string.IsNullOrEmpty(startLocation) || string.IsNullOrEmpty(endLocation))
            {
                return null;
            }
            // 起始位置
            CarModel start = new CarModel()
            {
                X = int.Parse(startLocation.Substring(0, 2)),
                Y = int.Parse(startLocation.Substring(2, 2)),
                Z = int.Parse(startLocation.Substring(4, 2)),
                NodeCom = 0
            };
            // 目标位置
            CarModel end = new CarModel()
            {
                X = int.Parse(endLocation.Substring(0, 2)),
                Y = int.Parse(endLocation.Substring(2, 2)),
                Z = int.Parse(endLocation.Substring(4, 2)),
                NodeCom = 0
            };
            // 获取储位表信息存储到集合里
            var layer = int.Parse(startLocation.Substring(4, 2));
            //  获取当前层储位信息
            var locationModels = _db.Queryable<WCSStorageLocat>()
                .Where(m => m.WareHouseNo == "W01" && m.Layer == layer && m.IsDelete == false)
                .ToList();
            #region 不用绘制地图,直接根据储位表计算 liudl
            // 绘制仓库地图 -1:不可用 0:主通道  1:子通道
            //int[,] warehouseMap = new int[maxRow, maxColumn];
            //for (int row = 0; row < maxRow; row++)
            //{
            //    for (int column = 0; column < maxColumn; column++)
            //    {
            //        // 获取当前位置储位信息
            //        var locationModel = locationModels.First(it => it.Row == row && it.Column == column);
            //        // 不存在此位置信息
            //        if (locationModel == null)
            //        {
            //            warehouseMap[row, column] = -1;
            //            continue;
            //        }
            //        // 储位状态为损坏不可通行 储位状态为屏蔽为可通行不可存储托盘
            //        if (locationModel.Flag == "2")
            //        {
            //            warehouseMap[row, column] = -1;
            //            continue;
            //        }
            //        warehouseMap[row, column] = int.Parse(locationModel.Make);
            //    }
            //}
            #endregion
            #region 使用算法计算小车路径
            try
            {
                // 定义开发列表存储路径节点
                var openSet = new SortedSet<(int fscore, CarModel pos)>();
                // 定义关闭节点字典
                var closeSet = new Dictionary<CarModel, CarModel>();
                // 定义上一位置与目标位置字典
                var cameFrom = new Dictionary<CarModel, CarModel>();
                // 定义上一位置与目标位置的实际距离字典
                var gScore = new Dictionary<CarModel, int>();
                // 定义上一位置与目标位置的预估距离字典
                var fScore = new Dictionary<CarModel, int>();
                // 存储最优距离,及起始节点
                openSet.Add((Heuristic(start, end), start));
                gScore[start] = 0;
                fScore[start] = Heuristic(start, end);
                // 循环查找路径
                while (openSet.Count > 0)
                {
                    var current = openSet.Min.pos;
                    openSet.Remove(openSet.Min);
                    if (current.Equals(end))
                    {
                        Log.Error(ReconstructPath(cameFrom, current).ToString());
                        return ReconstructPath(cameFrom, current);
                    }
                    // 存储小车可运行的方向
                    var validDirections = new List<CarModel>();
                    var currentLocation = locationModels.FirstOrDefault(m => m.Row == current.X && m.Column == current.Y);
                    if (currentLocation.Make == "0")
                    {
                        // 主通道
                        validDirections.Add(new CarModel() { X = 1, Y = 0 }); // 右
                        validDirections.Add(new CarModel() { X = -1, Y = 0 }); // 左
                        validDirections.Add(new CarModel() { X = 0, Y = 1 }); // 下
                        validDirections.Add(new CarModel() { X = 0, Y = -1 }); // 上
                    }
                    if (currentLocation.Make == "1" )
                    {
                        // 子通道
                        // 先拆分出口
                        var outNode = currentLocation.AisleOne;
                        if (string.IsNullOrEmpty(outNode))
                        {
                            throw new Exception("当前位置没有维护出口!");
                        }
                        int outX = int.Parse(outNode.Substring(0, 2));
                        int outY = int.Parse(outNode.Substring(2, 2));
                        if (current.X == outX)
                        {
                            validDirections.Add(new CarModel() { X = 0, Y = 1 }); // 下
                            validDirections.Add(new CarModel() { X = 0, Y = -1 }); // 上
                        }
                        else
                        {
                            validDirections.Add(new CarModel() { X = 1, Y = 0 }); // 右
                            validDirections.Add(new CarModel() { X = -1, Y = 0 }); // 左
                        }
                    }
                    // 循环连接节点。
                    bool isNextNode = false;
                    foreach (var dir in validDirections)
                    {
                        CarModel neighbor = new CarModel() { X = current.X + dir.X, Y = current.Y + dir.Y ,Z=layer};
                        // 验证下一节点位置是否可通行并且判断是否被其他小车占用
                        // 判断下一节点是否关闭
                        if (closeSet.ContainsKey(neighbor))
                        {
                            closeSet[neighbor] = neighbor;
                        }
                        // 当前节点
                        var currentModel = locationModels.FirstOrDefault(it => it.Row == current.X && it.Column == current.Y);
                        // 下一节点
                        var locationModel = locationModels.FirstOrDefault(it => it.Row == neighbor.X && it.Column == neighbor.Y);
                        // 不存在此位置信息
                        if (locationModel == null)
                        {
                            closeSet[neighbor] = neighbor;
                            continue;
                        }
                        // 储位状态为损坏不可通行 储位状态为屏蔽为可通行不可存储托盘
                        if (locationModel.Flag == "2")
                        {
                            closeSet[neighbor] = neighbor;
                            continue;
                        }
                        // 判断下一节点上是否有托盘
                        if (!string.IsNullOrEmpty(locationModel.PalletNo))
                        {
                            // 判断小车是否载托盘盘
                            if (isLoad == "1")
                            {
                                closeSet[neighbor] = neighbor;
                                // 小车上载托盘不可通行跳过
                                continue;
                            }
                        }
                        // 优化项,验证下一节点是否被别的小车占用 liudl:在此添加优化代码
                        // 更新实际距离
                        int tentativeGScore = gScore[current] + 1;
                        // 判断位置是否已包含在路径内 且 是否更近节点
                        if (!gScore.ContainsKey(neighbor) || tentativeGScore < gScore[neighbor])
                        {
                            neighbor.IsSendPlc = false;
                            // 补充参数
                            if (neighbor.Equals(end))
                            {
                                neighbor.NodeCom = moveType;
                                neighbor.IsSendPlc = true;
                            }
                            else if (currentModel.Make != locationModel.Make)
                            {
                                if (current.X == neighbor.X)
                                {
                                    neighbor.NodeCom = 3;
                                }
                                else if (current.Y == neighbor.Y)
                                {
                                    neighbor.NodeCom = 2;
                                }
                                neighbor.IsSendPlc = true;
                            }
                            // 更新实际距离与预估距离
                            cameFrom[neighbor] = current;
                            gScore[neighbor] = tentativeGScore;
                            fScore[neighbor] = tentativeGScore + Heuristic(neighbor, end);
                            openSet.Add((fScore[neighbor], neighbor));
                            isNextNode = true;
                        }
                    }
                    if (!isNextNode)
                    {
                        closeSet[current] = current;
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return null;
        }
        /// <summary>
        /// 计算曼哈顿距离
        /// </summary>
        /// <param name="start">起始位置</param>
        /// <param name="end">目标位置</param>
        /// <returns>位置距离</returns>
        private static int Heuristic(CarModel start, CarModel end)
        {
            return Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y);
        }
        /// <summary>
        /// 重构完整路径
        /// </summary>
        /// <param name="cameFrom"></param>
        /// <param name="current"></param>
        /// <returns></returns>
        private static List<CarModel> ReconstructPath(Dictionary<CarModel, CarModel> cameFrom, CarModel current)
        {
            var path = new List<CarModel> { current };
            while (cameFrom.ContainsKey(current))
            {
                current = cameFrom[current];
                path.Insert(0, current);
            }
            return path;
        }
    }
    public enum InOutFlag
    {
@@ -522,4 +787,66 @@
        [Description("质检请验单")]
        QC
    }
    public class CarModel : IComparable<CarModel>
    {
        /// <summary>
        /// 行=X
        /// </summary>
        public int X { get; set; }
        /// <summary>
        /// 列=Y
        /// </summary>
        public int Y { get; set; }
        /// <summary>
        /// 层=Z
        /// </summary>
        public int Z { get; set; }
        /// <summary>
        /// 节点命令 1:顶货  2:子通道运行  3:主通道运行  4:放货
        /// </summary>
        public int NodeCom { get; set; }
        /// <summary>
        /// 是否下发plc
        /// </summary>
        public bool IsSendPlc { get; set; }
        public int CompareTo(CarModel other)
        {
            if (other == null)
                return 1;
            // 这里根据 X、Y、Z 坐标进行比较
            int result = X.CompareTo(other.X);
            if (result != 0)
                return result;
            result = Y.CompareTo(other.Y);
            if (result != 0)
                return result;
            return Z.CompareTo(other.Z);
        }
        // 重写 Equals 方法
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;
            CarModel other = (CarModel)obj;
            return X == other.X && Y == other.Y && Z == other.Z;
        }
        // 重写 GetHashCode 方法
        public override int GetHashCode()
        {
            return HashCode.Combine(X, Y, Z);
        }
    }
}