@@ -488,6 +488,112 @@ public virtual void LoadFromWagFile(string wagFilePath)
488488 RearAirHose . Connected . ShapeFileName = null ;
489489 }
490490
491+ // If requested, use the shape file to determine the size of the wagon
492+ if ( ( AutoSize || AutoCenter ) && ! string . IsNullOrEmpty ( MainShapeFileName ) )
493+ {
494+ try // Shape file discrepancies might cause errors, we don't want to cause a crash here
495+ {
496+ // This might be a bad idea, usually we wait to deal with shape files until within viewing range
497+ // But my hubris has decided we can use for the shape for things other than graphics - Phillip
498+ ShapeFile wagShape = new ShapeFile ( wagonFolderSlash + MainShapeFileName , true ) ;
499+
500+ Vector3 mins = new Vector3 ( float . PositiveInfinity ) ;
501+ Vector3 maxes = new Vector3 ( float . NegativeInfinity ) ;
502+
503+ // Determine size specifically for LOD0's (nearest LOD) sub objects
504+ foreach ( sub_object subObj in wagShape . shape . lod_controls [ 0 ] . distance_levels [ 0 ] . sub_objects )
505+ {
506+ // Use vertex sets in the sub object to determine which vertices to check
507+ foreach ( vertex_set vSet in subObj . vertex_sets )
508+ {
509+ // Use the vertex state used by this vertex set to determine the matrix used
510+ vtx_state vState = wagShape . shape . vtx_states [ vSet . VtxStateIdx ] ;
511+
512+ // The index of the matrix used by this vertex state
513+ int mIndex = vState . imatrix ;
514+
515+ // The 'actual' XNA matrix used to determine the vertex transformation
516+ Matrix mat = Matrix . Identity ;
517+
518+ // Determine the overall transformation matrix from the root to the current matrix by following the hierarchy
519+ do
520+ {
521+ matrix m = wagShape . shape . matrices [ mIndex ] ;
522+
523+ // Convert the shape file matrix to an XNA matrix
524+ Matrix matTransform = new Matrix
525+ {
526+ M11 = m . AX ,
527+ M12 = m . AY ,
528+ M13 = m . AZ , //
529+ M14 = 0 ,
530+ M21 = m . BX ,
531+ M22 = m . BY ,
532+ M23 = m . BZ , //
533+ M24 = 0 ,
534+ M31 = m . CX , //
535+ M32 = m . CY , //
536+ M33 = m . CZ ,
537+ M34 = 0 ,
538+ M41 = m . DX ,
539+ M42 = m . DY ,
540+ M43 = m . DZ , //
541+ M44 = 1.0f
542+ } ;
543+
544+ // Add the effect of this transformation to the overall transformation
545+ mat = mat * matTransform ;
546+
547+ // Determine the index of the next highest matrix in the hierarchy
548+ mIndex = wagShape . shape . lod_controls [ 0 ] . distance_levels [ 0 ] . distance_level_header . hierarchy [ mIndex ] ;
549+ } // Keep calculating until we have calculated the root, or until a loop is encountered
550+ while ( mIndex > - 1 && mIndex != vState . imatrix && mIndex < wagShape . shape . matrices . Count ) ;
551+
552+ // Determine position of every vertex in this set from point position and tranformed by the matrix
553+ for ( int i = vSet . StartVtxIdx ; i < vSet . StartVtxIdx + vSet . VtxCount ; i ++ )
554+ {
555+ // Determine vertex position from vertex index and point index
556+ point p = wagShape . shape . points [ subObj . vertices [ i ] . ipoint ] ;
557+ Vector3 pPos = new Vector3 ( p . X , p . Y , p . Z ) ;
558+
559+ pPos = Vector3 . Transform ( pPos , mat ) ;
560+
561+ if ( pPos . X < mins . X )
562+ mins . X = pPos . X ;
563+ if ( pPos . X > maxes . X )
564+ maxes . X = pPos . X ;
565+
566+ if ( pPos . Y < mins . Y )
567+ mins . Y = pPos . Y ;
568+ if ( pPos . Y > maxes . Y )
569+ maxes . Y = pPos . Y ;
570+
571+ if ( pPos . Z < mins . Z )
572+ mins . Z = pPos . Z ;
573+ if ( pPos . Z > maxes . Z )
574+ maxes . Z = pPos . Z ;
575+ }
576+ }
577+ }
578+
579+ // Set dimensions of wagon if configured as such
580+ if ( AutoSize )
581+ {
582+ CarWidthM = Math . Max ( ( maxes . X - mins . X ) + AutoWidthOffsetM , 0.1f ) ;
583+ CarHeightM = Math . Max ( ( maxes . Y - mins . Y ) + AutoHeightOffsetM , 0.1f ) ;
584+ CarLengthM = Math . Max ( ( maxes . Z - mins . Z ) + AutoLengthOffsetM , 0.1f ) ;
585+ }
586+
587+ // Automatically determine the center of gravity offset required to perfectly center the shape (lengthwise)
588+ if ( AutoCenter )
589+ InitialCentreOfGravityM . Z = ( maxes . Z + mins . Z ) / 2.0f ;
590+ }
591+ catch
592+ {
593+ Trace . TraceWarning ( "Could not automatically determine size of shape {0} in wagon {1}, there may be an error in the shape." , MainShapeFileName , wagFilePath ) ;
594+ }
595+ }
596+
491597 // If trailing loco resistance constant has not been defined in WAG/ENG file then assign default value based upon orig Davis values
492598 if ( TrailLocoResistanceFactor == 0 )
493599 {
@@ -1287,6 +1393,14 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
12871393 CarLengthM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
12881394 stf . SkipRestOfBlock ( ) ;
12891395 break ;
1396+ case "wagon(ortsautosize" :
1397+ AutoSize = true ;
1398+ stf . MustMatch ( "(" ) ;
1399+ AutoWidthOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1400+ AutoHeightOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1401+ AutoLengthOffsetM = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
1402+ stf . SkipRestOfBlock ( ) ;
1403+ break ;
12901404 case "wagon(ortslengthbogiecentre" : CarBogieCentreLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
12911405 case "wagon(ortslengthcarbody" : CarBodyLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
12921406 case "wagon(ortslengthairhose" : CarAirHoseLengthM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
@@ -1304,6 +1418,7 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
13041418 stf . SkipRestOfBlock ( ) ;
13051419 }
13061420 break ;
1421+ case "wagon(centerofgravity" :
13071422 case "wagon(centreofgravity" :
13081423 stf . MustMatch ( "(" ) ;
13091424 InitialCentreOfGravityM . X = stf . ReadFloat ( STFReader . UNITS . Distance , null ) ;
@@ -1316,6 +1431,8 @@ public virtual void Parse(string lowercasetoken, STFReader stf)
13161431 }
13171432 stf . SkipRestOfBlock ( ) ;
13181433 break ;
1434+ case "wagon(ortsautocentre" :
1435+ case "wagon(ortsautocenter" : AutoCenter = stf . ReadBoolBlock ( false ) ; break ;
13191436 case "wagon(ortsunbalancedsuperelevation" : MaxUnbalancedSuperElevationM = stf . ReadFloatBlock ( STFReader . UNITS . Distance , null ) ; break ;
13201437 case "wagon(ortsrigidwheelbase" :
13211438 stf . MustMatch ( "(" ) ;
@@ -1723,7 +1840,6 @@ public virtual void Copy(MSTSWagon copy)
17231840 CarLengthM = copy . CarLengthM ;
17241841 TrackGaugeM = copy . TrackGaugeM ;
17251842 CentreOfGravityM = copy . CentreOfGravityM ;
1726- InitialCentreOfGravityM = copy . InitialCentreOfGravityM ;
17271843 MaxUnbalancedSuperElevationM = copy . MaxUnbalancedSuperElevationM ;
17281844 RigidWheelBaseM = copy . RigidWheelBaseM ;
17291845 CarBogieCentreLengthM = copy . CarBogieCentreLengthM ;
0 commit comments