using AngleSharp.Dom;
|
using Furion.Logging;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WCS.Application.Entity;
|
using static Elastic.Clients.Elasticsearch.JoinField;
|
using static SKIT.FlurlHttpClient.Wechat.Api.Models.CustomServiceKfSessionGetWaitCaseResponse.Types;
|
|
namespace WCS.Application.Util;
|
|
public static class FourWayCarUtil
|
{
|
private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
|
|
private static readonly WcsTaskService _taskService = App.GetService<WcsTaskService>();
|
|
/// <summary>
|
/// 完善小车下发节点、节点命令
|
/// </summary>
|
/// <param name="list">集合</param>
|
/// <param name="moveType">移动类型 0:移动 1:移货 </param>
|
/// <returns></returns>
|
public static List<CarModel> GetCarPathUp(List<CarModel> list, int moveType)
|
{
|
if (list == null)
|
{
|
return null;
|
}
|
for (int i = 0; i < list.Count; i++)
|
{
|
if (i >= 0 && i < list.Count - 1)
|
{
|
if (list[i].X == list[i + 1].X)
|
{
|
list[i].NodeCom = 2;
|
}
|
else if (list[i].Y == list[i + 1].Y)
|
{
|
list[i].NodeCom = 3;
|
}
|
|
}
|
if (i > 0 && i < list.Count - 1)
|
{
|
if (list[i].Make != list[i - 1].Make || list[i].Make != list[i + 1].Make)
|
{
|
if (list[i].X != list[i - 1].X || list[i].X != list[i + 1].X)
|
{
|
list[i].IsSendPlc = true;
|
}
|
|
//list[i - 1].IsSendPlc = true;
|
|
}
|
|
}
|
if (i == 0)
|
{
|
list[i].IsSendPlc = true;
|
if (moveType == 0)
|
{
|
if (list[i + 1] == null)
|
{
|
continue;
|
}
|
|
}
|
else
|
{
|
list[i].NodeCom = 1;
|
}
|
}
|
if (i == list.Count - 1)
|
{
|
list[i].IsSendPlc = true;
|
if (moveType == 0)
|
{
|
if (list[i].X == list[i - 1].X)
|
{
|
list[i].NodeCom = 2;
|
}
|
else if (list[i].Y == list[i - 1].Y)
|
{
|
list[i].NodeCom = 3;
|
}
|
}
|
else
|
{
|
list[i].NodeCom = 4;
|
}
|
}
|
}
|
return list;
|
}
|
|
/// <summary>
|
/// 获取小车移动的目标位置
|
/// </summary>
|
/// <param name="startLocation">起始位置</param>
|
/// <param name="noPathStr">不能存放的储位字符串</param>
|
/// <returns></returns>
|
public static string GetCarEndLocation(string startLocation, string noPathStr)
|
{
|
if (string.IsNullOrEmpty(startLocation))
|
{
|
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
|
};
|
|
// 获取储位表信息存储到集合里
|
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 MyRegion
|
|
var list = locationModels.Where(m => !noPathStr.Contains(m.LocatNo)).OrderBy(m => Math.Abs(start.X - m.Row) + Math.Abs(start.Y - m.Column)).ToList();
|
var locateStr = "";
|
foreach (var item in list)
|
{
|
// 储位状态为损坏不可通行 储位状态为屏蔽为可通行不可存储托盘
|
if (item.Flag == "2")
|
{
|
continue;
|
}
|
locateStr = item.LocatNo;
|
break;
|
}
|
return locateStr;
|
#endregion
|
}
|
|
/// <summary>
|
/// 获取任务号
|
/// </summary>
|
/// <returns></returns>
|
public static int GetTaskNo()
|
{
|
var list = _db.Queryable<WcsCarTasks>().ToList();
|
var maxNo = list.Max(m => m.CarTaskNo);
|
|
if (maxNo != null && maxNo > 0)
|
{
|
if (maxNo++ > 65535)
|
{
|
return 1;
|
}
|
|
return (int)maxNo++;
|
}
|
return 1;
|
|
}
|
|
public static bool AddCarTask(List<CarModel> data, List<CarInfo> kXCarList, CarInfo assignCar, WcsTask waitTask,int moveType)
|
{
|
#region 获取适合执行当前任务的小车 生成路径(需考虑小车阻阻挡)
|
var preId1 = "";//前置任务Id
|
var executionPath1 = "";//交互路径
|
var executionPath2 = "";//交互路径
|
var path = "";//所有路径
|
var isOk = "1"; //是否完整路径 1完整 2 两条路径
|
for (int i = 0; i < data.Count; i++)
|
{
|
//路径节点
|
var pathXYZ = data[i].X.ToString().PadLeft(2, '0') + data[i].Y.ToString().PadLeft(2, '0') + data[i].Z.ToString().PadLeft(2, '0') + data[i].NodeCom.ToString();
|
var pathXYZ2 = data[i].X.ToString().PadLeft(2, '0') + data[i].Y.ToString().PadLeft(2, '0') + data[i].Z.ToString().PadLeft(2, '0');
|
path += pathXYZ + ";";
|
|
//获取等待或正在执行的任务中包含当前节点的小车任务
|
var taskList = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing) && m.Path.Contains(pathXYZ2) && m.CarNo != assignCar.CarPlcIp).Select(m => m.Id).Distinct().ToList();
|
|
foreach (var item in taskList)
|
{
|
//判断如果是完整路径 记录交互路径
|
if (isOk == "1")
|
{
|
if (i == 0)
|
{
|
continue;
|
}
|
var pathXYZQian = data[i - 1].X.ToString().PadLeft(2, '0') + data[i - 1].Y.ToString().PadLeft(2, '0') + data[i - 1].Z.ToString().PadLeft(2, '0')+ data[i - 1].NodeCom.ToString();
|
var pathXYZQian2 = data[i - 1].X.ToString().PadLeft(2, '0') + data[i - 1].Y.ToString().PadLeft(2, '0') + data[i - 1].Z.ToString().PadLeft(2, '0');
|
if (!executionPath1.Contains(pathXYZQian2))
|
{
|
executionPath1 += pathXYZQian + ";";
|
}
|
executionPath2 += pathXYZQian + ";";
|
|
}
|
//判断添加前置任务Id
|
if (!preId1.Contains(item + ""))
|
{
|
preId1 += item + ";";
|
}
|
|
isOk = "2";
|
}
|
|
if (data[i].IsSendPlc)
|
{
|
if (isOk == "1")
|
{
|
executionPath1 += pathXYZ + ";";
|
}
|
else
|
{
|
executionPath2 += pathXYZ + ";";
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#region 判断是否有空闲小车阻挡路径 3
|
var preId3 = "";//前置任务Id
|
foreach (var item in kXCarList)
|
{
|
if (item == assignCar)
|
{
|
continue;//排除当前分配任务的小车
|
}
|
//小车位置
|
var carXYZ = item.X.ToString().PadLeft(2, '0') + item.Y.ToString().PadLeft(2, '0') + item.Z.ToString().PadLeft(2, '0');
|
//分配的任务路径中 当前小车是否阻挡
|
if (path.Contains(carXYZ))
|
{
|
//获取等待或正在执行的任务中包含当前节点的小车任务,不会有太多任务,同层有几个小车最多有几个任务
|
var taskList3 = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing)).ToList();
|
|
var str3 = "";//所有已分配或执行的任务全路径之和
|
|
foreach (var item2 in taskList3)
|
{
|
str3 += item2.Path;
|
}
|
var endLocate3 = "";
|
var executionPath3 = "";
|
var path3 = "";
|
var datas3 = new List<CarModel>();
|
//查找目标位置
|
while (endLocate3 == "" || datas3.Count == 0 || datas3 == null)
|
{
|
endLocate3 = FourWayCarUtil.GetCarEndLocation(carXYZ, str3);
|
var data3 = FourWayCarUtil.GetCarPath(carXYZ, endLocate3, "0");
|
datas3 = FourWayCarUtil.GetCarPathUp(data3, 0);
|
}
|
foreach (var itemPath in datas3)
|
{
|
var pathXYZ = itemPath.X.ToString().PadLeft(2, '0') + itemPath.Y.ToString().PadLeft(2, '0') + itemPath.Z.ToString().PadLeft(2, '0') + itemPath.NodeCom.ToString();
|
|
path3 += pathXYZ + ";";
|
if (itemPath.IsSendPlc)
|
{
|
executionPath3 += pathXYZ + ";";
|
}
|
}
|
WcsTask modTask = new WcsTask()
|
{
|
TaskNo = _taskService.GetTaskCode(),
|
TaskType = TaskTypeEnum.Move,
|
Type = PLCTypeEnum.ShuttleCar,
|
StartLocate = carXYZ,
|
EndLocate = endLocate3,
|
PalletNo = "",
|
Status = TaskStatusEnum.Wait,
|
Levels = 999,
|
Origin = "WCS",
|
CarIp = item.CarPlcIp
|
};
|
_db.Insertable(modTask).ExecuteCommand();
|
HubUtil.PublicTask(modTask.Adapt<WcsTaskOutput>());
|
//移动小车
|
var carTaskYC = new WcsCarTasks()
|
{
|
TaskNo = modTask.TaskNo,
|
PreId = "",
|
ExecutionPath = executionPath3,
|
Path = path3,
|
CarNo = item.CarPlcIp,
|
Status = TaskStatusEnum.Wait
|
};
|
var idLong = _db.Insertable(carTaskYC).ExecuteReturnSnowflakeId();
|
preId3 += idLong + ";";
|
}
|
}
|
|
#endregion
|
|
#region 判断现有任务中最终节点是否在当前分配路径中,如有 添加移走小车任务并加入前置任务 4
|
|
//获取等待或正在执行的任务中包含当前节点的小车任务,不会有太多任务,同层有几个小车最多有几个任务
|
var taskListTask4 = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing) && m.CarNo!=assignCar.CarPlcIp).GroupBy(m=>m.TaskNo).Select(m=>m.TaskNo).ToList();
|
var taskList4 = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing) && m.CarNo != assignCar.CarPlcIp).ToList();
|
var preId4 = "";//前置任务Id
|
var str4 = "";//所有已分配或执行的任务全路径之和
|
|
foreach (var item in taskList4)
|
{
|
str4 += item.Path;
|
}
|
//判断现有任务中最终节点是否在当前分配路径中,如有 添加移走小车任务并加入前置任务
|
foreach (var item in taskListTask4)
|
{
|
var lastTask = taskList4.Where(m => m.TaskNo == item ).OrderBy(m=>m.CreateTime).LastOrDefault();
|
if (lastTask == null)
|
{
|
continue;
|
}
|
var lastPathList = lastTask.ExecutionPath.Split(';');
|
// a;b;c; 最后一个位是“”,所以lastPathList.Length - 2
|
var lastPath = lastPathList[lastPathList.Length - 2];
|
var lastPath2 = lastPath.Substring(0,6);
|
|
//如果此此分配路径包含醉舞中最终节点路径,添加移走小车
|
if (path.Contains(lastPath2))
|
{
|
|
var endLocate = "";
|
var executionPath4 = "";
|
var path4 = "";
|
var datas4 = new List<CarModel>();
|
//查找目标位置
|
while (endLocate == "" || datas4.Count == 0 || datas4 == null)
|
{
|
endLocate = FourWayCarUtil.GetCarEndLocation(lastPath, str4+path);
|
var data4 = FourWayCarUtil.GetCarPath(lastPath, endLocate);
|
datas4 = FourWayCarUtil.GetCarPathUp(data4, 0);
|
}
|
foreach (var itemPath in datas4)
|
{
|
var pathXYZ = itemPath.X.ToString().PadLeft(2, '0') + itemPath.Y.ToString().PadLeft(2, '0') + itemPath.Z.ToString().PadLeft(2, '0') + itemPath.NodeCom.ToString();
|
|
path4 += pathXYZ + ";";
|
if (itemPath.IsSendPlc)
|
{
|
executionPath4 += pathXYZ + ";";
|
}
|
}
|
WcsTask modTask = new WcsTask()
|
{
|
TaskNo = _taskService.GetTaskCode(),
|
TaskType = TaskTypeEnum.Move,
|
Type = PLCTypeEnum.ShuttleCar,
|
StartLocate = lastPath,
|
EndLocate = endLocate,
|
PalletNo = "",
|
Status = TaskStatusEnum.Wait,
|
Levels = 999,
|
Origin = "WCS",
|
CarIp = lastTask.CarNo
|
};
|
_db.Insertable(modTask).ExecuteCommand();
|
HubUtil.PublicTask(modTask.Adapt<WcsTaskOutput>());
|
//移动小车
|
var carTaskYC = new WcsCarTasks()
|
{
|
TaskNo = modTask.TaskNo,
|
PreId = "",
|
ExecutionPath = executionPath4,
|
Path = path4,
|
CarNo = lastTask.CarNo,
|
Status = TaskStatusEnum.Wait
|
};
|
var idLong = _db.Insertable(carTaskYC).ExecuteReturnSnowflakeId();
|
preId4 += idLong + ";";
|
}
|
}
|
|
#endregion
|
|
#region 插入任务数据 改变任务状态
|
|
// 插入四向车任务表
|
var carTask1 = new WcsCarTasks()
|
{
|
TaskNo = waitTask.TaskNo,
|
PreId = preId1 + preId3 + preId4,
|
ExecutionPath = executionPath1,
|
Path = path,
|
CarNo = assignCar.CarPlcIp,
|
Status = TaskStatusEnum.Wait
|
};
|
_db.Insertable(carTask1).ExecuteCommand();
|
if (!string.IsNullOrWhiteSpace(executionPath1) && isOk == "2")
|
{
|
// 插入四向车任务表
|
var carTask2 = new WcsCarTasks()
|
{
|
TaskNo = waitTask.TaskNo,
|
PreId = "",
|
ExecutionPath = executionPath2,
|
Path = path,
|
CarNo = assignCar.CarPlcIp,
|
Status = TaskStatusEnum.Wait
|
};
|
_db.Insertable(carTask2).ExecuteCommand();
|
}
|
waitTask.CarIp = assignCar.CarPlcIp;
|
if (moveType == 1)
|
{
|
// 改变总任务表状态
|
waitTask.Status = TaskStatusEnum.Doing;
|
waitTask.UpdateTime = DateTime.Now;
|
}
|
_db.Updateable(waitTask).ExecuteCommand();
|
HubUtil.PublicTask(waitTask.Adapt<WcsTaskOutput>());
|
|
return true;
|
#endregion
|
}
|
|
|
/// <summary>
|
/// 获取小车路径
|
/// </summary>
|
/// <param name="startLocation">起始位置</param>
|
/// <param name="endLocation">目标位置</param>
|
/// <param name="isLoad">是否载货0:未载货 1:已载货</param>
|
/// <returns></returns>
|
public static List<CarModel> GetCarPath(string startLocation, string endLocation, string isLoad = "0")
|
{
|
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 使用算法计算小车路径
|
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"|| currentLocation.Make == "2")
|
{
|
// 主通道
|
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;
|
|
neighbor.Make = locationModel.Make;
|
current.Make = currentModel.Make;
|
|
// 更新实际距离与预估距离
|
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)
|
{
|
throw;
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
/// 获取总任务表下发ID主键
|
/// </summary>
|
/// <returns></returns>
|
public static int GetTaskId()
|
{
|
var list = _db.Queryable<WcsTask>().ToList();
|
var maxNo = list.Max(m => m.TaskId);
|
|
if (maxNo != null && maxNo > 0)
|
{
|
if (maxNo++ > 99999999)
|
{
|
return 1;
|
}
|
|
return (int)maxNo++;
|
}
|
|
return 1;
|
}
|
|
/// <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 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; }
|
|
/// <summary>
|
/// 0通道 1 储位
|
/// </summary>
|
public string Make { 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);
|
}
|
}
|
|
public class CarInfo
|
{
|
/// <summary>
|
/// 小车IP
|
/// </summary>
|
public string CarPlcIp { get; set; }
|
|
/// <summary>
|
/// 顺序等级
|
/// </summary>
|
public int Level { get; set; }
|
|
/// <summary>
|
/// 行=X
|
/// </summary>
|
public int X { get; set; }
|
|
/// <summary>
|
/// 列=Y
|
/// </summary>
|
public int Y { get; set; }
|
|
/// <summary>
|
/// 层=Z
|
/// </summary>
|
public int Z { get; set; }
|
}
|