Exemple #1
0
        void UpdateSwitch(Image image, Train train, bool front)
        {
            image.Source = new Rectangle(0, 0, SwitchImageSize, SwitchImageSize);

            var traveller = front ? new Traveller(train.FrontTDBTraveller) : new Traveller(train.RearTDBTraveller, Traveller.TravellerDirection.Backward);

            TrackNode SwitchPreviousNode = traveller.TN;
            TrackNode SwitchNode         = null;

            while (traveller.NextSection())
            {
                if (traveller.IsJunction)
                {
                    SwitchNode = traveller.TN;
                    break;
                }
                SwitchPreviousNode = traveller.TN;
            }
            if (SwitchNode == null)
            {
                return;
            }

            Debug.Assert(SwitchPreviousNode != null);
            Debug.Assert(SwitchNode.Inpins == 1);
            Debug.Assert(SwitchNode.Outpins == 2 || SwitchNode.Outpins == 3);               // allow for 3-way switch
            Debug.Assert(SwitchNode.TrPins.Count() == 3 || SwitchNode.TrPins.Count() == 4); // allow for 3-way switch
            Debug.Assert(SwitchNode.TrJunctionNode != null);
            Debug.Assert(SwitchNode.TrJunctionNode.SelectedRoute == 0 || SwitchNode.TrJunctionNode.SelectedRoute == 1);

            var switchPreviousNodeID     = Owner.Viewer.Simulator.TDB.TrackDB.TrackNodesIndexOf(SwitchPreviousNode);
            var switchBranchesAwayFromUs = SwitchNode.TrPins[0].Link == switchPreviousNodeID;
            var switchTrackSection       = Owner.Viewer.Simulator.TSectionDat.TrackShapes.Get(SwitchNode.TrJunctionNode.ShapeIndex); // TSECTION.DAT tells us which is the main route
            var switchMainRouteIsLeft    = SwitchNode.TrJunctionNode.GetAngle(Owner.Viewer.Simulator.TSectionDat) > 0;               // align the switch

            image.Source.X = ((switchBranchesAwayFromUs == front ? 1 : 3) + (switchMainRouteIsLeft ? 1 : 0)) * SwitchImageSize;
            image.Source.Y = SwitchNode.TrJunctionNode.SelectedRoute * SwitchImageSize;

            TrackCircuitSection switchSection = Owner.Viewer.Simulator.Signals.TrackCircuitList[SwitchNode.TCCrossReference[0].Index];

            if (switchSection.CircuitState.HasTrainsOccupying() || switchSection.CircuitState.SignalReserved >= 0 ||
                (switchSection.CircuitState.TrainReserved != null && switchSection.CircuitState.TrainReserved.Train.ControlMode != Train.TRAIN_CONTROL.MANUAL))
            {
                image.Source.Y += 2 * SwitchImageSize;
            }
        }
        // Set train route to alternative route - location based deadlock processing
        internal protected void ClearDeadlocks()
        {
            // clear deadlocks
            foreach (KeyValuePair <int, List <Dictionary <int, int> > > deadlock in DeadlockInfo)
            {
                TrackCircuitSection section = TrackCircuitSection.TrackCircuitList[deadlock.Key];
                foreach (Dictionary <int, int> deadlockTrapInfo in deadlock.Value)
                {
                    foreach (KeyValuePair <int, int> deadlockedTrain in deadlockTrapInfo)
                    {
                        Train otherTrain = GetOtherTrainByNumber(deadlockedTrain.Key);
                        if (otherTrain != null && otherTrain.DeadlockInfo.ContainsKey(deadlockedTrain.Value))
                        {
                            List <Dictionary <int, int> > otherDeadlock = otherTrain.DeadlockInfo[deadlockedTrain.Value];
                            for (int i = otherDeadlock.Count - 1; i >= 0; i--)
                            {
                                Dictionary <int, int> otherDeadlockInfo = otherDeadlock[i];
                                if (otherDeadlockInfo.ContainsKey(Number))
                                {
                                    otherDeadlockInfo.Remove(Number);
                                }
                                if (otherDeadlockInfo.Count <= 0)
                                {
                                    otherDeadlock.RemoveAt(i);
                                }
                            }

                            if (otherDeadlock.Count <= 0)
                            {
                                otherTrain.DeadlockInfo.Remove(deadlockedTrain.Value);
                            }

                            if (otherTrain.DeadlockInfo.Count <= 0)
                            {
                                section.ClearDeadlockTrap(otherTrain.Number);
                            }
                        }
                        TrackCircuitSection otherSection = TrackCircuitSection.TrackCircuitList[deadlockedTrain.Value];
                        otherSection.ClearDeadlockTrap(Number);
                    }
                }
            }

            DeadlockInfo.Clear();
        }
Exemple #3
0
        /// <summary>
        /// Reverse (or continue in same direction)
        /// <\summary>

        internal void Reverse(TrackDirection oldDirection, TrackCircuitPartialPathRoute route, float offset)
        {
            if (null == route)
            {
                throw new ArgumentNullException(nameof(route));
            }

            RouteListIndex = route.GetRouteIndex(TrackCircuitSectionIndex, 0);
            Direction      = RouteListIndex >= 0 ? route[RouteListIndex].Direction : Direction = Direction.Reverse();

            TrackCircuitSection section = TrackCircuitSection.TrackCircuitList[TrackCircuitSectionIndex];

            if (oldDirection != Direction)
            {
                Offset = section.Length - Offset; // actual reversal so adjust offset
            }
            DistanceTravelled = offset;
        }
        //================================================================================================//
        /// <summary>
        /// Constructor from CircuitSection
        /// </summary>
        public TrackCircuitRouteElement(TrackCircuitSection section, TrackDirection direction, int lastSectionIndex)
        {
            TrackCircuitSection      = section ?? throw new ArgumentNullException(nameof(section));
            Direction                = direction;
            OutPin[Location.NearEnd] = direction;
            OutPin[Location.FarEnd]  = TrackDirection.Ahead;          // always 0 for NORMAL sections, updated for JUNCTION sections

            if (section.CircuitType == TrackCircuitType.Crossover)
            {
                TrackDirection inPinLink = direction.Reverse();
                OutPin[Location.FarEnd] = (section.Pins[inPinLink, Location.NearEnd].Link == lastSectionIndex) ? TrackDirection.Ahead : TrackDirection.Reverse;
            }

            FacingPoint = (section.CircuitType == TrackCircuitType.Junction && section.Pins[direction, Location.FarEnd].Link != -1);

            UsedAlternativePath     = -1;
            MovingTableApproachPath = -1;
        }
        //================================================================================================//
        //
        // Check if conflict is real deadlock situation
        // Conditions :
        //   if section is part of deadlock definition, it is a deadlock
        //   if section has intermediate signals, it is a deadlock
        //   if section has no intermediate signals but there are signals on both approaches to the deadlock, it is not a deadlock
        // Return value : boolean to indicate it is a deadlock or not
        // If not a deadlock, the REF int elementIndex is set to index of the last common section (will be increased in the loop)
        //
        internal bool CheckRealDeadlockLocationBased(TrackCircuitPartialPathRoute route, TrackCircuitPartialPathRoute otherRoute, ref int elementIndex)
        {
            bool isValidDeadlock = false;

            TrackCircuitSection section = route[elementIndex].TrackCircuitSection;

            // check if section is start or part of deadlock definition
            if (section.DeadlockReference >= 0 || (section.DeadlockBoundaries != null && section.DeadlockBoundaries.Count > 0))
            {
                return(true);
            }

            // loop through common section - if signal is found, it is a deadlock
            bool validLoop       = true;
            int  otherRouteIndex = otherRoute.GetRouteIndex(section.Index, 0);

            for (int i = 0; validLoop; i++)
            {
                int thisElementIndex  = elementIndex + i;
                int otherElementIndex = otherRouteIndex - i;

                if (thisElementIndex > route.Count - 1)
                {
                    validLoop = false;
                }
                if (otherElementIndex < 0)
                {
                    validLoop = false;
                }

                if (validLoop)
                {
                    TrackCircuitSection thisRouteSection  = route[thisElementIndex].TrackCircuitSection;
                    TrackCircuitSection otherRouteSection = otherRoute[otherElementIndex].TrackCircuitSection;

                    if (thisRouteSection.Index != otherRouteSection.Index)
                    {
                        validLoop = false;
                    }
                    else if (thisRouteSection.EndSignals[TrackDirection.Ahead] != null || thisRouteSection.EndSignals[TrackDirection.Reverse] != null)
                    {
                        isValidDeadlock = true;
                        validLoop       = false;
                    }
                }
            }

            // if no signals along section, check if section is protected by signals - if so, it is not a deadlock
            // check only as far as maximum signal check distance
            if (!isValidDeadlock)
            {
                // this route backward first
                float totalDistance = 0.0f;
                bool  signalFound   = false;
                validLoop = true;

                for (int i = 0; validLoop; i--)
                {
                    int thisElementIndex = elementIndex + i; // going backward as iIndex is negative!
                    if (thisElementIndex < 0)
                    {
                        validLoop = false;
                    }
                    else
                    {
                        TrackCircuitRouteElement thisElement      = route[thisElementIndex];
                        TrackCircuitSection      thisRouteSection = thisElement.TrackCircuitSection;
                        totalDistance += thisRouteSection.Length;

                        if (thisRouteSection.EndSignals[thisElement.Direction] != null)
                        {
                            validLoop   = false;
                            signalFound = true;
                        }

                        if (totalDistance > MinCheckDistanceM)
                        {
                            validLoop = false;
                        }
                    }
                }

                // other route backward next
                totalDistance = 0.0f;
                bool otherSignalFound = false;
                validLoop = true;

                for (int iIndex = 0; validLoop; iIndex--)
                {
                    int thisElementIndex = otherRouteIndex + iIndex; // going backward as iIndex is negative!
                    if (thisElementIndex < 0)
                    {
                        validLoop = false;
                    }
                    else
                    {
                        TrackCircuitRouteElement thisElement      = otherRoute[thisElementIndex];
                        TrackCircuitSection      thisRouteSection = thisElement.TrackCircuitSection;
                        totalDistance += thisRouteSection.Length;

                        if (thisRouteSection.EndSignals[thisElement.Direction] != null)
                        {
                            validLoop        = false;
                            otherSignalFound = true;
                        }

                        if (totalDistance > MinCheckDistanceM)
                        {
                            validLoop = false;
                        }
                    }
                }

                if (!signalFound || !otherSignalFound)
                {
                    isValidDeadlock = true;
                }
            }

            // if not a valid deadlock, find end of common section
            if (!isValidDeadlock)
            {
                elementIndex = EndCommonSection(elementIndex, route, otherRoute);;
            }

            return(isValidDeadlock);
        }
        // Obtain deadlock details - new style location based logic
        private int[] SetDeadlockLocationBased(int index, TrackCircuitPartialPathRoute route, TrackCircuitPartialPathRoute otherRoute, Train otherTrain)
        {
            int[] returnValue = new int[2];
            returnValue[1] = -1;  // set to no alternative path used

            TrackCircuitRouteElement firstElement = route[index];
            int  firstSectionIndex = firstElement.TrackCircuitSection.Index;
            bool alreadyActive     = false;

            int trainSectionIndex;
            int otherTrainSectionIndex;

            // double index variables required as last valid index must be known when exiting loop
            int trainIndex          = index;
            int trainNextIndex      = trainIndex;
            int otherTrainIndex     = otherRoute.GetRouteIndex(firstSectionIndex, 0);
            int otherTrainNextIndex = otherTrainIndex;
            int otherFirstIndex     = otherTrainIndex;

            TrackCircuitRouteElement trainElement;
            TrackCircuitRouteElement otherTrainElement;

            bool validPassLocation    = false;
            int  endSectionRouteIndex = -1;

            bool endOfLoop = false;

            // loop while not at end of route for either train and sections are equal
            // loop is also exited when alternative path is found for either train
            while (!endOfLoop)
            {
                trainIndex        = trainNextIndex;
                trainElement      = route[trainIndex];
                otherTrainIndex   = otherTrainNextIndex;
                trainSectionIndex = trainElement.TrackCircuitSection.Index;

                otherTrainElement      = otherRoute[otherTrainIndex];
                otherTrainSectionIndex = otherTrainElement.TrackCircuitSection.Index;

                TrackCircuitSection section = otherTrainElement.TrackCircuitSection;

                // if sections not equal : test length of next not-common section, if long enough then exit loop
                if (trainSectionIndex != otherTrainSectionIndex)
                {
                    int nextThisRouteIndex = trainIndex;
                    TrackCircuitSection passLoopSection = ValidRoute[0][nextThisRouteIndex].TrackCircuitSection;
                    _ = otherRoute.GetRouteIndex(passLoopSection.Index, otherTrainIndex);

                    float passLength    = passLoopSection.Length;
                    bool  endOfPassLoop = false;

                    while (!endOfPassLoop)
                    {
                        // loop is longer as at least one of the trains so is valid
                        if (passLength > Length || passLength > otherTrain.Length)
                        {
                            endOfPassLoop = true;
                            endOfLoop     = true;
                        }

                        // get next section
                        else if (nextThisRouteIndex < ValidRoute[0].Count - 2)
                        {
                            nextThisRouteIndex++;
                            passLoopSection = ValidRoute[0][nextThisRouteIndex].TrackCircuitSection;
                            int nextOtherRouteIndex = otherRoute.GetRouteIndexBackward(passLoopSection.Index, otherTrainIndex);

                            // new common section after too short loop - not a valid deadlock point
                            if (nextOtherRouteIndex >= 0)
                            {
                                endOfPassLoop       = true;
                                trainNextIndex      = nextThisRouteIndex;
                                otherTrainNextIndex = nextOtherRouteIndex;
                            }
                            else
                            {
                                passLength += passLoopSection.Length;
                            }
                        }
                        // end of route
                        else
                        {
                            endOfPassLoop = true;
                            endOfLoop     = true;
                        }
                    }
                }
                // if section is a deadlock boundary, check available paths for both trains
                else
                {
                    List <int> trainAllocatedPaths      = new List <int>();
                    List <int> otherTrainAllocatedPaths = new List <int>();

                    bool gotoNextSection = true;

                    if (section.DeadlockReference >= 0 && trainElement.FacingPoint) // test for facing points only
                    {
                        bool trainFits      = false;
                        bool otherTrainFits = false;

                        int endSectionIndex = -1;

                        validPassLocation = true;

                        // get allocated paths for this train
                        DeadlockInfo deadlockInfo = Simulator.Instance.SignalEnvironment.DeadlockInfoList[section.DeadlockReference];

                        // get allocated paths for this train - if none yet set, create references
                        int trainReferenceIndex = deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath);
                        if (!deadlockInfo.TrainReferences.ContainsKey(trainReferenceIndex))
                        {
                            deadlockInfo.SetTrainDetails(Number, TCRoute.ActiveSubPath, Length, ValidRoute[0], trainIndex);
                        }

                        // if valid path for this train
                        if (deadlockInfo.TrainReferences.ContainsKey(trainReferenceIndex))
                        {
                            trainAllocatedPaths = deadlockInfo.TrainReferences[deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath)];

                            // if paths available, get end section and check train against shortest path
                            if (trainAllocatedPaths.Count > 0)
                            {
                                endSectionIndex      = deadlockInfo.AvailablePathList[trainAllocatedPaths[0]].EndSectionIndex;
                                endSectionRouteIndex = route.GetRouteIndex(endSectionIndex, trainIndex);
                                Dictionary <int, bool> trainFitList = deadlockInfo.TrainLengthFit[deadlockInfo.GetTrainAndSubpathIndex(Number, TCRoute.ActiveSubPath)];
                                foreach (int i in trainAllocatedPaths)
                                {
                                    if (trainFitList[i])
                                    {
                                        trainFits = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            validPassLocation = false;
                        }

                        // get allocated paths for other train - if none yet set, create references
                        int otherTrainReferenceIndex = deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath);
                        if (!deadlockInfo.TrainReferences.ContainsKey(otherTrainReferenceIndex))
                        {
                            int otherTrainElementIndex = otherTrain.ValidRoute[0].GetRouteIndexBackward(endSectionIndex, otherFirstIndex);
                            if (otherTrainElementIndex < 0) // train joins deadlock area on different node
                            {
                                validPassLocation = false;
                                deadlockInfo.RemoveTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath); // remove index as train has no valid path
                            }
                            else
                            {
                                deadlockInfo.SetTrainDetails(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath, otherTrain.Length,
                                                             otherTrain.ValidRoute[0], otherTrainElementIndex);
                            }
                        }

                        // if valid path for other train
                        if (validPassLocation && deadlockInfo.TrainReferences.ContainsKey(otherTrainReferenceIndex))
                        {
                            otherTrainAllocatedPaths =
                                deadlockInfo.TrainReferences[deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath)];

                            // if paths available, get end section (if not yet set) and check train against shortest path
                            if (otherTrainAllocatedPaths.Count > 0)
                            {
                                if (endSectionRouteIndex < 0)
                                {
                                    endSectionIndex      = deadlockInfo.AvailablePathList[otherTrainAllocatedPaths[0]].EndSectionIndex;
                                    endSectionRouteIndex = route.GetRouteIndex(endSectionIndex, trainIndex);
                                }

                                Dictionary <int, bool> otherTrainFitList =
                                    deadlockInfo.TrainLengthFit[deadlockInfo.GetTrainAndSubpathIndex(otherTrain.Number, otherTrain.TCRoute.ActiveSubPath)];
                                foreach (int iPath in otherTrainAllocatedPaths)
                                {
                                    if (otherTrainFitList[iPath])
                                    {
                                        otherTrainFits = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        // other train has no valid path relating to the passing path, so passing not possible
                        {
                            validPassLocation = false;
                        }

                        // if both trains have only one route, make sure it's not the same (inverse) route

                        if (trainAllocatedPaths.Count == 1 && otherTrainAllocatedPaths.Count == 1)
                        {
                            if (deadlockInfo.InverseInfo.ContainsKey(trainAllocatedPaths[0]) && deadlockInfo.InverseInfo[trainAllocatedPaths[0]] == otherTrainAllocatedPaths[0])
                            {
                                validPassLocation = false;
                            }
                        }

                        // if there are passing paths and at least one train fits in shortest path, it is a valid location so break loop
                        if (validPassLocation)
                        {
                            gotoNextSection = false;
                            if (trainFits || otherTrainFits)
                            {
                                if (section.IsSet(otherTrain, true))
                                {
                                    alreadyActive = true;
                                }
                                endOfLoop = true;
                            }
                            else
                            {
                                trainNextIndex      = endSectionRouteIndex;
                                otherTrainNextIndex = otherRoute.GetRouteIndexBackward(endSectionIndex, otherTrainIndex);
                                if (otherTrainNextIndex < 0)
                                {
                                    endOfLoop = true;
                                }
                            }
                        }
                    }

                    // if loop not yet ended - not a valid pass location, move to next section (if available)

                    if (gotoNextSection)
                    {
                        // if this section is occupied by other train, break loop - further checks are of no use
                        if (section.IsSet(otherTrain, true))
                        {
                            alreadyActive = true;
                            endOfLoop     = true;
                        }
                        else
                        {
                            trainNextIndex++;
                            otherTrainNextIndex--;

                            if (trainNextIndex > route.Count - 1 || otherTrainNextIndex < 0)
                            {
                                endOfLoop = true; // end of path reached for either train
                            }
                        }
                    }
                }
            }

            // if valid pass location : set return index

            if (validPassLocation && endSectionRouteIndex >= 0)
            {
                returnValue[1] = endSectionRouteIndex;
            }

            // get sections on which loop ended
            trainElement      = route[trainIndex];
            trainSectionIndex = trainElement.TrackCircuitSection.Index;

            otherTrainElement      = otherRoute[otherTrainIndex];
            otherTrainSectionIndex = otherTrainElement.TrackCircuitSection.Index;

            // if last sections are still equal - end of route reached for one of the trains
            // otherwise, last common sections was previous sections for this train
            TrackCircuitSection lastSection = (trainSectionIndex == otherTrainSectionIndex) ? TrackCircuitSection.TrackCircuitList[trainSectionIndex] :
                                              route[trainIndex - 1].TrackCircuitSection;

            // TODO : if section is not a junction but deadlock is already active, wind back to last junction
            // if section is not a junction, check if either route not ended, if so continue up to next junction
            if (lastSection.CircuitType != TrackCircuitType.Junction)
            {
                bool endSectionFound = false;
                if (trainIndex < (route.Count - 1))
                {
                    for (int iIndex = trainIndex; iIndex < route.Count - 1 && !endSectionFound; iIndex++)
                    {
                        lastSection     = route[iIndex].TrackCircuitSection;
                        endSectionFound = lastSection.CircuitType == TrackCircuitType.Junction;
                    }
                }

                else if (otherTrainIndex > 0)
                {
                    for (int i = otherTrainIndex; i >= 0 && !endSectionFound; i--)
                    {
                        lastSection     = otherRoute[i].TrackCircuitSection;
                        endSectionFound = false;

                        // junction found - end of loop
                        if (lastSection.CircuitType == TrackCircuitType.Junction)
                        {
                            endSectionFound = true;
                        }
                        // train has active wait condition at this location - end of loop
                        else if (otherTrain.CheckWaitCondition(lastSection.Index))
                        {
                            endSectionFound = true;
                        }

                        if (lastSection.IsSet(otherTrain, true))
                        {
                            alreadyActive = true;
                        }
                    }
                }
            }

            // set deadlock info for both trains
            SetDeadlockInfo(firstSectionIndex, lastSection.Index, otherTrain.Number);
            otherTrain.SetDeadlockInfo(lastSection.Index, firstSectionIndex, Number);

            if (alreadyActive)
            {
                lastSection.SetDeadlockTrap(otherTrain, otherTrain.DeadlockInfo[lastSection.Index]);
                returnValue[1] = route.Count;  // set beyond end of route - no further checks required
            }

            // if any section occupied by own train, reverse deadlock is active
            TrackCircuitSection firstSection = TrackCircuitSection.TrackCircuitList[firstSectionIndex];

            int firstRouteIndex = ValidRoute[0].GetRouteIndex(firstSectionIndex, 0);
            int lastRouteIndex  = ValidRoute[0].GetRouteIndex(lastSection.Index, 0);

            for (int i = firstRouteIndex; i < lastRouteIndex; i++)
            {
                TrackCircuitSection partSection = ValidRoute[0][i].TrackCircuitSection;
                if (partSection.IsSet(this, true))
                {
                    firstSection.SetDeadlockTrap(this, DeadlockInfo[firstSectionIndex]);
                }
            }

            returnValue[0] = route.GetRouteIndex(lastSection.Index, index);
            if (returnValue[0] < 0)
            {
                returnValue[0] = trainIndex;
            }
            return(returnValue);
        }
        // Obtain deadlock details - old style path based logic
        private int[] SetDeadlockPathBased(int index, TrackCircuitPartialPathRoute route, TrackCircuitPartialPathRoute otherRoute, Train otherTrain)
        {
            int[] returnValue = new int[2];
            returnValue[1] = -1;  // set to no alternative path used

            TrackCircuitRouteElement firstElement = route[index];
            int  firstSectionIndex = firstElement.TrackCircuitSection.Index;
            bool allreadyActive    = false;

            int trainSection      = firstSectionIndex;
            int otherTrainSection = firstSectionIndex;

            int trainIndex      = index;
            int otherTrainIndex = otherRoute.GetRouteIndex(firstSectionIndex, 0);

            int firstIndex      = trainIndex;
            int otherFirstIndex = otherTrainIndex;

            TrackCircuitRouteElement trainElement;
            TrackCircuitRouteElement otherTrainElement;

            // loop while not at end of route for either train and sections are equal
            // loop is also exited when alternative path is found for either train
            for (int i = 0; ((firstIndex + i) <= (route.Count - 1)) && ((otherFirstIndex - i)) >= 0 && (trainSection == otherTrainSection); i++)
            {
                trainIndex      = firstIndex + i;
                otherTrainIndex = otherFirstIndex - i;

                trainElement      = route[trainIndex];
                otherTrainElement = otherRoute[otherTrainIndex];
                trainSection      = trainElement.TrackCircuitSection.Index;
                otherTrainSection = otherTrainElement.TrackCircuitSection.Index;

                if (trainElement.StartAlternativePath != null)
                {
                    int endAlternativeSection = trainElement.StartAlternativePath.TrackCircuitSection.Index;
                    returnValue[1] = route.GetRouteIndex(endAlternativeSection, index);
                    break;
                }

                if (otherTrainElement.EndAlternativePath != null)
                {
                    int endAlternativeSection = otherTrainElement.EndAlternativePath.TrackCircuitSection.Index;
                    returnValue[1] = route.GetRouteIndex(endAlternativeSection, index);
                    break;
                }

                TrackCircuitSection section = TrackCircuitSection.TrackCircuitList[trainSection];
                if (section.IsSet(otherTrain, true))
                {
                    allreadyActive = true;
                }
            }

            // get sections on which loop ended
            trainElement = route[trainIndex];
            trainSection = trainElement.TrackCircuitSection.Index;

            otherTrainElement = otherRoute[otherTrainIndex];
            otherTrainSection = otherTrainElement.TrackCircuitSection.Index;

            // if last sections are still equal - end of route reached for one of the trains
            // otherwise, last common sections was previous sections for this train
            int lastSectionIndex = (trainSection == otherTrainSection) ? trainSection : route[trainIndex - 1].TrackCircuitSection.Index;

            // if section is not a junction, check if either route not ended, if so continue up to next junction
            TrackCircuitSection lastSection = TrackCircuitSection.TrackCircuitList[lastSectionIndex];

            if (lastSection.CircuitType != TrackCircuitType.Junction)
            {
                bool endSectionFound = false;
                if (trainIndex < (route.Count - 1))
                {
                    for (int i = trainIndex + 1; i < route.Count - 1 && !endSectionFound; i++)
                    {
                        lastSection     = route[i].TrackCircuitSection;
                        endSectionFound = lastSection.CircuitType == TrackCircuitType.Junction;
                    }
                }
                else if (otherTrainIndex > 0)
                {
                    for (int i = otherTrainIndex - 1; i >= 0 && !endSectionFound; i--)
                    {
                        lastSection     = otherRoute[i].TrackCircuitSection;
                        endSectionFound = lastSection.CircuitType == TrackCircuitType.Junction;
                        if (lastSection.IsSet(otherTrain, true))
                        {
                            allreadyActive = true;
                        }
                    }
                }
                lastSectionIndex = lastSection.Index;
            }

            // set deadlock info for both trains

            SetDeadlockInfo(firstSectionIndex, lastSectionIndex, otherTrain.Number);
            otherTrain.SetDeadlockInfo(lastSectionIndex, firstSectionIndex, Number);

            if (allreadyActive)
            {
                TrackCircuitSection section = TrackCircuitSection.TrackCircuitList[lastSectionIndex];
                section.SetDeadlockTrap(otherTrain, otherTrain.DeadlockInfo[lastSectionIndex]);
            }

            returnValue[0] = route.GetRouteIndex(lastSectionIndex, index);
            if (returnValue[0] < 0)
            {
                returnValue[0] = trainIndex;
            }
            return(returnValue);
        }
        // Check on deadlock
        private protected void CheckDeadlock(TrackCircuitPartialPathRoute route, int number)
        {
            // clear existing deadlock info
            ClearDeadlocks();

            // build new deadlock info
            foreach (Train otherTrain in simulator.Trains)
            {
                // check if not AI_Static
                if (Simulator.Instance.SignalEnvironment.UseLocationPassingPaths && otherTrain.GetAiMovementState() == AiMovementState.Static)
                {
                    continue;
                }

                if (otherTrain.Number != number && otherTrain.TrainType != TrainType.Static)
                {
                    TrackCircuitPartialPathRoute  otherRoute     = otherTrain.ValidRoute[0];
                    ILookup <int, TrackDirection> otherRouteDict = otherRoute.ConvertRoute();

                    for (int i = 0; i < route.Count; i++)
                    {
                        TrackCircuitRouteElement routeElement     = route[i];
                        TrackCircuitSection      section          = routeElement.TrackCircuitSection;
                        TrackDirection           sectionDirection = routeElement.Direction;

                        if (section.CircuitType != TrackCircuitType.Crossover)
                        {
                            if (otherRouteDict.Contains(section.Index))
                            {
                                TrackDirection otherTrainDirection = otherRouteDict[section.Index].First();
                                //<CSComment> Right part of OR clause refers to initial placement with trains back-to-back and running away one from the other</CSComment>
                                if (otherTrainDirection == sectionDirection ||
                                    (PresentPosition[Direction.Backward].TrackCircuitSectionIndex == otherTrain.PresentPosition[Direction.Backward].TrackCircuitSectionIndex && section.Index == PresentPosition[Direction.Backward].TrackCircuitSectionIndex &&
                                     PresentPosition[Direction.Backward].Offset + otherTrain.PresentPosition[Direction.Backward].Offset - 1 > section.Length))
                                {
                                    i = EndCommonSection(i, route, otherRoute);
                                }
                                else
                                {
                                    if (Simulator.Instance.SignalEnvironment.UseLocationPassingPaths) //new style location based logic
                                    {
                                        if (CheckRealDeadlockLocationBased(route, otherRoute, ref i))
                                        {
                                            int[] endDeadlock = SetDeadlockLocationBased(i, route, otherRoute, otherTrain);
                                            // use end of alternative path if set
                                            i = endDeadlock[1] > 0 ? --endDeadlock[1] : endDeadlock[0];
                                        }
                                    }
                                    else //old style path based logic
                                    {
                                        int[] endDeadlock = SetDeadlockPathBased(i, route, otherRoute, otherTrain);
                                        // use end of alternative path if set - if so, compensate for iElement++
                                        i = endDeadlock[1] > 0 ? --endDeadlock[1] : endDeadlock[0];
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        // Check if waiting for deadlock
        private bool CheckDeadlockWait(Signal nextSignal)
        {
            bool deadlockWait = false;

            // check section list of signal for any deadlock traps
            foreach (TrackCircuitRouteElement routeElement in nextSignal.SignalRoute)
            {
                TrackCircuitSection section = routeElement.TrackCircuitSection;
                if (section.DeadlockTraps.ContainsKey(Number))              // deadlock trap
                {
                    deadlockWait = true;

                    List <int> deadlockTrains = section.DeadlockTraps[Number];

                    if (DeadlockInfo.ContainsKey(section.Index) && !CheckWaitCondition(section.Index)) // reverse deadlocks and not waiting
                    {
                        foreach (Dictionary <int, int> deadlockList in DeadlockInfo[section.Index])
                        {
                            foreach (KeyValuePair <int, int> deadlock in deadlockList)
                            {
                                if (!deadlockTrains.Contains(deadlock.Key))
                                {
                                    TrackCircuitSection.TrackCircuitList[deadlock.Value].SetDeadlockTrap(Number, deadlock.Key);
                                }
                                else
                                {
                                    // check if train has reversal before end of path of other train
                                    if (TCRoute.TCRouteSubpaths.Count > (TCRoute.ActiveSubPath + 1))
                                    {
                                        Train otherTrain = GetOtherTrainByNumber(deadlock.Key);

                                        bool commonSectionFound = false;
                                        for (int i = otherTrain.PresentPosition[Direction.Forward].RouteListIndex + 1;
                                             i < otherTrain.ValidRoute[0].Count - 1 && !commonSectionFound;
                                             i++)
                                        {
                                            TrackCircuitSection otherSection = otherTrain.ValidRoute[0][i].TrackCircuitSection;
                                            for (int j = PresentPosition[Direction.Forward].RouteListIndex; j < ValidRoute[0].Count - 1; j++)
                                            {
                                                if (otherSection.Index == ValidRoute[0][j].TrackCircuitSection.Index)
                                                {
                                                    commonSectionFound = true;
                                                    break;
                                                }
                                            }
                                            if (otherSection.CircuitState.TrainReserved == null || otherSection.CircuitState.TrainReserved.Train.Number != otherTrain.Number)
                                            {
                                                break;
                                            }
                                            //if (sectionIndex == otherTrain.LastReservedSection[0]) lastReserved = true;
                                        }

                                        if (!commonSectionFound)
                                        {
                                            TrackCircuitSection endSection = TrackCircuitSection.TrackCircuitList[deadlock.Value];
                                            endSection.ClearDeadlockTrap(Number);
                                            section.ClearDeadlockTrap(otherTrain.Number);
                                            deadlockWait = false;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(deadlockWait);
        }
        /// Constructor (from route path details)
        public TrackCircuitReversalInfo(TrackCircuitPartialPathRoute lastRoute, int prevReversalIndex, TrackCircuitPartialPathRoute firstRoute, float reverseReversalOffset, int reversalIndex, int reversalSectionIndex)
        {
            // preset values
            Valid                  = false;
            LastDivergeIndex       = -1;
            FirstDivergeIndex      = -1;
            LastSignalIndex        = -1;
            FirstSignalIndex       = -1;
            SignalAvailable        = false;
            SignalUsed             = false;
            ReverseReversalOffset  = reverseReversalOffset;
            ReversalIndex          = reversalIndex;
            ReversalSectionIndex   = reversalSectionIndex;
            ReversalActionInserted = false;

            // search for first common section in last and first

            int lastIndex  = lastRoute.Count - 1;
            int firstIndex = 0;

            int lastCommonSection  = -1;
            int firstCommonSection = -1;

            bool commonFound   = false;
            bool validDivPoint = false;

            while (!commonFound && lastIndex >= 0)
            {
                TrackCircuitRouteElement lastElement = lastRoute[lastIndex];

                while (!commonFound && firstIndex <= firstRoute.Count - 1)
                {
                    TrackCircuitRouteElement firstElement = firstRoute[firstIndex];
                    if (lastElement.TrackCircuitSection.Index == firstElement.TrackCircuitSection.Index)
                    {
                        commonFound        = true;
                        lastCommonSection  = lastIndex;
                        firstCommonSection = firstIndex;

                        Valid = (lastElement.Direction != firstElement.Direction);
                    }
                    else
                    {
                        firstIndex++;
                    }
                }
                lastIndex--;
                firstIndex = 0;
            }

            // search for last common section going backward along route
            // do not go back on last route beyond previous reversal point to prevent fall through of reversals
            if (Valid)
            {
                Valid = false;

                lastIndex  = lastCommonSection;
                firstIndex = firstCommonSection;

                int endLastIndex = (prevReversalIndex > 0 && prevReversalIndex < lastCommonSection &&
                                    Simulator.Instance.TimetableMode) ? prevReversalIndex : 0;

                while (lastIndex >= endLastIndex && firstIndex <= (firstRoute.Count - 1) && lastRoute[lastIndex].TrackCircuitSection.Index == firstRoute[firstIndex].TrackCircuitSection.Index)
                {
                    LastDivergeIndex   = lastIndex;
                    FirstDivergeIndex  = firstIndex;
                    DivergeSectorIndex = lastRoute[lastIndex].TrackCircuitSection.Index;

                    lastIndex--;
                    firstIndex++;
                }

                // if next route ends within last one, last diverge index can be set to endLastIndex
                if (firstIndex > firstRoute.Count - 1)
                {
                    LastDivergeIndex   = endLastIndex;
                    DivergeSectorIndex = lastRoute[endLastIndex].TrackCircuitSection.Index;
                }

                Valid         = LastDivergeIndex >= 0; // it is a reversal
                validDivPoint = true;
                if (Simulator.Instance.TimetableMode)
                {
                    validDivPoint = LastDivergeIndex > 0 && FirstDivergeIndex < (firstRoute.Count - 1); // valid reversal point
                }
                if (lastRoute.Count == 1 && FirstDivergeIndex < (firstRoute.Count - 1))
                {
                    validDivPoint = true;                                                                     // valid reversal point in first and only section
                }
            }

            // determine offset

            if (validDivPoint)
            {
                DivergeOffset = 0.0f;
                for (int iSection = LastDivergeIndex; iSection < lastRoute.Count; iSection++)
                {
                    TrackCircuitSection thisSection = lastRoute[iSection].TrackCircuitSection;
                    DivergeOffset += thisSection.Length;
                }

                // find last signal furthest away from diverging point

                bool signalFound  = false;
                int  startSection = 0;

                if (!Simulator.Instance.TimetableMode)
                // In activity mode test starts only after reverse point.
                {
                    for (int iSection = 0; iSection < firstRoute.Count; iSection++)
                    {
                        if (firstRoute[iSection].TrackCircuitSection.Index == ReversalSectionIndex)
                        {
                            startSection = iSection;
                            break;
                        }
                    }
                    for (int iSection = startSection; iSection <= FirstDivergeIndex && !signalFound; iSection++)
                    {
                        TrackCircuitSection thisSection = firstRoute[iSection].TrackCircuitSection;
                        if (thisSection.EndSignals[firstRoute[iSection].Direction] != null)   // signal in required direction
                        {
                            signalFound       = true;
                            FirstSignalIndex  = iSection;
                            SignalSectorIndex = thisSection.Index;
                        }
                    }
                }
                // in timetable mode, search for first signal beyond diverging point
                else
                {
                    for (int iSection = FirstDivergeIndex; iSection >= startSection && !signalFound; iSection--)
                    {
                        TrackCircuitSection thisSection = firstRoute[iSection].TrackCircuitSection;
                        if (thisSection.EndSignals[firstRoute[iSection].Direction] != null)   // signal in required direction
                        {
                            signalFound       = true;
                            FirstSignalIndex  = iSection;
                            SignalSectorIndex = thisSection.Index;
                        }
                    }
                }

                // signal found
                if (signalFound)
                {
                    LastSignalIndex = lastRoute.GetRouteIndex(SignalSectorIndex, LastDivergeIndex);
                    if (LastSignalIndex > 0)
                    {
                        SignalAvailable = true;

                        SignalOffset = 0.0f;
                        for (int iSection = LastSignalIndex; iSection < lastRoute.Count; iSection++)
                        {
                            TrackCircuitSection thisSection = lastRoute[iSection].TrackCircuitSection;
                            SignalOffset += thisSection.Length;
                        }
                    }
                }
            }
            else
            {
                FirstDivergeIndex = -1;
                LastDivergeIndex  = -1;
            }
        }//constructor