Example #1
0
 protected void ParseScaleRange(STFReader stf)
 {
     stf.MustMatch("(");
     MinValue = stf.ReadDouble(null);
     MaxValue = stf.ReadDouble(null);
     stf.SkipRestOfBlock();
 }
Example #2
0
 public RouteStart(STFReader stf)
 {
     stf.MustMatch("(");
     WX = stf.ReadDouble(null);   // tilex
     WZ = stf.ReadDouble(null);   // tilez
     X  = stf.ReadDouble(null);
     Z  = stf.ReadDouble(null);
     stf.SkipRestOfBlock();
 }
Example #3
0
        protected void ParsePosition(STFReader stf)
        {
            stf.MustMatch("(");
            PositionX = stf.ReadDouble(null);
            PositionY = stf.ReadDouble(null);
            Width     = stf.ReadDouble(null);
            Height    = stf.ReadDouble(null);

            // Handling middle values
            while (!stf.EndOfBlock())
            {
                STFException.TraceWarning(stf, "Ignored additional positional parameters");
                Width  = Height;
                Height = stf.ReadInt(null);
            }
        }
Example #4
0
        protected virtual float ParseSwitchVal(STFReader stf)
        {
            stf.MustMatch("(");
            var switchVal = (float)(stf.ReadDouble(0));

            stf.SkipRestOfBlock();
            return(switchVal);
        }
Example #5
0
        protected void ParseFont(STFReader stf)
        {
            stf.MustMatch("(");
            FontSize  = (float)stf.ReadDouble(10);
            FontStyle = stf.ReadInt(0);
            var fontFamily = stf.ReadString();

            if (fontFamily != null)
            {
                FontFamily = fontFamily;
            }
            stf.SkipRestOfBlock();
        }
Example #6
0
        /// <summary>
        /// Default constructor used during file parsing.
        /// </summary>
        /// <param name="stf">The STFreader containing the file stream</param>
        /// <param name="idx">The index of this TrItem in the list of TrItems</param>
        internal SpeedPostItem(STFReader stf, int idx)
        {
            SignalObject = -1;
            stf.MustMatchBlockStart();
            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("tritemid", () => { ParseTrackItemId(stf, idx); }),
                new STFReader.TokenProcessor("tritemrdata", () => { ParseTrackItemRData(stf); }),
                new STFReader.TokenProcessor("tritemsdata", () => { ParseTrackItemSData(stf); }),

                new STFReader.TokenProcessor("speedposttritemdata", () => {
                    stf.MustMatchBlockStart();
                    flags = stf.ReadUInt(null);
                    if (!IsWarning && !IsLimit)
                    {
                        IsMilePost = true;
                    }
                    else
                    {
                        if (IsWarning && IsLimit)
                        {
                            flags   |= 0x1;
                            IsResume = true;
                        }
                    }

                    //  The number of parameters depends on the flags seeting
                    //  To do: Check flags seetings and parse accordingly.
                    if (!IsResume)
                    {
                        //SpeedInd = stf.ReadFloat(STFReader.Units.None, null);
                        if (IsMilePost && ((flags & (1 << 9)) == 0))
                        {
                            Distance = (float)Math.Truncate(stf.ReadDouble(null));
                        }
                        else
                        {
                            Distance = stf.ReadFloat(STFReader.Units.None, null);
                        }
                    }

                    if (ShowNumber)
                    {
                        NumberShown = stf.ReadInt(null);
                    }

                    Angle = MathHelper.WrapAngle(stf.ReadFloat(STFReader.Units.None, null));

                    stf.SkipRestOfBlock();
                }),
            });
        }
 public SectionIdx(STFReader stf)
 {
     stf.MustMatch("(");
     NoSections    = stf.ReadUInt(null);
     X             = stf.ReadDouble(null);
     Y             = stf.ReadDouble(null);
     Z             = stf.ReadDouble(null);
     A             = stf.ReadDouble(null);
     TrackSections = new uint[NoSections];
     for (int i = 0; i < NoSections; ++i)
     {
         string token = stf.ReadString();
         if (token == ")")
         {
             STFException.TraceWarning(stf, "Missing track section");
             return;   // there are many TSECTION.DAT's with missing sections so we will accept this error
         }
         if (!uint.TryParse(token, out TrackSections[i]))
         {
             STFException.TraceWarning(stf, "Invalid track section " + token);
         }
     }
     stf.SkipRestOfBlock();
 }
Example #8
0
        public CVCDiscrete(STFReader stf, string basepath)
        {
//            try
            {
                stf.MustMatch("(");
                stf.ParseBlock(new STFReader.TokenProcessor[] {
                    new STFReader.TokenProcessor("type", () => { ParseType(stf); }),
                    new STFReader.TokenProcessor("position", () => { ParsePosition(stf); }),
                    new STFReader.TokenProcessor("scalerange", () => { ParseScaleRange(stf); }),
                    new STFReader.TokenProcessor("graphic", () => { ParseGraphic(stf, basepath); }),
                    new STFReader.TokenProcessor("style", () => { ParseStyle(stf); }),
                    new STFReader.TokenProcessor("units", () => { ParseUnits(stf); }),
                    new STFReader.TokenProcessor("mousecontrol", () => { MouseControl = stf.ReadBoolBlock(false); }),
                    new STFReader.TokenProcessor("orientation", () => { Orientation = stf.ReadIntBlock(null); }),
                    new STFReader.TokenProcessor("dirincrease", () => { Direction = stf.ReadIntBlock(null); }),

                    new STFReader.TokenProcessor("numframes", () => {
                        stf.MustMatch("(");
                        FramesCount = stf.ReadInt(null);
                        FramesX     = stf.ReadInt(null);
                        FramesY     = stf.ReadInt(null);
                        stf.SkipRestOfBlock();
                    }),
                    // <CJComment> Would like to revise this, as it is difficult to follow and debug.
                    // Can't do that until interaction of ScaleRange, NumFrames, NumPositions and NumValues is more fully specified.
                    // What is needed is samples of data that must be accommodated.
                    // Some decisions appear unwise but they might be a pragmatic solution to a real problem. </CJComment>
                    //
                    // Code accommodates:
                    // - NumValues before NumPositions or the other way round.
                    // - More NumValues than NumPositions and the other way round - perhaps unwise.
                    // - The count of NumFrames, NumValues and NumPositions is ignored - perhaps unwise.
                    // - Abbreviated definitions so that values at intermediate unspecified positions can be omitted.
                    //   Strangely, these values are set to 0 and worked out later when drawing.
                    // Max and min NumValues which don't match the ScaleRange are ignored - perhaps unwise.
                    new STFReader.TokenProcessor("numpositions", () => {
                        stf.MustMatch("(");
                        // If Positions are not filled before by Values
                        bool shouldFill = (Positions.Count == 0);
                        numPositions    = stf.ReadInt(null); // Number of Positions

                        var minPosition   = 0;
                        var positionsRead = 0;
                        while (!stf.EndOfBlock())
                        {
                            int p = stf.ReadInt(null);

                            minPosition = positionsRead == 0 ? p : Math.Min(minPosition, p);  // used to get correct offset
                            positionsRead++;

                            // If Positions are not filled before by Values
                            if (shouldFill)
                            {
                                Positions.Add(p);
                            }
                        }

                        // If positions do not start at 0, add offset to shift them all so they do.
                        // An example of this is RENFE 400 (from http://www.trensim.com/lib/msts/index.php?act=view&id=186)
                        // which has a COMBINED_CONTROL with:
                        //   NumPositions ( 21 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 )
                        // Also handles definitions with position in reverse order, e.g.
                        //   NumPositions ( 5 8 7 2 1 0 )
                        positionsRead++;

                        if (minPosition < 0)
                        {
                            for (int iPos = 0; iPos <= Positions.Count - 1; iPos++)
                            {
                                Positions[iPos] -= minPosition;
                            }
                        }

                        // This is a hack for SLI locomotives which have the positions listed as "1056964608 0 0 0 ...".
                        if (Positions.Any(p => p > 0xFFFF))
                        {
                            STFException.TraceInformation(stf, "Renumbering cab control positions from zero due to value > 0xFFFF");
                            for (var i = 0; i < Positions.Count; i++)
                            {
                                Positions[i] = i;
                            }
                        }

                        // Check if eligible for filling

                        if (Positions.Count > 1 && Positions[0] != 0)
                        {
                            canFill = false;
                        }
                        else
                        {
                            for (var iPos = 1; iPos <= Positions.Count - 1; iPos++)
                            {
                                if (Positions[iPos] > Positions[iPos - 1])
                                {
                                    continue;
                                }
                                canFill = false;
                                break;
                            }
                        }

                        // This is a protection against GP40 locomotives that erroneously have positions pointing beyond frame count limit.

                        if (Positions.Count > 1 && canFill && Positions.Count < FramesCount && Positions[Positions.Count - 1] >= FramesCount && Positions[0] == 0)
                        {
                            STFException.TraceInformation(stf, "Some NumPositions entries refer to non-exisiting frames, trying to renumber");
                            Positions[Positions.Count - 1] = FramesCount - 1;
                            for (var iPos = Positions.Count - 2; iPos >= 1; iPos--)
                            {
                                if ((Positions[iPos] >= FramesCount || Positions[iPos] >= Positions[iPos + 1]))
                                {
                                    Positions[iPos] = Positions[iPos + 1] - 1;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }),
                    new STFReader.TokenProcessor("numvalues", () => {
                        stf.MustMatch("(");
                        var numValues = stf.ReadDouble(null); // Number of Values
                        while (!stf.EndOfBlock())
                        {
                            double v = stf.ReadDouble(null);
                            // If the Positions are less than expected add new Position(s)
                            while (Positions.Count <= _ValuesRead)
                            {
                                Positions.Add(_ValuesRead);
                            }
                            // Avoid later repositioning, put every value to its Position
                            // But before resize Values if needed
                            if (numValues != numPositions)
                            {
                                while (Values.Count <= Positions[_ValuesRead])
                                {
                                    Values.Add(0);
                                }
                                // Avoid later repositioning, put every value to its Position
                                Values[Positions[_ValuesRead]] = v;
                            }
                            Values.Add(v);
                            _ValuesRead++;
                        }
                    }),
                });

                // If no ACE, just don't need any fixup
                // Because Values are tied to the image Frame to be shown
                if (string.IsNullOrEmpty(ACEFile))
                {
                    return;
                }

                // Now, we have an ACE.

                // If read any Values, or the control requires Values to control
                //     The twostate, tristate, signal displays are not in these
                // Need check the Values collection for validity
                if (_ValuesRead > 0 || ControlStyle == CABViewControlStyles.SPRUNG || ControlStyle == CABViewControlStyles.NOT_SPRUNG ||
                    FramesCount > 0 || (FramesX > 0 && FramesY > 0))
                {
                    // Check max number of Frames
                    if (FramesCount == 0)
                    {
                        // Check valid Frame information
                        if (FramesX == 0 || FramesY == 0)
                        {
                            // Give up, it won't work
                            // Because later we won't know how to display frames from that
                            Trace.TraceWarning("Invalid Frames information given for ACE {0} in {1}", ACEFile, stf.FileName);
                            ACEFile = "";
                            return;
                        }

                        // Valid frames info, set FramesCount
                        FramesCount = FramesX * FramesY;
                    }

                    // Now we have an ACE and Frames for it.

                    // Only shuffle data in following cases

                    if (Values.Count != Positions.Count || (Values.Count < FramesCount & canFill) || (Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0))
                    {
                        // Fixup Positions and Values collections first

                        // If the read Positions and Values are not match
                        // Or we didn't read Values but have Frames to draw
                        // Do not test if FramesCount equals Values count, we trust in the creator -
                        //     maybe did not want to display all Frames
                        // (If there are more Values than Frames it will checked at draw time)
                        // Need to fix the whole Values
                        if (Positions.Count != _ValuesRead || (FramesCount > 0 && (Values.Count == 0 || Values.Count == 1)))
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. engine brake lever of Dash 9):
                            //NumFrames ( 22 11 2 )
                            //NumPositions ( 1 0 )
                            //NumValues ( 1 0 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Case 2 (e.g. throttle lever of Acela):
                            //NumFrames ( 25 5 5 )
                            //NumPositions ( 0 )
                            //NumValues ( 0 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Clear existing
                            Positions.Clear();
                            Values.Clear();

                            // Add the two sure positions, the two ends
                            Positions.Add(0);
                            // We will need the FramesCount later!
                            // We use Positions only here
                            Positions.Add(FramesCount);

                            // Fill empty Values
                            for (int i = 0; i < FramesCount; i++)
                            {
                                Values.Add(0);
                            }
                            Values[0] = MinValue;

                            Values.Add(MaxValue);
                        }
                        else if (Values.Count == 2 && Values[0] == 0 && Values[1] < MaxValue && Positions[0] == 0 && Positions[1] == 1 && Values.Count < FramesCount)
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. engine brake lever of gp38):
                            //NumFrames ( 18 2 9 )
                            //NumPositions ( 2 0 1 )
                            //NumValues ( 2 0 0.3 )
                            //Orientation ( 0 )
                            //DirIncrease ( 0 )
                            //ScaleRange ( 0 1 )
                            Positions.Add(FramesCount);
                            // Fill empty Values
                            for (int i = Values.Count; i < FramesCount; i++)
                            {
                                Values.Add(Values[1]);
                            }
                            Values.Add(MaxValue);
                        }

                        else
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. train brake lever of Acela):
                            //NumFrames ( 12 4 3 )
                            //NumPositions ( 5 0 1 9 10 11 )
                            //NumValues ( 5 0 0.2 0.85 0.9 0.95 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Fill empty Values
                            int iValues = 1;
                            for (int i = 1; i < FramesCount && i <= Positions.Count - 1 && Values.Count < FramesCount; i++)
                            {
                                var deltaPos = Positions[i] - Positions[i - 1];
                                while (deltaPos > 1 && Values.Count < FramesCount)
                                {
                                    Values.Insert(iValues, 0);
                                    iValues++;
                                    deltaPos--;
                                }
                                iValues++;
                            }

                            // Add the maximums to the end, the Value will be removed
                            // We use Positions only here
                            if (Values.Count > 0 && Values[0] <= Values[Values.Count - 1])
                            {
                                Values.Add(MaxValue);
                            }
                            else if (Values.Count > 0 && Values[0] > Values[Values.Count - 1])
                            {
                                Values.Add(MinValue);
                            }
                        }

                        // OK, we have a valid size of Positions and Values

                        // Now it is the time for checking holes in the given data
                        if ((Positions.Count < FramesCount - 1 && Values[0] <= Values[Values.Count - 1]) || (Values.Count > 1 && Values[0] == Values[Values.Count - 2] && Values[0] == 0))
                        {
                            int j = 1;
                            int p = 0;
                            // Skip the 0 element, that is the default MinValue
                            for (int i = 1; i < Positions.Count; i++)
                            {
                                // Found a hole
                                if (Positions[i] != p + 1)
                                {
                                    // Iterate to the next valid data and fill the hole
                                    for (j = p + 1; j < Positions[i]; j++)
                                    {
                                        // Extrapolate into the hole
                                        Values[j] = MathHelper.Lerp((float)Values[p], (float)Values[Positions[i]], (float)j / (float)Positions[i]);
                                    }
                                }
                                p = Positions[i];
                            }
                        }

                        // Don't need the MaxValue added before, remove it
                        Values.RemoveAt(Values.Count - 1);
                    }
                }

                // MSTS ignores/overrides various settings by the following exceptional cases:
                if (ControlType == CABViewControlTypes.CP_HANDLE)
                {
                    ControlStyle = CABViewControlStyles.NOT_SPRUNG;
                }
                if (ControlType == CABViewControlTypes.PANTOGRAPH || ControlType == CABViewControlTypes.PANTOGRAPH2)
                {
                    ControlStyle = CABViewControlStyles.ONOFF;
                }
                if (ControlType == CABViewControlTypes.HORN || ControlType == CABViewControlTypes.SANDERS || ControlType == CABViewControlTypes.BELL ||
                    ControlType == CABViewControlTypes.RESET)
                {
                    ControlStyle = CABViewControlStyles.WHILE_PRESSED;
                }
                if (ControlType == CABViewControlTypes.DIRECTION && Orientation == 0)
                {
                    Direction = 1 - Direction;
                }
            }
//            catch (Exception error)
//            {
//                if (error is STFException) // Parsing error, so pass it on
//                    throw;
//                else                       // Unexpected error, so provide a hint
//                    throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange");
//            } // End of Need check the Values collection for validity
        } // End of Constructor
Example #9
0
 protected virtual void ParseAccuracySwitch(STFReader stf)
 {
     stf.MustMatch("(");
     AccuracySwitch = stf.ReadDouble(0);
     stf.SkipRestOfBlock();
 }