/// <summary>
 /// Constructor
 /// </summary>
 /// <param name="node">The original trainpath node</param>
 /// <param name="isAFromNode">In a reconnect path, is this the junction from which to connect, or the junction to which to connect</param>
 /// <param name="isConnectingForward">Is this node connecting forwards (along the path) or not</param>
 public ConnectableNode(TrainpathNode node, bool isAFromNode, bool isConnectingForward)
 {
     OriginalNode        = node;
     IsFrom              = isAFromNode;
     IsConnectingForward = isConnectingForward;
     DetermineJunction();
 }
        /// <summary>
        /// Link the various nodes to each other. Do some initial processing on the path, like finding linking TVNs
        /// and determining whether junctions are facing or not.
        /// </summary>
        /// <param name="patFile">Patfile object containing the various unprocessed Track Path Nodes</param>
        /// <param name="Nodes">The list of as-of-yet unlinked processed path nodes</param>
        static private void LinkNodes(PathFile patFile, List <TrainpathNode> Nodes)
        {
            // Connect the various nodes to each other
            for (int i = 0; i < Nodes.Count; i++)
            {
                TrainpathNode node = Nodes[i];
                TrPathNode    tpn  = patFile.TrPathNodes[i];

                // find TvnIndex to next main node.
                if (tpn.HasNextMainNode)
                {
                    node.NextMainNode          = Nodes[(int)tpn.nextMainNode];
                    node.NextMainNode.PrevNode = node;
                    node.NextMainTvnIndex      = node.FindTvnIndex(node.NextMainNode);
                }

                // find TvnIndex to next siding node
                if (tpn.HasNextSidingNode)
                {
                    node.NextSidingNode = Nodes[(int)tpn.nextSidingNode];
                    if (node.NextSidingNode.PrevNode == null)
                    {
                        node.NextSidingNode.PrevNode = node;
                    }
                    node.NextSidingTvnIndex = node.FindTvnIndex(node.NextSidingNode);
                }

                if (node.NextMainNode != null && node.NextSidingNode != null)
                {
                    node.NodeType = TrainpathNodeType.SidingStart;
                }
            }
        }
        /// <summary>
        /// Can a node in a path be reversed without breaking something?
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private static bool CanReverse(TrainpathNode node)
        {
            bool outgoingAllowsReversal;

            if (node.NextSidingNode != null)
            {   // if there is a siding node, this is a siding start (probably) and things become too complex
                outgoingAllowsReversal = false;
            }
            else
            {
                if (node.NextMainNode == null)
                {   // no next main node, so we are fine with reversing
                    outgoingAllowsReversal = true;
                }
                else
                {
                    outgoingAllowsReversal = node.NextMainNode.IsBroken || (node.NextMainTvnIndex == -1);
                }
            }

            bool incomingAllowsReversal;

            if (node.PrevNode == null)
            {
                incomingAllowsReversal = true;
            }
            else
            {
                incomingAllowsReversal = node.PrevNode.IsBroken || (node.PrevNode.NextMainTvnIndex == -1);
            }

            return(incomingAllowsReversal && outgoingAllowsReversal);
        }
        /// <summary>
        /// Calculate the number of this node in the total path. FirstNode is 1.
        /// </summary>
        /// <param name="node">Node for which to calculate the number</param>
        /// <returns>The sequential number of the node in the path. -1 if not found</returns>
        public int GetNodeNumber(TrainpathNode node)
        {
            // first backup till we are on main track.
            int nodesOnSidingPath = 0;

            while (node.NextMainNode == null)
            {
                node = node.PrevNode;
                nodesOnSidingPath++;
                if (node == null)
                {
                    return(-1);
                }
            }

            int           nodesOnMainPath = 1;
            TrainpathNode mainNode        = FirstNode;

            while (mainNode != null && mainNode != node)
            {
                nodesOnMainPath++;
                mainNode = mainNode.NextMainNode;
            }

            if (mainNode == null)
            {
                return(-1);
            }
            return(nodesOnSidingPath + nodesOnMainPath);
        }
Beispiel #5
0
        /// <summary>
        /// Determine the orientation of the current node, by using the previousNode as well as the TVN that links the
        /// previous node with this node.
        /// </summary>
        /// <param name="previousNode">previouse node</param>
        /// <param name="linkingTvnIndex">the index of the Track Vector Node linking the previous node to this node</param>
        public override void DetermineOrientation(TrainpathNode previousNode, int linkingTvnIndex)
        {
            // the TVN is from the previous node, so backwards. Therefore:reverse
            if (DetermineOrientationSucceeded(linkingTvnIndex, true))
            {
                return;
            }

            // if it did not succeed, most likely previous node is broken.
            // Retry with next main or siding TVN. This will fail for the last node, so be it.)
            if (NextSidingNode != null)
            {
                linkingTvnIndex = NextSidingTvnIndex;
            }
            if (NextMainNode != null)
            {
                linkingTvnIndex = NextMainTvnIndex;
            }                                                          // might override result from previous line

            if (DetermineOrientationSucceeded(linkingTvnIndex, false)) // no reverse needed
            {
                return;
            }

            // nothing seems to work. Get default value, unless it is broken
            if (IsBroken)
            {
                return;
            }
            DetermineOrientationSucceeded(TrailingTvn, IsFacingPoint);
        }
Beispiel #6
0
 /// <summary>
 /// Constructor where location is copied from the given traveller
 /// </summary>
 /// <param name="otherNode">just another node to have access to trackDB and tsectiondat</param>
 /// <param name="traveller">The traveller that contains the exact location and distance on track to initialize the node</param>
 public TrainpathVectorNode(TrainpathNode otherNode, Traveller traveller)
     : base(otherNode)
 {
     CopyDataFromTraveller(traveller);
     Location        = traveller.WorldLocation; // Not part of CopyDataFromTraveller
     ForwardOriented = true;                    // only initial setting
 }
Beispiel #7
0
        /// <summary>
        /// Try to fix all broken nodes. Even if a node cannot be fixed, do try to fix the others.
        /// </summary>
        /// <returns>Whether all nodes were fixed and hence the path is now fine</returns>
        public bool AutoFixAllBrokenNodes()
        {
            bool fixSucceeded = true;
            int  nodeToTry    = 0;
            Collection <TrainpathNode>     brokenNodes      = CurrentTrainPath.GetBrokenNodes();
            EditorActionAutoFixBrokenNodes actionFixBroken  = new EditorActionAutoFixBrokenNodes();
            EditorActionFixInvalidNode     actionFixInvalid = new EditorActionFixInvalidNode();

            while (CurrentTrainPath.IsBroken && (nodeToTry < brokenNodes.Count))
            {
                brokenNodes = CurrentTrainPath.GetBrokenNodes();
                TrainpathNode nodeToFix         = brokenNodes[nodeToTry];
                bool          canExecuteBroken  = actionFixBroken.MenuState(CurrentTrainPath, nodeToFix, null, UpdateAfterEdits, 0, 0);
                bool          canExecuteInvalid = actionFixInvalid.MenuState(CurrentTrainPath, nodeToFix, null, UpdateAfterEdits, 0, 0);
                if (canExecuteBroken)
                {
                    actionFixBroken.DoAction();
                    brokenNodes = CurrentTrainPath.GetBrokenNodes();
                }
                else if (canExecuteInvalid)
                {
                    actionFixInvalid.DoAction();
                    brokenNodes = CurrentTrainPath.GetBrokenNodes();
                }
                else
                {
                    fixSucceeded = false;
                    nodeToTry++;
                }
            }
            return(fixSucceeded);
        }
Beispiel #8
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)
            {   // from junction to vector node.
                if (this.ConnectsToTrack(nextAsVectorNode.TvnIndex))
                {
                    return(nextAsVectorNode.TvnIndex);
                }
                else
                {   //node is perhaps not broken, but connecting track is
                    return(-1);
                }
            }

            //both this node and the next node are junctions: find the vector node connecting them.
            //Probably this can be faster, by just finding the TrPins from this and next junction and find the common one.
            int nextJunctionIndex = (nextNode as TrainpathJunctionNode).JunctionIndex;

            for (int i = 0; i < TrackDB.TrackNodes.Count(); i++)
            {
                TrackNode tn = TrackDB.TrackNodes[i];
                if (tn == null || tn.TrVectorNode == null)
                {
                    continue;
                }
                if ((tn.JunctionIndexAtStart() == this.JunctionIndex && tn.JunctionIndexAtEnd() == nextJunctionIndex) ||
                    (tn.JunctionIndexAtEnd() == this.JunctionIndex && tn.JunctionIndexAtStart() == nextJunctionIndex))
                {
                    return(i);
                }
            }
            return(-1);
        }
Beispiel #9
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;
            }
        }
Beispiel #10
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);
        }
        /// <summary>
        /// Find all nodes that are the end of a siding (so where main path and siding path come together again)
        /// </summary>
        private void FindSidingEnds()
        {
            TrainpathNode curSidingEnd = null; // if we are still looking for a sidingEnd

            for (TrainpathNode curMainNode = FirstNode; curMainNode != null; curMainNode = curMainNode.NextMainNode)
            {
                if (curSidingEnd != null)
                {
                    if (curMainNode == curSidingEnd)
                    { // end of siding
                        curSidingEnd = null;
                    }
                    else
                    {
                        curMainNode.HasSidingPath = true;
                    }
                }

                TrainpathNode curSidingNode = curMainNode.NextSidingNode;
                while (curSidingNode != null && curSidingNode.NextSidingNode != null)
                {
                    curSidingNode = curSidingNode.NextSidingNode;
                }
                if (curSidingNode != null)
                {
                    curSidingEnd              = curSidingNode;
                    curSidingEnd.NodeType     = TrainpathNodeType.SidingEnd;
                    curMainNode.HasSidingPath = true;
                }
            }
        }
 /// <summary>
 /// Create the initial list of nodes from the patFile. No linking or preoccessing
 /// </summary>
 /// <param name="patFile">Patfile object containing the various unprocessed Track Path Nodes</param>
 /// <param name="Nodes">The list that is going to be filled with as-of-yet unlinked and almost unprocessed path nodes</param>
 private void CreateNodes(PathFile patFile, List <TrainpathNode> Nodes)
 {
     foreach (TrPathNode tpn in patFile.TrPathNodes)
     {
         Nodes.Add(TrainpathNode.CreatePathNode(tpn, patFile.TrackPDPs[(int)tpn.fromPDP], trackDB, tsectionDat));
     }
     FirstNode          = Nodes[0];
     FirstNode.NodeType = TrainpathNodeType.Start;
 }
        /// <summary>
        /// Add zero or more additional main nodes
        /// </summary>
        /// <param name="lastNode">currently last node</param>
        /// <param name="numberOfNodesToAdd">The number of nodes to add</param>
        public void AddAdditionalMainNodes(TrainpathNode lastNode, int numberOfNodesToAdd)
        {
            int wantedNetNodesAdded = NetNodesAdded + numberOfNodesToAdd;

            while (NetNodesAdded < wantedNetNodesAdded && lastNode != null)
            {
                lastNode = AddAdditionalNode(lastNode, true);
            }
        }
Beispiel #14
0
 /// <summary>
 /// Add the fromNode and toNode to the list of drawn nodes indexed for the trackindex
 /// </summary>
 /// <param name="fromNode">The starting node of a drawn path-section</param>
 /// <param name="toNode">The end node of a drawn path-section</param>
 public void NoteAsDrawn(TrainpathNode fromNode, TrainpathNode toNode)
 {
     if (!DrawnTrackIndexes.ContainsKey(fromNode.NextMainTvnIndex))
     {
         DrawnTrackIndexes[fromNode.NextMainTvnIndex] = new List<TrainpathNode>();
     }
     DrawnTrackIndexes[fromNode.NextMainTvnIndex].Add(fromNode);
     DrawnTrackIndexes[fromNode.NextMainTvnIndex].Add(toNode);
 }
        /// <summary>
        /// Find all broken nodes of a path
        /// </summary>
        /// <returns>A collection of the broken nodes</returns>
        public Collection <TrainpathNode> GetBrokenNodes()
        {
            var brokenNodes = new Collection <TrainpathNode>();

            if (FirstNode == null)
            {
                return(brokenNodes);
            }

            TrainpathNode currentMainNode = FirstNode;

            while (currentMainNode.NextMainNode != null)
            {
                if (currentMainNode.IsBroken)
                {
                    brokenNodes.Add(currentMainNode);
                }
                else if (currentMainNode.NextMainTvnIndex == -1)
                {
                    brokenNodes.Add(currentMainNode.NextMainNode);
                }
                else
                {
                    // For siding paths, it is difficult to get the right main node to draw until
                    // Most important however is that at least IsBroken is set correctly
                    TrainpathNode currentSidingNode = currentMainNode;
                    while (currentSidingNode.NextSidingNode != null)
                    {
                        if (currentSidingNode.NextSidingNode.IsBroken)
                        {
                            brokenNodes.Add(currentMainNode.NextMainNode); // we cannot draw until a sidingNode
                        }
                        if (currentSidingNode.NextSidingTvnIndex == -1)
                        {
                            brokenNodes.Add(currentMainNode.NextMainNode);
                        }
                        currentSidingNode = currentSidingNode.NextSidingNode;

                        if (currentSidingNode.NextSidingNode == null &&
                            currentSidingNode.NodeType != TrainpathNodeType.SidingEnd)
                        {   // The end of a siding track while still not on siding end
                            brokenNodes.Add(currentMainNode.NextMainNode);
                        }
                    }
                }

                currentMainNode = currentMainNode.NextMainNode;
            }

            if (currentMainNode.IsBroken)
            {   //for last node
                brokenNodes.Add(currentMainNode);
            }

            return(brokenNodes);
        }
        /// <summary>
        /// Add information from Trainpaths
        /// </summary>
        /// <param name="trackViewer"></param>
        private void AddTrainpathStatus(TrackViewer trackViewer)
        {
            if (Properties.Settings.Default.statusShowTrainpath && (trackViewer.PathEditor != null))
            {
                if (trackViewer.PathEditor.HasValidPath)
                {
                    //gather some info on path status
                    List <string> statusItems = new List <string>();

                    if (trackViewer.PathEditor.HasEndingPath)
                    {
                        statusItems.Add("good end");
                    }
                    if (trackViewer.PathEditor.HasBrokenPath)
                    {
                        statusItems.Add("broken");
                    }
                    if (trackViewer.PathEditor.HasModifiedPath)
                    {
                        statusItems.Add("modified");
                    }
                    if (trackViewer.PathEditor.HasStoredTail)
                    {
                        statusItems.Add("stored tail");
                    }

                    string pathStatus = String.Join(", ", statusItems.ToArray());

                    ORTS.TrackViewer.Editing.TrainpathNode curNode = trackViewer.PathEditor.CurrentNode;

                    statusAdditional.Text += string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                           " {0} ({4}): TVNs=[{1} {2}] (type={3})",
                                                           trackViewer.PathEditor.FileName, curNode.NextMainTvnIndex, curNode.NextSidingTvnIndex,
                                                           curNode.NodeType, pathStatus);

                    if (curNode.IsBroken)
                    {
                        statusAdditional.Text += string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                               " Broken: {0} ", curNode.BrokenStatusString());
                    }
                    TrainpathVectorNode curVectorNode = curNode as TrainpathVectorNode;
                    if (curVectorNode != null && curNode.NodeType == TrainpathNodeType.Stop)
                    {
                        statusAdditional.Text += string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                               " (wait-time={0}s)",
                                                               curVectorNode.WaitTimeS);
                    }
                }
                else
                {
                    statusAdditional.Text += "Invalid path";
                }
            }
        }
        /// <summary>
        /// Reverse the path, including the metadata.
        /// Assumption is that it is not broken, and that both start and end are given
        /// </summary>
        public void ReversePath()
        {
            this.PathId = "new";
            string oldStart = this.PathStart;

            this.PathStart = this.PathEnd;
            this.PathEnd   = oldStart;
            this.PathName += " (reversed)";

            List <TrainpathNode> mainNodes = new List <TrainpathNode>();

            // Create list of nodes, in new order
            TrainpathNode currentMainNode = this.FirstNode;

            mainNodes.Add(currentMainNode);
            while (currentMainNode.NextMainNode != null)
            {
                mainNodes.Add(currentMainNode.NextMainNode);
                currentMainNode = currentMainNode.NextMainNode;
            }
            mainNodes.Reverse();
            int lastIndex = mainNodes.Count() - 1; // we now this is at least 1

            //new start
            this.FirstNode                = mainNodes[0];
            mainNodes[0].NextMainNode     = mainNodes[1];
            mainNodes[0].NextMainTvnIndex = mainNodes[1].NextMainTvnIndex;  // note main TVN index was in reverse direction
            mainNodes[0].PrevNode         = null;
            mainNodes[0].ReverseOrientation();
            mainNodes[0].NodeType = TrainpathNodeType.Start;

            //all intermediate nodes
            for (int i = 1; i < lastIndex; i++)
            {
                mainNodes[i].NextMainNode     = mainNodes[i + 1];
                mainNodes[i].NextMainTvnIndex = mainNodes[i + 1].NextMainTvnIndex;  // note main TVN index was in reverse direction
                mainNodes[i].PrevNode         = mainNodes[i - 1];
                if (mainNodes[i].NodeType != TrainpathNodeType.Reverse)
                {   // reverse nodes have input and output swapped, but they are not changed themselves!
                    mainNodes[i].ReverseOrientation();
                }

                if (mainNodes[i].NodeType == TrainpathNodeType.SidingStart)
                {
                    ReverseSidingPath(mainNodes[i]);
                }
            }

            //new end
            mainNodes[lastIndex].NextMainNode = null;
            mainNodes[lastIndex].PrevNode     = mainNodes[lastIndex - 1];
            mainNodes[lastIndex].ReverseOrientation();
            mainNodes[lastIndex].NodeType = TrainpathNodeType.End;
        }
Beispiel #18
0
        /// <summary>
        /// Draw the tail, and the connection to the tail from the last drawn node
        /// </summary>
        /// <param name="drawArea">Area to draw upon</param>
        /// <param name="colors">Colors to use for drawing</param>
        /// <param name="lastDrawnNode">Last drawn node, used as a starting point of connecting dashed line. Can be null</param>
        /// <param name="firstTailNode">Node where the tail starts</param>
        private void DrawTail(DrawArea drawArea, ColorScheme colors, TrainpathNode lastDrawnNode, TrainpathNode firstTailNode)
        {
            if (firstTailNode == null) return;

            if (lastDrawnNode != null)
            {
                drawArea.DrawDashedLine(1f, colors.BrokenPath, lastDrawnNode.Location, firstTailNode.Location);
            }
            DrawNodeItself(drawArea, firstTailNode);
            drawArea.DrawTexture(firstTailNode.Location, "ring", 8f, 7, colors.BrokenPath);

        }
            /// <summary>
            /// Perform a deep copy of a path consisting of linked nodes
            /// </summary>
            /// <param name="curFirstNode">First node of the current path</param>
            /// <returns>First node of the copied path</returns>
            static TrainpathNode DeepCopyOfLinkedNodes(TrainpathNode curFirstNode)
            {
                if (curFirstNode == null)
                {
                    return(null);
                }

                TrainpathNode newFirstNode = curFirstNode.ShallowCopyNoLinks();

                TrainpathNode curMainNode   = curFirstNode;
                TrainpathNode newMainNode   = newFirstNode;
                TrainpathNode curSidingNode = null;
                TrainpathNode newSidingNode = null;
                TrainpathNode newNextMainNode;

                while (curMainNode.NextMainNode != null)
                {
                    // in case there is a passing path, follow that first.
                    // At the end of the path, curSidingNode will be the main Node to link again to
                    if (curMainNode.NextSidingNode != null)
                    {
                        curSidingNode = curMainNode;
                        newSidingNode = newMainNode;
                        while (curSidingNode.NextSidingNode != null)
                        {
                            newSidingNode.NextSidingNode          = curSidingNode.NextSidingNode.ShallowCopyNoLinks();
                            newSidingNode.NextSidingNode.PrevNode = newSidingNode;

                            curSidingNode = curSidingNode.NextSidingNode;
                            newSidingNode = newSidingNode.NextSidingNode;
                        }
                    }

                    if (curSidingNode == curMainNode.NextMainNode)
                    {
                        // We need to relink to the end of a siding path. The corresponding node has already been created
                        newNextMainNode = newSidingNode;
                        curSidingNode   = null; // no linking needed anymore
                    }
                    else
                    {
                        newNextMainNode = curMainNode.NextMainNode.ShallowCopyNoLinks();
                    }
                    newNextMainNode.PrevNode = newMainNode;
                    newMainNode.NextMainNode = newNextMainNode;

                    curMainNode = curMainNode.NextMainNode;
                    newMainNode = newMainNode.NextMainNode;
                }

                return(newFirstNode);
            }
Beispiel #20
0
 /// <summary>
 /// Check the next and the previous nodes on whether they are disambiguity node, and if yes, remove them.
 /// </summary>
 /// <param name="keepNode">The (vector) node to keep</param>
 public void CleanAmbiguityNodes(TrainpathNode keepNode)
 {
     TrainpathNode[] nodesToCheck = { keepNode.PrevNode, keepNode.NextMainNode };
     foreach (TrainpathNode node in nodesToCheck)
     {
         if (node != null &&
             node.NodeType == TrainpathNodeType.Other &&
             node is TrainpathVectorNode)
         {
             RemoveIntermediatePoint(node);
         }
     }
 }
        /// <summary>
        /// Try to find a connection between two given nodes. Depth-first search via main track at junctions.
        /// Also reversing the start or reconnectNode is tried, in case one of these nodes has a non-defined orientation
        /// because both before and after the node the path is broken.
        /// </summary>
        /// <param name="fromNode">Node at which the reconnection should start</param>
        /// <param name="toNode">Node at which the reconnection should end</param>
        /// <param name="firstTvnIndex">In case defined, the index of the first TVN the path has to follow</param>
        /// <returns>True if a connection has been found</returns>
        public bool FindConnection(TrainpathNode fromNode, TrainpathNode toNode, int?firstTvnIndex)

        {
            // We try to find a connection between two non-broken nodes.
            // We store the connection as a stack of linking tvns (track-node-vector-indexes)
            // The connection will only contain junctions (apart from maybe start and end=reconnect nodes)

            autoConnectFromNode      = new ConnectableNode(fromNode, true, true);
            autoConnectToNodeOptions = new ReconnectNodeOptions(true);
            autoConnectToNodeOptions.AddNode(toNode, false); // only one option here

            return(FindConnectionFromTo(firstTvnIndex, false));
        }
Beispiel #22
0
        /// <summary>
        /// Draw the current path node texture, showing what kind of node it is
        /// </summary>
        /// <param name="drawArea">area to Draw upon</param>
        /// <param name="trainpathNode">current node for which we need to draw our texture</param>
        /// <param name="isLastNode">Is this the last node that will be drawn?</param>
        private void DrawNodeItself(DrawArea drawArea, TrainpathNode trainpathNode, bool isLastNode)
        {
            float pathPointSize = 7f; // in meters
            int   minPixelSize  = 7;
            int   maxPixelSize  = 24;
            float angle         = trainpathNode.TrackAngle;

            Color colorMain   = isLastNode ? this.ColorSchemeLast.TrackStraight : ColorSchemeMain.TrackStraight;
            Color colorSiding = this.ColorSchemeSiding.TrackStraight;
            Color colorBroken = this.ColorSchemeMain.BrokenNode;

            switch (trainpathNode.NodeType)
            {
            case TrainpathNodeType.Start:
                // first node; texture is not rotated
                drawArea.DrawTexture(trainpathNode.Location, "pathStart", pathPointSize, minPixelSize, maxPixelSize, colorMain);
                break;

            case TrainpathNodeType.End:
                // formal end node; texture is not rotated
                drawArea.DrawTexture(trainpathNode.Location, "pathEnd", pathPointSize, minPixelSize, maxPixelSize, colorMain);
                break;

            case TrainpathNodeType.Reverse:
                drawArea.DrawTexture(trainpathNode.Location, "pathReverse", pathPointSize, minPixelSize, maxPixelSize, colorMain, angle);
                break;

            case TrainpathNodeType.Stop:
                drawArea.DrawTexture(trainpathNode.Location, "pathWait", pathPointSize, minPixelSize, maxPixelSize, colorMain);
                break;

            case TrainpathNodeType.Temporary:
                drawArea.DrawTexture(trainpathNode.Location, "crossedRing", pathPointSize, minPixelSize, maxPixelSize, colorBroken);
                break;

            default:
                bool isSidingNode = (trainpathNode.NextMainNode == null) &&
                                    ((trainpathNode.NextSidingNode != null) || trainpathNode.IsBroken); // The IsBroken condition should indicate a dangling siding node
                Color normalColor = (isSidingNode) ? colorSiding : colorMain;
                drawArea.DrawTexture(trainpathNode.Location, "pathNormal", pathPointSize, minPixelSize, maxPixelSize, normalColor, angle);
                break;
            }

            if (trainpathNode.IsBroken)
            {
                drawArea.DrawTexture(trainpathNode.Location, "crossedRing", pathPointSize, minPixelSize, maxPixelSize, colorBroken);
            }
            //drawArea.DrawExpandingString(trainpathNode.Location, trainpathNode.NodeType.ToString()); //debug only
        }
Beispiel #23
0
        /// <summary>
        /// Remove a intermediate vector node. Possibly add a disambiguity node if needed.
        /// </summary>
        /// <param name="currentNode">Node to be removed</param>
        public void RemoveIntermediatePoint(TrainpathNode currentNode)
        {
            TrainpathNode prevNode = currentNode.PrevNode;

            prevNode.NextMainNode   = currentNode.NextMainNode;
            prevNode.NextSidingNode = null; // should not be needed
            //lastNodeSidingPath.NextMainTvnIndex should be the same still
            if (prevNode.NextMainNode != null)
            {   // there might not be a next node.
                prevNode.NextMainNode.PrevNode = prevNode;
            }
            NetNodesAdded--;

            AddDisambiguityNodeIfNeeded(prevNode);
        }
Beispiel #24
0
        /// <summary>
        /// Add a new vector node at the given location in the middle of a path
        /// </summary>
        /// <param name="nodeCandidate"></param>
        /// <returns>The just created node</returns>
        public TrainpathVectorNode AddIntermediateMainNode(TrainpathVectorNode nodeCandidate)
        {
            TrainpathNode prevNode = nodeCandidate.PrevNode;
            TrainpathNode nextNode = prevNode.NextMainNode;

            TrainpathVectorNode newNode = AddAdditionalVectorNode(prevNode, nodeCandidate, true);

            newNode.NextMainNode   = nextNode;
            newNode.NextSidingNode = null; // should not be needed
            nextNode.PrevNode      = newNode;

            CleanAmbiguityNodes(newNode);

            return(newNode);
        }
Beispiel #25
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)));
        }
Beispiel #26
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);
            }
        }
Beispiel #27
0
        /// <summary>
        /// Determine the orientation of the current node, by using the previousNode as well as the TVN that links the
        /// previous node with this node.
        /// </summary>
        /// <param name="previousNode">previouse node</param>
        /// <param name="linkingTvnIndex">the index of the Track Vector Node linking the previous node to this node</param>
        public override void DetermineOrientation(TrainpathNode previousNode, int linkingTvnIndex)
        {
            if (IsBroken)
            {   // do not update the orientation. Just use default
                return;
            }

            // this is a non-junction node. linkingTvnIndex should be the same as TvnIndex.
            ForwardOriented = !this.IsEarlierOnTrackThan(previousNode);

            if (NodeType == TrainpathNodeType.Reverse)
            {   // since direction is determined from previous node, after a reversal the direction is changed
                // needs to be done after checking with previous node
                ReverseOrientation();
            }
        }
Beispiel #28
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));
        }
        /// <summary>
        /// Actually create the path by linking nodes following the stored linking tvns.
        /// </summary>
        /// <param name="modificationTools">The tool set that is used to actually modify the path</param>
        /// <param name="isMainPath">Do we add the node to the main path or not</param>
        /// <param name="isFromNodeDirectionOK">Set this to true when the FromNode has already been set to correct orientation elsewhere</param>
        public void CreateFoundConnection(ModificationTools modificationTools, bool isMainPath, bool isFromNodeDirectionOK)
        {
            ConnectableNode autoConnectToNode = autoConnectToNodeOptions.ActualReconnectNode;


            if (FromNodeNeedsReverse && !isFromNodeDirectionOK)
            {
                autoConnectFromNode.ReverseOrientation();
            }
            if (ToNodeNeedsReverse)
            {
                autoConnectToNode.ReverseOrientation();
            }

            if (!autoConnectToNode.IsConnectingForward)
            {
                linkingTvns.Reverse();
                ConnectableNode swap = autoConnectToNode;
                autoConnectToNode   = autoConnectFromNode;
                autoConnectFromNode = swap;
            }


            TrainpathNode currentNode = autoConnectFromNode.OriginalNode;

            if ((currentNode is TrainpathVectorNode) && !sameTrackConnect)
            {   // in case the first node is a vector node (and not a direct connect), go to its junction first
                currentNode = modificationTools.AddAdditionalNode(currentNode, isMainPath);
            }

            //create the new path using the stored Tvns
            foreach (int tvn in linkingTvns)
            {
                currentNode = modificationTools.AddAdditionalNode(currentNode, tvn, isMainPath);
                while (currentNode is TrainpathVectorNode)
                {   // apparently a disambiguity node has been added.
                    currentNode = modificationTools.AddAdditionalNode(currentNode, tvn, isMainPath);
                }
            }

            //make the final connections
            TrainpathNode toNode = autoConnectToNode.OriginalNode;

            modificationTools.StitchTwoPaths(currentNode, toNode, isMainPath);
        }
        //static Dictionary<bool, Drawing.DebugWindow> debugWindows = new Dictionary<bool, Drawing.DebugWindow>();
        //static ContinuousAutoConnecting()
        //{
        //    debugWindows[true] = new Drawing.DebugWindow(10, 40);
        //    debugWindows[false] = new Drawing.DebugWindow(10, 60);
        //}
        //private string debugString = String.Empty;

        /// <summary>
        /// Constructor. This will also find store the candidates for reconnecting
        /// </summary>
        /// <param name="startNode">The node to start from for reconnection. Only used for initial determination of possible reconnection nodes</param>
        /// <param name="isConnectingForward">Is this node connecting forwards (along the path) or not</param>
        public ContinuousAutoConnecting(TrainpathNode startNode, bool isConnectingForward)
        {
            isForward = isConnectingForward;
            List <TrainpathNode> reconnectNodes = this.FindReconnectNodeCandidates(startNode, isConnectingForward, true);

            autoConnectToNodeOptions = new ReconnectNodeOptions(isConnectingForward);
            int count = 0;

            foreach (TrainpathNode node in reconnectNodes)
            {
                autoConnectToNodeOptions.AddNode(node, false);
                //debugString += node.ToStringShort();
                if (count++ > maxNumberNodesToCheckForAutoFix)
                {
                    break;
                }
            }
        }