Skip to content

Commit da4b28b

Browse files
authored
Merge pull request #1050 from twpol/refactor/train-car-junction-detection
refactor: TrainCar junction detection
2 parents 3b951a0 + ff5688f commit da4b28b

File tree

6 files changed

+54
-149
lines changed

6 files changed

+54
-149
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,7 +3108,7 @@ public virtual void UpdateWaterTroughRefill(float elapsedClockSeconds, float abs
31083108
Simulator.Confirmer.Message(ConfirmLevel.Error, Simulator.Catalog.GetString("Scoop is broken, can't refill"));
31093109
RefillingFromTrough = false;
31103110
}
3111-
else if (IsOverJunction())
3111+
else if (IsOverSwitch || IsOverCrossover)
31123112
{
31133113
if (!ScoopIsBroken) // Only display message first time scoop is broken
31143114
{
@@ -3118,7 +3118,7 @@ public virtual void UpdateWaterTroughRefill(float elapsedClockSeconds, float abs
31183118
RefillingFromTrough = false;
31193119
SignalEvent(Event.WaterScoopBroken);
31203120
}
3121-
else if (!IsOverTrough())
3121+
else if (!IsOverTrough)
31223122
{
31233123
if (!WaterScoopOverTroughFlag)
31243124
{
@@ -3163,7 +3163,7 @@ public virtual void UpdateWaterTroughRefill(float elapsedClockSeconds, float abs
31633163
}
31643164

31653165
}
3166-
else if (HasWaterScoop && MSTSWagon.RefillProcess.OkToRefill == true && IsOverTrough())// water scoop has been raised, stop water filling
3166+
else if (HasWaterScoop && MSTSWagon.RefillProcess.OkToRefill == true && IsOverTrough)// water scoop has been raised, stop water filling
31673167
{
31683168
MSTSWagon.RefillProcess.OkToRefill = false;
31693169
MSTSWagon.RefillProcess.ActivePickupObjectUID = 0;
@@ -3234,7 +3234,7 @@ public virtual void UpdateWaterTroughRefill(float elapsedClockSeconds, float abs
32343234
WaterScoopInputAmountL = 0;
32353235
WaterScoopVelocityMpS = 0;
32363236

3237-
if (!IsOverTrough()) // Only reset once train moves off the trough
3237+
if (!IsOverTrough) // Only reset once train moves off the trough
32383238
{
32393239
WaterScoopTotalWaterL = 0.0f; // Reset amount of water picked up by water sccop.
32403240
}

Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3525,7 +3525,7 @@ private void UpdateSpecialEffects(float elapsedClockSeconds)
35253525
}
35263526

35273527
// Water scoop spray effects control - always on when scoop over trough, regardless of whether above minimum speed or not
3528-
if (ProcessWaterEffects && LocomotiveParameters.IsWaterScoopDown && IsOverTrough() && AbsSpeedMpS > 0.1)
3528+
if (ProcessWaterEffects && LocomotiveParameters.IsWaterScoopDown && IsOverTrough && AbsSpeedMpS > 0.1)
35293529
{
35303530
float SpeedRatio = AbsSpeedMpS / MpS.FromMpH(100); // Ratio to reduce water disturbance with speed - an arbitary value of 100mph has been chosen as the reference
35313531

Source/Orts.Simulation/Simulation/RollingStocks/TrainCar.cs

Lines changed: 46 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// COPYRIGHT 2009 - 2022 by the Open Rails project.
1+
// COPYRIGHT 2009 - 2022 by the Open Rails project.
22
//
33
// This file is part of Open Rails.
44
//
@@ -2872,6 +2872,8 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
28722872
p.FindCenterLine();
28732873
}
28742874
}
2875+
2876+
UpdatePositionFlags();
28752877
}
28762878

28772879
#region Traveller-based updates
@@ -3091,140 +3093,67 @@ private void AddVibrations(float factor)
30913093
}
30923094
#endregion
30933095

3094-
// TODO These three fields should be in the TrainCarViewer.
3095-
public int TrackSoundType = 0;
3096-
public WorldLocation TrackSoundLocation = WorldLocation.None;
3097-
public float TrackSoundDistSquared = 0;
3098-
3096+
public bool IsOverSwitch { get; private set; }
3097+
public bool IsOverCrossover { get; private set; }
3098+
public bool IsOverTrough { get; private set; }
30993099

3100-
/// <summary>
3101-
/// Checks if traincar is over trough. Used to check if refill possible
3102-
/// </summary>
3103-
/// <returns> returns true if car is over trough</returns>
3104-
3105-
public bool IsOverTrough()
3100+
void UpdatePositionFlags()
31063101
{
3107-
var isOverTrough = false;
3108-
// start at front of train
3109-
int thisSectionIndex = Train.PresentPosition[0].TCSectionIndex;
3110-
if (thisSectionIndex < 0) return isOverTrough;
3111-
float thisSectionOffset = Train.PresentPosition[0].TCOffset;
3112-
int thisSectionDirection = Train.PresentPosition[0].TCDirection;
3102+
// Position flags can only change when we're moving!
3103+
if (Train == null || AbsSpeedMpS < 0.01f) return;
31133104

3105+
// Calculate the position of the ends of this car relative to the REAR of the train
3106+
var rearOffsetM = Train.PresentPosition[1].TCOffset;
3107+
for (var i = Train.Cars.IndexOf(this) + 1; i < Train.Cars.Count; i++)
3108+
rearOffsetM += Train.Cars[i - 1].CouplerSlackM + Train.Cars[i - 1].GetCouplerZeroLengthM() + Train.Cars[i].CarLengthM;
3109+
var frontOffsetM = rearOffsetM + CarLengthM;
31143110

3115-
float usedCarLength = CarLengthM;
3116-
float processedCarLength = 0;
3117-
bool validSections = true;
3111+
var isOverSwitch = false;
3112+
var isOverCrossover = false;
3113+
var isOverTrough = false;
31183114

3119-
while (validSections)
3115+
// Scan through the track sections forwards from the REAR of the train (`Train.PresentPosition[1]`),
3116+
// stopping as soon as we've passed this car (`checkedM`) or run out of track (`currentPin.Link`)
3117+
var checkedM = 0f;
3118+
var lastPin = new TrPin { Link = -1, Direction = -1 };
3119+
var currentPin = new TrPin { Link = Train.PresentPosition[1].TCSectionIndex, Direction = Train.PresentPosition[1].TCDirection };
3120+
while (checkedM <= frontOffsetM && currentPin.Link != -1)
31203121
{
3121-
TrackCircuitSection thisSection = Train.signalRef.TrackCircuitList[thisSectionIndex];
3122-
isOverTrough = false;
3122+
var section = Simulator.Signals.TrackCircuitList[currentPin.Link];
31233123

3124-
// car spans sections
3125-
if ((CarLengthM - processedCarLength) > thisSectionOffset)
3124+
// Does this car overlap this track section?
3125+
if (checkedM <= frontOffsetM && rearOffsetM <= checkedM + section.Length)
31263126
{
3127-
usedCarLength = thisSectionOffset - processedCarLength;
3128-
}
3129-
3130-
// section has troughs
3131-
if (thisSection.TroughInfo != null)
3132-
{
3133-
foreach (TrackCircuitSection.troughInfoData[] thisTrough in thisSection.TroughInfo)
3127+
if (section.CircuitType == TrackCircuitSection.TrackCircuitType.Junction) isOverSwitch = true;
3128+
if (section.CircuitType == TrackCircuitSection.TrackCircuitType.Crossover) isOverCrossover = true;
3129+
if (section.TroughInfo != null)
31343130
{
3135-
float troughStartOffset = thisTrough[thisSectionDirection].TroughStart;
3136-
float troughEndOffset = thisTrough[thisSectionDirection].TroughEnd;
3137-
3138-
if (troughStartOffset > 0 && troughStartOffset > thisSectionOffset) // start of trough is in section beyond present position - cannot be over this trough nor any following
3131+
foreach (var troughs in section.TroughInfo)
31393132
{
3140-
return isOverTrough;
3141-
}
3142-
3143-
if (troughEndOffset > 0 && troughEndOffset < (thisSectionOffset - usedCarLength)) // beyond end of trough, test next
3144-
{
3145-
continue;
3146-
}
3147-
3148-
if (troughStartOffset <= 0 || troughStartOffset < (thisSectionOffset - usedCarLength)) // start of trough is behind
3149-
{
3150-
isOverTrough = true;
3151-
return isOverTrough;
3133+
var trough = troughs[currentPin.Direction];
3134+
// Start and end are -1 if the trough extends beyond this section
3135+
var troughStart = trough.TroughStart < 0 ? 0 : trough.TroughStart;
3136+
var troughEnd = trough.TroughEnd < 0 ? section.Length : trough.TroughEnd;
3137+
if (checkedM + troughStart <= frontOffsetM && rearOffsetM <= checkedM + troughEnd) isOverTrough = true;
31523138
}
31533139
}
31543140
}
3155-
// tested this section, any need to go beyond?
3141+
checkedM += section.Length;
31563142

3157-
processedCarLength += usedCarLength;
3158-
{
3159-
// go back one section
3160-
int thisSectionRouteIndex = Train.ValidRoute[0].GetRouteIndexBackward(thisSectionIndex, Train.PresentPosition[0].RouteListIndex);
3161-
if (thisSectionRouteIndex >= 0)
3162-
{
3163-
thisSectionIndex = thisSectionRouteIndex;
3164-
thisSection = Train.signalRef.TrackCircuitList[thisSectionIndex];
3165-
thisSectionOffset = thisSection.Length; // always at end of next section
3166-
thisSectionDirection = Train.ValidRoute[0][thisSectionRouteIndex].Direction;
3167-
}
3168-
else // ran out of train
3169-
{
3170-
validSections = false;
3171-
}
3172-
}
3143+
var nextPin = section.GetNextActiveLink(currentPin.Direction, lastPin.Link);
3144+
lastPin = currentPin;
3145+
currentPin = nextPin;
31733146
}
3174-
return isOverTrough;
3175-
}
31763147

3177-
/// <summary>
3178-
/// Checks if traincar is over junction or crossover. Used to check if water scoop breaks
3179-
/// </summary>
3180-
/// <returns> returns true if car is over junction</returns>
3181-
3182-
public bool IsOverJunction()
3183-
{
3184-
3185-
// To Do - This identifies the start of the train, but needs to be further refined to work for each carriage.
3186-
var isOverJunction = false;
3187-
// start at front of train
3188-
int thisSectionIndex = Train.PresentPosition[0].TCSectionIndex;
3189-
float thisSectionOffset = Train.PresentPosition[0].TCOffset;
3190-
int thisSectionDirection = Train.PresentPosition[0].TCDirection;
3191-
3192-
3193-
float usedCarLength = CarLengthM;
3194-
3195-
if (Train.PresentPosition[0].TCSectionIndex != Train.PresentPosition[1].TCSectionIndex)
3196-
{
3197-
try
3198-
{
3199-
var copyOccupiedTrack = Train.OccupiedTrack.ToArray();
3200-
foreach (var thisSection in copyOccupiedTrack)
3201-
{
3202-
3203-
// Trace.TraceInformation(" Track Section - Index {0} Ciruit Type {1}", thisSectionIndex, thisSection.CircuitType);
3204-
3205-
if (thisSection.CircuitType == TrackCircuitSection.TrackCircuitType.Junction || thisSection.CircuitType == TrackCircuitSection.TrackCircuitType.Crossover)
3206-
{
3207-
3208-
// train is on a switch; let's see if car is on a switch too
3209-
WorldLocation switchLocation = TileLocation(Simulator.TDB.TrackDB.TrackNodes[thisSection.OriginalIndex].UiD);
3210-
var distanceFromSwitch = WorldLocation.GetDistanceSquared(WorldPosition.WorldLocation, switchLocation);
3211-
if (distanceFromSwitch < CarLengthM * CarLengthM + Math.Min(SpeedMpS * 3, 150))
3212-
{
3213-
isOverJunction = true;
3214-
return isOverJunction;
3215-
}
3216-
}
3217-
}
3218-
}
3219-
catch
3220-
{
3221-
3222-
}
3223-
}
3224-
3225-
return isOverJunction;
3148+
IsOverSwitch = isOverSwitch;
3149+
IsOverCrossover = isOverCrossover;
3150+
IsOverTrough = isOverTrough;
32263151
}
32273152

3153+
// TODO These three fields should be in the TrainCarViewer.
3154+
public int TrackSoundType = 0;
3155+
public WorldLocation TrackSoundLocation = WorldLocation.None;
3156+
public float TrackSoundDistSquared = 0;
32283157

32293158
public static WorldLocation TileLocation(UiD uid)
32303159
{

Source/RunActivity/Viewer3D/Popups/TrainDrivingWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ void AddSeparator() => AddLabel(new ListLabel
11871187
}
11881188
else if (locomotive.IsWaterScoopDown && !locomotive.ScoopIsBroken)
11891189
{
1190-
waterScoopIndicator = Viewer.Catalog.GetString("Down") + (locomotive.IsOverTrough() ? ColorCode[Color.Cyan] : ColorCode[Color.Orange]);
1190+
waterScoopIndicator = Viewer.Catalog.GetString("Down") + (locomotive.IsOverTrough ? ColorCode[Color.Cyan] : ColorCode[Color.Orange]);
11911191
waterScoopKey = Symbols.ArrowToRight + ColorCode[Color.Yellow];
11921192
}
11931193
else

Source/RunActivity/Viewer3D/Sound.cs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -395,32 +395,8 @@ public bool UpdateCarOnSwitchAndCurve()
395395

396396
var CarBehind = Car.Train.Cars[CarNo + CarIncr];
397397
var carPreviouslyOnSwitch = CarOnSwitch;
398-
CarOnSwitch = false;
399-
if (Car.Train.PresentPosition[0].TCSectionIndex != Car.Train.PresentPosition[1].TCSectionIndex)
400-
{
401-
try
402-
{
403-
var copyOccupiedTrack = Car.Train.OccupiedTrack.ToArray();
404-
foreach (var thisSection in copyOccupiedTrack)
405-
{
406-
if (thisSection.CircuitType == TrackCircuitSection.TrackCircuitType.Junction || thisSection.CircuitType == TrackCircuitSection.TrackCircuitType.Crossover)
407-
{
408-
// train is on a switch; let's see if car is on a switch too
409-
WorldLocation switchLocation = UidLocation(Viewer.Simulator.TDB.TrackDB.TrackNodes[thisSection.OriginalIndex].UiD);
410-
var distanceFromSwitch = WorldLocation.GetDistanceSquared(Car.WorldPosition.WorldLocation, switchLocation);
411-
if (distanceFromSwitch < Car.CarLengthM * Car.CarLengthM + Math.Min(Car.SpeedMpS * 3, 150))
412-
{
413-
CarOnSwitch = true;
414-
break;
415-
}
416-
}
417-
}
418-
}
419-
catch
420-
{
398+
CarOnSwitch = Car.IsOverSwitch || Car.IsOverCrossover;
421399

422-
}
423-
}
424400
// here check for curve
425401
var carPreviouslyOnCurve = CarOnCurve;
426402
CarOnCurve = false;

Source/RunActivity/Viewer3D/WebServices/TrainDrivingDisplay.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ void AddSeparator() => AddLabel(new ListLabel
729729
}
730730
else if (locomotive.WaterScoopDown && !locomotive.ScoopIsBroken)
731731
{
732-
waterScoopIndicator = Viewer.Catalog.GetString("Down") + (locomotive.IsOverTrough() ? ColorCode[Color.Cyan] : ColorCode[Color.Orange]);
732+
waterScoopIndicator = Viewer.Catalog.GetString("Down") + (locomotive.IsOverTrough ? ColorCode[Color.Cyan] : ColorCode[Color.Orange]);
733733
waterScoopKey = Symbols.ArrowToRight + ColorCode[Color.Yellow];
734734
}
735735
else

0 commit comments

Comments
 (0)