Skip to content

Commit 1383ac8

Browse files
authored
Merge pull request #943 from SteelFill/cab_dynamics_fix
Dynamic Brakes Behavior & Display Improvements
2 parents 27e5ffb + fb1f454 commit 1383ac8

File tree

5 files changed

+269
-207
lines changed

5 files changed

+269
-207
lines changed

Source/Orts.Formats.Msts/CabViewFile.cs

Lines changed: 95 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ public abstract class CVCWithFrames : CabViewControl
10221022
public bool MouseControl;
10231023
public int Orientation;
10241024
public int Direction;
1025+
public bool Reversed { get; protected set; } = false;
10251026

10261027
public List<double> Values
10271028
{
@@ -1037,8 +1038,8 @@ public class CVCDiscrete : CVCWithFrames
10371038
public List<int> Positions = new List<int>();
10381039

10391040
private int _ValuesRead;
1040-
private int numPositions;
1041-
private bool canFill = true;
1041+
private int NumPositions;
1042+
private bool CanFill = true;
10421043

10431044
public struct NewScreenData
10441045
{
@@ -1091,7 +1092,7 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
10911092
stf.MustMatch("(");
10921093
// If Positions are not filled before by Values
10931094
bool shouldFill = (Positions.Count == 0);
1094-
numPositions = stf.ReadInt(null); // Number of Positions
1095+
NumPositions = stf.ReadInt(null); // Number of Positions
10951096

10961097
var minPosition = 0;
10971098
var positionsRead = 0;
@@ -1130,22 +1131,33 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
11301131
Positions[i] = i;
11311132
}
11321133

1133-
// Check if eligible for filling
1134+
// Possible that positions were defined in reverse, eg: 3DTrains Surfliner trains
1135+
// Ensure positions are sorted from least to greatest before proceeding
1136+
if (Positions.Count > 0 && Positions[0] > Positions[Positions.Count - 1])
1137+
{
1138+
Reversed ^= true;
1139+
// Recalculate positions in reverse
1140+
for (int i = 0; i < Positions.Count; i++)
1141+
Positions[i] = (FramesCount - 1) - Positions[i];
1142+
}
11341143

1135-
if (Positions.Count > 1 && Positions[0] != 0) canFill = false;
1144+
// Check if eligible for filling
1145+
if (Positions.Count > 1 && Positions[0] != 0)
1146+
CanFill = false;
11361147
else
11371148
{
11381149
for (var iPos = 1; iPos <= Positions.Count - 1; iPos++)
11391150
{
1140-
if (Positions[iPos] > Positions[iPos-1]) continue;
1141-
canFill = false;
1151+
if (Positions[iPos] > Positions[iPos-1])
1152+
continue;
1153+
CanFill = false;
11421154
break;
11431155
}
11441156
}
11451157

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

1148-
if (Positions.Count > 1 && canFill && Positions.Count < FramesCount && Positions[Positions.Count-1] >= FramesCount && Positions[0] == 0)
1160+
if (Positions.Count > 1 && CanFill && Positions.Count < FramesCount && Positions[Positions.Count-1] >= FramesCount && Positions[0] == 0)
11491161
{
11501162
STFException.TraceInformation(stf, "Some NumPositions entries refer to non-exisiting frames, trying to renumber");
11511163
Positions[Positions.Count - 1] = FramesCount - 1;
@@ -1170,7 +1182,7 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
11701182
}
11711183
// Avoid later repositioning, put every value to its Position
11721184
// But before resize Values if needed
1173-
if (numValues != numPositions)
1185+
if (numValues != NumPositions)
11741186
{
11751187
while (Values.Count <= Positions[_ValuesRead])
11761188
{
@@ -1232,7 +1244,7 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
12321244

12331245
// Only shuffle data in following cases
12341246

1235-
if (Values.Count != Positions.Count || (Values.Count < FramesCount & canFill)|| ( Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0))
1247+
if (Values.Count != Positions.Count || (Values.Count < FramesCount & CanFill)|| ( Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0))
12361248
{
12371249

12381250
// Fixup Positions and Values collections first
@@ -1270,42 +1282,52 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
12701282
Positions.Add(0);
12711283
// We will need the FramesCount later!
12721284
// We use Positions only here
1273-
Positions.Add(FramesCount);
1285+
Positions.Add(FramesCount - 1);
12741286

12751287
// Fill empty Values
1276-
for (int i = 0; i < FramesCount; i++)
1288+
for (int i = 0; i < (FramesCount - 1); i++)
12771289
Values.Add(0);
1278-
Values[0] = MinValue;
1279-
1280-
Values.Add(MaxValue);
1290+
// Offset for min and max values to achieve equal frame spacing
1291+
double offset = 1.0 / (2.0 * FramesCount);
1292+
// Some dummy controls will have only one frame
1293+
if (Values.Count > 0)
1294+
Values[0] = MinValue + offset;
1295+
else
1296+
Values.Add(MinValue + offset);
1297+
1298+
// Add maximum value to the end
1299+
Values.Add(MaxValue - offset);
12811300
}
12821301
else if (Values.Count == 2 && Values[0] == 0 && Values[1] < MaxValue && Positions[0] == 0 && Positions[1] == 1 && Values.Count < FramesCount)
12831302
{
12841303
//This if clause covers among others following cases:
12851304
// Case 1 (e.g. engine brake lever of gp38):
1286-
//NumFrames ( 18 2 9 )
1287-
//NumPositions ( 2 0 1 )
1288-
//NumValues ( 2 0 0.3 )
1289-
//Orientation ( 0 )
1290-
//DirIncrease ( 0 )
1291-
//ScaleRange ( 0 1 )
1292-
Positions.Add(FramesCount);
1305+
//NumFrames ( 18 2 9 )
1306+
//NumPositions ( 2 0 1 )
1307+
//NumValues ( 2 0 0.3 )
1308+
//Orientation ( 0 )
1309+
//DirIncrease ( 0 )
1310+
//ScaleRange ( 0 1 )
1311+
// Add missing positions
1312+
Positions.Add(FramesCount - 1);
12931313
// Fill empty Values
1294-
for (int i = Values.Count; i < FramesCount; i++)
1295-
Values.Add(Values[1]);
1296-
Values.Add(MaxValue);
1314+
for (int i = Values.Count; i < (FramesCount - 1); i++)
1315+
Values.Add(0);
1316+
// Offset for min and max values to achieve equal frame spacing
1317+
double offset = 1.0 / (2.0 * FramesCount);
1318+
// Add maximum value to the end
1319+
Values.Add(MaxValue - offset);
12971320
}
1298-
12991321
else
13001322
{
13011323
//This if clause covers among others following cases:
13021324
// Case 1 (e.g. train brake lever of Acela):
1303-
//NumFrames ( 12 4 3 )
1304-
//NumPositions ( 5 0 1 9 10 11 )
1305-
//NumValues ( 5 0 0.2 0.85 0.9 0.95 )
1306-
//Orientation ( 1 )
1307-
//DirIncrease ( 1 )
1308-
//ScaleRange ( 0 1 )
1325+
//NumFrames ( 12 4 3 )
1326+
//NumPositions ( 5 0 1 9 10 11 )
1327+
//NumValues ( 5 0 0.2 0.85 0.9 0.95 )
1328+
//Orientation ( 1 )
1329+
//DirIncrease ( 1 )
1330+
//ScaleRange ( 0 1 )
13091331
//
13101332
// Fill empty Values
13111333
int iValues = 1;
@@ -1321,11 +1343,6 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
13211343
}
13221344
iValues++;
13231345
}
1324-
1325-
// Add the maximums to the end, the Value will be removed
1326-
// We use Positions only here
1327-
if (Values.Count > 0 && Values[0] <= Values[Values.Count - 1]) Values.Add(MaxValue);
1328-
else if (Values.Count > 0 && Values[0] > Values[Values.Count - 1]) Values.Add(MinValue);
13291346
}
13301347

13311348
// OK, we have a valid size of Positions and Values
@@ -1351,9 +1368,6 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
13511368
p = Positions[i];
13521369
}
13531370
}
1354-
1355-
// Don't need the MaxValue added before, remove it
1356-
Values.RemoveAt(Values.Count - 1);
13571371
}
13581372
}
13591373

@@ -1378,13 +1392,21 @@ public CVCDiscrete(STFReader stf, string basepath, DiscreteStates discreteState)
13781392
break;
13791393
}
13801394
}
1381-
// catch (Exception error)
1382-
// {
1383-
// if (error is STFException) // Parsing error, so pass it on
1384-
// throw;
1385-
// else // Unexpected error, so provide a hint
1386-
// throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange");
1387-
// } // End of Need check the Values collection for validity
1395+
// catch (Exception error)
1396+
// {
1397+
// if (error is STFException) // Parsing error, so pass it on
1398+
// throw;
1399+
// else // Unexpected error, so provide a hint
1400+
// throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange");
1401+
// } // End of Need check the Values collection for validity
1402+
1403+
// Ensure resulting set of values has the correct format (sorted least to greatest) and resort
1404+
// Assume values have been entered in reverse order if final value is less than initial value
1405+
if (Values.Count > 0 && Values[0] > Values[Values.Count - 1])
1406+
Reversed ^= true;
1407+
// Force sort values from least to greatest
1408+
Values.Sort();
1409+
13881410
} // End of Constructor
13891411

13901412
protected void ParseNewScreen(STFReader stf)
@@ -1432,13 +1454,12 @@ public CVCMultiStateDisplay(STFReader stf, string basepath)
14321454
stf.ParseBlock( new STFReader.TokenProcessor[] {
14331455
new STFReader.TokenProcessor("style", ()=>{ MSStyles.Add(ParseNumStyle(stf));
14341456
}),
1435-
new STFReader.TokenProcessor("switchval", ()=>{ Values.Add(stf.ReadFloatBlock(STFReader.UNITS.None, null))
1457+
new STFReader.TokenProcessor("switchval", ()=>{ Values.Add(stf.ReadDoubleBlock(null))
14361458
; }),
14371459
});}),
14381460
});
1439-
if (Values.Count > 0) MaxValue = Values.Last();
1440-
for (int i = Values.Count; i < FramesCount; i++)
1441-
Values.Add(-10000);
1461+
if (Values.Count > 0)
1462+
MaxValue = Values.Max();
14421463
}),
14431464
new STFReader.TokenProcessor("ortsdisplay", ()=>{ParseDisplay(stf); }),
14441465
new STFReader.TokenProcessor("ortsscreenpage", () => {ParseScreen(stf); }),
@@ -1447,6 +1468,16 @@ public CVCMultiStateDisplay(STFReader stf, string basepath)
14471468
new STFReader.TokenProcessor("ortsunitsscalefactor", ()=>{ UnitsScale = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
14481469
new STFReader.TokenProcessor("ortsunitsoffset", ()=>{ UnitsOffset = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
14491470
});
1471+
1472+
// Ensure resulting set of values has the correct format (sorted least to greatest) and resort
1473+
// Assume values have been entered in reverse order if final value is less than initial value
1474+
if (Values.Count > 0 && Values[0] > Values[Values.Count - 1])
1475+
Reversed ^= true;
1476+
// Fill in missing values
1477+
for (int i = Values.Count; i < FramesCount; i++)
1478+
Values.Add(Values[Values.Count - 1]);
1479+
// Force sort values from least to greatest
1480+
Values.Sort();
14501481
}
14511482
protected int ParseNumStyle(STFReader stf)
14521483
{
@@ -1485,13 +1516,12 @@ public CVCAnimatedDisplay(STFReader stf, string basepath)
14851516
stf.ParseBlock( new STFReader.TokenProcessor[] {
14861517
new STFReader.TokenProcessor("style", ()=>{ MSStyles.Add(ParseNumStyle(stf));
14871518
}),
1488-
new STFReader.TokenProcessor("switchval", ()=>{ Values.Add(stf.ReadFloatBlock(STFReader.UNITS.None, null))
1519+
new STFReader.TokenProcessor("switchval", ()=>{ Values.Add(stf.ReadDoubleBlock(null))
14891520
; }),
14901521
});}),
14911522
});
1492-
if (Values.Count > 0) MaxValue = Values.Last();
1493-
for (int i = Values.Count; i < FramesCount; i++)
1494-
Values.Add(-10000);
1523+
if (Values.Count > 0)
1524+
MaxValue = Values.Max();
14951525
}),
14961526
new STFReader.TokenProcessor("ortsdisplay", ()=>{ParseDisplay(stf); }),
14971527
new STFReader.TokenProcessor("ortsscreenpage", () => {ParseScreen(stf); }),
@@ -1500,6 +1530,16 @@ public CVCAnimatedDisplay(STFReader stf, string basepath)
15001530
new STFReader.TokenProcessor("ortsunitsscalefactor", ()=>{ UnitsScale = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
15011531
new STFReader.TokenProcessor("ortsunitsoffset", ()=>{ UnitsOffset = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
15021532
});
1533+
1534+
// Ensure resulting set of values has the correct format (sorted least to greatest) and resort
1535+
// Assume values have been entered in reverse order if final value is less than initial value
1536+
if (Values.Count > 0 && Values[0] > Values[Values.Count - 1])
1537+
Reversed ^= true;
1538+
// Fill in missing values
1539+
for (int i = Values.Count; i < FramesCount; i++)
1540+
Values.Add(Values[Values.Count - 1]);
1541+
// Force sort values from least to greatest
1542+
Values.Sort();
15031543
}
15041544
protected int ParseNumStyle(STFReader stf)
15051545
{

0 commit comments

Comments
 (0)