Files

166 lines
6.3 KiB
C#
Raw Permalink Normal View History

using Simple3.RCS;
2026-07-17 13:36:01 +08:00
using SimpleCore.PropType;
using StandardScene.CarTypes;
using System;
using System.Globalization;
using Simple3.RCS.CarTypes;
2026-07-17 13:36:01 +08:00
namespace StandardScene.Scheduler.FassEvent
{
/// <summary>
/// 将 StandardScene 车辆对象转换为 FASS 事件系统可识别的快照字段。
/// 负责编号、地标、状态、电量等与 <c>EventCarService.TriggerHandler</c> 对齐的映射。
/// </summary>
internal static class FassEventCarSnapshotFactory
{
/// <summary>
/// 获取车辆“下一地标”编码。
/// 优先级:status.enums["NextNode"] → tags["NextNode"] → pendingLocks 首站(TagValue 或站点 ID)。
/// </summary>
public static string GetNextNodeCode(Car car)
{
if (car.status?.enums != null && car.status.enums.TryGetValue("NextNode", out var node) && !string.IsNullOrWhiteSpace(node))
{
return node;
}
if (car.tags != null && car.tags.TryGetValue("NextNode", out var tagNode) && !string.IsNullOrWhiteSpace(tagNode))
{
return tagNode;
}
// 调度 pendingLocks 通常表示车辆即将前往的站点,可近似为 FASS NextNodeCode。
if (car.status?.pendingLocks != null && car.status.pendingLocks.Length > 0)
{
var pendingSiteId = car.status.pendingLocks[0];
var site = SimpleCore.SimpleLib.GetSite(pendingSiteId);
if (site?.fields != null && site.fields.TryGetValue("TagValue", out var tagValue) && !string.IsNullOrWhiteSpace(tagValue))
{
return tagValue;
}
return pendingSiteId.ToString(CultureInfo.InvariantCulture);
}
return string.Empty;
}
/// <summary>
/// 根据车辆与上一周期地标构建完整快照。
/// </summary>
/// <param name="car">场景车辆。</param>
/// <param name="prevNodeCode">上一周期 CurrentNode,由 EventCarMission 维护。</param>
/// <param name="nextNodeCode">下一地标;为空时自动调用 <see cref="GetNextNodeCode"/>。</param>
public static FassEventCarSnapshot Create(Car car, string prevNodeCode, string nextNodeCode)
{
return new FassEventCarSnapshot
{
CarId = car.id,
Code = GetCarCode(car),
CarModel = GetCarModel(car),
PrevNodeCode = prevNodeCode,
CurrentNodeCode = GetCurrentNodeCode(car),
NextNodeCode = string.IsNullOrWhiteSpace(nextNodeCode) ? GetNextNodeCode(car) : nextNodeCode,
State = GetFassState(car),
Angle = (int)Math.Round(car.th),
Charge = GetCharge(car)
};
}
/// <summary>
/// 获取 FASS 车辆编号。MagCar 优先使用 VehicleCode,否则 fields["Code"],最后回退 name。
/// </summary>
public static string GetCarCode(Car car)
{
if (car is MagCar magCar && magCar.VehicleCode > 0)
{
return magCar.VehicleCode.ToString(CultureInfo.InvariantCulture);
}
if (car.fields != null && car.fields.TryGetValue("Code", out var code) && !string.IsNullOrWhiteSpace(code))
{
return code;
}
return car.name;
}
/// <summary>获取车型。下料站 InplaceStaion 根据 CarModel 在 ME11 / 放行车型间切换。</summary>
public static string GetCarModel(Car car)
{
if (car.fields != null && car.fields.TryGetValue("CarModel", out var model) && !string.IsNullOrWhiteSpace(model))
{
return model;
}
return car.GetType().Name;
}
/// <summary>
/// 获取当前地标号。MagCar 上报后写入 status.enums["CurrentNode"]
/// 其他车型可回退到 siteID。
/// </summary>
public static string GetCurrentNodeCode(Car car)
{
if (car.status?.enums != null && car.status.enums.TryGetValue("CurrentNode", out var node) && !string.IsNullOrWhiteSpace(node))
{
return node;
}
return car.siteID > 0 ? car.siteID.ToString(CultureInfo.InvariantCulture) : string.Empty;
}
/// <summary>
/// 将 StandardScene 车辆状态映射为 FASS 英文字符串。
/// <para>
/// 可手动覆盖:tags["FassState"] 或 enums["FassState"]。
/// WaitPass 需在停止中且 tags 含 WaitPass(FASS 中“等待放行”态)。
/// </para>
/// </summary>
public static string GetFassState(Car car)
{
if (car.tags != null && car.tags.TryGetValue("FassState", out var tagState) && !string.IsNullOrWhiteSpace(tagState))
{
return tagState;
}
if (car.status?.enums != null && car.status.enums.TryGetValue("FassState", out var enumState) && !string.IsNullOrWhiteSpace(enumState))
{
return enumState;
}
if (car.status?.enums != null && car.status.enums.TryGetValue("State", out var state))
{
switch (state)
{
case "运行中":
return "Running";
case "停止中":
return car.tags != null && car.tags.ContainsKey("WaitPass") ? "WaitPass" : "Stopping";
case "未准备":
return "NotReady";
case "充电中":
return "Charging";
default:
return state;
}
}
return string.Empty;
}
/// <summary>从 status.enums["Soc"] 解析电量百分比。</summary>
private static double GetCharge(Car car)
{
if (car.status?.enums != null &&
car.status.enums.TryGetValue("Soc", out var soc) &&
double.TryParse(soc, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
{
return value;
}
return 0;
}
}
}