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> /// Function to parse the contents of TravelStopData class /// </summary> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="SectionElement">The XElement to parse</param> /// <returns>An instance of the new TravelStopData class with the parse result applied</returns> private static TravelStopData ParseTravelStopNode(string FileName, XElement SectionElement) { string Section = SectionElement.Name.LocalName; TravelStopData Data = new TravelStopData(); ParseTravelDataNode(FileName, SectionElement, Data); foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "stoptime": if (Value.Any() && !Interface.TryParseTime(Value, out Data.StopTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "doors": { int Door = 0; bool DoorBoth = false; switch (Value.ToLowerInvariant()) { case "l": case "left": Door = -1; break; case "r": case "right": Door = 1; break; case "n": case "none": case "neither": Door = 0; break; case "b": case "both": DoorBoth = true; break; default: if (Value.Any() && !NumberFormats.TryParseIntVb6(Value, out Door)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; } Data.OpenLeftDoors = Door < 0.0 | DoorBoth; Data.OpenRightDoors = Door > 0.0 | DoorBoth; } break; case "direction": { int d = 0; switch (Value.ToLowerInvariant()) { case "f": d = 1; break; case "r": d = -1; break; default: if (Value.Any() && (!NumberFormats.TryParseIntVb6(Value, out d) || !Enum.IsDefined(typeof(TravelDirection), d))) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); d = 1; } break; } Data.Direction = (TravelDirection)d; } break; case "decelerate": case "position": case "stopposition": case "accelerate": case "targetspeed": case "rail": // Already parsed break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } return(Data); }
/// <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; } } }