Skip to content

Commit fbeaf73

Browse files
authored
Merge pull request #754 from Csantucci/container-weights-official
Container weights: https://blueprints.launchpad.net/or/+spec/container-weights Blueprint approved and code merged. Thanks, Carlo, Chris
2 parents 1cc4a74 + 3549c39 commit fbeaf73

File tree

8 files changed

+167
-43
lines changed

8 files changed

+167
-43
lines changed

Source/Documentation/Manual/features-rollingstock.rst

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@ Here below a sample of a ``.load-or`` file::
599599
"Shape" : "COMMON_Container_3d\\Cont_40ftHC\\container-40ftHC_Triton.s",
600600
"ContainerType" : "C40ftHC",
601601
"IntrinsicShapeOffset": [0,1.175,0],
602+
"EmptyMassKG": 2100.,
603+
"MaxMassWhenLoadedKG": 28000.,
602604
}
603605
}
604606

@@ -621,20 +623,30 @@ Here below a sample of a ``.load-or`` file::
621623
container with respect to the container shape file coordinates. Unfortunately often such
622624
offset is not [0,0,0], which would be advisable for newly produced containers. A simple way to
623625
state such offset is to use the ``Show Bounding Info`` of ``Shape Viewer``.
626+
- "EmptyMassKG" is an optional parameter that defines the tare (weight when empty) of the
627+
container. If the parameter is not present, OR uses a default parameter, specific for that
628+
ContainerType.
629+
- "MaxMassWhenLoadedKG" is an optional parameter that defines the sum of the tare plus the maximum
630+
allowed payload. As above, if the parameter is not present, OR uses a default parameter, specific for that
631+
ContainerType.
632+
624633

625634
Pre-setting a .wag file to accommodate containers
626635
-------------------------------------------------
627636

628637
As a minimum following block must be present in the .wag file for a double stacker::
629638

630639
ORTSFreightAnims (
640+
WagonEmptyWeight ( 12.575t )
631641
LoadingAreaLength ( 12.20 )
632642
AboveLoadingAreaLength ( 12.20 )
633643
DoubleStacker ()
634644
Offset( 0 0.34 0 )
635645
IntakePoint ( 0 6.0 Container)
636646
)
637647

648+
- WagonEmptyWeight is the weight of the wagon, when it has neither containers nor other
649+
weighing freight animations on board
638650
- LoadingAreaLength is the length in meters of the loading area available for containers
639651
- AboveLoadingAreaLength is the length in meters of the above loading area available
640652
for containers (parameter not needed if not double stacker)
@@ -694,9 +706,9 @@ shown here::
694706

695707
Wagon (
696708
WagonData ( DTTX_620040_A ATW.DTTX_620040 )
697-
LoadData ( 20cmacgm common.containerdata CenterFront)
698-
LoadData ( 20hamburgsud common.containerdata CenterRear)
699-
LoadData ( 40msc common.containerdata Above)
709+
LoadData ( 20cmacgm common.containerdata CenterFront Empty)
710+
LoadData ( 20hamburgsud common.containerdata CenterRear Loaded)
711+
LoadData ( 40msc common.containerdata Above Random)
700712
UiD ( 11 )
701713
)
702714

@@ -707,7 +719,17 @@ present. The meaning of the parameters is as follows:
707719
- The first parameter is the name of the ``.load-or`` file
708720
- The second parameter is the path (having ``Trainset`` as base path) where the ``.load-or``
709721
file resides
710-
- The third parameter indicates where the container is allocated on the wagon.
722+
- The third parameter indicates where the container is allocated on the wagon
723+
- The fourth parameter, which is optional, defines the load state of the related container,
724+
which is used to derive the weight of the container. If ``Empty`` is present, the weight
725+
of the empty container is used as actual weight; if ``Loaded`` is present, the maximum
726+
weight (tare + payload) of the container is used; if ``Random`` is present, the weight
727+
is computed as follows: a random number between 0 and 100 is generated. If the number is
728+
below 31, the container is considered empty; else the number is used as percentage of the
729+
maximum weight of the container (tare + payload). The weight of the containers are added to
730+
the empty weight of the wagon, to compute the total weight of the wagon. If the parameter
731+
is not present, the ``Random`` value is assumed.
732+
711733

712734
The entry for the container allocated ``Above`` must be the last one.
713735

@@ -733,18 +755,19 @@ A minimum ``FreightAnimations`` entry in a ``.wag`` file to have the same pre-lo
733755
set as in the previous paragraph is as follows::
734756

735757
ORTSFreightAnims (
736-
LoadingAreaLength ( 14.6 )
737-
AboveLoadingAreaLength ( 16.15 )
758+
WagonEmptyWeight ( 12.575t )
759+
LoadingAreaLength ( 14.6 )
760+
AboveLoadingAreaLength ( 16.15 )
738761
DoubleStacker ()
739762
Offset( 0 0.34 0 )
740763
IntakePoint ( 0 6.0 Container)
741-
LoadData ( 20cmacgm common.containerdata CenterFront)
742-
LoadData ( 20hamburgsud common.containerdata CenterRear)
743-
LoadData ( 40msc common.containerdata Above)
764+
LoadData ( 20cmacgm common.containerdata CenterFront Empty)
765+
LoadData ( 20hamburgsud common.containerdata CenterRear Loaded)
766+
LoadData ( 40msc common.containerdata Above Random)
744767
)
745768

746769
As can be seen, the syntax of the ``LoadData`` entries is the same as in the case of
747-
the ``.con`` file.
770+
the ``.con`` file. Also here the fourth parameter is optional.
748771

749772
Obviously, using ``.wag`` files for this type of info, a different ``.wag`` file must
750773
be created for every desired pre-loaded set of containers.
@@ -1048,9 +1071,9 @@ The ``.load-stations-loads-or`` file is a Json file. An example is shown here be
10481071
{
10491072
"LoadStationID" : { "wfile" : "w-005354+014849.w", "UiD" : 21, },
10501073
"LoadData" : [
1051-
{ "File" : "40HCcai", "Folder" : "common.containerdata", "StackLocation" : 0, },
1052-
{ "File" : "40HCcai", "Folder" : "common.containerdata", "StackLocation" : 0, },
1053-
{ "File" : "20cmacgm", "Folder" : "common.containerdata", "StackLocation" : 2, },
1074+
{ "File" : "40HCcai", "Folder" : "common.containerdata", "StackLocation" : 0, "LoadState" : "Empty"},
1075+
{ "File" : "40HCcai", "Folder" : "common.containerdata", "StackLocation" : 0, "LoadState" : "Loaded"},
1076+
{ "File" : "20cmacgm", "Folder" : "common.containerdata", "StackLocation" : 2, "LoadState" : "Random"},
10541077
{ "File" : "20kline", "Folder" : "common.containerdata", "StackLocation" : 2, },
10551078
{ "File" : "45HCtriton", "Folder" : "common.containerdata", "StackLocation" : 5, },
10561079
{ "File" : "45HCtriton", "Folder" : "common.containerdata", "StackLocation" : 5, },
@@ -1081,6 +1104,8 @@ The file can define the population at startup of many container stations.
10811104
index refers to a child stack location.
10821105
- If more than a container is defined for a stack location, they are stacked one above the
10831106
other.
1107+
- The ``LoadState`` parameter is optional, and has the same meaning and values as the
1108+
parameter of the same name which can be present in .con or .wag files.
10841109

10851110
The container station population file must be written taking into account the constraints
10861111
of the stack locations (container length must be smaller than stack location lenght,

Source/ORTS.Common/enums.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,14 @@ public enum LoadPosition
7272
Above
7373
}
7474

75+
/// <summary>
76+
/// Defines the loading state of a load (e.g. a container) on a wagon
77+
/// </summary>
78+
public enum LoadState
79+
{
80+
Random,
81+
Empty,
82+
Loaded,
83+
}
84+
7585
}

Source/Orts.Formats.Msts/ActivityFile.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ public struct LoadData
296296
public string Name;
297297
public string Folder;
298298
public LoadPosition LoadPosition;
299+
public LoadState LoadState;
299300
}
300301

301302
/// <summary>
@@ -1341,8 +1342,15 @@ public Wagon(STFReader stf) {
13411342
loadData.Folder = stf.ReadString();
13421343
var positionString = stf.ReadString();
13431344
Enum.TryParse(positionString, out loadData.LoadPosition);
1344-
LoadDataList.Add(loadData);
1345-
stf.MustMatch(")");
1345+
var state = stf.ReadString();
1346+
if (state != ")")
1347+
{
1348+
Enum.TryParse(state, out loadData.LoadState);
1349+
LoadDataList.Add(loadData);
1350+
stf.MustMatch(")");
1351+
}
1352+
else
1353+
LoadDataList.Add(loadData);
13461354
}),
13471355
});
13481356
}

Source/Orts.Formats.OR/ContainerFile.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ public class ContainerParameters
6565
public string ShapeFileName;
6666
public string ContainerType;
6767
public Vector3 IntrinsicShapeOffset = new Vector3(0f, 1.17f, 0f);
68-
68+
public float EmptyMassKG = -1;
69+
public float MaxMassWhenLoadedKG = -1;
6970

7071
public ContainerParameters(JsonReader json)
7172
{
@@ -80,6 +81,8 @@ bool TryParse(JsonReader item)
8081
case "Shape": ShapeFileName = item.AsString(ShapeFileName); break;
8182
case "ContainerType": ContainerType = item.AsString("40ftHC"); break;
8283
case "IntrinsicShapeOffset[]": IntrinsicShapeOffset = item.AsVector3(Vector3.Zero); break;
84+
case "EmptyMassKG": EmptyMassKG = item.AsFloat(-1); break;
85+
case "MaxMassWhenLoadedKG": MaxMassWhenLoadedKG = item.AsFloat(-1); break;
8386
default: return false;
8487
}
8588
return true;

Source/Orts.Formats.OR/LoadStationsPopulationFile.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
using System.Text;
2323
using System.IO;
2424
using Microsoft.Xna.Framework;
25+
using Orts.Formats.Msts;
2526
using Orts.Parsers.OR;
27+
using ORTS.Common;
2628

2729
namespace Orts.Formats.OR
2830
{
@@ -113,6 +115,7 @@ public class LoadDataEntry
113115
public string FileName;
114116
public string FolderName;
115117
public int StackLocation;
118+
public LoadState LoadState;
116119

117120
public LoadDataEntry(JsonReader json)
118121
{
@@ -126,6 +129,7 @@ bool TryParse(JsonReader item)
126129
case "File": FileName = item.AsString(""); break;
127130
case "Folder": FolderName = item.AsString(""); break;
128131
case "StackLocation": StackLocation = item.AsInteger(0); break;
132+
case "LoadState": Enum.TryParse(item.AsString(""), out LoadState); break;
129133
default: return false;
130134
}
131135
return true;

Source/Orts.Simulation/Simulation/Container.cs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,17 @@ public enum Status
6666
public string ShapeFileName;
6767
public string BaseShapeFileFolderSlash;
6868
public float MassKG = 2000;
69+
public float EmptyMassKG;
70+
public float MaxMassWhenLoadedKG;
6971
public float WidthM = 2.44f;
7072
public float LengthM = 12.19f;
7173
public float HeightM = 2.59f;
7274
public ContainerType ContainerType = ContainerType.C40ft;
7375
public bool Flipped = false;
7476
public static float Length20ftM = 6.095f;
7577
public static float Length40ftM = 12.19f;
76-
78+
public static float[] DefaultEmptyMassKG = { 0, 2160, 3900, 4100, 4500, 4700, 4900, 5040 };
79+
public static float[] DefaultMaxMassWhenLoadedKG = { 0, 24000, 30500, 30500, 30500, 30500, 30500, 30500 };
7780
public WorldPosition WorldPosition = new WorldPosition(); // current position of the container
7881
public float RealRelativeYOffset = 0;
7982
public float RealRelativeZOffset = 0;
@@ -117,6 +120,8 @@ public virtual void Copy(Container containerCopy)
117120
ComputeDimensions();
118121
Flipped = containerCopy.Flipped;
119122
MassKG = containerCopy.MassKG;
123+
EmptyMassKG = containerCopy.EmptyMassKG;
124+
MaxMassWhenLoadedKG = containerCopy.MaxMassWhenLoadedKG;
120125
}
121126

122127
public Container(BinaryReader inf, FreightAnimationDiscrete freightAnimDiscrete, ContainerHandlingItem containerStation, bool fromContainerStation, int stackLocationIndex = 0)
@@ -134,6 +139,8 @@ public Container(BinaryReader inf, FreightAnimationDiscrete freightAnimDiscrete,
134139
ComputeDimensions();
135140
Flipped = inf.ReadBoolean();
136141
MassKG = inf.ReadSingle();
142+
EmptyMassKG = inf.ReadSingle();
143+
MaxMassWhenLoadedKG = inf.ReadSingle();
137144
if (fromContainerStation)
138145
{
139146
// compute WorldPosition starting from offsets and position of container station
@@ -231,6 +238,8 @@ public void Save(BinaryWriter outf, bool fromContainerStation = false)
231238
outf.Write((int)ContainerType);
232239
outf.Write(Flipped);
233240
outf.Write(MassKG);
241+
outf.Write(EmptyMassKG);
242+
outf.Write(MaxMassWhenLoadedKG);
234243
if (fromContainerStation)
235244
{
236245

@@ -254,6 +263,8 @@ public void LoadFromContainerFile(string loadFilePath, string baseFolder)
254263
ComputeDimensions();
255264
IntrinsicShapeOffset = containerParameters.IntrinsicShapeOffset;
256265
IntrinsicShapeOffset.Z *= -1;
266+
EmptyMassKG = containerParameters.EmptyMassKG != -1 ? containerParameters.EmptyMassKG : DefaultEmptyMassKG[(int)ContainerType] ;
267+
MaxMassWhenLoadedKG = containerParameters.MaxMassWhenLoadedKG != -1 ? containerParameters.MaxMassWhenLoadedKG : DefaultMaxMassWhenLoadedKG[(int)ContainerType];
257268
}
258269

259270
public void ComputeWorldPosition (FreightAnimationDiscrete freightAnimDiscrete)
@@ -268,6 +279,24 @@ public void ComputeWorldPosition (FreightAnimationDiscrete freightAnimDiscrete)
268279
var invWagonMatrix = Matrix.Invert(freightAnimDiscrete.Wagon.WorldPosition.XNAMatrix);
269280
RelativeContainerMatrix = Matrix.Multiply(WorldPosition.XNAMatrix, invWagonMatrix);
270281
}
282+
283+
public void ComputeLoadWeight(LoadState loadState)
284+
{
285+
switch (loadState)
286+
{
287+
case LoadState.Empty:
288+
MassKG = EmptyMassKG;
289+
break;
290+
case LoadState.Loaded:
291+
MassKG = MaxMassWhenLoadedKG;
292+
break;
293+
case LoadState.Random:
294+
var loadPercent = Simulator.Random.Next(101);
295+
if (loadPercent < 30) MassKG = EmptyMassKG;
296+
else MassKG = MaxMassWhenLoadedKG * loadPercent / 100f;
297+
break;
298+
}
299+
}
271300
}
272301

273302
public class ContainerManager
@@ -511,14 +540,14 @@ public void PreloadContainerStation(PickupObj thisWorldObj)
511540
Trace.TraceWarning($"Ignored missing load {loadFilePath}");
512541
continue;
513542
}
514-
Preload(loadFilePath, loadDataEntry.StackLocation);
543+
Preload(loadFilePath, loadDataEntry.StackLocation, loadDataEntry.LoadState);
515544
}
516545
break;
517546
}
518547
}
519548
}
520549

521-
public void Preload(string loadFilePath, int stackLocationIndex)
550+
public void Preload(string loadFilePath, int stackLocationIndex, LoadState loadState)
522551
{
523552
Container container;
524553
container = new Container(null, loadFilePath, this);
@@ -531,6 +560,8 @@ public void Preload(string loadFilePath, int stackLocationIndex)
531560
container.LoadFromContainerFile(loadFilePath, Simulator.BasePath + @"\trains\trainset\");
532561
ContainerManager.LoadedContainers.Add(loadFilePath, container);
533562
}
563+
container.ComputeLoadWeight(loadState);
564+
534565
var stackLocation = StackLocations[stackLocationIndex];
535566
if (stackLocation.Containers != null && stackLocation.Containers.Count >= stackLocation.MaxStackedContainers)
536567
Trace.TraceWarning("Stack Location {0} is full, can't lay down container", stackLocationIndex);

0 commit comments

Comments
 (0)