Skip to content

Commit ed3f512

Browse files
committed
Use freight animations in auto size and auto center
1 parent 16cf00c commit ed3f512

File tree

4 files changed

+157
-96
lines changed

4 files changed

+157
-96
lines changed

Source/Documentation/Manual/features-rollingstock.rst

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -741,9 +741,7 @@ To simplify this process, and produce more reasonable dimensions for rolling sto
741741
automatically calculate the dimensions of rolling stock based on the shape file used. Enter
742742
``ORTSAutoSize`` in the Wagon section of an engine or wagon to allow OR to determine
743743
the width, height, and length of the rolling stock based on the dimensions of the main shape file,
744-
ignoring any values entered manually in the MSTS Size parameter. Note that this process is
745-
not aware of any :ref:`shape descriptor overrides <features-shape-manipulation>` so any changes made
746-
to the shape there will not be reflected in the automatically calculated size.
744+
ignoring any values entered manually in the MSTS Size parameter.
747745

748746
``ORTSAutoSize`` accepts 3 (optional) arguments, default units in meters, corresponding to offsets from the
749747
shape's width, height, and length respectively. For example, ``ORTSAutoSize ( 0.1m, -0.2m, -0.18m )``
@@ -754,11 +752,12 @@ arguments can be set to 0, and the length argument adjusted to produce the desir
754752
no arguments are specified (ie: ``ORTSAutoSize ()`` was entered in the Wagon section) then all three
755753
offsets are assumed to be 0 meters.
756754

757-
Note that automatic sizing uses the nearest LOD of the main shape file. LODs for further distances
758-
and freight animation shape files have no effect on the automatic sizing. This method also works best for rolling
759-
stock with standard buffers/couplers on each end. Automatic sizing generally can't produce reasonable results
760-
for articulated rolling stock. And should something go wrong with the shape file causing automatic sizing to fail,
761-
OR will revert to the values entered in the ``Size`` parameter.
755+
Note that automatic sizing uses the nearest LOD of the main shape file and attached freight animations. LODs for further
756+
distances have no effect on the automatic sizing. :ref:`Shape descriptor overrides <features-shape-manipulation>`
757+
are also not considered at this phase, so if any changes are made in the .sd file, this feature may not provide
758+
good results. This method also works best for rolling stock with standard buffers/couplers on each end.
759+
Automatic sizing generally can't produce reasonable results for articulated rolling stock. And should something go
760+
wrong with the shape file causing automatic sizing to fail, OR will revert to the values entered in the ``Size`` parameter.
762761

763762
Improved wagon alignment tools
764763
------------------------------
@@ -800,9 +799,9 @@ not change the X or Y components. Should no re-centering be required, none will
800799
Some rolling stock will not align correctly when auto-centered. As with ``ORTSAutoSize``, this
801800
feature should be employed on rolling stock with standard buffers or couplers, and will
802801
not produce suitable results for articulated rolling stock or stock with different coupler
803-
types at each end. Only the highest detail LOD of the main shape is used to auto-center the
804-
rolling stock, other LODs and freight animations are ignored. If the process fails, a warning
805-
will be written to the log and the automatic calculation will be skipped.
802+
types at each end. Only the highest detail LOD of the main shape and freight animations are
803+
used, the .sd file is not checked. If the process fails, a warning will be written to the
804+
log and the automatic calculation will be skipped.
806805

807806
Advanced articulation control
808807
-----------------------------

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)