protected void ParseScaleRange(STFReader stf) { stf.MustMatch("("); MinValue = stf.ReadDouble(null); MaxValue = stf.ReadDouble(null); stf.SkipRestOfBlock(); }
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(); }
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); } }
protected virtual float ParseSwitchVal(STFReader stf) { stf.MustMatch("("); var switchVal = (float)(stf.ReadDouble(0)); stf.SkipRestOfBlock(); return(switchVal); }
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(); }
/// <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(); }
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
protected virtual void ParseAccuracySwitch(STFReader stf) { stf.MustMatch("("); AccuracySwitch = stf.ReadDouble(0); stf.SkipRestOfBlock(); }