Ejemplo n.º 1
0
        /// <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;
                }
            }
        }
Ejemplo n.º 2
0
        // Possible interpretation (as found on internet, by krausyao)
        // TrPathNode ( AAAABBBB mainIdx passingIdx pdpIdx )
        // AAAA wait time seconds in hexidecimal
        // BBBB (Also hexidecimal, so 16 bits)
        // Bit 0 - connected pdp-entry references a reversal-point (1/x1)
        // Bit 1 - waiting point (2/x2)
        // Bit 2 - intermediate point between switches (4/x4)
        // Bit 3 - 'other exit' is used (8/x8)
        // Bit 4 - 'optional Route' active (16/x10)
        //
        // But the interpretation below is a bit more complicated.
        // TODO. Since this interpretation belongs to the PATfile itself,
        // in principle it would be more logical to have it in PATfile.cs. But this leads to too much code duplication
        private void InterpretPathNodeFlags(TrPathNode tpn, TrackPDP pdp, bool isTimetableMode)
        {
            if ((tpn.pathFlags & 03) == 0)
            {
                return;
            }
            // bit 0 and/or bit 1 is set.

            if ((tpn.pathFlags & 01) != 0)
            {
                // if bit 0 is set: reversal
                Type = AIPathNodeType.Reverse;
            }
            else
            {
                // bit 0 is not set, but bit 1 is set:waiting point
                Type = AIPathNodeType.Stop;
                //<CSComment> tests showed me that value 9 in pdp is generated  when the waiting point (or also
                //a path start or end point) are dragged within the path editor of the MSTS activity editor; the points are still valid;
                // however, as a contradictory case of the past has been reported, the check is skipped only when the enhanced compatibility flag is on;
                if (pdp.IsInvalid && isTimetableMode) // not a valid point
                {
                    Type = AIPathNodeType.Invalid;
                }
            }

            WaitTimeS = (int)((tpn.pathFlags >> 16) & 0xffff); // get the AAAA part.
            // computations for absolute wait times are made within AITrain.cs

/*            if (WaitTimeS >= 30000 && WaitTimeS < 40000)
 *          {
 *              // real wait time.
 *              // waitTimeS (in decimal notation) = 3HHMM  (hours and minuts)
 *              int hour = (WaitTimeS / 100) % 100;
 *              int minute = WaitTimeS % 100;
 *              WaitUntil = 60 * (minute + 60 * hour);
 *              WaitTimeS = 0;
 *          }*/
            // computations are made within AITrain.cs

/*            else if (WaitTimeS >= 40000 && WaitTimeS < 60000)
 *          {
 *              // Uncouple if a wait=stop point
 *              // waitTimeS (in decimal notation) = 4NNSS (uncouple NN cars, wait SS seconds)
 *              //                                or 5NNSS (uncouple NN cars, keep rear, wait SS seconds)
 *              NCars = (WaitTimeS / 100) % 100;
 *              if (WaitTimeS >= 50000)
 *                  NCars = -NCars;
 *              WaitTimeS %= 100;
 *              if (Type == AIPathNodeType.Stop)
 *                  Type = AIPathNodeType.Uncouple;
 *          }
 *          else if (WaitTimeS >= 60000)  // this is old and should be removed/reused
 *          {
 *              // waitTimes = 6xSSS  with waitTime SSS seconds.
 *              WaitTimeS %= 1000;
 *          } */
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Draw the actual path coded in the PATfile (for a number of nodes that can be extended or reduced)
        /// </summary>
        /// <param name="drawArea">Area to draw upon</param>
        public void Draw(DrawArea drawArea)
        {
            //draw actual path
            currentMainNodeIndex = 0;        // starting point
            int currentSidingNodeIndex = -1; // we start without siding path

            for (int i = 0; i < Math.Min(patFile.TrPathNodes.Count - 1, numberToDraw); i++)
            {
                // If we have a current siding track, we draw it step to the next main line first.
                if (currentSidingNodeIndex > 0)
                {
                    //while tracking a siding, it has its own main node
                    int nextNodeIndexOnSiding = (int)patFile.TrPathNodes[currentSidingNodeIndex].nextSidingNode;
                    if (nextNodeIndexOnSiding > 0) // because also this path can run off at the end
                    {
                        TrPathNode    curNode  = patFile.TrPathNodes[currentSidingNodeIndex];
                        WorldLocation curLoc   = GetPdpLocation(patFile.TrackPDPs[(int)curNode.fromPDP]);
                        TrPathNode    nextNode = patFile.TrPathNodes[nextNodeIndexOnSiding];
                        WorldLocation nextLoc  = GetPdpLocation(patFile.TrackPDPs[(int)nextNode.fromPDP]);

                        drawArea.DrawLine(1, DrawColors.colorsPathSiding.TrackStraight, curLoc, nextLoc);
                    }
                    currentSidingNodeIndex = nextNodeIndexOnSiding;
                }

                TrPathNode    curMainNode = patFile.TrPathNodes[currentMainNodeIndex];
                WorldLocation curMainLoc  = GetPdpLocation(patFile.TrackPDPs[(int)curMainNode.fromPDP]);

                // from this main line point to the next siding node.
                // If there is a next siding node, we also reset the currentSidingNodeIndex
                // but probably it is not allowed to have siding
                int nextSidingNodeIndex = (int)curMainNode.nextSidingNode;
                if (nextSidingNodeIndex >= 0)
                {
                    // draw the start of a siding path
                    TrPathNode    nextNode = patFile.TrPathNodes[nextSidingNodeIndex];
                    WorldLocation nextLoc  = GetPdpLocation(patFile.TrackPDPs[(int)nextNode.fromPDP]);

                    drawArea.DrawLine(1, DrawColors.colorsPathSiding.TrackStraight, curMainLoc, nextLoc);
                    currentSidingNodeIndex = nextSidingNodeIndex;
                }

                // From this main line point to the next
                int nextMainNodeIndex = (int)curMainNode.nextMainNode;
                if (nextMainNodeIndex >= 0)
                {
                    TrPathNode    nextNode = patFile.TrPathNodes[nextMainNodeIndex];
                    WorldLocation nextLoc  = GetPdpLocation(patFile.TrackPDPs[(int)nextNode.fromPDP]);

                    drawArea.DrawLine(1, DrawColors.colorsPathMain.TrackStraight, curMainLoc, nextLoc);
                    currentMainNodeIndex = nextMainNodeIndex;
                }
            }
        }
Ejemplo n.º 4
0
        public bool IsVisited;              // true if the train has visited this node

        /// <summary>
        /// Creates a single AIPathNode and initializes everything that do not depend on other nodes.
        /// The AIPath constructor will initialize the rest.
        /// </summary>
        public AIPathNode(TrPathNode tpn, TrackPDP pdp, TrackDB trackDB, bool isTimetableMode)
        {
            ID = (int)tpn.fromPDP;
            InterpretPathNodeFlags(tpn, pdp, isTimetableMode);

            Location = new WorldLocation(pdp.TileX, pdp.TileZ, pdp.X, pdp.Y, pdp.Z);
            if (pdp.IsJunction)
            {
                JunctionIndex = FindJunctionOrEndIndex(Location, trackDB, true);
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Sort of constructor. But it creates the right sub-class
 /// </summary>
 /// <returns>A sub-class object properly initialized</returns>
 public static TrainpathNode CreatePathNode(TrPathNode tpn, TrackPDP pdp, TrackDB trackDB, TrackSectionsFile tsectionDat)
 {
     if (pdp.IsJunction)
     {
         // we do not use tpn: this means we do not interpret the flags
         return(new TrainpathJunctionNode(pdp, trackDB, tsectionDat));
     }
     else
     {
         return(new TrainpathVectorNode(tpn, pdp, trackDB, tsectionDat));
     }
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Add information of the basic MSTS PATfile
 /// </summary>
 /// <param name="trackViewer"></param>
 private void AddPATfileStatus(TrackViewer trackViewer)
 {
     if (Properties.Settings.Default.statusShowPATfile && (trackViewer.DrawPATfile != null))
     {
         TrPathNode curNode = trackViewer.DrawPATfile.CurrentNode;
         TrackPDP   curPDP  = trackViewer.DrawPATfile.CurrentPdp;
         statusAdditional.Text += string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                                " {7}: {3}, {4} [{1} {2}] [{5} {6}] <{0}>",
                                                curNode.pathFlags, (int)curNode.nextMainNode, (int)curNode.nextSidingNode,
                                                curPDP.X, curPDP.Z, curPDP.junctionFlag, curPDP.invalidFlag, trackViewer.DrawPATfile.FileName);
     }
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Constructor based on PAT file information.
        /// </summary>
        /// <param name="tpn">TrPathNode from .pat file</param>
        /// <param name="pdp">TrackPDP from .pat file</param>
        /// <param name="trackDB"></param>
        /// <param name="tsectionDat"></param>
        public TrainpathVectorNode(TrPathNode tpn, TrackPDP pdp, TrackDB trackDB, TrackSectionsFile tsectionDat)
            : base(pdp, trackDB, tsectionDat)
        {
            try
            {
                Traveller traveller = new Traveller(tsectionDat, trackDB.TrackNodes, this.Location);
                CopyDataFromTraveller(traveller);
            }
            catch
            {
                SetBroken(NodeStatus.NotOnTrack);
            }

            ForwardOriented = true; // only initial setting

            InterpretPathNodeFlags(tpn);
        }
Ejemplo n.º 8
0
        // Flag Intepretation
        // (No flag interpretation for junction nodes)

        // Possible interpretation (as found on internet, by krausyao)
        // TrPathNode ( AAAABBBB mainIdx passingIdx pdpIdx )
        // AAAA wait time seconds in hexidecimal
        // BBBB (Also hexidecimal, so 16 bits)
        // Bit 0 - connected pdp-entry references a reversal-point (1/x1)
        // Bit 1 - waiting point (2/x2)
        // Bit 2 - intermediate point between switches (4/x4)
        // Bit 3 - 'other exit' is used (8/x8)
        // Bit 4 - 'optional Route' active (16/x10)
        //
        // But the interpretation below is a bit more complicated.
        // Since this interpretation belongs to the PATfile itself,
        // in principle it would be more logical to have it in PATfile.cs. But this leads to too much code duplication
        private void InterpretPathNodeFlags(TrPathNode tpn)
        {
            if ((tpn.pathFlags & 03) == 0)
            {
                return;
            }
            // bit 0 and/or bit 1 is set.

            if ((tpn.pathFlags & 01) != 0)
            {
                // if bit 0 is set: reversal
                NodeType = TrainpathNodeType.Reverse;
            }
            else
            {
                // bit 0 is not set, but bit 1 is set:waiting point
                NodeType = TrainpathNodeType.Stop;
            }

            WaitTimeS = (int)((tpn.pathFlags >> 16) & 0xffff); // get the AAAA part.
        }
Ejemplo n.º 9
0
        public AIPath(TDBFile TDB, TSectionDatFile tsectiondat, string filePath)
#endif
        {
            PathFile patFile = new PathFile(filePath);

            pathName    = patFile.Name;
            TrackDB     = TDB.TrackDB;
            TSectionDat = tsectiondat;
#if ACTIVITY_EDITOR
            orRouteConfig = orRouteConf;
#endif
            bool fatalerror = false;
            if (patFile.TrPathNodes.Count <= 0)
            {
                fatalerror = true;
                Nodes      = null;
                return;
            }
            foreach (TrPathNode tpn in patFile.TrPathNodes)
            {
                Nodes.Add(new AIPathNode(tpn, patFile.TrackPDPs[(int)tpn.fromPDP], TrackDB, isTimetableMode));
            }
            FirstNode = Nodes[0];
            //LastVisitedNode = FirstNode;

            // Connect the various nodes to each other
            for (int i = 0; i < Nodes.Count; i++)
            {
                AIPathNode node = Nodes[i];
                node.Index = i;
                TrPathNode tpn = patFile.TrPathNodes[i];

                // find TVNindex to next main node.
                if (tpn.HasNextMainNode)
                {
                    node.NextMainNode     = Nodes[(int)tpn.nextMainNode];
                    node.NextMainTVNIndex = node.FindTVNIndex(node.NextMainNode, TDB, tsectiondat);
                    if (node.JunctionIndex >= 0)
                    {
                        node.IsFacingPoint = TestFacingPoint(node.JunctionIndex, node.NextMainTVNIndex);
                    }
                    if (node.NextMainTVNIndex < 0)
                    {
                        node.NextMainNode = null;
                        Trace.TraceWarning("Cannot find main track for node {1} in path {0}", filePath, i);
                        fatalerror = true;
                    }
                }

                // find TVNindex to next siding node
                if (tpn.HasNextSidingNode)
                {
                    node.NextSidingNode     = Nodes[(int)tpn.nextSidingNode];
                    node.NextSidingTVNIndex = node.FindTVNIndex(node.NextSidingNode, TDB, tsectiondat);
                    if (node.JunctionIndex >= 0)
                    {
                        node.IsFacingPoint = TestFacingPoint(node.JunctionIndex, node.NextSidingTVNIndex);
                    }
                    if (node.NextSidingTVNIndex < 0)
                    {
                        node.NextSidingNode = null;
                        Trace.TraceWarning("Cannot find siding track for node {1} in path {0}", filePath, i);
                        fatalerror = true;
                    }
                }

                if (node.NextMainNode != null && node.NextSidingNode != null)
                {
                    node.Type = AIPathNodeType.SidingStart;
                }
            }

            FindSidingEnds();

            if (fatalerror)
            {
                Nodes = null;             // invalid path - do not return any nodes
            }
        }