Example #1
0
        /// <summary>
        /// Add an additional node, from the current last node along the next TrackNodeVector (given by index)
        /// The added node will always be a junction node.
        /// </summary>
        /// <param name="lastNode">Currently last node of path</param>
        /// <param name="nextTvnIndex">TrackNodeVector index along which to place the track</param>
        /// <param name="isMainPath">Are we adding a node on the main path (alternative is passing path)</param>
        /// <returns>The newly created junction path node</returns>
        TrainpathJunctionNode AddAdditionalJunctionNode(TrainpathNode lastNode, int nextTvnIndex, bool isMainPath)
        {
            // we add a new activeNodeAsJunction
            TrainpathJunctionNode newNode = new TrainpathJunctionNode(lastNode);

            if (TrackExtensions.TrackNode(nextTvnIndex) == null)
            {
                return(null); // apparently there is some issue in the track.
            }

            newNode.JunctionIndex = lastNode.GetNextJunctionIndex(nextTvnIndex);
            newNode.SetLocationFromTrackNode();

            // simple linking
            newNode.PrevNode = lastNode;
            if (isMainPath)
            {
                lastNode.NextMainTvnIndex = nextTvnIndex;
                lastNode.NextMainNode     = newNode;
            }
            else
            {
                lastNode.NextSidingTvnIndex = nextTvnIndex;
                lastNode.NextSidingNode     = newNode;
            }

            newNode.SetFacingPoint();
            newNode.DetermineOrientation(lastNode, nextTvnIndex);

            NetNodesAdded++;
            return(newNode);
        }
Example #2
0
        /// <summary>
        /// Make sure the junction nodes of have the exact location of the junctions in the track database.
        /// This is to make sure changes in the track database are taken over in the path
        /// </summary>
        void SnapAllJunctionNodes()
        {
            TrainpathNode mainNode = CurrentTrainPath.FirstNode;

            while (mainNode != null)
            {
                //siding path. For this routine we do not care if junctions are done twice
                TrainpathNode sidingNode = mainNode.NextSidingNode;
                while (sidingNode != null)
                {
                    TrainpathJunctionNode sidingNodeAsJunction = sidingNode as TrainpathJunctionNode;
                    if ((sidingNodeAsJunction != null) && !sidingNode.IsBroken)
                    {
                        sidingNode.Location = DrawTrackDB.UidLocation(trackDB.TrackNodes[sidingNodeAsJunction.JunctionIndex].UiD);
                    }
                    sidingNode = sidingNode.NextSidingNode;
                }

                TrainpathJunctionNode mainNodeAsJunction = mainNode as TrainpathJunctionNode;
                if ((mainNodeAsJunction != null) && !mainNode.IsBroken)
                {
                    mainNode.Location = DrawTrackDB.UidLocation(trackDB.TrackNodes[mainNodeAsJunction.JunctionIndex].UiD);
                }
                mainNode = mainNode.NextMainNode;
            }
        }
Example #3
0
        /// <summary>
        /// Make a shallow copy with all links to other nodes set to null;
        /// </summary>
        /// <returns>a copy of this node</returns>
        public override TrainpathNode ShallowCopyNoLinks()
        {
            TrainpathJunctionNode newNode = (TrainpathJunctionNode)this.MemberwiseClone();

            newNode.NextMainNode   = null;
            newNode.NextSidingNode = null;
            newNode.PrevNode       = null;
            return(newNode);
        }
Example #4
0
        /// <summary>
        /// Create a (still unlinked) node halfway through the next section (so halfway between this
        /// and the next junction. Needed specially for disambiguity.
        /// </summary>
        /// <param name="junctionNode">The junction node where we start</param>
        /// <param name="tvnIndex">The TrackVectorNode index for the path</param>
        /// <returns>An unlinked vectorNode at the midpoint.</returns>
        private TrainpathVectorNode CreateHalfWayNode(TrainpathJunctionNode junctionNode, int tvnIndex)
        {   // The idea here is to use all the code in traveller to make life easier.
            // move the traveller halfway through the next vector section
            Traveller traveller        = junctionNode.PlaceTravellerAfterJunction(tvnIndex);
            float     distanceToTravel = traveller.TrackNodeLength / 2;

            traveller.Move(distanceToTravel);

            TrainpathVectorNode halfwayNode = new TrainpathVectorNode(junctionNode, traveller);

            halfwayNode.DetermineOrientation(junctionNode, tvnIndex);

            return(halfwayNode);
        }
Example #5
0
 /// <summary>
 /// For all the junction nodes, set whether it is a facing point or not
 /// </summary>
 /// <param name="Nodes">The list of path nodes that now need to be linked</param>
 static private void SetFacingPoints(List <TrainpathNode> Nodes)
 {
     // It is just a convenience to use the list of Nodes.
     // In principle this can be done without the list by following the path
     for (int i = 0; i < Nodes.Count; i++)
     {
         TrainpathJunctionNode node = Nodes[i] as TrainpathJunctionNode;
         if (node == null)
         {
             continue;
         }
         node.SetFacingPoint();
     }
 }
Example #6
0
        /// <summary>
        /// Determine whether this node is earlier on a track than the given otherNode. Earlier here is defined
        /// in terms of the track orientation itself (so not in terms of the direction of a path).
        /// </summary>
        /// <param name="otherNode">Other node to compare against</param>
        /// <returns>true if this node is earlier on the track.</returns>
        public bool IsEarlierOnTrackThan(TrainpathNode otherNode)
        {
            TrainpathJunctionNode otherJunctionNode = otherNode as TrainpathJunctionNode;

            if (otherJunctionNode != null)
            {
                return(otherJunctionNode.JunctionIndex == TrackDB.TrackNodes[TvnIndex].JunctionIndexAtEnd());
            }

            TrainpathVectorNode otherVectorNode = otherNode as TrainpathVectorNode;

            return((TrackVectorSectionIndex < otherVectorNode.TrackVectorSectionIndex) ||
                   ((TrackVectorSectionIndex == otherVectorNode.TrackVectorSectionIndex) &&
                    (TrackSectionOffset < otherVectorNode.TrackSectionOffset)));
        }
Example #7
0
        /// <summary>
        /// Check if after this node a disambiguity node needs to be added
        /// </summary>
        /// <param name="currentNode"></param>
        public void AddDisambiguityNodeIfNeeded(TrainpathNode currentNode)
        {
            //Check if we need to add an disambiguity node
            TrainpathJunctionNode currentNodeAsJunction = currentNode as TrainpathJunctionNode;

            if ((currentNodeAsJunction != null) &&
                (currentNode.NextMainNode != null) &&
                (currentNode.NextMainNode is TrainpathJunctionNode) &&
                (currentNodeAsJunction.IsSimpleSidingStart())
                )
            {
                TrainpathVectorNode halfwayNode = CreateHalfWayNode(currentNodeAsJunction, currentNodeAsJunction.NextMainTvnIndex);
                halfwayNode.PrevNode = currentNode;
                AddIntermediateMainNode(halfwayNode);
            }
        }
Example #8
0
        /// <summary>
        /// Add a single TrPathNode. Make sure the pdp's are updated as needed.
        /// </summary>
        /// <param name="node">path node, needed for location, and various flags</param>
        /// <param name="nextMainIndex">Index of the next main node</param>
        /// <param name="nextSidingIndex">Index of the next siding node</param>
        private static void AddNode(TrainpathNode node, uint nextMainIndex, uint nextSidingIndex)
        {
            int    pdpIndex;
            string trackPDPstart = String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                                 "\tTrackPDP ( {0,6:D} {1,6:D} {2,9} {3,9:F3} {4,9:F3}",
                                                 node.Location.TileX, node.Location.TileZ,
                                                 node.Location.Location.X.ToString("F3", System.Globalization.CultureInfo.CreateSpecificCulture("en-US")),
                                                 node.Location.Location.Y.ToString("F3", System.Globalization.CultureInfo.CreateSpecificCulture("en-US")),
                                                 node.Location.Location.Z.ToString("F3", System.Globalization.CultureInfo.CreateSpecificCulture("en-US")));

            pdpIndex = trackPDPs.Count(); // default PDP index
            TrainpathJunctionNode nodeAsJunction = node as TrainpathJunctionNode;

            if (nodeAsJunction != null)
            {
                int junctionIndex = nodeAsJunction.JunctionIndex;
                if (!node.IsBroken && pdpOfJunction.ContainsKey(junctionIndex))
                {
                    //this junction is already in the list of PDPs, so use another PDP index;
                    pdpIndex = pdpOfJunction[junctionIndex];
                }
                else
                {
                    trackPDPs.Add(String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                                "{0} {1} {2} )", trackPDPstart, 2, 0));
                    pdpOfJunction[junctionIndex] = pdpIndex;
                }
            }
            else
            {   // TrainpathVectorNode
                if (node.NodeType == TrainpathNodeType.Start || node.NodeType == TrainpathNodeType.End)
                {
                    trackPDPs.Add(String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                                "{0} {1} {2} )", trackPDPstart, 1, 0));
                }
                else
                {
                    trackPDPs.Add(String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                                "{0} {1} {2} )", trackPDPstart, 1, 1));
                }
            }

            trpathnodes.Add(String.Format(System.Globalization.CultureInfo.InvariantCulture,
                                          "\t\tTrPathNode ( {0} {1} {2} {3} )",
                                          node.FlagsToString(), nextMainIndex, nextSidingIndex, pdpIndex));
        }
Example #9
0
        /// <summary>
        /// Determine the details of junction from which we connect
        /// </summary>
        private void DetermineJunction()
        {
            OriginalNodeAsVector = OriginalNode as TrainpathVectorNode;
            if (OriginalNodeAsVector != null)
            {
                DetermineJunctionForVectorNode();
            }
            else
            {
                TrainpathJunctionNode nodeAsJunction = OriginalNode as TrainpathJunctionNode; // cannot be null
                this.ConnectingJunctionIndex    = nodeAsJunction.JunctionIndex;
                this.IsConnectingJunctionFacing = nodeAsJunction.IsFacingPoint;
            }

            if (!IsConnectingForward)
            {
                this.IsConnectingJunctionFacing = !this.IsConnectingJunctionFacing;
            }
        }
Example #10
0
        /// <summary>
        /// Try to find the index of the vector node connecting this path node to the (given) nextNode.
        /// </summary>
        /// <returns>The index of the vector node connection, or -1</returns>
        public override int FindTvnIndex(TrainpathNode nextNode)
        {
            TrainpathVectorNode nextAsVectorNode = nextNode as TrainpathVectorNode;

            if ((nextAsVectorNode != null) && (this.TvnIndex == nextAsVectorNode.TvnIndex))
            {   // two vector nodes, tvn indices must be the same
                return(this.TvnIndex);
            }

            TrainpathJunctionNode nextAsJunctionNode = nextNode as TrainpathJunctionNode;

            if ((nextAsJunctionNode != null) && nextAsJunctionNode.ConnectsToTrack(TvnIndex))
            {   // vector node to junction node, junction must connect to tvnIndex
                return(this.TvnIndex);
            }

            //The nodes themselves might not be broken, but the link between them is.
            return(-1);
        }
Example #11
0
        /// <summary>
        /// Add an additional node starting at the given node, following the TvnIndex,
        /// but take care of a possible need for disambiguity.
        /// </summary>
        /// <param name="lastNode">Node after which a new node needs to be added</param>
        /// <param name="tvnIndex">TrackVectorNode index of the track the path needs to be on</param>
        /// <param name="isMainPath">Do we add the node to the main path or not</param>
        /// <returns>The newly created path node</returns>
        public TrainpathNode AddAdditionalNode(TrainpathNode lastNode, int tvnIndex, bool isMainPath)
        {
            TrainpathVectorNode lastNodeAsVector = lastNode as TrainpathVectorNode;

            if (lastNodeAsVector != null)
            {
                return(AddAdditionalJunctionNode(lastNode, lastNodeAsVector.TvnIndex, isMainPath));
            }

            TrainpathJunctionNode junctionNode = lastNode as TrainpathJunctionNode;

            if (junctionNode.IsSimpleSidingStart())
            {   // start of a simple siding. So the next node should be a node to remove disambiguity.
                TrainpathVectorNode halfwayNode = CreateHalfWayNode(junctionNode, tvnIndex);
                return(AddAdditionalVectorNode(junctionNode, halfwayNode, isMainPath));
            }
            else
            {
                return(AddAdditionalJunctionNode(junctionNode, tvnIndex, isMainPath));
            }
        }
Example #12
0
        /// <summary>
        /// Add an additional node, where the next track node is not yet given.
        /// </summary>
        /// <param name="lastNode">currently last node</param>
        /// <param name="isMainPath">Do we add the node to the main path or not</param>
        /// <returns>The newly created (unlinked) path node</returns>
        public TrainpathNode AddAdditionalNode(TrainpathNode lastNode, bool isMainPath)
        {
            TrainpathVectorNode lastNodeAsVector = lastNode as TrainpathVectorNode;

            if (lastNodeAsVector != null)
            {
                return(AddAdditionalNode(lastNode, lastNodeAsVector.TvnIndex, isMainPath));
            }

            TrainpathJunctionNode junctionNode = lastNode as TrainpathJunctionNode;

            if (junctionNode.IsEndNode)
            {
                return(null);                         // if it happens to be the end of a path, forget about it.
            }
            if (junctionNode.IsFacingPoint)
            {
                return(AddAdditionalNode(lastNode, junctionNode.MainTvn, isMainPath));
            }
            else
            {
                return(AddAdditionalNode(lastNode, junctionNode.TrailingTvn, isMainPath));
            }
        }
Example #13
0
        /// <summary>
        /// Create a partial path from the current node, along the new track vector index, until we can reconnect again
        /// </summary>
        /// <param name="currentNode">Starting place of the new partial path</param>
        /// <param name="newTvnIndex">Index of the new track vector node along which the path starts</param>
        /// <param name="reconnectNode">Node at we will reconnect to current path again</param>
        /// <param name="isMainPath">Do we add the node to the main path or not</param>
        /// <returns>The last node on the partial path, just before the reconnect node.</returns>
        public TrainpathNode CreatePartialPath(TrainpathNode currentNode, int newTvnIndex, TrainpathJunctionNode reconnectNode, bool isMainPath)
        {
            bool newHasSidingPath = isMainPath && currentNode.HasSidingPath;

            currentNode.HasSidingPath = newHasSidingPath;

            TrainpathNode newNode = AddAdditionalNode(currentNode, newTvnIndex, isMainPath);

            do
            {
                TrainpathJunctionNode newNodeAsJunction = newNode as TrainpathJunctionNode;
                if (newNodeAsJunction != null && (newNodeAsJunction.JunctionIndex == reconnectNode.JunctionIndex))
                {
                    //we have reached the reconnection point
                    break;
                }
                currentNode = newNode;
                currentNode.HasSidingPath = newHasSidingPath;
                newNode = AddAdditionalNode(currentNode, isMainPath);
            } while (newNode != null); // if we get here, something is wrong, because we checked we could reconnect

            // The returned node will not be the last node created, because that one is at the same location as the reconnect node
            return(currentNode);
        }
Example #14
0
        /// <summary>
        /// Find the nodes that can be used to relink for a siding path, or a 'take-other-exit' path, ...
        /// The reconnecing nodes all have to be before the first special node (wait, uncouple, reverse, end).
        /// They also have to be before the end of the (current path), even if it does not have a formal end,
        /// and they have to be before a possible next siding start. At last, it needs to be a non-facing junction.
        /// (similar conditions apply for searching backwards.
        /// </summary>
        /// <param name="startNode">Node on train path to start searching</param>
        /// <param name="searchForward">Do you want the reconnect nodes forward or backwards along the path?</param>
        /// <param name="includeLastVectorNode">Is a vectorNode (start, end, wait, reverse) allowed?</param>
        /// <returns>List of possible reconnect nodes. Might be empty</returns>
        public List <TrainpathNode> FindReconnectNodeCandidates(TrainpathNode startNode, bool searchForward, bool includeLastVectorNode)
        {
            List <TrainpathNode> reconnectNodeCandidates = new List <TrainpathNode>();

            TrainpathNode mainNode = startNode;

            //follow the train path and see what we find
            while (true)
            {
                mainNode = searchForward ? mainNode.NextMainNode : mainNode.PrevNode;
                if (mainNode == null)
                {
                    break;
                }

                TrainpathJunctionNode mainNodeAsJunction = mainNode as TrainpathJunctionNode;

                if (mainNodeAsJunction == null)
                {
                    if (mainNode.NodeType != TrainpathNodeType.Other)
                    {   // if it is not an other-node (so not a disambiguity node), stop searching
                        if (includeLastVectorNode)
                        {
                            reconnectNodeCandidates.Add(mainNode);
                        }
                        break;
                    }
                }
                else
                {
                    if (searchForward)
                    {
                        if (mainNode.NodeType == TrainpathNodeType.SidingStart)
                        {   // if a new siding path is started, stop searching
                            // But nevertheless, it is still possible to connect a vector node here
                            reconnectNodeCandidates.Add(mainNode);
                            break;
                        }
                        if (mainNode.NodeType == TrainpathNodeType.SidingEnd)
                        {   // A siding end already has already both an incoming main and incoming end node
                            // So there is no way to reconnect to an empty track
                            break;
                        }
                        if (!mainNodeAsJunction.IsFacingPoint)
                        {   // add the trailing junction.
                            reconnectNodeCandidates.Add(mainNode);
                        }
                    }
                    else // searching backward
                    {
                        if (mainNode.NodeType == TrainpathNodeType.SidingEnd)
                        {   // if a new siding path is started (looking backwards), stop searching
                            // But nevertheless, it is still possible to connect a vector node here
                            reconnectNodeCandidates.Add(mainNode);
                            break;
                        }
                        if (mainNode.NodeType == TrainpathNodeType.SidingStart)
                        {   // Searching back, a siding start has already two outgoing tracks. so there is no free track we could use
                            break;
                        }
                        if (mainNodeAsJunction.IsFacingPoint)
                        {   // add the facing junction.
                            reconnectNodeCandidates.Add(mainNode);
                        }
                    }
                }
            }

            return(reconnectNodeCandidates);
        }
Example #15
0
        /// <summary>
        /// Draw a path on a vector node, meaning that the vector node will be drawn (possibly partly), in path colors
        /// </summary>
        /// <param name="drawArea">Area to draw upon</param>
        /// <param name="colors">Colorscheme to use</param>
        /// <param name="currentNode">Current path node</param>
        /// <param name="nextNode">Next path Node</param>
        /// <param name="TvnIndex">The index of the track vector node that is between the two path nodes</param>
        /// <remarks>Note that it is not clear yet whether the direction of current to next is the same as the
        /// direction of the vector node</remarks>
        private void DrawPathOnVectorNode(DrawArea drawArea, ColorScheme colors, TrainpathNode currentNode, TrainpathNode nextNode, int TvnIndex)
        {
            if (currentNode.IsBrokenOffTrack || nextNode.IsBrokenOffTrack || (TvnIndex == -1))
            {
                DrawPathBrokenNode(drawArea, colors, currentNode, nextNode);
                return;
            }
            TrackNode tn = trackDB.TrackNodes[TvnIndex];

            TrainpathJunctionNode nextJunctionNode = nextNode as TrainpathJunctionNode;
            TrainpathVectorNode nextVectorNode = nextNode as TrainpathVectorNode;

            //Default situation (and most occuring) is to draw the complete vector node 
            int tvsiStart = 0;
            int tvsiStop = tn.TrVectorNode.TrVectorSections.Length-1;
            float sectionOffsetStart = 0;
            float sectionOffsetStop = -1;
            if (currentNode is TrainpathJunctionNode)
            {
                // If both ends are junctions, just draw the full track. Otherwise:
                if (nextVectorNode != null)
                {
                    // Draw from the current junction node to the next mid-point node
                    if (nextVectorNode.IsEarlierOnTrackThan(currentNode))
                    {   // trackvectornode is oriented the other way as path
                        tvsiStart = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = nextVectorNode.TrackSectionOffset;
                    }
                    else
                    {
                        // trackvectornode is oriented in the same way as path
                        tvsiStop = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStop = nextVectorNode.TrackSectionOffset;
                    }
                }
            }
            else
            {
                TrainpathVectorNode currentVectorNode = currentNode as TrainpathVectorNode;
                if (nextJunctionNode != null)
                {
                    // Draw from current mid-point node to next junction node
                    if (currentVectorNode.IsEarlierOnTrackThan(nextNode))
                    {   // trackvectornode is oriented in the same way as path
                        tvsiStart = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = currentVectorNode.TrackSectionOffset;
                    }
                    else
                    {   // trackvectornode is oriented the other way around.
                        tvsiStop = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStop = currentVectorNode.TrackSectionOffset;
                    }
                }
                if (nextVectorNode != null)
                {
                    // Draw from a current vector node to the next vector node, e.g. for multiple wait points 
                    if (currentVectorNode.IsEarlierOnTrackThan(nextVectorNode))
                    {   // from current to next is in the direction of the vector node
                        tvsiStart = currentVectorNode.TrackVectorSectionIndex;
                        tvsiStop = nextVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = currentVectorNode.TrackSectionOffset;
                        sectionOffsetStop = nextVectorNode.TrackSectionOffset;
                    }
                    else
                    {   // from next to current is in the direction of the vector node
                        tvsiStart = nextVectorNode.TrackVectorSectionIndex;
                        tvsiStop = currentVectorNode.TrackVectorSectionIndex;
                        sectionOffsetStart = nextVectorNode.TrackSectionOffset;
                        sectionOffsetStop = currentVectorNode.TrackSectionOffset;
                    }
                }
            }
            DrawVectorNode(drawArea, tn, colors, tvsiStart, tvsiStop, sectionOffsetStart, sectionOffsetStop);
        }