@@ -44,6 +44,12 @@ public class MSTSWagonViewer : TrainCarViewer
44
44
protected AnimatedShape FrontCouplerOpenShape ;
45
45
protected AnimatedShape RearCouplerShape ;
46
46
protected AnimatedShape RearCouplerOpenShape ;
47
+
48
+ protected AnimatedShape FrontAirHoseShape ;
49
+ protected AnimatedShape FrontAirHoseDisconnectedShape ;
50
+ protected AnimatedShape RearAirHoseShape ;
51
+ protected AnimatedShape RearAirHoseDisconnectedShape ;
52
+
47
53
public static readonly Action Noop = ( ) => { } ;
48
54
/// <summary>
49
55
/// Dictionary of built-in locomotive control keyboard commands, Action[] is in the order {KeyRelease, KeyPress}
@@ -276,6 +282,28 @@ from data in effect.Value
276
282
RearCouplerOpenShape = new AnimatedShape ( viewer , wagonFolderSlash + car . RearCouplerOpenShapeFileName + '\0 ' + wagonFolderSlash , new WorldPosition ( car . WorldPosition ) , ShapeFlags . ShadowCaster ) ;
277
283
}
278
284
285
+ // Initialise air hose shapes
286
+
287
+ if ( car . FrontAirHoseShapeFileName != null )
288
+ {
289
+ FrontAirHoseShape = new AnimatedShape ( viewer , wagonFolderSlash + car . FrontAirHoseShapeFileName + '\0 ' + wagonFolderSlash , new WorldPosition ( car . WorldPosition ) , ShapeFlags . ShadowCaster ) ;
290
+ }
291
+
292
+ if ( car . FrontAirHoseDisconnectedShapeFileName != null )
293
+ {
294
+ FrontAirHoseDisconnectedShape = new AnimatedShape ( viewer , wagonFolderSlash + car . FrontAirHoseDisconnectedShapeFileName + '\0 ' + wagonFolderSlash , new WorldPosition ( car . WorldPosition ) , ShapeFlags . ShadowCaster ) ;
295
+ }
296
+
297
+ if ( car . RearAirHoseShapeFileName != null )
298
+ {
299
+ RearAirHoseShape = new AnimatedShape ( viewer , wagonFolderSlash + car . RearAirHoseShapeFileName + '\0 ' + wagonFolderSlash , new WorldPosition ( car . WorldPosition ) , ShapeFlags . ShadowCaster ) ;
300
+ }
301
+
302
+ if ( car . RearAirHoseDisconnectedShapeFileName != null )
303
+ {
304
+ RearAirHoseDisconnectedShape = new AnimatedShape ( viewer , wagonFolderSlash + car . RearAirHoseDisconnectedShapeFileName + '\0 ' + wagonFolderSlash , new WorldPosition ( car . WorldPosition ) , ShapeFlags . ShadowCaster ) ;
305
+ }
306
+
279
307
280
308
if ( car . InteriorShapeFileName != null )
281
309
InteriorShape = new AnimatedShape ( viewer , wagonFolderSlash + car . InteriorShapeFileName + '\0 ' + wagonFolderSlash , car . WorldPosition , ShapeFlags . Interior , 30.0f ) ;
@@ -892,7 +920,8 @@ private void UpdateCouplers(RenderFrame frame, ElapsedTime elapsedTime)
892
920
{
893
921
// Get the movement that would be needed to locate the coupler on the car if they were pointing in the default direction.
894
922
var displacement = new Vector3
895
- { X = Car . FrontCouplerAnimWidthM ,
923
+ {
924
+ X = Car . FrontCouplerAnimWidthM ,
896
925
Y = Car . FrontCouplerAnimHeightM ,
897
926
Z = ( Car . FrontCouplerAnimLengthM + ( Car . CarLengthM / 2.0f ) + Car . FrontCouplerSlackM - Car . WagonFrontCouplerCurveExtM )
898
927
} ;
@@ -993,6 +1022,105 @@ private void UpdateCouplers(RenderFrame frame, ElapsedTime elapsedTime)
993
1022
RearCouplerShape . PrepareFrame ( frame , elapsedTime ) ;
994
1023
}
995
1024
}
1025
+
1026
+ // Display front airhose in sim if open coupler shape is configured, otherwise skip to next section, and just display closed (default) coupler if configured
1027
+ if ( FrontAirHoseShape != null && ! ( Viewer . Camera . AttachedCar == this . MSTSWagon && Viewer . Camera . Style == Camera . Styles . ThreeDimCab ) )
1028
+ {
1029
+ // Get the movement that would be needed to locate the coupler on the car if they were pointing in the default direction.
1030
+ var displacement = new Vector3
1031
+ {
1032
+ X = Car . FrontAirHoseAnimWidthM ,
1033
+ Y = Car . FrontAirHoseAnimHeightM ,
1034
+ Z = ( Car . FrontAirHoseAnimLengthM + ( Car . CarLengthM / 2.0f ) ) // Reversed as this is the rear coupler of the wagon
1035
+ } ;
1036
+
1037
+ if ( Car . CarAhead != null ) // Display animated coupler if there is a car behind this car
1038
+ {
1039
+ var quaternion = PositionCoupler ( Car , FrontAirHoseShape , displacement ) ;
1040
+
1041
+ var quaternionCar = new Quaternion ( quaternion . X , quaternion . Y , quaternion . Z , quaternion . W ) ;
1042
+
1043
+ var maximumCouplerExtension = Me . FromIn ( 3.0f ) ;
1044
+ var AirHoseAngleRadians = ( Car . CouplerSlackM / maximumCouplerExtension ) * 0.174533f ;
1045
+
1046
+ AlignCouplerWithCar ( Car , FrontAirHoseShape ) ;
1047
+
1048
+ AdjustAirHoseAngle ( Car , FrontAirHoseShape , quaternionCar , AirHoseAngleRadians ) ;
1049
+
1050
+ // Display Animation Shape
1051
+ FrontAirHoseShape . PrepareFrame ( frame , elapsedTime ) ;
1052
+
1053
+ }
1054
+ else if ( FrontAirHoseDisconnectedShape != null && Car . RearCouplerOpenFitted && Car . RearCouplerOpen ) // Display open coupler if no car is behind car, and an open coupler shape is present
1055
+ {
1056
+ var quaternion = PositionCoupler ( Car , FrontAirHoseDisconnectedShape , displacement ) ;
1057
+
1058
+ AlignCouplerWithCar ( Car , FrontAirHoseDisconnectedShape ) ;
1059
+
1060
+ // Display Animation Shape
1061
+ FrontAirHoseDisconnectedShape . PrepareFrame ( frame , elapsedTime ) ;
1062
+ }
1063
+ else //Display closed static coupler by default if other conditions not met
1064
+ {
1065
+ var quaternion = PositionCoupler ( Car , FrontAirHoseShape , displacement ) ;
1066
+
1067
+ AlignCouplerWithCar ( Car , FrontAirHoseShape ) ;
1068
+
1069
+ // Display Animation Shape
1070
+ FrontAirHoseShape . PrepareFrame ( frame , elapsedTime ) ;
1071
+ }
1072
+ }
1073
+
1074
+
1075
+ // Display rear airhose in sim if open coupler shape is configured, otherwise skip to next section, and just display closed (default) coupler if configured
1076
+ if ( RearAirHoseShape != null && ! ( Viewer . Camera . AttachedCar == this . MSTSWagon && Viewer . Camera . Style == Camera . Styles . ThreeDimCab ) )
1077
+ {
1078
+ // Get the movement that would be needed to locate the coupler on the car if they were pointing in the default direction.
1079
+ var displacement = new Vector3
1080
+ {
1081
+ X = Car . RearAirHoseAnimWidthM ,
1082
+ Y = Car . RearAirHoseAnimHeightM ,
1083
+ Z = - ( Car . RearAirHoseAnimLengthM + ( Car . CarLengthM / 2.0f ) ) // Reversed as this is the rear coupler of the wagon
1084
+ } ;
1085
+
1086
+ if ( Car . CarBehind != null ) // Display animated coupler if there is a car behind this car
1087
+ {
1088
+ var quaternion = PositionCoupler ( Car , RearAirHoseShape , displacement ) ;
1089
+
1090
+ var quaternionCar = new Quaternion ( quaternion . X , quaternion . Y , quaternion . Z , quaternion . W ) ;
1091
+
1092
+ var maximumCouplerExtension = Me . FromIn ( 3.0f ) ;
1093
+ var AirHoseAngleRadians = - ( Car . CouplerSlackM / maximumCouplerExtension ) * 0.174533f ;
1094
+
1095
+ AlignCouplerWithCar ( Car , RearAirHoseShape ) ;
1096
+
1097
+ AdjustAirHoseAngle ( Car , RearAirHoseShape , quaternionCar , AirHoseAngleRadians ) ;
1098
+
1099
+ // Display Animation Shape
1100
+ RearAirHoseShape . PrepareFrame ( frame , elapsedTime ) ;
1101
+
1102
+ }
1103
+ else if ( RearAirHoseDisconnectedShape != null && Car . RearCouplerOpenFitted && Car . RearCouplerOpen ) // Display open coupler if no car is behind car, and an open coupler shape is present
1104
+ {
1105
+ var quaternion = PositionCoupler ( Car , RearAirHoseDisconnectedShape , displacement ) ;
1106
+
1107
+ AlignCouplerWithCar ( Car , RearAirHoseDisconnectedShape ) ;
1108
+
1109
+ // Display Animation Shape
1110
+ RearAirHoseDisconnectedShape . PrepareFrame ( frame , elapsedTime ) ;
1111
+ }
1112
+ else //Display closed static coupler by default if other conditions not met
1113
+ {
1114
+ var quaternion = PositionCoupler ( Car , RearAirHoseShape , displacement ) ;
1115
+
1116
+ AlignCouplerWithCar ( Car , RearAirHoseShape ) ;
1117
+
1118
+ // Display Animation Shape
1119
+ RearAirHoseShape . PrepareFrame ( frame , elapsedTime ) ;
1120
+ }
1121
+ }
1122
+
1123
+
996
1124
}
997
1125
998
1126
/// <summary>
@@ -1058,11 +1186,31 @@ private void AdjustCouplerAngle(TrainCar adjacentCar, AnimatedShape couplerShape
1058
1186
}
1059
1187
1060
1188
/// <summary>
1061
- /// Rotate the coupler to align with the direction (attitude) of the car.
1189
+ /// Turn coupler the required angle between the cars
1062
1190
/// </summary>
1063
- /// <param name="car "></param>
1191
+ /// <param name="adjacentCar "></param>
1064
1192
/// <param name="couplerShape"></param>
1065
- private void AlignCouplerWithCar ( TrainCar car , AnimatedShape couplerShape )
1193
+ /// <param name="quaternionCar"></param>
1194
+ private void AdjustAirHoseAngle ( TrainCar adjacentCar , AnimatedShape airhoseShape , Quaternion quaternionCar , float angle )
1195
+ {
1196
+ var mRotation = Matrix . CreateRotationZ ( angle ) ;
1197
+
1198
+ // Rotate the coupler to align with the calculated angle direction
1199
+ airhoseShape . Location . XNAMatrix = mRotation * airhoseShape . Location . XNAMatrix ;
1200
+
1201
+ // var mextRotation = Matrix.CreateRotationX(-angle);
1202
+
1203
+ // Rotate the coupler to align with the calculated angle direction
1204
+ // airhoseShape.Location.XNAMatrix = mextRotation * airhoseShape.Location.XNAMatrix;
1205
+
1206
+ }
1207
+
1208
+ /// <summary>
1209
+ /// Rotate the coupler to align with the direction (attitude) of the car.
1210
+ /// </summary>
1211
+ /// <param name="car"></param>
1212
+ /// <param name="couplerShape"></param>
1213
+ private void AlignCouplerWithCar ( TrainCar car , AnimatedShape couplerShape )
1066
1214
{
1067
1215
1068
1216
var p = new WorldPosition ( car . WorldPosition ) ;
0 commit comments