Skip to content

Commit 5560ecd

Browse files
committed
Automatic merge of T1.6-115-g0d2de70b7 and 12 pull requests
- Pull request #1082 at 8538170: Allow variable water level in glass gauge - Pull request #1156 at f46d5f2: Fix incorrectly disabled options in train operations window - Pull request #1091 at 492795a: Automatic speed control - Pull request #1122 at b9b077b: Wagon Size and Centering Controls - Pull request #1124 at e241a0d: Built-in PBL2 brake controller - Pull request #1128 at d116396: Particle Emitter Overhaul - Pull request #1157 at 39cd994: Dynamic brake authorization by TCS - Pull request #1159 at 48c9a63: Skip OR warnings about TSRE-specific token Ruler - Pull request #1160 at c64daa0: Route Based TTrack Sounds - Pull request #1163 at 2f9e292: Fix: Crash when using Camera 8 and F9. - Pull request #1164 at 1ad9889: Fix: F9 crashes with a front coupled single steam locomotive by Csantucci. - Pull request #1165 at 168c27c: docs: Add code guidelines for logging
14 parents 1c16e0c + 0d2de70 + 8538170 + f46d5f2 + 492795a + b9b077b + e241a0d + d116396 + 39cd994 + 48c9a63 + c64daa0 + 2f9e292 + 1ad9889 + 168c27c commit 5560ecd

File tree

5 files changed

+343
-53
lines changed

5 files changed

+343
-53
lines changed

Source/Documentation/Manual/features-rollingstock.rst

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -411,34 +411,84 @@ some steps of the content creation process or allow more control over content th
411411
possible. The goal of these features is to save content creators' time, give additional power to
412412
creators, and to simplify the installation process for end users.
413413

414-
Advanced articulation control
415-
-----------------------------
416-
417-
A wide variety of modern rolling stock uses articulation, in which multiple rail vehicles
418-
share a single "Jacobs Bogie". Open Rails offers partial support for such passenger and
419-
freight units by allowing one wagon to include a bogie in its 3D model while the next
420-
wagon removes the bogie from its 3D model. Ideally, OR will then add an invisible bogie
421-
to the end of the wagon without the bogie to emulate "sharing" the bogie with the previous
422-
wagon.
423-
424-
However, this automatic system is limited. OR will check for wheels in the wagon's 3D
425-
model and will assume the wagon is articulated at one end if there are no wheels towards
426-
that end of the 3D model. This approach will only be used on 3D models with 3, 2, or 0 axles
427-
(the 1-axle case is excluded for compatibility reasons) and won't be used on locomotives.
428-
In some cases, this approach will result in false negative or false positive detection
429-
of articulation. Should the automatic articulation method not produce the expected track
430-
following behavior, it is now possible to manually define whether a wagon or engine
431-
should use the articulation behavior.
414+
Automatic wagon size calculation
415+
--------------------------------
416+
417+
Determining the appropriate values to enter in the ``Size ( w, h, l )`` parameter of an engine or
418+
wagon can be tedious, as reasonable settings for the simulated width, height, and length of rolling
419+
stock depend on measurements of the 3D model used. Many content creators have entered largely
420+
arbitrary values of width and height into the size parameter, only adjusting the length value to
421+
give correct coupler alignement.
422+
423+
.. index::
424+
single: ORTSAutoSize
425+
426+
To simplify this process, and produce more reasonable dimensions for rolling stock, OR can now
427+
automatically calculate the dimensions of rolling stock based on the shape file used. Enter
428+
``ORTSAutoSize`` in the Wagon section of an engine or wagon to allow OR to determine
429+
the width, height, and length of the rolling stock based on the dimensions of the main shape file,
430+
ignoring any values entered manually in the MSTS Size parameter.
431+
432+
``ORTSAutoSize`` accepts 3 (optional) arguments, default units in meters, corresponding to offsets from the
433+
shape's width, height, and length respectively. For example, ``ORTSAutoSize ( 0.1m, -0.2m, -0.18m )``
434+
would tell OR to automatically determine the wagon's dimensions from the shape file, then subsequently
435+
add 0.1 meters to the width, subtract 0.2 meters from the height, and subtract 0.18 meters from the length,
436+
using the resulting values to set the simulated size of the wagon. In most cases, the width and height
437+
arguments can be set to 0, and the length argument adjusted to produce the desired coupler spacing. If
438+
no arguments are specified (ie: ``ORTSAutoSize ()`` was entered in the Wagon section) then all three
439+
offsets are assumed to be 0 meters.
440+
441+
Note that automatic sizing uses the nearest LOD of the main shape file and attached freight animations. LODs for further
442+
distances have no effect on the automatic sizing. Freight animations using the ``ShapeHierarchy`` feature are also
443+
skipped due to potential unintended behaviors. :ref:`Shape descriptor overrides <features-shape-manipulation>`
444+
are also not considered at this phase, so if any changes are made in the .sd file, this feature may not provide
445+
good results. This method also works best for rolling stock with standard buffers/couplers on each end.
446+
Automatic sizing generally can't produce reasonable results for articulated rolling stock. And should something go
447+
wrong with the shape file causing automatic sizing to fail, OR will revert to the values entered in the ``Size`` parameter.
448+
449+
Improved wagon alignment tools
450+
------------------------------
451+
452+
Many MSTS and OR creators have encountered rolling stock shapes that were not correctly aligned,
453+
resulting in couplers/buffers clipping at one end of the wagon and separating at the other end.
454+
Normally, this would require inspecting the 3D model to determine exactly how off-center it was
455+
and carefully setting the Z value of ``CentreOfGravity ( x, y, z )`` to "nudge" the wagon shape
456+
until it is centered.
457+
458+
.. index::
459+
single: ORTSShapeNudge
460+
461+
In some cases, this approach could still be insufficient as the Z offset is limited to 2 meters in
462+
order to prevent unusual behaviors with some MSTS models that used unreasonably large Z offsets.
463+
To facilitate models that need large offsets without introducing errors, OR now accepts this offset
464+
with the parameter ``ORTSShapeNudge ( z )``, which can be set to *any length offset without limit*.
465+
466+
.. index::
467+
single: CentreOfGravity
468+
469+
However, this does not entirely replace ``CentreOfGravity``. The Y (height) value of the CoG is
470+
still used by the physics system and should still be defined. In this case, simply use
471+
``CentreOfGravity ( y )`` where y is the CoG height in meters (or other units, as desired).
472+
Unlike entering all 3 values for the CoG, entering only the Y value will NOT affect the alignment
473+
of the 3D model, allowing the "physical" CoG to be entered separately from the "visual" CoG.
432474

433475
.. index::
434-
single: ORTSFrontArticulation
435-
single: ORTSRearArticulation
436-
437-
To forcibly enable the articulation behavior at the front of the rail vehicle, use
438-
``ORTSFrontArticulation ( 1 )`` and at the rear use ``ORTSRearArticulation ( 1 )``.
439-
Conversely, use ``ORTSFrontArticulation ( 0 )`` or ``ORTSRearArticulation ( 0 )`` to
440-
force disable articulation behavior. Entering a value of -1 provides the default
441-
automatic behavior.
476+
single: ORTSAutoCenter
477+
478+
And, for the sake of simplicity, it may be desired to just center the 3D model lengthwise
479+
such that the couplers/buffers are equidistant from the centerpoint of the model. To make this
480+
specific case easier, OR now includes the ``ORTSAutoCenter`` parameter. When ``ORTSAutoCenter ( 1 )``
481+
is included in the Wagon section of an engine or wagon, OR will inspect the main shape file used by
482+
the wagon to determine the exact Z value of CentreOfGravity required to re-center the shape in the
483+
simulation. This will overwrite the manually entered Z component of ``CentreOfGravity ( x y z )`` but
484+
will not change the X or Y components. Should no re-centering be required, none will be applied.
485+
486+
Some rolling stock will not align correctly when auto-centered. As with ``ORTSAutoSize``, this
487+
feature should be employed on rolling stock with standard buffers or couplers, and will
488+
not produce suitable results for articulated rolling stock or stock with different coupler
489+
types at each end. Only the highest detail LOD of the main shape and freight animations are
490+
used, the .sd file is not checked. If the process fails, a warning will be written to the
491+
log and the automatic calculation will be skipped.
442492

443493
Freight animations and pickups
444494
==============================

Source/Orts.Formats.Msts/ShapeFile.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// You should have received a copy of the GNU General Public License
1616
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
1717

18+
using Microsoft.Xna.Framework;
1819
using Orts.Parsers.Msts;
1920
using System;
2021
using System.Collections.Generic;
@@ -109,7 +110,99 @@ public void ReadAnimationBlock(string orFileName)
109110
file.VerifyEndOfBlock();
110111
}
111112

113+
/// <summary>
114+
/// Determines the corners of the 'bounding box' for the shape
115+
/// </summary>
116+
/// <returns>Two Vector3s, the first measuring the minimum extent of the shape,
117+
/// the second measuring the maximum extent of the shape</returns>
118+
public (Vector3, Vector3) GetBoundingLimits()
119+
{
120+
Vector3 mins = new Vector3(float.PositiveInfinity);
121+
Vector3 maxes = new Vector3(float.NegativeInfinity);
122+
123+
// Determine size specifically for LOD0's (nearest LOD) sub objects
124+
foreach (sub_object subObj in shape.lod_controls[0].distance_levels[0].sub_objects)
125+
{
126+
// Use vertex sets in the sub object to determine which vertices to check
127+
foreach (vertex_set vSet in subObj.vertex_sets)
128+
{
129+
// Use the vertex state used by this vertex set to determine the matrix used
130+
vtx_state vState = shape.vtx_states[vSet.VtxStateIdx];
131+
132+
// The index of the matrix used by this vertex state
133+
int mIndex = vState.imatrix;
134+
135+
// The 'actual' XNA matrix used to determine the vertex transformation
136+
Matrix mat = Matrix.Identity;
137+
138+
// How deep are we in the hierarchy? Set a limit to prevent infinite loops
139+
int depth = 0;
112140

141+
// Determine the overall transformation matrix from the root to the current matrix by following the hierarchy
142+
do
143+
{
144+
matrix m = shape.matrices[mIndex];
145+
146+
// Convert the shape file matrix to an XNA matrix
147+
Matrix matTransform = new Matrix
148+
{
149+
M11 = m.AX,
150+
M12 = m.AY,
151+
M13 = m.AZ, //
152+
M14 = 0,
153+
M21 = m.BX,
154+
M22 = m.BY,
155+
M23 = m.BZ, //
156+
M24 = 0,
157+
M31 = m.CX, //
158+
M32 = m.CY, //
159+
M33 = m.CZ,
160+
M34 = 0,
161+
M41 = m.DX,
162+
M42 = m.DY,
163+
M43 = m.DZ, //
164+
M44 = 1.0f
165+
};
166+
167+
// Add the effect of this transformation to the overall transformation
168+
mat = mat * matTransform;
169+
170+
// Determine the index of the next highest matrix in the hierarchy
171+
mIndex = shape.lod_controls[0].distance_levels[0].distance_level_header.hierarchy[mIndex];
172+
173+
depth++;
174+
} // Keep calculating until we have calculated the root, or until a loop is encountered
175+
while (mIndex > -1 && mIndex != vState.imatrix && mIndex < shape.matrices.Count && depth < 32);
176+
177+
// Determine position of every vertex in this set from point position and tranformed by the matrix
178+
for (int i = vSet.StartVtxIdx; i < vSet.StartVtxIdx + vSet.VtxCount; i++)
179+
{
180+
// Determine vertex position from vertex index and point index
181+
point p = shape.points[subObj.vertices[i].ipoint];
182+
Vector3 pPos = new Vector3(p.X, p.Y, p.Z);
183+
184+
pPos = Vector3.Transform(pPos, mat);
185+
186+
if (pPos.X < mins.X)
187+
mins.X = pPos.X;
188+
if (pPos.X > maxes.X)
189+
maxes.X = pPos.X;
190+
191+
if (pPos.Y < mins.Y)
192+
mins.Y = pPos.Y;
193+
if (pPos.Y > maxes.Y)
194+
maxes.Y = pPos.Y;
195+
196+
if (pPos.Z < mins.Z)
197+
mins.Z = pPos.Z;
198+
if (pPos.Z > maxes.Z)
199+
maxes.Z = pPos.Z;
200+
}
201+
}
202+
}
203+
204+
return (mins, maxes);
205+
}
113206
}
114207

115208
public class shape

0 commit comments

Comments
 (0)