public string?GetTrack(ITrain train, Station sta, TrainDirection dir, ArrDep timetableEntry, TrackQuery track) { var path = new TrainPathData(train.ParentTimetable, train); if (!path.ContainsStation(sta)) { return(null); } var exitRoute = path.GetExitRoute(sta); if (track == TrackQuery.Departure) { return(Fallback(timetableEntry.DepartureTrack, Fallback(timetableEntry.ArrivalTrack, Fallback(dir == TrainDirection.ti ? sta.DefaultTrackRight.GetValue(exitRoute) : sta.DefaultTrackLeft.GetValue(exitRoute), "")))); } return(Fallback(timetableEntry.ArrivalTrack, Fallback(timetableEntry.DepartureTrack, Fallback(dir == TrainDirection.ti ? sta.DefaultTrackRight.GetValue(exitRoute) : sta.DefaultTrackLeft.GetValue(exitRoute), "")))); }
public IEnumerable <string> Check(Timetable tt) { var result = new ConcurrentBag <string>(); Parallel.ForEach(tt.Trains, train => { var arrdeps = new TrainPathData(train.ParentTimetable, train); TimeEntry last = default; foreach (var arrdep in arrdeps.PathEntries) { if (arrdep.ArrDep == null) { continue; } if (arrdep.ArrDep.HasMinOneTimeSet && arrdep.ArrDep.FirstSetTime < last) { result.Add(T._("Der Zug {0} verkehrt über Mitternacht hinweg!", train.TName)); return; } last = arrdep.ArrDep.Departure == default ? arrdep.ArrDep.Arrival : arrdep.ArrDep.Departure; } }); return(result); }
public IEnumerable <string> Check(Timetable tt) { foreach (var train in tt.Trains) { var arrdeps = new TrainPathData(train._parent, train); TimeSpan last = default; bool hasOverflow = false; foreach (var arrdep in arrdeps.PathEntries) { if (arrdep.ArrDep == null) { continue; } if (arrdep.ArrDep.HasMinOneTimeSet && arrdep.ArrDep.FirstSetTime < last) { hasOverflow = true; } last = arrdep.ArrDep.Departure == default ? arrdep.ArrDep.Arrival : arrdep.ArrDep.Departure; } if (hasOverflow) { yield return($"Der Zug {train.TName} verkehrt über Mitternacht hinweg!"); } } }
public bool Export(Timetable tt, string filename, IInfo info) { if (tt.Type == TimetableType.Network) { throw new Exception("Der Fahrplan ist bereits ein Netzwerk-Fahrplan"); } var clone = tt.Clone(); var trainPaths = new Dictionary <Train, TrainPathData>(); foreach (var orig in clone.Trains) { trainPaths[orig] = new TrainPathData(clone, orig); } var rt = Timetable.LINEAR_ROUTE_ID.ToString(); var id = 0; var y = 0; foreach (var sta in clone.Stations) { ConvertStationLinToNet(sta); sta.SetAttribute("fpl-rt", rt); sta.SetAttribute("fpl-pos", (y += 40).ToString() + ";0"); sta.SetAttribute("fpl-id", id++.ToString()); } var actions = info.GetRegistered <ITimetableTypeChangeAction>(); foreach (var action in actions) { action.ToNetwork(clone); } clone.SetAttribute("version", TimetableVersion.Extended_FPL.ToNumberString()); foreach (var train in clone.Trains) { var data = trainPaths[train]; train.Children.Clear(); train.AddAllArrDeps(data.GetRawPath()); train.XMLEntity.XName = "tr"; foreach (var sta in data.PathEntries) { if (sta.ArrDep != null) { train.GetArrDep(sta.Station).ApplyCopy(sta.ArrDep); } } } ColorTimetableConverter.ConvertAll(clone); return(new XMLExport().Export(clone, filename, info)); }
/// <summary> /// Perform a deep copy on the current instance /// </summary> /// <returns>The copied instance.</returns> public TrainPathData DeepCopy() { TrainPathData newData = (TrainPathData)this.MemberwiseClone(); newData.firstNode = DeepCopyOfLinkedNodes(firstNode); newData.firstNodeOfTail = DeepCopyOfLinkedNodes(firstNodeOfTail); return(newData); }
/// <summary> /// Store the current path (without metadata), so we can undo later. /// This is done by making a deep copy of path (as defined by nodes), and putting the copy in the list. /// This makes sure that the currently active references are still pointing to nodes in the current active path. /// </summary> public void StoreCurrentPath() { int newIndex = currentIndex + 1; if (trainPaths.Count > newIndex) { trainPaths.RemoveRange(newIndex, trainPaths.Count - newIndex); } // insert copy just before current active one TrainPathData newTrainData = trainPaths[currentIndex].DeepCopy(); trainPaths.Insert(currentIndex, newTrainData); currentIndex = newIndex; //Since we store the path, we must assume something has been modified (or will in a jiffy) IsModified = true; }
private IEnumerable <ITrain> IntersectTrainsAtStations(ITrain ot, Station s, bool crossing) { var probeTrainStart = ot.GetArrDep(s).Arrival; var probeTrainEnd = ot.GetArrDep(s).Departure; if (probeTrainStart == TimeEntry.Zero || probeTrainEnd == TimeEntry.Zero) { yield break; } // Prepare matching criteria for trains collection Func <ITrain, bool> pred; if (tt.Type == TimetableType.Linear) { pred = t => t.Direction == ot.Direction; // Overtaking if (crossing) { pred = t => t.Direction != ot.Direction; // Crossing } } else { var surrounding = new TrainPathData(tt, ot).GetSurroundingStations(s, 1); pred = t => { var p = new TrainPathData(tt, t).GetSurroundingStations(s, 1); var x = new int[p.Length]; for (int i = 0; i < p.Length; i++) { x[i] = Array.IndexOf(surrounding, p[i]); } // We have only one station in common (the center station), this is definitely a crossing (from another route) if (x.Count(i => i >= 0) < 2) { return(crossing); } var compare = x.FirstOrDefault().CompareTo(x.LastOrDefault()); return(crossing ? compare > 0 : compare < 0); }; } foreach (var train in tt.Trains.Where(pred)) { if (train == ot || !train.GetPath().Contains(s)) { continue; } var ardp = train.GetArrDep(s); var curTrainStart = ardp.Arrival; var curTrainEnd = ardp.Departure; if (curTrainStart == TimeEntry.Zero || curTrainEnd == TimeEntry.Zero) { continue; } var st = probeTrainStart < curTrainStart ? curTrainStart : probeTrainStart; var en = probeTrainEnd < curTrainEnd ? probeTrainEnd : curTrainEnd; var isCrossing = st <= en; if (isCrossing && ot.Days.IsIntersecting(train.Days)) { yield return(train); } } }
public bool Export(Timetable tt, Stream stream, IReducedPluginInterface pluginInterface, string[] flags = null) { if (tt.Type == TimetableType.Linear) { throw new TimetableTypeNotSupportedException(TimetableType.Linear, "convert to linear"); } if (tt.GetRoutes().Length != 1) { throw new NotSupportedException(T._("Der Fahrplan hat mehr als eine oder keine Strecke")); } if (tt.Version.CompareTo(TimetableVersion.Extended_FPL2) >= 0 && Timetable.DefaultLinearVersion.CompareTo(TimetableVersion.JTG3_3) < 0) { throw new NotSupportedException(T._("Eine Fahrplandatei der Version >= 101 kann nicht als lineare Datei <= 012 exportiert werden!")); } var clone = tt.Clone(); var trainPaths = new Dictionary <ITrain, TrainPathData>(); foreach (var orig in clone.Trains) { trainPaths[orig] = new TrainPathData(clone, orig); } var route = clone.GetRoutes().Single().Index; foreach (var sta in clone.Stations) { ConvertStationNetToLin(sta, route); sta.RemoveAttribute("fpl-rt"); sta.RemoveAttribute("fpl-pos"); sta.RemoveAttribute("fpl-id"); } var actions = pluginInterface.GetRegistered <ITimetableTypeChangeAction>(); foreach (var action in actions) { action.ToLinear(clone); } clone.SetVersion(Timetable.DefaultLinearVersion); var sortedStations = clone.GetRoutes()[Timetable.LINEAR_ROUTE_ID].Stations; foreach (var t in clone.Trains) { var data = trainPaths[t]; var sta1 = data.PathEntries.FirstOrDefault()?.Station; var sta2 = data.PathEntries.LastOrDefault()?.Station; var dir = TrainDirection.ti; if (sta1 != sta2) { if (sortedStations.IndexOf(sta1) > sortedStations.IndexOf(sta2)) { dir = TrainDirection.ta; } } else if (sortedStations.IndexOf(sta1) == sortedStations.Count - 1) { dir = TrainDirection.ta; } t.XMLEntity.XName = dir.ToString(); if (!(t is IWritableTrain wt)) { continue; } wt.Children.Clear(); // Clear all existing arrdeps... wt.AddLinearArrDeps(); // ...and re-add all linear ones. foreach (var sta in data.PathEntries) { if (sta.ArrDep != null) { t.GetArrDep(sta.Station).ApplyCopy(sta.ArrDep); } } } return(new XMLExport().Export(clone, stream, pluginInterface)); }
public bool Export(Timetable tt, string filename, IInfo info) { if (tt.Type == TimetableType.Linear) { throw new Exception("Der Fahrplan ist bereits ein Linear-Fahrplan"); } if (tt.GetRoutes().Count() != 1) { throw new Exception("Der Fahrplan hat mehr als eine oder keine Strecke"); } var clone = tt.Clone(); var trainPaths = new Dictionary <Train, TrainPathData>(); foreach (var orig in clone.Trains) { trainPaths[orig] = new TrainPathData(clone, orig); } var route = clone.GetRoutes().FirstOrDefault().Index; foreach (var sta in clone.Stations) { ConvertStationNetToLin(sta, route, Timetable.DefaultLinearVersion); sta.RemoveAttribute("fpl-rt"); sta.RemoveAttribute("fpl-pos"); sta.RemoveAttribute("fpl-id"); } var actions = info.GetRegistered <ITimetableTypeChangeAction>(); foreach (var action in actions) { action.ToLinear(clone); } clone.SetAttribute("version", Timetable.DefaultLinearVersion.ToNumberString()); var sortedStations = clone.GetRoutes()[Timetable.LINEAR_ROUTE_ID].GetOrderedStations(); foreach (var t in clone.Trains) { var data = trainPaths[t]; var sta1 = data.PathEntries.FirstOrDefault()?.Station; var sta2 = data.PathEntries.LastOrDefault()?.Station; var dir = TrainDirection.ti; if (sta1 != sta2) { if (sortedStations.IndexOf(sta1) > sortedStations.IndexOf(sta2)) { dir = TrainDirection.ta; } } else if (sortedStations.IndexOf(sta1) == sortedStations.Count - 1) { dir = TrainDirection.ta; } t.XMLEntity.XName = dir.ToString(); t.Children.Clear(); t.AddLinearArrDeps(); foreach (var sta in data.PathEntries) { if (sta.ArrDep != null) { t.GetArrDep(sta.Station).ApplyCopy(sta.ArrDep); } } } ColorTimetableConverter.ConvertAll(clone); return(new XMLExport().Export(clone, filename, info)); }
public bool Export(Timetable tt, Stream stream, IReducedPluginInterface pluginInterface, string[] flags = null) { if (tt.Type == TimetableType.Network) { throw new TimetableTypeNotSupportedException(TimetableType.Network, "convert to network"); } if (tt.Version.CompareTo(TimetableVersion.JTG3_3) <= 0) { pluginInterface.Logger.Error(T._("Bitte zuerst die lineare Strecke auf die neueste Version aktualisieren!")); return(false); } var clone = tt.Clone(); var trainPaths = new Dictionary <ITrain, TrainPathData>(); foreach (var orig in clone.Trains) { trainPaths[orig] = new TrainPathData(clone, orig); } var rt = Timetable.LINEAR_ROUTE_ID.ToString(); var id = 0; var y = 0; foreach (var sta in clone.Stations) { ConvertStationLinToNet(sta); sta.SetAttribute("fpl-rt", rt); // Normally this would need a cache invalidation, but here it does not. sta.SetAttribute("fpl-pos", (y += 40).ToString() + ";0"); sta.SetAttribute("fpl-id", id++.ToString()); } var actions = pluginInterface.GetRegistered <ITimetableTypeChangeAction>(); foreach (var action in actions) { action.ToNetwork(clone); } clone.SetVersion(TimetableVersion.Extended_FPL2); foreach (var train in clone.Trains) { var data = trainPaths[train]; if (!(train is IWritableTrain wt)) { continue; } wt.Children.Clear(); wt.AddAllArrDeps(data.GetRawPath()); wt.XMLEntity.XName = "tr"; foreach (var sta in data.PathEntries) { if (sta.ArrDep != null) { wt.GetArrDep(sta.Station).ApplyCopy(sta.ArrDep); } } } return(new XMLExport().Export(clone, stream, pluginInterface)); }