Skip to content

Commit 43a12f4

Browse files
committed
Non-driven axles
1 parent bcdce8b commit 43a12f4

File tree

6 files changed

+123
-33
lines changed

6 files changed

+123
-33
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/MSTSDieselLocomotive.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public override void Parse(string lowercasetoken, STFReader stf)
178178
var transmissionType = stf.ReadString();
179179
try
180180
{
181-
DieselTransmissionType = (DieselTransmissionTypes)Enum.Parse(typeof(DieselTransmissionTypes), transmissionType.First().ToString().ToUpper() + transmissionType.Substring(1));
181+
DieselTransmissionType = (DieselTransmissionTypes)Enum.Parse(typeof(DieselTransmissionTypes), transmissionType, true);
182182
}
183183
catch
184184
{

Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,7 +2742,7 @@ protected virtual void UpdateTractiveForce(float elapsedClockSeconds)
27422742
{
27432743
if (axle.DriveType == AxleDriveType.ForceDriven)
27442744
{
2745-
axle.DriveForceN = TractiveForceN / LocomotiveAxles.Count;
2745+
axle.DriveForceN = TractiveForceN * axle.TractiveForceFraction;
27462746
if (SlipControlSystem == SlipControlType.Full)
27472747
{
27482748
// Simple slip control
@@ -3112,7 +3112,7 @@ protected virtual void UpdateAxles(float elapsedClockSeconds)
31123112

31133113
foreach (var axle in LocomotiveAxles)
31143114
{
3115-
axle.BrakeRetardForceN = BrakeRetardForceN / LocomotiveAxles.Count;
3115+
axle.BrakeRetardForceN = BrakeRetardForceN * axle.BrakeForceFraction;
31163116
axle.TrainSpeedMpS = SpeedMpS; //Set the train speed of the axle mod
31173117
axle.WheelRadiusM = DriverWheelRadiusM;
31183118
axle.WheelDistanceGaugeM = TrackGaugeM;

Source/Orts.Simulation/Simulation/RollingStocks/MSTSSteamLocomotive.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,35 @@ public override void Restore(BinaryReader inf)
13011301

13021302
public override void Initialize()
13031303
{
1304+
bool notDrivenAxle = false;
1305+
for (int i = 0; i < LocomotiveAxles.Count; i++)
1306+
{
1307+
var axle = LocomotiveAxles[i];
1308+
bool driven = false;
1309+
if (SteamEngines.Count > 0)
1310+
{
1311+
foreach (var engine in SteamEngines)
1312+
{
1313+
if (engine.AttachedAxle == axle)
1314+
{
1315+
driven = true;
1316+
}
1317+
}
1318+
}
1319+
else if (i == 0) driven = true;
1320+
if (!driven)
1321+
{
1322+
axle.DriveType = AxleDriveType.NotDriven;
1323+
notDrivenAxle = true;
1324+
}
1325+
}
1326+
if (!notDrivenAxle)
1327+
{
1328+
var axle = new Axle(this);
1329+
axle.DriveType = AxleDriveType.NotDriven;
1330+
LocomotiveAxles.Add(axle);
1331+
}
1332+
13041333
base.Initialize();
13051334

13061335
// Create a steam engine block if none exits, typically for a MSTS or BASIC configuration
@@ -6718,7 +6747,7 @@ protected override void UpdateAxles(float elapsedClockSeconds)
67186747
}
67196748
foreach (var axle in LocomotiveAxles)
67206749
{
6721-
axle.BrakeRetardForceN = BrakeRetardForceN / LocomotiveAxles.Count;
6750+
axle.BrakeRetardForceN = BrakeRetardForceN * axle.BrakeForceFraction;
67226751
axle.TrainSpeedMpS = SpeedMpS; //Set the train speed of the axle mod
67236752
axle.WheelDistanceGaugeM = TrackGaugeM;
67246753
axle.CurrentCurveRadiusM = CurrentCurveRadiusM;

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
using SharpDX.Direct3D9;
3232
using Orts.Formats.OR;
3333
using static Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions.Axle;
34+
using MonoGame.Framework.Utilities.Deflate;
3435

3536
namespace Orts.Simulation.RollingStocks.SubSystems.PowerTransmissions
3637
{
@@ -345,19 +346,32 @@ public void Copy(Axles other)
345346
public void Initialize()
346347
{
347348
ResetTime = Car.Simulator.GameTime;
349+
int numForce = 0;
350+
int numMotor = 0;
348351
foreach (var axle in AxleList)
349352
{
350-
if (Car is MSTSLocomotive locomotive)
353+
if (!(Car is MSTSLocomotive)) axle.DriveType = AxleDriveType.NotDriven;
354+
else if (axle.DriveType == AxleDriveType.ForceDriven) numForce++;
355+
else if (axle.DriveType == AxleDriveType.MotorDriven) numMotor++;
356+
}
357+
foreach (var axle in AxleList)
358+
{
359+
if (numMotor > 0 && axle.DriveType == AxleDriveType.ForceDriven) axle.DriveType = AxleDriveType.NotDriven;
360+
else if (axle.DriveType == AxleDriveType.ForceDriven) axle.TractiveForceFraction = 1.0f / numForce;
361+
else if (axle.DriveType == AxleDriveType.MotorDriven) axle.TractiveForceFraction = 1.0f / numMotor;
362+
int numDriven = numMotor > 0 ? numMotor : numForce;
363+
int numNotDriven = AxleList.Count - numDriven;
364+
var locomotive = Car as MSTSLocomotive;
365+
if (locomotive != null)
351366
{
352-
if (axle.InertiaKgm2 <= 0) axle.InertiaKgm2 = locomotive.AxleInertiaKgm2 / AxleList.Count;
353-
if (axle.WheelWeightKg <= 0) axle.WheelWeightKg = locomotive.DrvWheelWeightKg / AxleList.Count;
354-
if (axle.AxleWeightN <= 0) axle.AxleWeightN = 9.81f * axle.WheelWeightKg; //remains fixed for diesel/electric locomotives, but varies for steam locomotives
355-
if (axle.NumWheelsetAxles <= 0) axle.NumWheelsetAxles = locomotive.LocoNumDrvAxles;
356-
if (axle.WheelRadiusM <= 0) axle.WheelRadiusM = locomotive.DriverWheelRadiusM;
357-
if (axle.WheelFlangeAngleRad <= 0) axle.WheelFlangeAngleRad = locomotive.MaximumWheelFlangeAngleRad;
358-
if (axle.DampingNs <= 0) axle.DampingNs = locomotive.MassKG / 1000.0f / AxleList.Count;
359-
if (axle.FrictionN <= 0) axle.FrictionN = locomotive.MassKG / 1000.0f / AxleList.Count;
360-
367+
if (axle.DriveType != AxleDriveType.NotDriven)
368+
{
369+
axle.BrakeForceFraction = 1.0f / (locomotive.DriveWheelOnlyBrakes ? numDriven : AxleList.Count);
370+
if (axle.WheelWeightKg <= 0) axle.WheelWeightKg = locomotive.DrvWheelWeightKg / numDriven;
371+
if (axle.NumWheelsetAxles <= 0) axle.NumWheelsetAxles = locomotive.LocoNumDrvAxles / numDriven;
372+
if (axle.WheelRadiusM <= 0) axle.WheelRadiusM = locomotive.DriverWheelRadiusM;
373+
}
374+
361375
// set the wheel slip threshold times for different types of locomotives
362376
// Because of the irregular force around the wheel for a steam engine during a revolution, "response" time for warnings needs to be lower
363377
if (locomotive.EngineType == TrainCar.EngineTypes.Steam)
@@ -371,6 +385,23 @@ public void Initialize()
371385
axle.WheelSlipWarningThresholdTimeS = 1;
372386
}
373387
}
388+
if (axle.DriveType == AxleDriveType.NotDriven)
389+
{
390+
var wagon = Car as MSTSWagon;
391+
axle.BrakeForceFraction = locomotive != null && locomotive.DriveWheelOnlyBrakes ? 0 :1.0f / AxleList.Count;
392+
if (axle.WheelWeightKg <= 0)
393+
{
394+
if (locomotive != null) axle.WheelWeightKg = Math.Max((Car.MassKG - locomotive.DrvWheelWeightKg) / numNotDriven, 500);
395+
else axle.WheelWeightKg = Car.MassKG / numNotDriven;
396+
}
397+
if (axle.NumWheelsetAxles <= 0) axle.NumWheelsetAxles = Math.Max(Car.GetWagonNumAxles() / numNotDriven, 1);
398+
if (axle.WheelRadiusM <= 0) axle.WheelRadiusM = wagon.WheelRadiusM;
399+
}
400+
if (axle.InertiaKgm2 <= 0) axle.InertiaKgm2 = (Car as MSTSWagon).AxleInertiaKgm2 / AxleList.Count;
401+
if (axle.WheelFlangeAngleRad <= 0) axle.WheelFlangeAngleRad = Car.MaximumWheelFlangeAngleRad;
402+
if (axle.AxleWeightN <= 0) axle.AxleWeightN = 9.81f * axle.WheelWeightKg; //remains fixed for diesel/electric locomotives, but varies for steam locomotives
403+
if (axle.DampingNs <= 0) axle.DampingNs = axle.WheelWeightKg / 1000.0f;
404+
if (axle.FrictionN <= 0) axle.FrictionN = axle.WheelWeightKg / 1000.0f;
374405
axle.Initialize();
375406
}
376407
}
@@ -529,6 +560,15 @@ public class Axle : ISubSystem<Axle>
529560
{
530561
public int NumOfSubstepsPS { get; set; }
531562

563+
/// <summary>
564+
/// Contribution of this axle to the total tractive force
565+
/// </summary>
566+
public float TractiveForceFraction;
567+
/// <summary>
568+
/// Contribution of this axle to the total brake force
569+
/// </summary>
570+
public float BrakeForceFraction;
571+
532572
/// <summary>
533573
/// Positive only brake force to the individual axle, in Newtons
534574
/// </summary>
@@ -1261,6 +1301,7 @@ void Integrate(float elapsedClockSeconds)
12611301
public virtual void Update(float elapsedSeconds)
12621302
{
12631303
bool advancedAdhesion = Car is MSTSLocomotive locomotive && locomotive.AdvancedAdhesionModel;
1304+
advancedAdhesion &= DriveType != AxleDriveType.NotDriven; // Skip integrator for undriven axles to save CPU
12641305
forceToAccelerationFactor = WheelRadiusM * WheelRadiusM / totalInertiaKgm2;
12651306
if (!advancedAdhesion)
12661307
{
@@ -1390,8 +1431,25 @@ public void UpdateSimpleAdhesion(float elapsedClockSeconds)
13901431
if (Math.Abs(axleOutForceN) > maxAdhesionForceN)
13911432
{
13921433
axleOutForceN = MathHelper.Clamp(axleOutForceN, -maxAdhesionForceN, maxAdhesionForceN);
1393-
if (Car is MSTSLocomotive locomotive && !locomotive.AntiSlip && locomotive.SlipControlSystem == MSTSLocomotive.SlipControlType.None) axleOutForceN *= locomotive.Adhesion1;
1394-
//else if (!(Car is MSTSLocomotive) && Car.Simulator.UseAdvancedAdhesion && !Car.Simulator.Settings.SimpleControlPhysics && Car.IsPlayerTrain) axleOutForceN = MathHelper.Clamp(axleOutForceN, -);
1434+
if (!Car.Simulator.UseAdvancedAdhesion || Car.Simulator.Settings.SimpleControlPhysics || !Car.Train.IsPlayerDriven)
1435+
{
1436+
if (Car is MSTSLocomotive locomotive && !locomotive.AntiSlip) axleOutForceN *= locomotive.Adhesion1;
1437+
}
1438+
else
1439+
{
1440+
float adhesionForceN;
1441+
if ((TrainSpeedMpS > 0 && axleOutForceN < 0) || (TrainSpeedMpS < 0 && axleOutForceN > 0))
1442+
{
1443+
// Compute adhesion as if wheel is fully locked
1444+
adhesionForceN = AxleWeightN * SlipCharacteristicsPacha(-TrainSpeedMpS, TrainSpeedMpS, AdhesionK, AdhesionLimit);
1445+
}
1446+
else
1447+
{
1448+
// Get asymptotic (dynamic) adhesion coefficient
1449+
adhesionForceN = AxleWeightN * SlipCharacteristicsPacha(1000.0f, Math.Abs(TrainSpeedMpS), AdhesionK, AdhesionLimit);
1450+
}
1451+
axleOutForceN = MathHelper.Clamp(axleOutForceN, -adhesionForceN, adhesionForceN);
1452+
}
13951453

13961454
HuDIsWheelSlip = HuDIsWheelSlipWarning = IsWheelSlip = IsWheelSlipWarning = true;
13971455

@@ -1418,7 +1476,7 @@ public void UpdateSimpleAdhesion(float elapsedClockSeconds)
14181476
}
14191477
AxlePositionRad += AxleSpeedMpS / WheelRadiusM * elapsedClockSeconds;
14201478

1421-
if (Math.Abs(TrainSpeedMpS) < 0.001f && Math.Abs(axleInForceN) < frictionForceN)
1479+
if (Math.Abs(TrainSpeedMpS) < 0.001f && Math.Abs(axleInForceN) < totalFrictionForceN)
14221480
{
14231481
axleOutForceN = 0;
14241482
}

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/InductionMotor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public override double GetDevelopedTorqueNm(double motorSpeedRadpS)
5050
}
5151
public override void Update(float timeSpan)
5252
{
53-
TargetForceN = Locomotive.TractiveForceN / Locomotive.TractionMotors.Count;
53+
TargetForceN = Locomotive.TractiveForceN * AxleConnected.TractiveForceFraction;
5454
EngineMaxSpeedMpS = Locomotive.MaxSpeedMpS;
5555
SlipControl = Locomotive.SlipControlSystem == MSTSLocomotive.SlipControlType.Full;
5656
float linToAngFactor = AxleConnected.TransmissionRatio / AxleConnected.WheelRadiusM;

Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -467,13 +467,19 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
467467
// Gate all RunningGearPartIndexes on this!
468468
var matrixAnimated = TrainCarShape.SharedShape.Animations != null && TrainCarShape.SharedShape.Animations.Count > 0 && TrainCarShape.SharedShape.Animations[0].anim_nodes.Count > matrix && TrainCarShape.SharedShape.Animations[0].anim_nodes[matrix].controllers.Count > 0;
469469
int? LinkedAxleIndex = null;
470+
int? notDrivenAxleIndex = null;
471+
int? drivenAxleIndex = null;
470472
for (int i=0; i<car.LocomotiveAxles.Count; i++)
471473
{
472474
if (car.LocomotiveAxles[i].AnimatedParts.Contains(matrixName))
473475
{
474476
LinkedAxleIndex = i;
475477
break;
476478
}
479+
// Do not attach parts to this axle by default if it contains a list of animated parts
480+
if (car.LocomotiveAxles[i].AnimatedParts.Count > 0) continue;
481+
if (notDrivenAxleIndex == null && car.LocomotiveAxles[i].DriveType == Simulation.RollingStocks.SubSystems.PowerTransmissions.AxleDriveType.NotDriven) notDrivenAxleIndex = i;
482+
if (drivenAxleIndex == null && car.LocomotiveAxles[i].DriveType != Simulation.RollingStocks.SubSystems.PowerTransmissions.AxleDriveType.NotDriven) drivenAxleIndex = i;
477483
}
478484
if (matrixName.StartsWith("WHEELS") && (matrixName.Length == 7 || matrixName.Length == 8 || matrixName.Length == 9))
479485
{
@@ -492,9 +498,9 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
492498
if (matrixName.Length == 8 || matrixName.Length == 9)
493499
Int32.TryParse(matrixName.Substring(6, 1), out id);
494500
if (matrixName.Length == 8 || matrixName.Length == 9 || !matrixAnimated)
495-
WheelPartIndexes[LinkedAxleIndex ?? -1].Add(matrix);
501+
WheelPartIndexes[LinkedAxleIndex ?? notDrivenAxleIndex ?? drivenAxleIndex ?? -1].Add(matrix);
496502
else
497-
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);
503+
RunningGears[LinkedAxleIndex ?? drivenAxleIndex ?? -1].AddMatrix(matrix);
498504
var pmatrix = TrainCarShape.SharedShape.GetParentMatrix(matrix);
499505
car.AddWheelSet(m.Translation, id, pmatrix, matrixName.ToString(), bogie1Axles, bogie2Axles);
500506
}
@@ -657,7 +663,7 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
657663
else
658664
{
659665
if (matrixAnimated && matrix != 0)
660-
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);
666+
RunningGears[LinkedAxleIndex ?? drivenAxleIndex ?? -1].AddMatrix(matrix);
661667

662668
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
663669
if (TrainCarShape.Hierarchy[i] == matrix)
@@ -802,18 +808,16 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
802808

803809
private void UpdateAnimation(RenderFrame frame, ElapsedTime elapsedTime)
804810
{
805-
806-
float distanceTravelledM = 0.0f; // Distance travelled by non-driven wheels
811+
float distanceTravelledM; // Distance travelled by non-driven wheels
807812
float AnimationWheelRadiusM = MSTSWagon.WheelRadiusM; // Radius of non driven wheels
808813
float AnimationDriveWheelRadiusM = MSTSWagon.DriverWheelRadiusM; // Radius of driven wheels
809814

810-
if (MSTSWagon is MSTSLocomotive loco && loco.AdvancedAdhesionModel)
815+
if (MSTSWagon is MSTSLocomotive loco)
811816
{
812817
//TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
813818
// To achieve the same result with other means, without flipping trainset physics, the line should be changed as follows:
814-
// distanceTravelledM = MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
815-
distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
816-
if (Car.BrakeSkid && !loco.DriveWheelOnlyBrakes) distanceTravelledM = 0;
819+
// distanceTravelledM = MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
820+
distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
817821
foreach (var kvp in RunningGears)
818822
{
819823
if (!kvp.Value.Empty())
@@ -829,28 +833,27 @@ private void UpdateAnimation(RenderFrame frame, ElapsedTime elapsedTime)
829833
}
830834
foreach (var kvp in WheelPartIndexes)
831835
{
832-
var axle = kvp.Key < loco.LocomotiveAxles.Count && kvp.Key >= 0 ? loco.LocomotiveAxles[kvp.Key] : (Car.EngineType == TrainCar.EngineTypes.Steam ? null : loco.LocomotiveAxles[0]);
833-
Matrix wheelRotationMatrix;
836+
var axle = kvp.Key < loco.LocomotiveAxles.Count && kvp.Key >= 0 ? loco.LocomotiveAxles[kvp.Key] : null;
834837
if (axle != null)
835838
{
836839
//TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
837-
wheelRotationMatrix = Matrix.CreateRotationX(((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * -(float)axle.AxlePositionRad);
840+
WheelRotationR = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * -(float)axle.AxlePositionRad;
838841
}
839842
else
840843
{
841844
var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM; // in radians
842845
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
843-
wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
844846
}
847+
Matrix wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
845848
foreach (var iMatrix in kvp.Value)
846849
{
847850
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
848851
}
849852
}
850853
}
851-
else // set values for simple adhesion
854+
else // set values for wagons (not handled by Axle class)
852855
{
853-
distanceTravelledM = ((MSTSWagon.IsDriveable && MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
856+
distanceTravelledM = MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
854857
if (Car.BrakeSkid) distanceTravelledM = 0;
855858
foreach (var kvp in RunningGears)
856859
{

0 commit comments

Comments
 (0)