using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.Design;
|
using System.Data;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using Model.ModelDto.BllSoDto;
|
using Model.ModelDto.SysDto;
|
using Serilog;
|
using SqlSugar;
|
using WMS.Entity.BllAsnEntity;
|
using WMS.Entity.BllCheckEntity;
|
using WMS.Entity.BllQualityEntity;
|
using WMS.Entity.BllSoEntity;
|
using WMS.Entity.Context;
|
using WMS.Entity.LogEntity;
|
using WMS.Entity.SysEntity;
|
|
|
namespace WMS.DAL
|
{
|
public class Common
|
{
|
//public static readonly DataContext Db = new DataContext();
|
|
|
/// <summary>
|
/// 获取深度为1的储位号(根据深度为2的储位号)
|
/// </summary>
|
/// <param name="houseNo">仓库号</param>
|
/// <param name="locateNo">储位号</param>
|
/// <returns></returns>
|
public SysStorageLocat GetLocateNoDepth1(string houseNo, string locateNo)
|
{
|
try
|
{
|
var Db = DataContext.Db;
|
//获取储位信息
|
//var sql = $@"select * from SysStorageLocat where WareHouseNo = '{houseNo}' and LocatNo = '{locateNo}'; ";
|
var locate = Db.Queryable<SysStorageLocat>().Where(s => s.WareHouseNo == houseNo && s.LocatNo == locateNo).First();
|
if (locate == null)
|
{
|
throw new Exception($"未查询到仓库号为{houseNo}、储位号为{locateNo}的信息");
|
}
|
//获取深度为2的储位信息
|
//var sql2 = $@"select * from SysStorageLocat where WareHouseNo = '{houseNo}' and row = {locate.Row} and [Column] = {locate.Column} and Layer = {locate.Layer} and Depth = '01'; ";
|
//var data = Db.Ado.SqlQuery<SysStorageLocat>(sql2).First();
|
var data = Db.Queryable<SysStorageLocat>().Where(s => s.WareHouseNo == houseNo && s.Row == locate.Row && s.Column == locate.Column && s.Layer == locate.Layer && s.Depth == "01").First();
|
if (data == null)
|
{
|
throw new Exception($"未查询到仓库号为{houseNo}、储位号为{locateNo}的里面储位信息");
|
}
|
|
return data;
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
/// <summary>
|
/// 获取深度为2的储位号(根据深度为1的储位号)
|
/// </summary>
|
/// <param name="houseNo">仓库号</param>
|
/// <param name="locateNo">储位号</param>
|
/// <returns></returns>
|
public SysStorageLocat GetLocateNoDepth2(string houseNo, string locateNo)
|
{
|
try
|
{
|
var Db = DataContext.Db;
|
//获取储位信息
|
//var sql = $@"select * from SysStorageLocat where WareHouseNo = '{houseNo}' and LocatNo = '{locateNo}'; ";
|
//var locate = Db.Ado.SqlQuery<SysStorageLocat>(sql).First();
|
var locate = Db.Queryable<SysStorageLocat>().Where(s => s.WareHouseNo == houseNo && s.LocatNo == locateNo).First();
|
if (locate == null)
|
{
|
throw new Exception($"未查询到仓库号为{houseNo}、储位号为{locateNo}的信息");
|
}
|
//获取深度为2的储位信息
|
//var sql2 = $@"select * from SysStorageLocat where WareHouseNo = '{houseNo}' and row = {locate.Row} and [Column] = {locate.Column} and Layer = {locate.Layer} and Depth = '02'; ";
|
//var data = Db.Ado.SqlQuery<SysStorageLocat>(sql2).First();
|
var data = Db.Queryable<SysStorageLocat>().Where(s => s.WareHouseNo == houseNo && s.Row == locate.Row && s.Column == locate.Column && s.Layer == locate.Layer && s.Depth == "02").First();
|
if (data == null)
|
{
|
throw new Exception($"未查询到仓库号为{houseNo}、储位号为{locateNo}的里面储位信息");
|
}
|
return data;
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 获取移库目标库位
|
/// </summary>
|
/// <param name="oldAddress">需要移动的库位地址</param>
|
/// <param name="roadWay">巷道</param>
|
/// <param name="skuNo">物料编码</param>
|
/// <returns>目标库位地址 为"" 直接下发两次出库指令</returns>
|
public string MoveAddress(string oldAddress, string roadWay, string skuNo)//01020201 排-列-层-深度
|
{
|
string nowAddress = "";
|
var Db = DataContext.Db;
|
//根据物料编码获取对应区域
|
var skuCategoryNo = Db.Queryable<SysMaterials>().Where(a => a.IsDel == "0" && a.SkuNo == skuNo).Select(a => a.CategoryNo).First();
|
var category = Db.Queryable<SysMaterialCategory>().First(a => a.IsDel == "0" && a.CategoryNo == skuCategoryNo);
|
|
// 获取移库目标储位
|
var row = int.Parse(oldAddress.Substring(0, 2));
|
var lie = int.Parse(oldAddress.Substring(2, 2));
|
var ceng = int.Parse(oldAddress.Substring(4, 2));
|
|
//var sqlString = $@"select LocatNo,[Row],[Column],Layer, (ABS(Row-{row}) + ABS([Column]-{lie}) + ABS(Layer-{ceng})) as distNum from SysStorageLocat where Flag = '0' and Status = '0' and Depth = '02' and RoadwayNo = '{roadWay}' and AreaNo in ('{category.AreaNo}') order by distNum;";
|
|
//var addressModels = Db.Ado.SqlQuery<AddressCls>(sqlString).ToList();
|
var listArea = category.AreaNo.Split(',');
|
var addressModels = Db.Queryable<SysStorageLocat>()
|
.Where(s => s.Flag == "0" && s.Status == "0" && s.Depth == "02" && s.RoadwayNo == roadWay && listArea.Contains(s.AreaNo))
|
.Select(s => new AddressCls()
|
{
|
LocatNo = s.LocatNo,
|
Row = s.Row,
|
Column = s.Column,
|
Layer = s.Layer,
|
DistNum = SqlFunc.Abs(s.Row - row) + SqlFunc.Abs(s.Column - lie) + SqlFunc.Abs(s.Layer - ceng)
|
})
|
.OrderBy(s => s.DistNum)
|
.ToList();
|
if (addressModels.Count > 0) // 判断同巷道内排空库位
|
{
|
var listLocaete = new List<string>();
|
foreach (var item in addressModels)
|
{
|
// 目标内库位对应的外库位
|
string addressee = item.LocatNo.Substring(0, 6) + "01";
|
|
// 判断目标库位的外库位是否存在货物 (正常情况下正在移入情况不存在,因为移库先移入里面,后移入外面)
|
//SlotStatus 0: 空储位 1:有货 2:正在入库 3:正在出库 4:正在移入 5:正在移出
|
//sqlString = $"select count(*) from SysStorageLocat where LocatNo = '{addressee}' and Status = '0' and Flag in ('0','1') ; ";
|
//var rowNum = Db.Ado.SqlQuery<int>(sqlString).First();
|
var rowNum = Db.Queryable<SysStorageLocat>().Count(s => s.LocatNo == addressee && s.Status == "0" && (s.Flag == "0" || s.Flag == "1"));
|
if (rowNum == 0)
|
{
|
continue;
|
}
|
else
|
{
|
nowAddress = item.LocatNo;
|
break;
|
}
|
}
|
}
|
if (nowAddress == "")
|
{
|
// 判断同巷道外排空库位
|
//sqlString = $@"select LocatNo,[Row],[Column],Layer, (ABS(Row-{row}) + ABS([Column]-{lie}) + ABS(Layer-{ceng})) as distNum
|
// from SysStorageLocat
|
// where Flag = '0' and Status = '0' and Depth = '01' and RoadwayNo = '{roadWay}' and AreaNo in '{category}'
|
// order by distNum;";
|
//var adderModeling = Db.Ado.SqlQuery<AddressCls>(sqlString).ToList();
|
var adderModeling = Db.Queryable<SysStorageLocat>()
|
.Where(s => s.Flag == "0" && s.Status == "0" && s.Depth == "01" && s.RoadwayNo == roadWay && listArea.Contains(s.AreaNo))
|
.Select(s => new AddressCls()
|
{
|
LocatNo = s.LocatNo,
|
Row = s.Row,
|
Column = s.Column,
|
Layer = s.Layer,
|
DistNum = SqlFunc.Abs(s.Row - row) + SqlFunc.Abs(s.Column - lie) + SqlFunc.Abs(s.Layer - ceng)
|
})
|
.OrderBy(s => s.DistNum)
|
.ToList();
|
if (adderModeling.Count > 0)
|
{
|
nowAddress = adderModeling[0].LocatNo;
|
}
|
else
|
{
|
// 库内不存在空储位
|
nowAddress = "";
|
}
|
}
|
|
|
return nowAddress;
|
}
|
|
/// <summary>
|
/// 根据前缀获取最大单据号
|
/// </summary>
|
/// <param name="codeFlag">单据前缀</param>
|
/// <returns></returns>
|
public string GetMaxNo(string codeFlag)
|
{
|
try
|
{
|
var maxNo = "";
|
//获取异常号
|
maxNo = SelectMaxNo(codeFlag);
|
if (!string.IsNullOrEmpty(maxNo))
|
{
|
maxNo = maxNo.Substring(codeFlag.Length);
|
}
|
//获取数据库时间八位
|
string date = DateTime.Now.ToString("yyyyMMdd").Trim();
|
string no = "";
|
if (string.IsNullOrEmpty(maxNo))
|
{
|
no = codeFlag + date + "00001";
|
}
|
else
|
{
|
if (maxNo.Substring(0, 8) == date)
|
{
|
int lastNo = Convert.ToInt32(maxNo.Substring(8, 5)) + 1;
|
no = codeFlag + date + (lastNo.ToString().PadLeft(5, '0'));
|
}
|
else
|
{
|
no = codeFlag + date + "00001";
|
}
|
}
|
return no;
|
}
|
catch (Exception e)
|
{
|
Console.WriteLine(e);
|
throw;
|
}
|
}
|
/// <summary>
|
/// 根据前缀判断出当前最大单据号
|
/// </summary>
|
/// <param name="codeFlag">单据前缀</param>
|
/// <returns></returns>
|
public string SelectMaxNo(string codeFlag)
|
{
|
try
|
{
|
string orderNo = "";
|
if (codeFlag == InOutFlag.SO.ToString())//出库
|
{
|
var list = DataContext.Db.Queryable<BllExportNotice>().Where(m => m.SONo.StartsWith("SO")).ToList();
|
orderNo = list.Max(a => a.SONo);
|
}
|
if (codeFlag == InOutFlag.WSO.ToString())//波次出库
|
{
|
var list = DataContext.Db.Queryable<BllWaveMage>().Where(m => m.WaveNo.StartsWith("WSO")).ToList();
|
orderNo = list.Select(a => a.WaveNo).Max();
|
}
|
else if (codeFlag == InOutFlag.ASN.ToString())//入库
|
{
|
var list = DataContext.Db.Queryable<BllArrivalNotice>().Where(m => m.ASNNo.StartsWith("ASN")).ToList();
|
orderNo = list.Select(a => a.ASNNo).Max();
|
}
|
else if (codeFlag == InOutFlag.PM.ToString())//移库
|
{
|
}
|
else if (codeFlag == InOutFlag.CR.ToString())//盘点
|
{
|
var list = DataContext.Db.Queryable<BllStockCheck>().Where(m => m.CRNo.StartsWith("CR")).ToList();
|
orderNo = list.Select(a => a.CRNo).Max();
|
}
|
else if (codeFlag == InOutFlag.TK.ToString())//任务
|
{
|
var list = DataContext.Db.Queryable<LogTask>().Where(m => m.TaskNo.StartsWith("TK")).ToList();
|
orderNo = list.Max(m => m.TaskNo);
|
}
|
else if (codeFlag == InOutFlag.EX.ToString())//异常
|
{
|
var list = DataContext.Db.Queryable<SysException>().Where(m => m.ExceptionNo.StartsWith("EX")).ToList();
|
orderNo = list.Max(a => a.ExceptionNo);
|
}
|
else if (codeFlag == InOutFlag.QC.ToString())//质检请验单
|
{
|
var list = DataContext.Db.Queryable<BllQualityInspectionRequest>().Where(m => m.QcNo.StartsWith("QC")).ToList();
|
orderNo = list.Max(a => a.QcNo);
|
}
|
|
return orderNo;
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 执行sql语句获取行数
|
/// </summary>
|
/// <param name="sqlString">查询语句</param>
|
/// <returns>行数</returns>
|
public int GetRowCount(string sqlString)
|
{
|
try
|
{
|
var db = DataContext.Db;
|
var rowCount = db.Ado.GetInt(sqlString);
|
|
return rowCount;
|
}
|
catch (Exception ex)
|
{
|
throw new Exception(ex.Message);
|
}
|
}
|
|
/// <summary>
|
/// 判断托盘是否在入库中
|
/// </summary>
|
/// <param name="palletNo">托盘号</param>
|
/// <returns></returns>
|
public LogTask GetImTask(string palletNo)
|
{
|
try
|
{
|
var db = DataContext.Db;
|
//查询托盘是否有正在入库的任务
|
var imTask = db.Queryable<LogTask>().First(m => m.PalletNo == palletNo && m.IsDel == "0" && m.Status == "1");
|
|
return imTask;
|
}
|
catch (Exception ex)
|
{
|
throw new Exception(ex.Message);
|
}
|
}
|
|
/// <summary>
|
/// //获取包装信息 托盘内数、箱内数
|
/// </summary>
|
/// <param name="packNo"></param>
|
/// <param name="pNum">托盘包装数</param>
|
/// <param name="bNum">箱包装数</param>
|
public void GetPackQtyInfo(string packNo, ref int pNum, ref int bNum)
|
{
|
try
|
{
|
var db = DataContext.Db;
|
var pack = db.Queryable<SysPackag>().First(m => m.PackagNo == packNo);
|
if (pack != null)
|
{
|
if (pack.L5Num.HasValue)
|
{
|
pNum = Convert.ToInt32(pack.L5Num);
|
bNum = Convert.ToInt32(pack.L4Num);
|
}
|
else if (pack.L4Num.HasValue)
|
{
|
pNum = Convert.ToInt32(pack.L4Num);
|
bNum = Convert.ToInt32(pack.L3Num);
|
}
|
else if (pack.L3Num.HasValue)
|
{
|
pNum = Convert.ToInt32(pack.L3Num);
|
bNum = Convert.ToInt32(pack.L2Num);
|
}
|
else if (pack.L2Num.HasValue)
|
{
|
pNum = Convert.ToInt32(pack.L2Num);
|
bNum = Convert.ToInt32(pack.L1Num);
|
}
|
else if (pack.L1Num.HasValue)
|
{
|
pNum = Convert.ToInt32(pack.L1Num);
|
bNum = Convert.ToInt32(pack.L1Num);
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 获取系统功能设定小数位数设定值,默认为4位
|
/// </summary>
|
/// <returns></returns>
|
public double GetSysDecimalDigit()
|
{
|
try
|
{
|
var db = DataContext.Db;
|
var funSet = db.Queryable<SysFunSetting>().First(m => m.IsDel == "0" && m.FunSetName == "小数点位数" && m.IsEnable == "NO");
|
|
|
var allotSet = 4;//分配规则设定
|
|
if (funSet != null)
|
{
|
switch (funSet.SetValue)
|
{
|
case "1":
|
allotSet = 1;
|
break;
|
case "2":
|
allotSet = 2;
|
break;
|
case "3":
|
allotSet = 3;
|
break;
|
case "4":
|
allotSet = 4;
|
break;
|
default:
|
allotSet = 4;// 默认:4
|
break;
|
}
|
}
|
|
return allotSet;
|
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <summary>
|
/// 根据小数位数值转换展示值
|
/// </summary>
|
/// <param name="digit"></param>
|
/// <param name="val"></param>
|
/// <returns></returns>
|
public double GetViewVal(int digit, decimal? val)
|
{
|
try
|
{
|
if (val == null)
|
{
|
throw new Exception("val值为空,请核实");
|
}
|
decimal s = (decimal)val;
|
string r = "0";
|
double data;
|
//decimal data2 = 0.00M;
|
switch (digit)
|
{
|
case 1:
|
r = s.ToString("0.0");
|
data = Math.Round(double.Parse(r), 1);
|
break;
|
case 2:
|
r = s.ToString("0.00");
|
data = Math.Round(double.Parse(r), 2);
|
break;
|
case 3:
|
r = s.ToString("0.000");
|
data = Math.Round(double.Parse(r), 3);
|
break;
|
case 4:
|
r = s.ToString("0.0000");
|
//var ss = double.Parse(r);
|
data = Math.Round(double.Parse(r), 4);
|
//data2 = Math.Round(decimal.Parse(r), 4);
|
break;
|
default:
|
throw new Exception("功能设定小数位数值错误");
|
}
|
|
//var db = DataContext.Db;
|
//var detail = db.Queryable<BllExportNoticeDetail>().First(m => m.SONo == "SO2024040100001");
|
|
//detail.Qty = data2;
|
//var x = db.Updateable(detail).ExecuteCommand();
|
return data;
|
|
}
|
catch (Exception e)
|
{
|
throw new Exception(e.Message);
|
}
|
}
|
|
/// <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
|
{
|
/// <summary>
|
/// 入库单
|
/// </summary>
|
[Description("入库单")]
|
ASN,
|
/// <summary>
|
/// 出库单
|
/// </summary>
|
[Description("出库单")]
|
SO,
|
/// <summary>
|
/// 波次出库单
|
/// </summary>
|
[Description("波次出库单")]
|
WSO,
|
/// <summary>
|
/// 出库单
|
/// </summary>
|
[Description("盘点单")]
|
CR,
|
/// <summary>
|
/// 移库单
|
/// </summary>
|
[Description("移库单")]
|
PM,
|
|
/// <summary>
|
/// 任务
|
/// </summary>
|
[Description("任务")]
|
TK,
|
/// <summary>
|
/// 异常号
|
/// </summary>
|
[Description("异常")]
|
EX,
|
/// <summary>
|
/// 质检请验单
|
/// </summary>
|
[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);
|
}
|
}
|
|
}
|