Elvas Tower: Improving calculation of train path in explorer mode - Elvas Tower

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Improving calculation of train path in explorer mode Rate Topic: -----

#1 User is offline   cesarbl 

  • Conductor
  • Group: Status: Active Member
  • Posts: 395
  • Joined: 30-March 20
  • Gender:Male
  • Simulator:Open Rails
  • Country:

Posted 22 April 2020 - 12:40 AM

We have found a problem with the way train paths are calculated in explorer mode. Currently, only sections 5km ahead of the train are taken into account when clearing signals. Further signals are cleared too, but its route is not updated. This can lead to bad signal sequences, especially in high speed lines. For example, if a signal depends on the state of a switch, but it is not detected, it will be cleared with a wrong aspect, propagating the wrong aspect to previous signals. Once the train approaches the signal, it will either be correctly updated, showing a restrictive aspect which train cannot obey because there is not enough braking distance, or show the wrong aspect, leading to dangerous situations.

I suggest the following logic for the calculation. It seems to work:

  • If there is no path for the train, it is built until 5km are passed or a signal is found.
  • If the first signal in path is found and closer than 5km:
    • The signal is cleared, propagating the request using SignalNumClearAhead. The path is extended up to the last cleared signal.
    • If following signals aren't cleared, they are requested to do so continuously, again using SignalNumClearAhead, starting from train's first signal.


My principal concern is what to do if there is a signal protecting the entry of a non-signalled area. In this case, path should be restricted by distance. However, there is no way to distinguish between this case and a really long block-section, but followed by another signal. Maybe using a special value for SignalNumClearAhead or another flag could be the solution.

I would like to hear your opinions, and if I am forgetting something, please let me know.

Regards,
César Benito

#2 User is offline   cesarbl 

  • Conductor
  • Group: Status: Active Member
  • Posts: 395
  • Joined: 30-March 20
  • Gender:Male
  • Simulator:Open Rails
  • Country:

Posted 13 September 2020 - 02:47 AM

Recently this pull request was merged into the code, addressing some of the issues I mentioned in the above post. However, with that implementation I have found that ahead signals are sometimes not displayed in TrackMonitor, so probably TCS scripts will fail too. I also think that minCheckDistanceM should still be used in some situations (for example, when starting the simulation or in unsignalled areas).

Here there is a diff file with the code we use in our OR modified version in order to improve multiplayer experience, just in case anyone is interested:

diff --git a/Source/Orts.Simulation/Simulation/Physics/Train.cs b/Source/Orts.Simulation/Simulation/Physics/Train.cs
index 9eebe56d0..fba715f04 100644
--- a/Source/Orts.Simulation/Simulation/Physics/Train.cs
+++ b/Source/Orts.Simulation/Simulation/Physics/Train.cs
@@ -9010,8 +9010,8 @@ public void UpdateExplorerMode(int signalObjectIndex)
                 List<int> tempSections = new List<int>();
 
                 tempSections = signalRef.ScanRoute(this, requiredPosition.TCSectionIndex, requiredPosition.TCOffset,
-                        requiredPosition.TCDirection, forward, -1, true, false,
-                        false, false, true, false, false, false, false, IsFreight);
+                        requiredPosition.TCDirection, forward, minCheckDistanceM, true, false,
+                        true, false, true, false, false, false, false, IsFreight);
 
                 if (tempSections.Count > 0)
                 {
@@ -9045,6 +9045,7 @@ public void UpdateExplorerMode(int signalObjectIndex)
             thisSection = signalRef.TrackCircuitList[requiredPosition.TCSectionIndex];
             offsetM = direction == 0 ? requiredPosition.TCOffset : thisSection.Length - requiredPosition.TCOffset;
             bool endWithSignal = false;    // ends with signal at STOP
+            bool hasEndSignal = false;     // ends with cleared signal
             int sectionWithSignalIndex = 0;
 
             for (int iindex = 0; iindex < newRoute.Count && !endWithSignal; iindex++)
@@ -9063,17 +9064,19 @@ public void UpdateExplorerMode(int signalObjectIndex)
                 {
                     var endSignal = thisSection.EndSignals[reqDirection];
                     var thisAspect = thisSection.EndSignals[reqDirection].this_sig_lr(MstsSignalFunction.NORMAL);
+                    hasEndSignal = true;
 
                     if (thisAspect == MstsSignalAspect.STOP && endSignal.hasPermission != SignalObject.Permission.Granted)
                     {
                         endWithSignal = true;
                         sectionWithSignalIndex = iindex;
                     }
-                    else if (!endSignal.enabled)   // signal cleared by default only - request for proper clearing
+                    else if (endSignal.enabledTrain == null)   // signal cleared by default only - request for proper clearing
                     {
-                        endSignal.requestClearSignalExplorer(newRoute, thisRouted, true, 0);  // do NOT propagate
+                        var extendedRoute = endSignal.requestClearSignalExplorer(newRoute, thisRouted, true, 0);  // do NOT propagate
+                        if (iindex + 1 == newRoute.Count)
+                            newRoute = extendedRoute;
                     }
-
                 }
             }
 
@@ -9090,6 +9093,64 @@ public void UpdateExplorerMode(int signalObjectIndex)
                 }
             }
 
+            // if route does not end with signal and is too short, extend
+
+            if (!endWithSignal && totalLengthM < minCheckDistanceM)
+            {
+
+                float extendedDistanceM = minCheckDistanceM - totalLengthM;
+                TCRouteElement lastElement = newRoute[newRoute.Count - 1];
+
+                int lastSectionIndex = lastElement.TCSectionIndex;
+                TrackCircuitSection lastSection = signalRef.TrackCircuitList[lastSectionIndex];
+
+                int nextSectionIndex = lastSection.Pins[lastElement.OutPin[0], lastElement.OutPin[1]].Link;
+                int nextSectionDirection = lastSection.Pins[lastElement.OutPin[0], lastElement.OutPin[1]].Direction;
+
+                // check if last item is non-aligned switch
+
+                MisalignedSwitch[direction, 0] = -1;
+                MisalignedSwitch[direction, 1] = -1;
+
+                TrackCircuitSection nextSection = nextSectionIndex >= 0 ? signalRef.TrackCircuitList[nextSectionIndex] : null;
+                if (nextSection != null && nextSection.CircuitType == TrackCircuitSection.TrackCircuitType.Junction)
+                {
+                    if (nextSection.Pins[0, 0].Link != lastSectionIndex &&
+                        nextSection.Pins[0, 1].Link != lastSectionIndex &&
+                        nextSection.Pins[1, nextSection.JunctionLastRoute].Link != lastSectionIndex)
+                    {
+                        MisalignedSwitch[direction, 0] = nextSection.Index;
+                        MisalignedSwitch[direction, 1] = lastSectionIndex;
+                    }
+                }
+
+                List<int> tempSections = new List<int>();
+
+                if (nextSectionIndex >= 0 && MisalignedSwitch[direction, 0] < 0)
+                {
+                    bool reqAutoAlign = hasEndSignal; // auto-align switches if route is extended from signal
+
+                    tempSections = signalRef.ScanRoute(this, nextSectionIndex, 0,
+                            nextSectionDirection, forward, extendedDistanceM, true, reqAutoAlign,
+                            true, false, true, false, false, false, false, IsFreight);
+                }
+
+                if (tempSections.Count > 0)
+                {
+                    // add new sections
+
+                    int prevSection = lastElement.TCSectionIndex;
+
+                    foreach (int sectionIndex in tempSections)
+                    {
+                        thisElement = new Train.TCRouteElement(signalRef.TrackCircuitList[Math.Abs(sectionIndex)],
+                                sectionIndex > 0 ? 0 : 1, signalRef, prevSection);
+                        newRoute.Add(thisElement);
+                        prevSection = Math.Abs(sectionIndex);
+                    }
+                }
+            }
+
             // check for any uncleared signals in route - if first found, request clear signal
 
             bool unclearedSignal = false;
@@ -9255,12 +9316,67 @@ public void UpdateExplorerMode(int signalObjectIndex)
 
                 if (endAuthority == END_AUTHORITY.SIGNAL)
                 {
-                    TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[newRoute.Count - 1].TCSectionIndex];
-                    int lastDirection = newRoute[newRoute.Count - 1].Direction;
-                    if (lastSection.EndSignals[lastDirection] != null && lastSection.EndSignals[lastDirection].thisRef == nextUnclearSignalIndex)
+                    //TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[newRoute.Count - 1].TCSectionIndex];
+                    //int lastDirection = newRoute[newRoute.Count - 1].Direction;
+
+                    if (unclearedSignal && signalIndex < newRoute.Count)
                     {
+                        //TrackCircuitSection lastSection = signalRef.TrackCircuitList[newRoute[signalIndex].TCSectionIndex];
                         SignalObject reqSignal = signalRef.SignalObjects[nextUnclearSignalIndex];
-                        newRoute = reqSignal.requestClearSignalExplorer(newRoute, forward ? routedForward : routedBackward, false, 0);
+                        bool firstSignalPassed = false;
+                        int numCleared = 0;
+                        totalLengthM = 0;
+                        offsetM = direction == 0 ? requiredPosition.TCOffset : thisSection.Length - requiredPosition.TCOffset;
+                        for (int iindex = 0; iindex < newRoute.Count && (firstSignalPassed || totalLengthM < minCheckDistanceM); iindex++)
+                        {
+                            thisSection = signalRef.TrackCircuitList[newRoute[iindex].TCSectionIndex];
+                            int actDirection = newRoute[iindex].Direction;
+
+                            if (!thisSection.IsAvailable(this))
+                                break;
+
+                            totalLengthM += thisSection.Length - offsetM;
+                            offsetM = 0;
+
+                            if (thisSection.EndSignals[actDirection] != null)
+                            {
+                                var thisSignal = thisSection.EndSignals[actDirection];
+                                if (!firstSignalPassed)
+                                {
+                                    firstSignalPassed = true;
+                                    if (thisSignal == reqSignal)
+                                    {
+                                        for (int i = newRoute.Count - 1; i >= iindex + 1; i--)
+                                        {
+                                            thisSection = signalRef.TrackCircuitList[newRoute[i].TCSectionIndex];
+                                            thisSection.RemoveTrain(this, true);
+                                            newRoute.RemoveAt(i);
+                                        }
+                                        newRoute = thisSignal.requestClearSignalExplorer(newRoute, thisRouted, false, 0);
+                                        break;
+                                    }
+                                    int num = thisSignal.SignalNumClearAhead_MSTS;
+                                    if (num <= -2)
+                                        num = thisSignal.SignalNumClearAheadActive;
+                                    numCleared = Math.Max(num - thisSignal.SignalNumNormalHeads, 0);
+                                }
+                                else
+                                {
+                                    if (thisSignal == reqSignal && numCleared > 0)
+                                    {
+                                        for (int i = newRoute.Count - 1; i >= iindex + 1; i--)
+                                        {
+                                            thisSection = signalRef.TrackCircuitList[newRoute[i].TCSectionIndex];
+                                            thisSection.RemoveTrain(this, true);
+                                            newRoute.RemoveAt(i);
+                                        }
+                                        newRoute = thisSignal.requestClearSignalExplorer(newRoute, thisRouted, true, numCleared);
+                                        break;
+                                    }
+                                    numCleared = Math.Max(numCleared - thisSignal.SignalNumNormalHeads, 0);
+                                }
+                            }
+                        }
                     }
                 }
             }



Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users