Files

190 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using SimpleLite.RCS.CarTypes;
namespace StandardScene.Signal.Logic
{
/// <summary>
/// 磁条管控区占用判定:他车占用「当前策略」管控站点列表的数量 ≥ 容量则不放行;本车不计入。
/// 磁条交管进程只对停在触发点的 MagCar 调用,满足后发启动。
/// </summary>
public static class MagControlAreaGate
{
public const byte StartStopPass = 1;
public const byte StartStopControlStart = 11;
private static readonly char[] SiteIdSeparators = { ',', ';', '|', ' ', '\t', '[', ']', '(', ')', '{', '}' };
public static byte NormalizeReleaseStartStop(byte value)
{
if (value == StartStopPass || value == StartStopControlStart)
return value;
return StartStopControlStart;
}
public static int NormalizeCapacity(int capacity)
{
return capacity < 1 ? 1 : capacity;
}
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 string NormalizeCompatGroup(string value)
{
return (value ?? string.Empty).Trim();
}
public static bool SitesIntersect(IReadOnlyList<int> a, IReadOnlyList<int> b)
{
if (a == null || b == null || a.Count == 0 || b.Count == 0)
return false;
for (var i = 0; i < a.Count; i++)
{
var left = a[i];
if (left <= 0)
continue;
for (var j = 0; j < b.Count; j++)
{
if (b[j] == left)
return true;
}
}
return false;
}
public static MagControlReleaseDecision Evaluate(
int selfCarId,
int triggerSit,
IReadOnlyList<int> areaSiteIds,
int capacity,
byte releaseStartStop,
IReadOnlyList<(int CarId, IReadOnlyList<int> OccupiedSiteIds)> occupancies)
{
var sites = areaSiteIds == null || areaSiteIds.Count == 0
? (triggerSit > 0 ? new[] { triggerSit } : Array.Empty<int>())
: areaSiteIds;
capacity = NormalizeCapacity(capacity);
releaseStartStop = NormalizeReleaseStartStop(releaseStartStop);
var others = 0;
if (occupancies != null)
{
foreach (var occupancy in occupancies)
{
if (occupancy.CarId == selfCarId)
continue;
if (OccupiesListedSites(occupancy.OccupiedSiteIds, sites))
others++;
}
}
var canRelease = others < capacity;
var areaId = string.Join(",", sites);
return new MagControlReleaseDecision
{
RuleFound = true,
CanRelease = canRelease,
AreaId = areaId,
Capacity = capacity,
OthersInArea = others,
ReleaseStartStop = releaseStartStop,
Reason = canRelease
? "area clear"
: $"area occupied cars={others}, capacity={capacity}"
};
}
/// <summary>统计占用管控区内部站点的车辆数,可排除排队车和在途车。</summary>
public static int CountOccupyingCars(
IReadOnlyList<(int CarId, IReadOnlyList<int> OccupiedSiteIds)> occupancies,
IReadOnlyList<int> areaSiteIds,
HashSet<int> excludeCarIds)
{
if (occupancies == null || occupancies.Count == 0 ||
areaSiteIds == null || areaSiteIds.Count == 0)
return 0;
var others = 0;
foreach (var occupancy in occupancies)
{
if (excludeCarIds != null && excludeCarIds.Contains(occupancy.CarId))
continue;
if (OccupiesListedSites(occupancy.OccupiedSiteIds, areaSiteIds))
others++;
}
return others;
}
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;
}
/// <summary>统计一辆车占用的站点:物理 siteID + holdingLocks。</summary>
public static IReadOnlyList<int> CollectOccupiedSiteIds(Car car)
{
var ids = new List<int>();
if (car == null)
return ids;
try
{
if (car.siteID > 0)
ids.Add(car.siteID);
}
catch
{
}
var holding = car.status?.holdingLocks;
if (holding == null)
return ids;
foreach (var lockId in holding)
{
if (lockId > 0 && !ids.Contains(lockId))
ids.Add(lockId);
}
return ids;
}
}
}