@@ -2744,9 +2744,7 @@ protected void SetUpWheelsArticulation(int carIndex)
27442744
27452745 public void ComputePosition ( Traveller traveler , bool backToFront , float elapsedTimeS , float distance , float speed )
27462746 {
2747- // Superelevation visual roll angle, will be determined during parts update
2748- float rollAngle ;
2749- float [ ] bogieRoll ;
2747+ // Position of bogies relative to model center, used for determining curve physics
27502748 float [ ] bogieOffsets = new float [ Parts . Count - 1 ] ;
27512749
27522750 for ( var j = 0 ; j < Parts . Count ; j ++ )
@@ -2764,7 +2762,7 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
27642762 l ++ ;
27652763 }
27662764
2767- bogieRoll = UpdateCurveData ( new Traveller ( traveler ) , bogieOffsets , out rollAngle ) ;
2765+ UpdateCurvePhys ( new Traveller ( traveler ) , bogieOffsets ) ;
27682766
27692767 o = - CarLengthM / 2 - CentreOfGravityM . Z ;
27702768 for ( var k = 0 ; k < WheelAxles . Count ; k ++ )
@@ -2775,7 +2773,12 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
27752773 var x = traveler . X + 2048 * ( traveler . TileX - tileX ) ;
27762774 var y = traveler . Y ;
27772775 var z = traveler . Z + 2048 * ( traveler . TileZ - tileZ ) ;
2778- WheelAxles [ k ] . Part . AddWheelSetLocation ( 1 , o , x , y , z ) ;
2776+
2777+ Vector3 location = new Vector3 ( x , y , z ) + traveler . CalcElevationPositionOffset ( Simulator . Settings . UseSuperElevation > 0 , out float r ) ;
2778+ // This car is flipped, so flip roll direction.
2779+ r *= - 1 ;
2780+
2781+ WheelAxles [ k ] . Part . AddWheelSetLocation ( 1 , o , location . X , location . Y , location . Z , r ) ;
27792782 }
27802783 o = CarLengthM / 2 - CentreOfGravityM . Z - o ;
27812784 traveler . Move ( o ) ;
@@ -2791,7 +2794,7 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
27912794 l ++ ;
27922795 }
27932796
2794- bogieRoll = UpdateCurveData ( new Traveller ( traveler ) , bogieOffsets , out rollAngle ) ;
2797+ UpdateCurvePhys ( new Traveller ( traveler ) , bogieOffsets ) ;
27952798
27962799 o = CarLengthM / 2 - CentreOfGravityM . Z ;
27972800 for ( var k = WheelAxles . Count - 1 ; k >= 0 ; k -- )
@@ -2802,7 +2805,10 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
28022805 var x = traveler . X + 2048 * ( traveler . TileX - tileX ) ;
28032806 var y = traveler . Y ;
28042807 var z = traveler . Z + 2048 * ( traveler . TileZ - tileZ ) ;
2805- WheelAxles [ k ] . Part . AddWheelSetLocation ( 1 , o , x , y , z ) ;
2808+
2809+ Vector3 location = new Vector3 ( x , y , z ) + traveler . CalcElevationPositionOffset ( Simulator . Settings . UseSuperElevation > 0 , out float r ) ;
2810+
2811+ WheelAxles [ k ] . Part . AddWheelSetLocation ( 1 , o , location . X , location . Y , location . Z , r ) ;
28062812 }
28072813 o = CarLengthM / 2 + CentreOfGravityM . Z + o ;
28082814 traveler . Move ( o ) ;
@@ -2812,9 +2818,21 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
28122818 for ( int i = 1 ; i < Parts . Count ; i ++ )
28132819 {
28142820 TrainCarPart p = Parts [ i ] ;
2815- p . FindCenterLine ( ) ;
2816- if ( p . SumWgt > 1.5 )
2821+
2822+ if ( p . SumWgt > 1.5f )
2823+ {
2824+ p . FindCenterLine ( ) ;
28172825 p0 . AddPartLocation ( 1 , p ) ;
2826+ }
2827+ else if ( p . SumWgt > 0.5f ) // Handle edge case of single axle pony trucks
2828+ {
2829+ double d = p . OffsetM - p . SumOffset / p . SumWgt ;
2830+ if ( - .2 < d && d < .2 )
2831+ continue ;
2832+ // Add a fake "wheel" to serve as a pivot point
2833+ p . AddWheelSetLocation ( 1 , p . OffsetM , p0 . Pos [ 0 ] + p . OffsetM * p0 . Dir [ 0 ] , p0 . Pos [ 1 ] + p . OffsetM * p0 . Dir [ 1 ] , p0 . Pos [ 2 ] + p . OffsetM * p0 . Dir [ 2 ] , 0 ) ;
2834+ p . FindCenterLine ( ) ;
2835+ }
28182836 }
28192837 p0 . FindCenterLine ( ) ;
28202838 Vector3 fwd = new Vector3 ( p0 . Dir [ 0 ] , p0 . Dir [ 1 ] , - p0 . Dir [ 2 ] ) ;
@@ -2832,11 +2850,11 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
28322850 m . Backward = fwd ;
28332851
28342852 // Roll the car for superelevation
2835- Matrix superelevationRoll = Matrix . CreateRotationZ ( rollAngle ) ;
2836- m = superelevationRoll * m ;
2853+ m = Matrix . CreateRotationZ ( p0 . Roll ) * m ;
28372854
28382855 // Rolling stock seems to always sit 0.275 meters above the track height
28392856 float railOffset = 0.275f ;
2857+
28402858 Vector3 pos = new Vector3 ( p0 . Pos [ 0 ] , p0 . Pos [ 1 ] , - p0 . Pos [ 2 ] ) ;
28412859 m . Translation = pos + m . Up * railOffset ;
28422860
@@ -2845,29 +2863,6 @@ public void ComputePosition(Traveller traveler, bool backToFront, float elapsedT
28452863 WorldPosition . TileZ = tileZ ;
28462864
28472865 UpdatedTraveler ( traveler , elapsedTimeS , distance , speed ) ;
2848-
2849- // Determine superelevation angle for bogies
2850- for ( int i = 1 ; i < Parts . Count ; i ++ )
2851- {
2852- TrainCarPart p = Parts [ i ] ;
2853- if ( p . SumWgt < .5 ) // No wheels on this bogie, skip it
2854- continue ;
2855- if ( p . SumWgt < 1.5 )
2856- { // single axle pony trunk
2857- double d = p . OffsetM - p . SumOffset / p . SumWgt ;
2858- if ( - .2 < d && d < .2 )
2859- continue ;
2860- // Add a fake "wheel" to serve as a pivot point
2861- p . AddWheelSetLocation ( 1 , p . OffsetM , p0 . Pos [ 0 ] + p . OffsetM * p0 . Dir [ 0 ] , p0 . Pos [ 1 ] + p . OffsetM * p0 . Dir [ 1 ] , p0 . Pos [ 2 ] + p . OffsetM * p0 . Dir [ 2 ] ) ;
2862- p . FindCenterLine ( ) ;
2863- }
2864-
2865- // Generate superelevation rotation matrix for the bogie
2866- if ( Flipped == backToFront )
2867- p . Rotation = Matrix . CreateRotationZ ( bogieRoll [ i - 1 ] ) ;
2868- else
2869- p . Rotation = Matrix . CreateRotationZ ( bogieRoll [ ( Parts . Count - 1 ) - i ] ) ;
2870- }
28712866 }
28722867
28732868 #region Traveller-based updates
@@ -2890,47 +2885,21 @@ internal void UpdatedTraveler(Traveller traveler, float elapsedTimeS, float dist
28902885 /// This WILL move the traveller by the total amount of all the offsets.
28912886 /// Directly sets the superelevation and curve radius for car physics.
28922887 /// </summary>
2893- /// <returns>Returns an array giving the angle of visual superelevation at each calculated point.</returns>
2894- public float [ ] UpdateCurveData ( Traveller traveller , float [ ] offsets , out float roll )
2888+ public void UpdateCurvePhys ( Traveller traveller , float [ ] offsets )
28952889 {
2896- roll = 0 ;
2897- bool visualElevationEnabled = Simulator . Settings . UseSuperElevation > 0 ;
2898-
28992890 // Ensure at least one offset is given
29002891 if ( offsets == null || offsets . Length <= 0 )
29012892 offsets = new [ ] { 0.0f } ;
29022893
29032894 // Need to get superelevation at both ends of the car by offsetting the traveller
2904- float [ ] visualElevation = traveller . GetSuperElevation ( visualElevationEnabled , offsets , out float [ ] physicsElevation , out float [ ] curveRadii ) ;
2905-
2906- float [ ] angles = new float [ visualElevation . Length ] ;
2895+ traveller . GetCurveData ( offsets , out float [ ] physicsElevation , out float [ ] curveRadii ) ;
29072896
29082897 // Superelevation MUST be limited to track gauge to avoid NaN errors
29092898 SuperelevationM = Math . Min ( physicsElevation . Average ( ) , TrackGaugeM ) ;
29102899 // Set superelevation angle used by physics system
29112900 SuperElevationAngleRad = ( float ) Math . Asin ( SuperelevationM / TrackGaugeM ) ;
29122901
29132902 CurrentCurveRadiusM = curveRadii . Min ( ) ;
2914- float z = visualElevation . Average ( ) ;
2915-
2916- // Determine superelevation angle for animation, assuming there is any visual elevation
2917- if ( z != 0 )
2918- {
2919- roll = ( float ) Math . Asin ( z / TrackGaugeM ) ;
2920-
2921- if ( Flipped )
2922- roll *= - 1 ;
2923-
2924- for ( int v = 0 ; v < visualElevation . Length ; v ++ )
2925- {
2926- angles [ v ] = ( float ) Math . Asin ( visualElevation [ v ] / TrackGaugeM ) ;
2927-
2928- if ( Flipped )
2929- angles [ v ] *= - 1 ;
2930- }
2931- }
2932-
2933- return angles ;
29342903 }
29352904 #endregion
29362905
@@ -3559,7 +3528,6 @@ public class TrainCarPart
35593528 {
35603529 public float OffsetM ; // distance from center of model, positive forward
35613530 public int iMatrix ; // matrix index in shape that needs to be moved
3562- public Matrix Rotation = Matrix . Identity ; // Matrix giving the roll angle of the bogie in absolute terms
35633531 // line fitting variables
35643532 public double SumWgt ; // Sum of component weights
35653533 public double SumOffset ; // Sum of component weights times offsets
@@ -3568,6 +3536,8 @@ public class TrainCarPart
35683536 public double [ ] SumPosOffset = new double [ 3 ] ; // Sum of component locations [x, y, z] times offsets
35693537 public float [ ] Pos = new float [ 3 ] ; // Position [x, y, z] of this part, calculated with y-intercept of linear regression
35703538 public float [ ] Dir = new float [ 3 ] ; // Oritentation [x, y, z] of this part, calculated with slope of linear regression
3539+ public float SumRoll ; // Sum of all roll angles of components
3540+ public float Roll ; // Roll angle of this part
35713541 public bool Bogie ; // True if this is a bogie
35723542 public TrainCarPart ( float offset , int i )
35733543 {
@@ -3583,13 +3553,14 @@ public void InitLineFit()
35833553 SumWgt = SumOffset = SumOffsetSq = 0 ;
35843554 for ( int i = 0 ; i < 3 ; i ++ )
35853555 SumPos [ i ] = SumPosOffset [ i ] = 0 ;
3556+ SumRoll = 0 ;
35863557 }
35873558
35883559 /// <summary>
35893560 /// Directly adds the 3D position values of a sub part to this part. The position
35903561 /// of sub parts will be used to derive the position of this part.
35913562 /// </summary>
3592- public void AddWheelSetLocation ( float weight , float offset , float x , float y , float z )
3563+ public void AddWheelSetLocation ( float weight , float offset , float x , float y , float z , float roll )
35933564 {
35943565 SumWgt += weight ;
35953566 SumOffset += weight * offset ;
@@ -3600,6 +3571,7 @@ public void AddWheelSetLocation(float weight, float offset, float x, float y, fl
36003571 SumPosOffset [ 1 ] += weight * y * offset ;
36013572 SumPos [ 2 ] += weight * z ;
36023573 SumPosOffset [ 2 ] += weight * z * offset ;
3574+ SumRoll += weight * roll ;
36033575 }
36043576
36053577 /// <summary>
@@ -3616,6 +3588,7 @@ public void AddPartLocation(float weight, TrainCarPart part)
36163588 SumPos [ i ] += weight * position ;
36173589 SumPosOffset [ i ] += weight * position * part . OffsetM ;
36183590 }
3591+ SumRoll += weight * part . Roll ;
36193592 }
36203593
36213594 /// <summary>
@@ -3655,6 +3628,8 @@ public void FindCenterLine()
36553628 Dir [ i ] = 0 ;
36563629 }
36573630 }
3631+
3632+ Roll = SumRoll / ( float ) SumWgt ;
36583633 }
36593634 }
36603635}
0 commit comments