Skip to content

Commit 073cb17

Browse files
committed
Allow manually defining articulation
1 parent 0250537 commit 073cb17

File tree

3 files changed

+52
-17
lines changed

3 files changed

+52
-17
lines changed

Source/Documentation/Manual/features-rollingstock.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,35 @@ types at each end. Only the highest detail LOD of the main shape is used to auto
488488
rolling stock, other LODs and freight animations are ignored. If the process fails, a warning
489489
will be written to the log and the automatic calculation will be skipped.
490490

491+
Advanced articulation control
492+
-----------------------------
493+
494+
A wide variety of modern rolling stock uses articulation, in which multiple rail vehicles
495+
share a single "Jacobs Bogie". Open Rails offers partial support for such passenger and
496+
freight units by allowing one wagon to include a bogie in its 3D model while the next
497+
wagon removes the bogie from its 3D model. Ideally, OR will then add an invisible bogie
498+
to the end of the wagon without the bogie to emulate "sharing" the bogie with the previous
499+
wagon.
500+
501+
However, this automatic system is limited. OR will check for wheels in the wagon's 3D
502+
model and will assume the wagon is articulated at one end if there are no wheels towards
503+
that end of the 3D model. This approach will only be used on 3D models with 3, 2, or 0 axles
504+
(the 1-axle case is excluded for compatibility reasons) and won't be used on locomotives.
505+
In some cases, this approach will result in false negative or false positive detection
506+
of articulation. Should the automatic articulation method not produce the expected track
507+
following behavior, it is now possible to manually define whether a wagon or engine
508+
should use the articulation behavior.
509+
510+
.. index::
511+
single: ORTSFrontArticulation
512+
single: ORTSRearArticulation
513+
514+
To forcibly enable the articulation behavior at the front of the rail vehicle, use
515+
``ORTSFrontArticulation ( 1 )`` and at the rear use ``ORTSRearArticulation ( 1 )``.
516+
Conversely, use ``ORTSFrontArticulation ( 0 )`` or ``ORTSRearArticulation ( 0 )`` to
517+
force disable articulation behavior. Entering a value of -1 provides the default
518+
automatic behavior.
519+
491520
Freight animations and pickups
492521
==============================
493522

Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,8 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
14281428
AutoLengthOffsetM = stf.ReadFloat(STFReader.UNITS.Distance, null);
14291429
stf.SkipRestOfBlock();
14301430
break;
1431+
case "wagon(ortsfrontarticulation": FrontArticulation = stf.ReadIntBlock(null); break;
1432+
case "wagon(ortsreararticulation": RearArticulation = stf.ReadIntBlock(null); break;
14311433
case "wagon(ortslengthbogiecentre": CarBogieCentreLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
14321434
case "wagon(ortslengthcarbody": CarBodyLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
14331435
case "wagon(ortslengthairhose": CarAirHoseLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// COPYRIGHT 2009 - 2022 by the Open Rails project.
1+
// COPYRIGHT 2009 - 2022 by the Open Rails project.
22
//
33
// This file is part of Open Rails.
44
//
@@ -191,6 +191,8 @@ public static Interpolator SteamHeatBoilerFuelUsageGalukpH()
191191
public float AutoWidthOffsetM;
192192
public float AutoLengthOffsetM;
193193
public float AutoHeightOffsetM;
194+
public int FrontArticulation = -1; // -1: Determine front articulation automatically, 0: Force no front articulation, 1: Force front articulation
195+
public int RearArticulation = -1; // -1: Determine rear articulation automatically, 0: Force no rear articulation, 1: Force rear articulation
194196
public float MassKG = 10000; // Mass in KG at runtime; coincides with InitialMassKG if there is no load and no ORTS freight anim
195197
public float InitialMassKG = 10000;
196198
public bool IsDriveable;
@@ -2715,34 +2717,36 @@ public void SetUpWheels()
27152717
// Decided to control what is sent to SetUpWheelsArticulation()by using
27162718
// WheelAxlesLoaded as a flag. This way, wagons that have to be processed are included
27172719
// and the rest left out.
2718-
bool articulatedFront = !WheelAxles.Any(a => a.OffsetM.Z < 0);
2719-
bool articulatedRear = !WheelAxles.Any(a => a.OffsetM.Z > 0);
2720-
var carIndex = Train.Cars.IndexOf(this);
2721-
//Certain locomotives are testing as articulated wagons for some reason.
2722-
if (WagonType != WagonTypes.Engine)
2723-
if (WheelAxles.Count != 1 && (articulatedFront || articulatedRear))
2724-
{
2725-
WheelAxlesLoaded = true;
2726-
SetUpWheelsArticulation(carIndex);
2727-
}
2720+
2721+
// Force articulation if stock is configured as such
2722+
// Otherwise, use default behavior which gives articulation if there are no axles forward/reareward on the mode,
2723+
// disables articulation on engines, and only allows articulation with 3 or fewer axles, but not 1 axle
2724+
bool articulatedFront = (FrontArticulation == 1 ||
2725+
(FrontArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z < 0) && WagonType != WagonTypes.Engine && WheelAxles.Count != 1 && WheelAxles.Count <= 3));
2726+
bool articulatedRear = (RearArticulation == 1 ||
2727+
(RearArticulation == -1 && !WheelAxles.Any(a => a.OffsetM.Z > 0) && WagonType != WagonTypes.Engine && WheelAxles.Count != 1 && WheelAxles.Count <= 3));
2728+
2729+
if (articulatedFront || articulatedRear)
2730+
{
2731+
WheelAxlesLoaded = true;
2732+
SetUpWheelsArticulation(articulatedFront, articulatedRear);
2733+
}
27282734
} // end SetUpWheels()
27292735

2730-
protected void SetUpWheelsArticulation(int carIndex)
2736+
protected void SetUpWheelsArticulation(bool front, bool rear)
27312737
{
27322738
// If there are no forward wheels, this car is articulated (joined
27332739
// to the car in front) at the front. Likewise for the rear.
2734-
bool articulatedFront = !WheelAxles.Any(a => a.OffsetM.Z < 0);
2735-
bool articulatedRear = !WheelAxles.Any(a => a.OffsetM.Z > 0);
27362740
// Original process originally used caused too many issues.
27372741
// The original process did include the below process of just using WheelAxles.Add
27382742
// if the initial test did not work. Since the below process is working without issues the
27392743
// original process was stripped down to what is below
2740-
if (articulatedFront || articulatedRear)
2744+
if (front || rear)
27412745
{
2742-
if (articulatedFront && WheelAxles.Count <= 3)
2746+
if (front)
27432747
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, -CarLengthM / 2.0f), 0, 0) { Part = Parts[0] });
27442748

2745-
if (articulatedRear && WheelAxles.Count <= 3)
2749+
if (rear)
27462750
WheelAxles.Add(new WheelAxle(new Vector3(0.0f, BogiePivotHeightM, CarLengthM / 2.0f), 0, 0) { Part = Parts[0] });
27472751

27482752
WheelAxles.Sort(WheelAxles[0]);

0 commit comments

Comments
 (0)