private void GetNewState(double Time, out double NewMileage, out double NewPosition, out TravelDirection NewDirection, out bool OpenLeftDoors, out bool OpenRightDoors) { double DeltaT; double DeltaPosition; OpenLeftDoors = false; OpenRightDoors = false; { // The first point must be TravelStopData. TravelStopData FirstData = (TravelStopData)Data[0]; NewMileage = FirstData.Mileage; NewPosition = FirstData.Position; NewDirection = FirstData.Direction; if (Time <= FirstData.ArrivalTime) { return; } if (Time <= FirstData.ClosingDoorsStartTime) { OpenLeftDoors = FirstData.OpenLeftDoors; OpenRightDoors = FirstData.OpenRightDoors; return; } if (Time <= FirstData.DepartureTime) { return; } // The start point does not slow down. Acceleration only. if (Time <= FirstData.AccelerationEndTime) { DeltaT = Time - FirstData.DepartureTime; DeltaPosition = 0.5 * FirstData.Accelerate * Math.Pow(DeltaT, 2.0); NewMileage += DeltaPosition; NewPosition += (int)NewDirection * DeltaPosition; return; } NewMileage += Math.Abs(FirstData.AccelerationEndPosition - NewPosition); NewPosition = FirstData.AccelerationEndPosition; } for (int i = 1; i < Data.Length; i++) { if (Time <= Data[i].DecelerationStartTime) { DeltaT = Time - Data[i - 1].AccelerationEndTime; DeltaPosition = Data[i - 1].TargetSpeed * DeltaT; NewMileage += DeltaPosition; NewPosition += (int)NewDirection * DeltaPosition; return; } NewMileage += Math.Abs(Data[i].DecelerationStartPosition - NewPosition); NewPosition = Data[i].DecelerationStartPosition; if (Time <= Data[i].ArrivalTime) { DeltaT = Time - Data[i].DecelerationStartTime; DeltaPosition = Data[i - 1].TargetSpeed * DeltaT + 0.5 * Data[i].Decelerate * Math.Pow(DeltaT, 2.0); NewMileage += DeltaPosition; NewPosition += (int)NewDirection * DeltaPosition; return; } TravelStopData StopData = Data[i] as TravelStopData; NewMileage = Data[i].Mileage; NewPosition = Data[i].Position; NewDirection = StopData?.Direction ?? NewDirection; if (Time <= StopData?.ClosingDoorsStartTime) { OpenLeftDoors = StopData.OpenLeftDoors; OpenRightDoors = StopData.OpenRightDoors; return; } // The end point does not accelerate. if (Time <= Data[i].DepartureTime || i == Data.Length - 1) { return; } if (Time <= Data[i].AccelerationEndTime) { DeltaT = Time - Data[i].DepartureTime; DeltaPosition = Data[i].PassingSpeed * DeltaT + 0.5 * Data[i].Accelerate * Math.Pow(DeltaT, 2.0); NewMileage += DeltaPosition; NewPosition += (int)NewDirection * DeltaPosition; return; } NewMileage += Math.Abs(Data[i].AccelerationEndPosition - NewPosition); NewPosition = Data[i].AccelerationEndPosition; } }
/// <summary>Create a train operation plan.</summary> internal void SetupTravelData(double InitializeTime) { // The first point must be TravelStopData. TravelStopData FirstData = (TravelStopData)Data[0]; // Calculate the end point of acceleration and the start point of deceleration. { TravelDirection LastDirection; double DeltaPosition; // The start point does not slow down. Acceleration only. { FirstData.Mileage = 0.0; LastDirection = FirstData.Direction; DeltaPosition = 0.0; if (FirstData.Accelerate != 0.0) { DeltaPosition = Math.Pow(FirstData.TargetSpeed, 2.0) / (2.0 * FirstData.Accelerate); } FirstData.AccelerationEndPosition = FirstData.Position + (int)LastDirection * DeltaPosition; } for (int i = 1; i < Data.Length; i++) { DeltaPosition = 0.0; if (Data[i].Decelerate != 0.0) { DeltaPosition = (Math.Pow(Data[i].PassingSpeed, 2.0) - Math.Pow(Data[i - 1].TargetSpeed, 2.0)) / (2.0 * Data[i].Decelerate); } Data[i].DecelerationStartPosition = Data[i].Position - (int)LastDirection * DeltaPosition; Data[i].Mileage = Data[i - 1].Mileage + Math.Abs(Data[i].Position - Data[i - 1].Position); LastDirection = (Data[i] as TravelStopData)?.Direction ?? LastDirection; DeltaPosition = 0.0; if (Data[i].Accelerate != 0.0) { DeltaPosition = (Math.Pow(Data[i].TargetSpeed, 2.0) - Math.Pow(Data[i].PassingSpeed, 2.0)) / (2.0 * Data[i].Accelerate); } Data[i].AccelerationEndPosition = Data[i].Position + (int)LastDirection * DeltaPosition; } } // Time to operate the door double OpeningDoorsTime = 0.0; double ClosingDoorsTime = 0.0; if (Train.Cars[0].Specs.DoorOpenFrequency != 0.0) { OpeningDoorsTime = 1.0 / Train.Cars[0].Specs.DoorOpenFrequency; } if (Train.Cars[0].Specs.DoorCloseFrequency != 0.0) { ClosingDoorsTime = 1.0 / Train.Cars[0].Specs.DoorCloseFrequency; } // Reflect the delay until the TFO becomes effective at the first point. { FirstData.ArrivalTime = InitializeTime; AppearanceTime = InitializeTime; LeaveTime = Train.LeaveTime + InitializeTime; FirstData.OpeningDoorsEndTime = FirstData.ArrivalTime; if (FirstData.OpenLeftDoors || FirstData.OpenRightDoors) { FirstData.OpeningDoorsEndTime += OpeningDoorsTime; } FirstData.ClosingDoorsStartTime = FirstData.OpeningDoorsEndTime + FirstData.StopTime; FirstData.DepartureTime = FirstData.ClosingDoorsStartTime; if (FirstData.OpenLeftDoors || FirstData.OpenRightDoors) { FirstData.DepartureTime += ClosingDoorsTime; } } // Calculate the time of each point. { double DeltaT; // The start point does not slow down. Acceleration only. { DeltaT = 0.0; if (FirstData.Accelerate != 0.0) { DeltaT = FirstData.TargetSpeed / FirstData.Accelerate; } FirstData.AccelerationEndTime = FirstData.DepartureTime + DeltaT; } for (int i = 1; i < Data.Length; i++) { DeltaT = 0.0; if (Data[i - 1].TargetSpeed != 0.0) { DeltaT = Math.Abs(Data[i].DecelerationStartPosition - Data[i - 1].AccelerationEndPosition) / Data[i - 1].TargetSpeed; } Data[i].DecelerationStartTime = Data[i - 1].AccelerationEndTime + DeltaT; DeltaT = 0.0; if (Data[i].Decelerate != 0.0) { DeltaT = (Data[i].PassingSpeed - Data[i - 1].TargetSpeed) / Data[i].Decelerate; } Data[i].ArrivalTime = Data[i].DecelerationStartTime + DeltaT; TravelStopData StopData = Data[i] as TravelStopData; if (StopData != null) { StopData.OpeningDoorsEndTime = StopData.ArrivalTime; if (StopData.OpenLeftDoors || StopData.OpenRightDoors) { StopData.OpeningDoorsEndTime += OpeningDoorsTime; } StopData.ClosingDoorsStartTime = StopData.OpeningDoorsEndTime + StopData.StopTime; StopData.DepartureTime = StopData.ClosingDoorsStartTime; if (StopData.OpenLeftDoors || StopData.OpenRightDoors) { StopData.DepartureTime += ClosingDoorsTime; } } DeltaT = 0.0; if (Data[i].Accelerate != 0.0) { DeltaT = (Data[i].TargetSpeed - Data[i].PassingSpeed) / Data[i].Accelerate; } Data[i].AccelerationEndTime = Data[i].DepartureTime + DeltaT; } } }