示例#1
0
 /// <inheritdoc />
 public Dictionary <Station, ArrDep> GetArrDepsUnsorted()
 {
     return(baseTrain
            .GetArrDepsUnsorted()
            .ToDictionary(
                kvp => kvp.Key,
                kvp => link.ProcessArrDep(kvp.Value, countingIndex)));
 }
示例#2
0
        public TrainPathData(Timetable tt, ITrain train) : base(tt)
        {
            var path    = train.GetPath().ToArray();
            var arrDeps = train.GetArrDepsUnsorted();

            Entries = Init(path, (s, r) =>
            {
                arrDeps.TryGetValue(s, out var ardp);
                return(new TrainPathEntry(s, ardp, r));
            });
            PathEntries = Entries.OfType <TrainPathEntry>().ToArray();
        }
示例#3
0
        private IEnumerable <Station> GetSortedStations(ITrain train)
        {
            var path    = train.GetPath();
            var arrdeps = train.GetArrDepsUnsorted();

            foreach (var sta in path)
            {
                if (arrdeps[sta].HasMinOneTimeSet)
                {
                    yield return(sta);
                }
            }
        }
示例#4
0
        /// <summary>
        /// Get the direction the train passes through this station.
        /// </summary>
        /// <remarks>This direction may differ from train to train (at the same station) and from station to station (with the same train).</remarks>
        /// <returns>If null, the train does not pass through this station.</returns>
        public TrainDirection?GetTrainDirectionAtStation(ITrain train, Station sta)
        {
            var stasAfter  = GetStationsInDir(TrainDirection.ti, sta);
            var stasBefore = GetStationsInDir(TrainDirection.ta, sta);

            var path = train.GetPath();

            if (!path.Contains(sta))
            {
                return(null);
            }

            var ardeps     = train.GetArrDepsUnsorted();
            var isStopping = ardeps[sta].HasMinOneTimeSet;

            Station?nextStopStation = path.Where(s => stasAfter.Contains(s)).FirstOrDefault(s => ardeps[s].HasMinOneTimeSet);
            Station?lastStopStation = null;

            if (nextStopStation == null || !isStopping)
            {
                lastStopStation = path.Where(s => stasBefore.Contains(s)).FirstOrDefault(s => ardeps[s].HasMinOneTimeSet);
            }

            // We have a stop at this station, use time difference between first/last and current.
            if (isStopping)
            {
                if (nextStopStation == null)
                {
                    if (lastStopStation == null)
                    {
                        return(null);
                    }
                    var lastStopTime = ardeps[lastStopStation].LastSetTime;
                    return(lastStopTime < ardeps[sta].FirstSetTime ? TrainDirection.ti : TrainDirection.ta);
                }

                var nextStopTime = ardeps[nextStopStation].FirstSetTime;
                return(nextStopTime > ardeps[sta].LastSetTime ? TrainDirection.ti : TrainDirection.ta);
            }

            if (lastStopStation == null || nextStopStation == null)
            {
                return(null); // We are (proven!) not running over this station.
            }
            // Passthrough, use difference between first and last
            return(ardeps[nextStopStation].FirstSetTime > ardeps[lastStopStation].LastSetTime ? TrainDirection.ti : TrainDirection.ta);
        }
示例#5
0
        public void Render(Graphics g, ITrain train, bool exportColor)
        {
            var style = new TrainStyle(train, attrs);

            if (!style.CalcedShow)
            {
                return;
            }

            var ardps = train.GetArrDepsUnsorted();
            var dir   = GetTrainDirection(train);

            using var pen = new Pen(style.CalcedColor.ToSD(exportColor), style.CalcedWidth)
                  {
                      DashPattern = ds.ParseDashstyle(style.CalcedLineStyle)
                  };
            using var brush = new SolidBrush(style.CalcedColor.ToSD(exportColor));

            List <PointF> points = new List <PointF>();
            bool          hadFirstArrival = false, hadLastDeparture = false, isFirst = true;
            var           stas = dir ? Enumerable.Reverse(stations) : stations;

            int trainTravelsRouteCount = 0;

            foreach (var sta in stas)
            {
                if (!ardps.ContainsKey(sta))
                {
                    continue;
                }
                var ardp = ardps[sta];
                trainTravelsRouteCount++;

                if (!ardp.HasMinOneTimeSet)
                {
                    continue;
                }

                MaybeAddPoint(points, GetGutterPoint(true, dir, stationOffsets[sta], ardp.Arrival));
                MaybeAddPoint(points, GetInternalPoint(stationOffsets[sta], ardp.Arrival, ardp.ArrivalTrack));

                foreach (var shunt in ardp.ShuntMoves)
                {
                    MaybeAddPoint(points, GetInternalPoint(stationOffsets[sta], shunt.Time, shunt.SourceTrack));
                    MaybeAddPoint(points, GetInternalPoint(stationOffsets[sta], shunt.Time, shunt.TargetTrack));
                }

                MaybeAddPoint(points, GetInternalPoint(stationOffsets[sta], ardp.Departure, ardp.DepartureTrack));
                MaybeAddPoint(points, GetGutterPoint(false, dir, stationOffsets[sta], ardp.Departure));

                hadLastDeparture = ardp.Departure != default;
                if (isFirst)
                {
                    hadFirstArrival = ardp.Arrival != default;
                }
                isFirst = false;
            }

            // Halbe Linien bei Abfahrten / Ankünften ohne Gegenstelle
            if (attrs.DrawNetworkTrains)
            {
                var hly = !dir ? 20 : -20;
                if (hadLastDeparture)
                {
                    points.Add(points.Last() + new Size(50, hly));
                }
                if (hadFirstArrival)
                {
                    points.Insert(0, points.First() - new Size(50, hly));
                }
            }
            else if (trainTravelsRouteCount <= 1)
            {
                return; // This train has only one station on this route and we don't draw network trains.
            }
            if (points.Count == 0)
            {
                return; // This train is not travelling on this route
            }
            // Transition to the next train; filtered by days and station.
            var lastStaOfFirst = GetSortedStations(train)?.LastOrDefault();
            var transition     = tt.GetTransition(train, renderDays, lastStaOfFirst);

            if (transition != null && !hadLastDeparture && attrs.StationLines != StationLineStyle.None && transition.Days.IsIntersecting(renderDays))
            {
                var firstStaOfNext = GetSortedStations(transition)?.FirstOrDefault();

                if (lastStaOfFirst == firstStaOfNext)
                {
                    var departure = transition.GetArrDep(firstStaOfNext).Departure;
                    points.Add(new PointF(points.Last().X, GetTimeY(departure)));
                }
            }

            using var p = new GraphicsPath();

            for (int i = 0; i < points.Count; i += 1)
            {
                if (points.Count <= i + 1)
                {
                    continue;
                }

                var isStationLine = (int)points[i].X == (int)points[i + 1].X;
                if (isStationLine)
                {
                    var preX         = i > 0 ? points[i - 1].X : 0;
                    var postX        = i < points.Count - 2 ? points[i + 2].X : 0;
                    var x            = points[i].X;
                    var isTransition = isStationLine && (points.Count == i + 2 || Math.Sign(preX - x) == Math.Sign(postX - x));

                    float bezierFactor = !isTransition ?
                                         ((preX < postX) ? -1 : 1) : // preX < postX --> TrainDirection.ti
                                         Math.Sign(preX - x);        // Transition
                    if (isTransition)
                    {
                        bezierFactor *= 0.5f;
                    }
                    var bezierOffset  = new SizeF(bezierFactor * 14, (points[i + 1].Y - points[i].Y) / -4.0f);
                    var bezierOffsetT = new SizeF(bezierOffset.Width, -bezierOffset.Height);

                    switch (attrs.StationLines)
                    {
                    case StationLineStyle.None:
                        p.MoveTo(points[i + 1]);
                        break;

                    case StationLineStyle.Normal:
                        p.AddLine(points[i], points[i + 1]);
                        break;

                    case StationLineStyle.Cubic:
                        var control2 = points[i + 1] + (!isTransition ? bezierOffset : (SizeF.Empty - bezierOffsetT));
                        p.AddBezier(points[i], points[i] - bezierOffset, control2, points[i + 1]);
                        break;
                    }
                }
                else
                {
                    p.AddLine(points[i], points[i + 1]); // Normal line between stations
                }
                if (points[i].X == points[i + 1].X || points[i].Y == points[i + 1].Y)
                {
                    continue;
                }
                // Zugnummern zeichnen
                var trainFont = (Font)attrs.TrainFont;

                var     size = g.MeasureString(trainFont, train.TName);
                float[] ys   = { points[i].Y, points[i + 1].Y };
                float[] xs   = { points[i].X, points[i + 1].X };
                float   ty   = ys.Min() + (ys.Max() - ys.Min()) / 2 - (size.Height / 2);
                float   tx   = xs.Min() + (xs.Max() - xs.Min()) / 2;

                if (g.Clip.IsVisible(new PointF(tx, ty))) // translated drawing does not respect clip (Idk why)
                {
                    float angle = CalcAngle(ys, xs, train);

                    var matrix = g.Transform.Clone();

                    g.TranslateTransform(tx, ty);
                    g.RotateTransform(-angle);
                    g.DrawText(trainFont, brush, -(size.Width / 2), -(size.Height / 2), train.TName);

                    g.Transform = matrix;
                }
            }
            g.DrawPath(pen, p);
        }