@@ -445,6 +445,112 @@ public virtual void LoadFromWagFile(string wagFilePath)
445445 RearAirHose . Connected . ShapeFileName = null ;
446446 }
447447
448+ // If requested, use the shape file to determine the size of the wagon
449+ if ( ( AutoSize || AutoCenter ) && ! string . IsNullOrEmpty ( MainShapeFileName ) )
450+ {
451+ try // Shape file discrepancies might cause errors, we don't want to cause a crash here
452+ {
453+ // This might be a bad idea, usually we wait to deal with shape files until within viewing range
454+ // But my hubris has decided we can use for the shape for things other than graphics - Phillip
455+ ShapeFile wagShape = new ShapeFile ( wagonFolderSlash + MainShapeFileName , true ) ;
456+
457+ Vector3 mins = new Vector3 ( float . PositiveInfinity ) ;
458+ Vector3 maxes = new Vector3 ( float . NegativeInfinity ) ;
459+
460+ // Determine size specifically for LOD0's (nearest LOD) sub objects
461+ foreach ( sub_object subObj in wagShape . shape . lod_controls [ 0 ] . distance_levels [ 0 ] . sub_objects )
462+ {
463+ // Use vertex sets in the sub object to determine which vertices to check
464+ foreach ( vertex_set vSet in subObj . vertex_sets )
465+ {
466+ // Use the vertex state used by this vertex set to determine the matrix used
467+ vtx_state vState = wagShape . shape . vtx_states [ vSet . VtxStateIdx ] ;
468+
469+ // The index of the matrix used by this vertex state
470+ int mIndex = vState . imatrix ;
471+
472+ // The 'actual' XNA matrix used to determine the vertex transformation
473+ Matrix mat = Matrix . Identity ;
474+
475+ // Determine the overall transformation matrix from the root to the current matrix by following the hierarchy
476+ do
477+ {
478+ matrix m = wagShape . shape . matrices [ mIndex ] ;
479+
480+ // Convert the shape file matrix to an XNA matrix
481+ Matrix matTransform = new Matrix
482+ {
483+ M11 = m . AX ,
484+ M12 = m . AY ,
485+ M13 = m . AZ , //
486+ M14 = 0 ,
487+ M21 = m . BX ,
488+ M22 = m . BY ,
489+ M23 = m . BZ , //
490+ M24 = 0 ,
491+ M31 = m . CX , //
492+ M32 = m . CY , //
493+ M33 = m . CZ ,
494+ M34 = 0 ,
495+ M41 = m . DX ,
496+ M42 = m . DY ,
497+ M43 = m . DZ , //
498+ M44 = 1.0f
499+ } ;
500+
501+ // Add the effect of this transformation to the overall transformation
502+ mat = mat * matTransform ;
503+
504+ // Determine the index of the next highest matrix in the hierarchy
505+ mIndex = wagShape . shape . lod_controls [ 0 ] . distance_levels [ 0 ] . distance_level_header . hierarchy [ mIndex ] ;
506+ } // Keep calculating until we have calculated the root, or until a loop is encountered
507+ while ( mIndex > - 1 && mIndex != vState . imatrix && mIndex < wagShape . shape . matrices . Count ) ;
508+
509+ // Determine position of every vertex in this set from point position and tranformed by the matrix
510+ for ( int i = vSet . StartVtxIdx ; i < vSet . StartVtxIdx + vSet . VtxCount ; i ++ )
511+ {
512+ // Determine vertex position from vertex index and point index
513+ point p = wagShape . shape . points [ subObj . vertices [ i ] . ipoint ] ;
514+ Vector3 pPos = new Vector3 ( p . X , p . Y , p . Z ) ;
515+
516+ pPos = Vector3 . Transform ( pPos , mat ) ;
517+
518+ if ( pPos . X < mins . X )
519+ mins . X = pPos . X ;
520+ if ( pPos . X > maxes . X )
521+ maxes . X = pPos . X ;
522+
523+ if ( pPos . Y < mins . Y )
524+ mins . Y = pPos . Y ;
525+ if ( pPos . Y > maxes . Y )
526+ maxes . Y = pPos . Y ;
527+
528+ if ( pPos . Z < mins . Z )
529+ mins . Z = pPos . Z ;
530+ if ( pPos . Z > maxes . Z )
531+ maxes . Z = pPos . Z ;
532+ }
533+ }
534+ }
535+
536+ // Set dimensions of wagon if configured as such
537+ if ( AutoSize )
538+ {
539+ CarWidthM = Math . Max ( ( maxes . X - mins . X ) + AutoWidthOffsetM , 0.1f ) ;
540+ CarHeightM = Math . Max ( ( maxes . Y - mins . Y ) + AutoHeightOffsetM , 0.1f ) ;
541+ CarLengthM = Math . Max ( ( maxes . Z - mins . Z ) + AutoLengthOffsetM , 0.1f ) ;
542+ }
543+
544+ // Automatically determine the center of gravity offset required to perfectly center the shape (lengthwise)
545+ if ( AutoCenter )
546+ InitialCentreOfGravityM . Z = ( maxes . Z + mins . Z ) / 2.0f ;
547+ }
548+ catch
549+ {
550+ Trace . TraceWarning ( "Could not automatically determine size of shape {0} in wagon {1}, there may be an error in the shape." , MainShapeFileName , wagFilePath ) ;
551+ }
552+ }
553+
448554 // If trailing loco resistance constant has not been defined in WAG/ENG file then assign default value based upon orig Davis values
449555 if ( TrailLocoResistanceFactor == 0 )
450556 {
@@ -1203,6 +1309,14 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
12031309 CarLengthM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
12041310 stf . SkipRestOfBlock ( ) ;
12051311 break ;
1312+ case "wagon(ortsautosize" :
1313+ AutoSize = true ;
1314+ stf . MustMatch ( "(" ) ;
1315+ AutoWidthOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1316+ AutoHeightOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1317+ AutoLengthOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1318+ stf . SkipRestOfBlock ( ) ;
1319+ break ;
12061320 case "wagon(ortslengthbogiecentre" : CarBogieCentreLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
12071321 case "wagon(ortslengthcarbody" : CarBodyLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
12081322 case "wagon(ortslengthairhose" : CarAirHoseLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
@@ -1220,6 +1334,7 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
12201334 stf . SkipRestOfBlock ( ) ;
12211335 }
12221336 break ;
1337+ case "wagon(centerofgravity" :
12231338 case "wagon(centreofgravity" :
12241339 stf . MustMatch ( "(" ) ;
12251340 InitialCentreOfGravityM . X = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
@@ -1232,6 +1347,8 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
12321347 }
12331348 stf . SkipRestOfBlock ( ) ;
12341349 break ;
1350+ case "wagon(ortsautocentre" :
1351+ case "wagon(ortsautocenter" : AutoCenter = stf . ReadBoolBlock ( false ) ; break ;
12351352 case "wagon(ortsunbalancedsuperelevation" : MaxUnbalancedSuperElevationM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
12361353 case "wagon(ortsrigidwheelbase" :
12371354 stf . MustMatch ( "(" ) ;
@@ -1614,7 +1731,6 @@ public virtual void Copy(MSTSWagon copy)
16141731 CarLengthM = copy . CarLengthM ;
16151732 TrackGaugeM = copy . TrackGaugeM ;
16161733 CentreOfGravityM = copy . CentreOfGravityM ;
1617- InitialCentreOfGravityM = copy . InitialCentreOfGravityM ;
16181734 MaxUnbalancedSuperElevationM = copy . MaxUnbalancedSuperElevationM ;
16191735 RigidWheelBaseM = copy . RigidWheelBaseM ;
16201736 CarBogieCentreLengthM = copy . CarBogieCentreLengthM ;
0 commit comments