ATC Dimetronic: Implement double signal codes

This commit is contained in:
Marc Riera 2024-12-23 01:25:25 +01:00
parent 77869e9c1e
commit 5477d7389c
3 changed files with 70 additions and 28 deletions

View file

@ -51,15 +51,15 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The current state of the track.</summary>
private TrackStates TrackState;
/// <summary>The current position of the train.</summary>
private double TrainLocation;
/// <summary>The length of the train.</summary>
private readonly double TrainLength;
/// <summary>The maximum speed in YARD mode.</summary>
private readonly Speed YardMaximumSpeed;
/// <summary>The speed limit for each signal aspect.</summary>
private readonly Speed[] AspectLimit = { new Speed(0), new Speed(25 / 3.6), new Speed(25 / 3.6), new Speed(25 / 3.6), new Speed(25 / 3.6), new Speed(45 / 3.6), new Speed(45 / 3.6), new Speed(45 / 3.6), new Speed(45 / 3.6), new Speed(70 / 3.6), new Speed(70 / 3.6), new Speed(70 / 3.6), new Speed(70 / 3.6) };
/// <summary>The target speed limit for each signal aspect.</summary>
private readonly Speed[] AspectTargetLimit = { new Speed(0), new Speed(0), new Speed(0), new Speed(25 / 3.6), new Speed(25 / 3.6), new Speed(0), new Speed(0), new Speed(45 / 3.6), new Speed(45 / 3.6), new Speed(0), new Speed(0), new Speed(70 / 3.6), new Speed(70 / 3.6) };
/// <summary>Whether ATO is available or not on the train.</summary>
private readonly bool AtoAvailable;
@ -113,17 +113,21 @@ namespace OpenbveFcmbTrainPlugin
internal int Aspect;
internal Speed Limit;
internal Speed Target;
internal Speed EntryTarget;
internal SignalCode(int aspect, string data)
{
Aspect = aspect;
Limit = new Speed(0);
Target = new Speed(0);
EntryTarget = new Speed(0);
if (data.Contains("/"))
{
int separator = data.IndexOf('/');
string a = data.Substring(0, separator);
string b = data.Substring(separator + 1);
string[] speeds = data.Split('/');
if (speeds.Length > 1)
{
string a = speeds[0];
string b = speeds[1];
if (double.TryParse(a, NumberStyles.Float, CultureInfo.InvariantCulture, out double an) && double.TryParse(b, NumberStyles.Float, CultureInfo.InvariantCulture, out double bn))
{
if (an >= bn && an >= 0)
@ -134,6 +138,14 @@ namespace OpenbveFcmbTrainPlugin
{
Target = new Speed(bn / 3.6);
}
if (speeds.Length > 2)
{
if (double.TryParse(speeds[2], NumberStyles.Float, CultureInfo.InvariantCulture, out double cn))
{
EntryTarget = new Speed(cn / 3.6);
}
}
}
}
}
}
@ -145,6 +157,12 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The aspect of the current signal in the route.</summary>
private int CurrentSignalAspect;
/// <summary>The start position of the current signal.</summary>
private double CurrentSignalStartLocation;
/// <summary>The end position of the current signal.</summary>
private double CurrentSignalEndLocation;
/// <summary>The ideal power notch for the AI.</summary>
private int AiPowerNotch;
@ -155,8 +173,9 @@ namespace OpenbveFcmbTrainPlugin
/// <param name="yardMaxSpeed">The maximum speed in YARD mode, in km/h.</param>
/// <param name="signalCodes">The list of signal codes recognised by the device.</param>
/// <param name="atoAvailable">Whether ATO is available or not.</param>
internal AtcDimetronic(Speed yardMaxSpeed, List<SignalCode> signalCodes, bool atoAvailable)
internal AtcDimetronic(double trainLength, Speed yardMaxSpeed, List<SignalCode> signalCodes, bool atoAvailable)
{
TrainLength = trainLength;
YardMaximumSpeed = yardMaxSpeed;
SignalCodes = signalCodes;
AtoAvailable = atoAvailable;
@ -175,6 +194,10 @@ namespace OpenbveFcmbTrainPlugin
DeviceState = DeviceStates.NoMode;
}
// Update train location
// TODO: implement runback/rollfoward protection
TrainLocation = train.State.Location;
double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05;
@ -252,13 +275,13 @@ namespace OpenbveFcmbTrainPlugin
case DeviceStates.ATP:
train.ContinuousProtection = true;
train.VigilanceOverride = false;
CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
CurrentSpeedCode = GetSpeedCodeFromAspect();
break;
// ATC device is in ATO driving mode
case DeviceStates.ATO:
train.ContinuousProtection = true;
train.VigilanceOverride = true;
CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
CurrentSpeedCode = GetSpeedCodeFromAspect();
break;
}
@ -376,6 +399,8 @@ namespace OpenbveFcmbTrainPlugin
internal override void SetSignal(SignalData[] signal)
{
CurrentSignalAspect = signal[0].Aspect;
CurrentSignalStartLocation = signal[0].Distance + TrainLocation;
CurrentSignalEndLocation = signal.Length > 1 ? signal[1].Distance + TrainLocation : double.MaxValue;
}
/// <summary>Is called when a beacon is passed.</summary>
@ -511,15 +536,18 @@ namespace OpenbveFcmbTrainPlugin
}
/// <summary>Generates the corresponding speed code from a signal aspect.</summary>
/// <param name="signalCodes">The list of signal codes.</param>
/// <param name="aspect">The current signal aspect.</param>
private SpeedCode GetSpeedCodeFromAspect(List<SignalCode> signalCodes, int aspect)
private SpeedCode GetSpeedCodeFromAspect()
{
foreach (SignalCode signal in signalCodes)
foreach (SignalCode signal in SignalCodes)
{
if (signal.Aspect == aspect)
if (signal.Aspect == CurrentSignalAspect)
{
return new SpeedCode(signal.Limit, signal.Target);
if (TrainLocation - TrainLength < CurrentSignalStartLocation && signal.EntryTarget.MetersPerSecond > 0)
{
// The train has not fully entered the signal section, use the entry target speed
return new SpeedCode(signal.Limit, signal.EntryTarget, CurrentSignalEndLocation);
}
return new SpeedCode(signal.Limit, signal.Target, CurrentSignalEndLocation);
}
}
return new SpeedCode(new Speed(0), new Speed(0));

View file

@ -11,6 +11,8 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Represents a collection of plugin settings.</summary>
internal class SettingsCollection
{
internal double TrainLength;
internal bool DoorSelectionDeviceEnabled;
internal bool DoorClosingSoundDeviceEnabled;
internal bool DoorTractionCutDeviceEnabled;
@ -75,6 +77,19 @@ namespace OpenbveFcmbTrainPlugin
}
switch (Section)
{
case "train":
switch (Key)
{
case "length":
{
if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double a))
{
PluginSettings.TrainLength = a;
}
}
break;
}
break;
case "doorselection":
switch (Key)
{
@ -211,8 +226,7 @@ namespace OpenbveFcmbTrainPlugin
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
break;
default:
int aspect;
if (int.TryParse(Key, NumberStyles.Integer, CultureInfo.InvariantCulture, out aspect))
if (int.TryParse(Key, NumberStyles.Integer, CultureInfo.InvariantCulture, out int aspect))
{
AtcDimetronic.SignalCode signalCode = new AtcDimetronic.SignalCode(aspect, Value);
if (signalCode != null)

View file

@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin
}
if (settings.AtcDimetronicDeviceEnabled)
{
Devices.Add(new AtcDimetronic(settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
Devices.Add(new AtcDimetronic(settings.TrainLength, settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
}
}