215 lines
7.0 KiB
C#
215 lines
7.0 KiB
C#
using StandardScene.Magnetic.Protocol;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
|
|
namespace StandardScene.Magnetic.Tasking
|
|
{
|
|
/// <summary>
|
|
/// 管控停止(StartStop=12)按车放行:地图站点保持 12,仅改本车任务报文。
|
|
/// </summary>
|
|
public sealed class Fass2ControlAreaInfo
|
|
{
|
|
public int SiteId { get; set; }
|
|
public string AreaId { get; set; } = string.Empty;
|
|
public int[] AreaSiteIds { get; set; } = Array.Empty<int>();
|
|
public int Capacity { get; set; } = 1;
|
|
public byte ReleaseStartStop { get; set; } = Fass2TaskBuilder.StartStopControlStart;
|
|
}
|
|
|
|
public sealed class Fass2ControlOccupancy
|
|
{
|
|
public Fass2ControlOccupancy(int carId, IReadOnlyList<int> occupiedSiteIds)
|
|
{
|
|
CarId = carId;
|
|
OccupiedSiteIds = occupiedSiteIds ?? Array.Empty<int>();
|
|
}
|
|
|
|
public int CarId { get; }
|
|
public IReadOnlyList<int> OccupiedSiteIds { get; }
|
|
}
|
|
|
|
public sealed class Fass2ControlReleaseCheck
|
|
{
|
|
public bool CanRelease { get; set; }
|
|
public string AreaId { get; set; } = string.Empty;
|
|
public int Capacity { get; set; } = 1;
|
|
public int OthersInArea { get; set; }
|
|
public byte ReleaseStartStop { get; set; } = Fass2TaskBuilder.StartStopControlStart;
|
|
public string Reason { get; set; } = string.Empty;
|
|
}
|
|
|
|
public static class Fass2ControlAreaGate
|
|
{
|
|
private static readonly char[] SiteIdSeparators = { ',', ';', '|', ' ', '\t', '[', ']', '(', ')', '{', '}' };
|
|
|
|
public static bool IsControlStop(byte startStop)
|
|
{
|
|
return startStop == Fass2TaskBuilder.StartStopControlStop;
|
|
}
|
|
|
|
public static bool AllowsLeave(byte startStop)
|
|
{
|
|
return startStop == Fass2TaskBuilder.StartStopPass
|
|
|| startStop == Fass2TaskBuilder.StartStopControlStart;
|
|
}
|
|
|
|
public static Fass2ControlAreaInfo Resolve(Fass2SiteActionData data, int siteId)
|
|
{
|
|
data ??= new Fass2SiteActionData();
|
|
var areaSites = ParseSiteIds(data.ControlArea, siteId);
|
|
var capacity = data.ControlCapacity.GetValueOrDefault(1);
|
|
if (capacity < 1)
|
|
{
|
|
capacity = 1;
|
|
}
|
|
|
|
var release = data.ControlReleaseStartStop ?? Fass2TaskBuilder.StartStopControlStart;
|
|
if (release != Fass2TaskBuilder.StartStopPass &&
|
|
release != Fass2TaskBuilder.StartStopControlStart)
|
|
{
|
|
release = Fass2TaskBuilder.StartStopControlStart;
|
|
}
|
|
|
|
return new Fass2ControlAreaInfo
|
|
{
|
|
SiteId = siteId,
|
|
AreaSiteIds = areaSites,
|
|
AreaId = string.Join(",", areaSites),
|
|
Capacity = capacity,
|
|
ReleaseStartStop = release
|
|
};
|
|
}
|
|
|
|
public static int[] ParseSiteIds(string text, int fallbackSiteId)
|
|
{
|
|
var ids = new List<int>();
|
|
if (!string.IsNullOrWhiteSpace(text))
|
|
{
|
|
var parts = text.Split(SiteIdSeparators, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (var part in parts)
|
|
{
|
|
if (int.TryParse(part.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var id) &&
|
|
id > 0 && !ids.Contains(id))
|
|
{
|
|
ids.Add(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ids.Count == 0 && fallbackSiteId > 0)
|
|
{
|
|
ids.Add(fallbackSiteId);
|
|
}
|
|
|
|
return ids.ToArray();
|
|
}
|
|
|
|
public static int LimitWindowCount(
|
|
IReadOnlyList<Fass2NodeMessage> nodes,
|
|
int startIndex,
|
|
int count,
|
|
int releasedIndex)
|
|
{
|
|
if (nodes == null || count <= 0 || startIndex < 0 || startIndex >= nodes.Count)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
var limited = Math.Min(count, nodes.Count - startIndex);
|
|
for (var i = 0; i < limited; i++)
|
|
{
|
|
var node = nodes[startIndex + i];
|
|
if (node != null && IsControlStop(node.StartStop) && releasedIndex != startIndex + i)
|
|
{
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
return limited;
|
|
}
|
|
|
|
public static Fass2ControlReleaseCheck Evaluate(
|
|
int selfCarId,
|
|
Fass2ControlAreaInfo area,
|
|
IReadOnlyList<Fass2ControlOccupancy> occupancies)
|
|
{
|
|
area ??= new Fass2ControlAreaInfo();
|
|
if (area.AreaSiteIds == null || area.AreaSiteIds.Length == 0)
|
|
{
|
|
area.AreaSiteIds = area.SiteId > 0 ? new[] { area.SiteId } : Array.Empty<int>();
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(area.AreaId))
|
|
{
|
|
area.AreaId = string.Join(",", area.AreaSiteIds);
|
|
}
|
|
|
|
if (area.Capacity < 1)
|
|
{
|
|
area.Capacity = 1;
|
|
}
|
|
|
|
var others = 0;
|
|
if (occupancies != null)
|
|
{
|
|
foreach (var occupancy in occupancies)
|
|
{
|
|
if (occupancy == null || occupancy.CarId == selfCarId)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (OccupiesListedSites(occupancy.OccupiedSiteIds, area.AreaSiteIds))
|
|
{
|
|
others++;
|
|
}
|
|
}
|
|
}
|
|
|
|
var canRelease = others < area.Capacity;
|
|
return new Fass2ControlReleaseCheck
|
|
{
|
|
CanRelease = canRelease,
|
|
AreaId = area.AreaId,
|
|
Capacity = area.Capacity,
|
|
OthersInArea = others,
|
|
ReleaseStartStop = area.ReleaseStartStop == 0
|
|
? Fass2TaskBuilder.StartStopControlStart
|
|
: area.ReleaseStartStop,
|
|
Reason = canRelease
|
|
? "area clear"
|
|
: $"area occupied cars={others}, capacity={area.Capacity}"
|
|
};
|
|
}
|
|
|
|
public static bool OccupiesListedSites(IReadOnlyList<int> occupiedSiteIds, IReadOnlyList<int> areaSiteIds)
|
|
{
|
|
if (occupiedSiteIds == null || occupiedSiteIds.Count == 0 ||
|
|
areaSiteIds == null || areaSiteIds.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < occupiedSiteIds.Count; i++)
|
|
{
|
|
var occupied = occupiedSiteIds[i];
|
|
if (occupied <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (var j = 0; j < areaSiteIds.Count; j++)
|
|
{
|
|
if (areaSiteIds[j] == occupied)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|