Skip to content

Commit d36c372

Browse files
committed
Refactor detection of WheelAxlesLoaded, remove fake axles from calculations where appropriate
1 parent 6cf8c3e commit d36c372

File tree

3 files changed

+129
-104
lines changed

3 files changed

+129
-104
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/CruiseControl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ private void ComputeNumberOfAxles()
432432
SelectedNumberOfAxles = 0;
433433
foreach (TrainCar tc in Locomotive.Train.Cars)
434434
{
435-
SelectedNumberOfAxles += tc.WheelAxles.Count;
435+
SelectedNumberOfAxles += tc.WheelAxles.Sum(w => w.Fake ? 0 : 1);
436436
}
437437
}
438438
}

Source/Orts.Simulation/Simulation/RollingStocks/TrainCar.cs

Lines changed: 69 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -911,9 +911,11 @@ public virtual void Update(float elapsedClockSeconds)
911911
// Initialize RigidWheelBaseM in first loop if not defined in ENG file, then ignore
912912
if (RigidWheelBaseM == 0 && !RigidWheelBaseInitialised) // Calculate default values if no value in Wag File
913913
{
914-
float Axles = WheelAxles.Count;
915-
float Bogies = Parts.Count - 1;
916-
float BogieSize = Axles / Bogies;
914+
int Axles = WheelAxles.Sum(w => w.Fake ? 0 : 1); // Only consider real axles
915+
int Bogies = Parts.Sum(p => p.Bogie ? 1 : 0);
916+
int BogieSize = Axles;
917+
if (Bogies > 0)
918+
BogieSize = (int)(WheelAxles.Sum(w => !w.Fake && w.Part.Bogie ? 1 : 0) / Bogies); // Only consider axles attached to bogies
917919

918920
RigidWheelBaseM = 1.6764f; // Set a default in case no option is found - assume a standard 4 wheel (2 axle) bogie - wheel base - 5' 6" (1.6764m)
919921

@@ -2804,16 +2806,20 @@ public void SetUpWheels()
28042806
// No parts means no bogies (always?), so make sure we've got Parts[0] for the car itself.
28052807
if (Parts.Count == 0)
28062808
Parts.Add(new TrainCarPart(Vector3.Zero, 0));
2807-
// No axles but we have bogies.
2808-
if (WheelAxles.Count == 0 && Parts.Count > 1)
2809-
{
2810-
// Fake the axles by pretending each bogie has 1 axle.
2809+
// Determine how many parts are considered bogies (used to calculate position of the car)
2810+
int bogieCount = 0;
2811+
foreach (TrainCarPart p in Parts)
2812+
if (p.Bogie == true)
2813+
bogieCount++;
2814+
// No axles but we have bogies. Each bogie needs axles to function correctly
2815+
if (WheelAxles.Count == 0 && bogieCount > 0)
2816+
{
2817+
// Add a fake axle to each bogie, a second fake axle will be added later if needed
28112818
for (int i = 1; i < Parts.Count; i++)
2812-
WheelAxles.Add(new WheelAxle(Parts[i].OffsetM, i, Parts[i].iMatrix));
2813-
Trace.TraceInformation("Wheel axle data faked based on {1} bogies for {0}", WagFilePath, Parts.Count - 1);
2819+
if (Parts[i].Bogie == true)
2820+
WheelAxles.Add(new WheelAxle(Parts[i].OffsetM, i, Parts[i].iMatrix, true));
2821+
Trace.TraceInformation("Wheel axle data faked based on {1} bogies for {0}", WagFilePath, bogieCount);
28142822
}
2815-
bool articFront = !WheelAxles.Any(a => a.OffsetM.Z < 0);
2816-
bool articRear = !WheelAxles.Any(a => a.OffsetM.Z > 0);
28172823
// Validate the axles' assigned bogies and count up the axles on each bogie.
28182824
if (WheelAxles.Count > 0)
28192825
{
@@ -2833,10 +2839,6 @@ public void SetUpWheels()
28332839
w.Part = Parts[w.BogieIndex];
28342840
w.Part.SumWgt++;
28352841
}
2836-
2837-
// Make sure the axles are sorted by OffsetM along the car.
2838-
// Attempting to sort car w/o WheelAxles will resort to an error.
2839-
WheelAxles.Sort(WheelAxles[0]);
28402842
}
28412843

28422844
//fix bogies with only one wheel set:
@@ -2856,7 +2858,7 @@ public void SetUpWheels()
28562858
{
28572859
if (w.OffsetM.Z.AlmostEqual(Parts[i].OffsetM.Z, 0.6f))
28582860
{
2859-
var w1 = new WheelAxle(new Vector3(w.OffsetM.X, w.OffsetM.Y, w.OffsetM.Z - 0.5f), w.BogieIndex, i);
2861+
var w1 = new WheelAxle(new Vector3(w.OffsetM.X, w.OffsetM.Y, w.OffsetM.Z - 0.5f), w.BogieIndex, i, true);
28602862
w1.Part = Parts[w1.BogieIndex]; //create virtual wheel
28612863
w1.Part.SumWgt++;
28622864
WheelAxles.Add(w1);
@@ -2869,34 +2871,29 @@ public void SetUpWheels()
28692871
}
28702872
}
28712873

2872-
// Count up the number of bogies (parts) with at least 2 axles.
2874+
// Check how many parts can drive the position of the car itself
2875+
// Each part needs at least 2 components (sum of weights > 1.5) for position calculation to work
28732876
for (var i = 1; i < Parts.Count; i++)
28742877
if (Parts[i].SumWgt > 1.5)
28752878
Parts[0].SumWgt++;
28762879

2877-
// This check is for the single axle/bogie issue.
2878-
// Check SumWgt using Parts[0].SumWgt.
2879-
// Certain locomotives do not test well when using Part.SumWgt versus Parts[0].SumWgt.
2880-
// Make sure test using Parts[0] is performed after the above for loop.
2880+
// Check if articulation is desired on this car, as this requires different handling
2881+
bool articFront = (FrontArticulation == 1 || (FrontArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z < 0)));
2882+
bool articRear = (RearArticulation == 1 || (RearArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z > 0)));
2883+
2884+
// If car has insufficient bogies and it's not because of articulation, attempt to avoid position calculation errors
2885+
// Detach wheels from the last bogie, and instead attach to the main part, which should allow calculations to work properly
28812886
if (!articFront && !articRear && (Parts[0].SumWgt < 1.5))
28822887
{
2883-
foreach (var w in WheelAxles)
2888+
foreach (WheelAxle w in WheelAxles)
28842889
{
28852890
if (w.BogieIndex >= Parts.Count - 1)
28862891
{
28872892
w.BogieIndex = 0;
28882893
w.Part = Parts[w.BogieIndex];
2889-
28902894
}
28912895
}
28922896
}
2893-
// Using WheelAxles.Count test to control WheelAxlesLoaded flag.
2894-
if (WheelAxles.Count >= 2) // Some cars only have two axles.
2895-
{
2896-
WheelAxles.Sort(WheelAxles[0]);
2897-
WheelAxlesLoaded = true;
2898-
}
2899-
29002897

29012898
#if DEBUG_WHEELS
29022899
Console.WriteLine(WagFilePath);
@@ -2907,43 +2904,49 @@ public void SetUpWheels()
29072904
foreach (var p in Parts)
29082905
Console.WriteLine(" part: matrix {1,5:F0} offset {0,10:F4} weight {2,5:F0}", p.OffsetM, p.iMatrix, p.SumWgt);
29092906
#endif
2910-
// Decided to control what is sent to SetUpWheelsArticulation()by using
2911-
// WheelAxlesLoaded as a flag. This way, wagons that have to be processed are included
2912-
// and the rest left out.
2913-
2914-
// Force articulation if stock is configured as such
2915-
// Otherwise, use default behavior which gives articulation if there are no axles forward/rearward on the model,
2916-
// disables articulation on engines, and only allows articulation with 3 or fewer axles, but not 1 axle
2917-
bool articulatedFront = (FrontArticulation == 1 ||
2918-
(FrontArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z < 0) && WagonType != WagonTypes.Engine && WheelAxles.Count != 1 && WheelAxles.Count <= 3));
2919-
bool articulatedRear = (RearArticulation == 1 ||
2920-
(RearArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z > 0) && WagonType != WagonTypes.Engine && WheelAxles.Count != 1 && WheelAxles.Count <= 3));
2921-
2922-
if (articulatedFront || articulatedRear)
2923-
{
2907+
// Add fake axle(s) to train car for articulation when desired
2908+
// Adding fake axles automatically is only allowed on non-engines with 0, 2, or 3 axles
2909+
// These limitations prevent various incompatibilities with existing content
2910+
bool allowAutoArticulate = WagonType != WagonTypes.Engine && WheelAxles.Count != 1 && WheelAxles.Count <= 3;
2911+
articFront &= !(FrontArticulation == -1 && !allowAutoArticulate);
2912+
articRear &= !(RearArticulation == -1 && !allowAutoArticulate);
2913+
2914+
if (articFront || articRear)
2915+
SetUpWheelsArticulation(articFront, articRear);
2916+
2917+
// Other calculations require axles to be sorted based on their Z-offset
2918+
WheelAxles.Sort(WheelAxles[0]);
2919+
2920+
// After all processing is complete, check if the car can have its position calculated
2921+
// using the position of the axles, which is indicated by the 'WheelAxlesLoaded' flag.
2922+
// The train car must have at least 2 position references. These references can be either
2923+
// an axle or a bogie, but each bogie itself needs 2 position references.
2924+
int[] posReferences = new int[Parts.Count];
2925+
// Count the number of axles associated with each part (including main object)
2926+
foreach (WheelAxle w in WheelAxles)
2927+
posReferences[w.BogieIndex]++;
2928+
// Add a position reference to the main object for each bogie itself with at least 2 position references
2929+
for (int i = 1; i < Parts.Count; i++)
2930+
if (posReferences[i] >= 2)
2931+
posReferences[0]++;
2932+
// Car has a suitable arrangement of axles for position calculation if the main object has at least 2 position references
2933+
if (posReferences[0] >= 2)
29242934
WheelAxlesLoaded = true;
2925-
SetUpWheelsArticulation(articulatedFront, articulatedRear);
2926-
}
29272935
} // end SetUpWheels()
29282936

29292937
protected void SetUpWheelsArticulation(bool front, bool rear)
29302938
{
2931-
// If there are no forward wheels, this car is articulated (joined
2939+
// If there are no forward axles, this car is articulated (joined
29322940
// to the car in front) at the front. Likewise for the rear.
2933-
// Original process originally used caused too many issues.
2934-
// The original process did include the below process of just using WheelAxles.Add
2935-
// if the initial test did not work. Since the below process is working without issues the
2936-
// original process was stripped down to what is below
2937-
if (front || rear)
2938-
{
2939-
if (front)
2940-
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, -CarLengthM / 2.0f), 0, 0) { Part = Parts[0] });
2941+
// This will cause the car to move incorrectly, so to produce the
2942+
// expected motion, a fake axle is added at the articulated end(s)
2943+
// of the car, attached to the car itself. This will drive the positioning
2944+
// of the car as expected.
2945+
if (front)
2946+
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, -CarLengthM / 2.0f), 0, 0, true) { Part = Parts[0] });
29412947

2942-
if (rear)
2943-
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, CarLengthM / 2.0f), 0, 0) { Part = Parts[0] });
2944-
2945-
WheelAxles.Sort(WheelAxles[0]);
2946-
}
2948+
if (rear)
2949+
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, CarLengthM / 2.0f), 0, 0, true) { Part = Parts[0] });
29472950

29482951

29492952
#if DEBUG_WHEELS
@@ -3718,14 +3721,16 @@ public void UpdateGravity(Matrix orientation)
37183721
public class WheelAxle : IComparer<WheelAxle>
37193722
{
37203723
public Vector3 OffsetM; // Offset from the bogie center
3721-
public int BogieIndex;
3722-
public int BogieMatrix;
3723-
public TrainCarPart Part;
3724-
public WheelAxle(Vector3 offset, int bogie, int parentMatrix)
3724+
public int BogieIndex; // Index in the Parts list of the bogie this is attached to
3725+
public int BogieMatrix; // Index in the matrix hierarchy of the bogie this is attached to
3726+
public TrainCarPart Part; // Reference to the object for the bogie this is attached to
3727+
public bool Fake; // True for axles that aren't present in the 3D model
3728+
public WheelAxle(Vector3 offset, int bogie, int parentMatrix, bool fake = false)
37253729
{
37263730
OffsetM = offset;
37273731
BogieIndex = bogie;
37283732
BogieMatrix = parentMatrix;
3733+
Fake = fake;
37293734
}
37303735
public int Compare(WheelAxle a, WheelAxle b)
37313736
{

Source/RunActivity/Viewer3D/Popups/HUDWindow.cs

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -608,53 +608,66 @@ static string GetCarWhyteLikeNotation(TrainCar car)
608608

609609
foreach (var axle in car.WheelAxles)
610610
{
611-
if (!axle.Part.Bogie) // if not a bogie then check for the number of axles.
611+
// Do not consider fake axles
612+
if (!axle.Fake)
612613
{
613-
if (currentBogie != axle.BogieIndex && currentCount != 0)
614+
if (!axle.Part.Bogie) // if not a bogie then check for the number of axles.
614615
{
615-
whyte.Add(currentCount.ToString());
616-
currentBogie = axle.BogieIndex;
617-
currentCount = 0;
618-
}
616+
if (currentBogie != axle.BogieIndex)
617+
{
618+
if (currentCount != 0)
619+
{
620+
whyte.Add(currentCount.ToString());
621+
currentCount = 0;
622+
}
623+
currentBogie = axle.BogieIndex;
624+
}
619625

620-
if (steamloco.SteamEngines[i].AuxiliarySteamEngineType != SteamEngine.AuxiliarySteamEngineTypes.Booster)
626+
if (steamloco.SteamEngines[i].AuxiliarySteamEngineType != SteamEngine.AuxiliarySteamEngineTypes.Booster)
627+
{
628+
currentCount += 2;
629+
axlesCount += 1;
630+
631+
if (axlesCount >= steamloco.SteamEngines[i].AttachedAxle.NumWheelsetAxles)
632+
{
633+
if (currentCount != 0)
634+
{
635+
whyte.Add(currentCount.ToString());
636+
currentCount = 0;
637+
}
638+
currentBogie = axle.BogieIndex;
639+
axlesCount = 0;
640+
i = i + 1;
641+
}
642+
}
643+
}
644+
else if (axle.Part.Bogie) // this is a bogie
621645
{
622-
currentCount += 2;
623-
axlesCount += 1;
646+
if (PreviousAxlePart)
647+
{
648+
currentBogie = axle.BogieIndex;
649+
}
624650

625-
if (axlesCount >= steamloco.SteamEngines[i].AttachedAxle.NumWheelsetAxles && currentCount != 0)
651+
if (currentBogie != axle.BogieIndex)
626652
{
627-
whyte.Add(currentCount.ToString());
653+
if (currentCount != 0)
654+
{
655+
whyte.Add(currentCount.ToString());
656+
currentCount = 0;
657+
}
628658
currentBogie = axle.BogieIndex;
629-
currentCount = 0;
630-
axlesCount = 0;
631-
i = i + 1;
632659
}
660+
currentCount += 2;
633661
}
634-
}
635-
else if (axle.Part.Bogie) // this is a bogie
636-
{
637-
if ( PreviousAxlePart)
662+
663+
if (axle.Part.Bogie)
638664
{
639-
currentBogie = axle.BogieIndex;
665+
PreviousAxlePart = true;
640666
}
641-
642-
if (currentBogie != axle.BogieIndex && currentCount != 0)
667+
else
643668
{
644-
whyte.Add(currentCount.ToString());
645-
currentBogie = axle.BogieIndex;
646-
currentCount = 0;
669+
PreviousAxlePart = false;
647670
}
648-
currentCount += 2;
649-
}
650-
651-
if (axle.Part.Bogie)
652-
{
653-
PreviousAxlePart = true;
654-
}
655-
else
656-
{
657-
PreviousAxlePart = false;
658671
}
659672
}
660673

@@ -665,13 +678,20 @@ static string GetCarWhyteLikeNotation(TrainCar car)
665678
{
666679
foreach (var axle in car.WheelAxles)
667680
{
668-
if (currentBogie != axle.BogieIndex && currentCount != 0)
681+
// Do not consider fake axles
682+
if (!axle.Fake)
669683
{
670-
whyte.Add(currentCount.ToString());
671-
currentBogie = axle.BogieIndex;
672-
currentCount = 0;
684+
if (currentBogie != axle.BogieIndex)
685+
{
686+
if (currentCount != 0)
687+
{
688+
whyte.Add(currentCount.ToString());
689+
currentCount = 0;
690+
}
691+
currentBogie = axle.BogieIndex;
692+
}
693+
currentCount += 2;
673694
}
674-
currentCount += 2;
675695
}
676696
whyte.Add(currentCount.ToString());
677697
return String.Join("-", whyte.ToArray());

0 commit comments

Comments
 (0)