磁导航1.0内部交管和信号交互
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user