コード例 #1
0
        public void Render(Graphics g, Train train)
        {
            var style = new TrainStyle(train, attrs);

            if (!style.CalcedShow)
            {
                return;
            }

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

            using (var pen = new Pen((Color)style.CalcedColor, style.CalcedWidth)
            {
                DashStyle = ds.ParseDashstyle(style.CalcedLineStyle)
            })
                using (var brush = new SolidBrush((Color)style.CalcedColor))
                {
                    List <PointF> points = new List <PointF>();
                    bool          hadFirstArrival = false, hadLastDeparture = false, isFirst = true;
                    var           stas = dir ? Enumerable.Reverse(stations) : stations;

                    //TODO: Those helpers are ugly in this part of the code...
                    // Render helpers
                    float GetTimeY(TimeSpan time) => margin.Top + ((time - startTime).GetMinutes() * attrs.HeightPerHour / 60f);

                    PointF?GetGutterPoint(bool arrival, StationX sx, TimeSpan time)
                    {
                        if (time == default)
                        {
                            return(null);
                        }
                        var x = arrival ^ dir ? sx.Left : sx.Right;

                        return(new PointF(margin.Left + x, GetTimeY(time)));
                    }

                    PointF?GetInternalPoint(StationX sx, TimeSpan time, string track)
                    {
                        if (time == default || track == null || !sx.TrackOffsets.TryGetValue(track, out float x))
                        {
                            return(null);
                        }
                        return(new PointF(margin.Left + x, GetTimeY(time)));
                    }

                    void MaybeAddPoint(PointF?point)
                    {
                        if (point.HasValue)
                        {
                            points.Add(point.Value);
                        }
                    }

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

                        if (!ardp.HasMinOneTimeSet)
                        {
                            continue;
                        }

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

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

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

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

                    // Halbe Linien bei Abfahrten / Ankünften ohne Gegenstelle
                    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));
                    }

                    // Verbindung zum Folgezug
                    var transition = tt.GetTransition(train);
                    if (transition != null && !hadLastDeparture && attrs.StationLines != StationLineStyle.None)
                    {
                        var lastStaOfFirst = GetSortedStations(train)?.LastOrDefault();
                        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);        // Bei Transitions
                                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 : -bezierOffsetT);
                                    p.AddBezier(points[i], points[i] - bezierOffset, control2, points[i + 1]);
                                    break;
                                }
                            }
                            else
                            {
                                p.AddLine(points[i], points[i + 1]); // Normale Zuglinie
                            }
                            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   = new[] { points[i].Y, points[i + 1].Y };
                            float[] xs   = new[] { 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;

                            float angle = CalcAngle(ys, xs, train);
                            g.SaveTransform();
                            g.TranslateTransform(tx, ty);
                            g.RotateTransform(-angle);
                            g.DrawText(trainFont, brush, -(size.Width / 2), -(size.Height / 2), train.TName);
                            g.RestoreTransform();
                        }
                        g.DrawPath(pen, p);
                    }
                }
        }
コード例 #2
0
ファイル: TrainRenderer.cs プロジェクト: FPLedit/FPLedit
        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);
        }
コード例 #3
0
ファイル: HeaderRenderer.cs プロジェクト: fadoe/FPLedit
        public Dictionary <Station, StationX> Render(Graphics g, Margins margin, float width, float height, bool drawHeader)
        {
            var stationFont    = (Font)attrs.StationFont; // Reminder: Do not dispose, will be disposed with MFont instance!
            var firstStation   = stations.First();
            var lastStation    = stations.Last();
            var stationOffsets = new Dictionary <Station, StationX>();

            var allTrackCount  = stations.Select(s => s.Tracks.Count).Sum();
            var stasWithTracks = stations.Count(s => s.Tracks.Any());
            var allTrackWidth  = (stasWithTracks + allTrackCount) * StationX.IndividualTrackOffset;

            var emSize = g.MeasureString(stationFont, "M").Width;

            StationX lastPos = null;

            foreach (var sta in stations)
            {
                var style = new StationStyle(sta, attrs);

                var kil    = sta.Positions.GetPosition(route) - firstStation.Positions.GetPosition(route);
                var length = lastStation.Positions.GetPosition(route) - firstStation.Positions.GetPosition(route);

                if (!kil.HasValue || !length.HasValue)
                {
                    throw new Exception("Unerwarteter Fehler beim Rendern der Route!");
                }

                StationX posX;
                if (!attrs.MultiTrack)
                {
                    posX = new StationX(sta, kil.Value, ((kil / length) * (width - margin.Right - margin.Left)).Value);
                }
                else
                {
                    var availWidth = width - margin.Right - margin.Left - allTrackWidth;
                    var lastKil    = lastPos?.CurKilometer ?? 0f;
                    var lastRight  = lastPos?.Right ?? 0f;
                    var leftOffset = (((kil / length) - (lastKil / length)) * availWidth).Value;
                    posX = new StationX(sta, kil.Value, lastRight + leftOffset, true);
                }
                lastPos = posX;
                stationOffsets.Add(sta, posX);

                if (!style.CalcedShow)
                {
                    continue;
                }

                using (var pen = new Pen((Color)style.CalcedColor, style.CalcedWidth)
                {
                    DashStyle = ds.ParseDashstyle(style.CalcedLineStyle)
                })
                    using (var brush = new SolidBrush((Color)style.CalcedColor))
                    {
                        if (!attrs.MultiTrack)
                        {
                            // Linie (Single-Track-Mode)
                            g.DrawLine(pen, margin.Left + posX.Center, margin.Top - 5, margin.Left + posX.Center, height - margin.Bottom);
                        }
                        else
                        {
                            // Linie (Multi-Track-Mode)
                            g.DrawLine(pen, margin.Left + posX.Left, margin.Top - 5, margin.Left + posX.Left, height - margin.Bottom);
                            foreach (var trackX in posX.TrackOffsets)
                            {
                                g.DrawLine(pen, margin.Left + trackX.Value, margin.Top - 5, margin.Left + trackX.Value, height - margin.Bottom);
                            }
                            g.DrawLine(pen, margin.Left + posX.Right, margin.Top - 5, margin.Left + posX.Right, height - margin.Bottom);
                        }

                        if (!drawHeader)
                        {
                            continue;
                        }

                        // Stationsnamen
                        if (attrs.DrawHeader)
                        {
                            var display = sta.ToString(attrs.DisplayKilometre, route);
                            var size    = g.MeasureString(stationFont, display);

                            var addOffset = attrs.MultiTrack ? emSize + 3 : 0;

                            if (attrs.StationVertical)
                            {
                                g.SaveTransform();
                                g.TranslateTransform(margin.Left + posX.Center + (size.Height / 2), margin.Top - 8 - addOffset - size.Width);
                                g.RotateTransform(90);
                                g.DrawText(stationFont, brush, 0, 0, display);
                                g.RestoreTransform();
                            }
                            else
                            {
                                g.DrawText(stationFont, brush, margin.Left + posX.Center - (size.Width / 2), margin.Top - size.Height - addOffset - 5, display);
                            }

                            if (attrs.MultiTrack)
                            {
                                foreach (var track in posX.TrackOffsets)
                                {
                                    var trackSize = g.MeasureString(stationFont, track.Key);
                                    g.DrawText(stationFont, brush, margin.Left + track.Value - (trackSize.Width / 2), margin.Top - trackSize.Height - 5, track.Key);
                                }
                            }
                        }
                    }// Disposing Pens and Brushes
            }
            return(stationOffsets);
        }
コード例 #4
0
        public Dictionary <Station, StationRenderProps> Render(Graphics g, Margins margin, float width, float height, bool drawHeader, bool exportColor)
        {
            var stationFont    = (Font)attrs.StationFont; // Reminder: Do not dispose, will be disposed with MFont instance!
            var stationOffsets = new Dictionary <Station, StationRenderProps>();

            var raw                 = path.GetRawPath().ToList();
            var allTrackCount       = raw.Select(s => s.Tracks.Count).Sum();
            var stasWithTracks      = raw.Count(s => s.Tracks.Any());
            var allTrackWidth       = (stasWithTracks + allTrackCount) * StationRenderProps.IndividualTrackOffset;
            var verticalTrackOffset = GetTrackOffset(g, stationFont) + TOP_GAP;

            float length = 0f;

            PathEntry lastpe = null;

            foreach (var sta in path.PathEntries)
            {
                var er = path.GetEntryRoute(sta.Station);
                if (er != Timetable.UNASSIGNED_ROUTE_ID)
                {
                    length += (sta !.Station.Positions.GetPosition(er) - lastpe !.Station.Positions.GetPosition(er)) !.Value;
                }
                lastpe = sta;
            }

            StationRenderProps lastPos = null;

            lastpe = null;
            float kil = 0f;

            foreach (var sta in path.PathEntries)
            {
                var style = new StationStyle(sta.Station, attrs);

                var er = path.GetEntryRoute(sta.Station);
                if (er != Timetable.UNASSIGNED_ROUTE_ID)
                {
                    kil += (sta !.Station.Positions.GetPosition(er) - lastpe !.Station.Positions.GetPosition(er)) !.Value;
                }
                lastpe = sta;

                StationRenderProps posX;
                if (!attrs.MultiTrack)
                {
                    posX = new StationRenderProps(sta.Station, kil, ((kil / length) * (width - margin.Right - margin.Left)));
                }
                else
                {
                    var availWidth = width - margin.Right - margin.Left - allTrackWidth;
                    var lastKil    = lastPos?.CurKilometer ?? 0f;
                    var lastRight  = lastPos?.Right ?? 0f;
                    var leftOffset = (((kil / length) - (lastKil / length)) * availWidth);
                    posX = new StationRenderProps(sta.Station, kil, lastRight + leftOffset, true);
                }
                lastPos = posX;
                stationOffsets.Add(sta.Station, posX);

                if (!style.CalcedShow)
                {
                    continue;
                }

                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));

                if (!attrs.MultiTrack)
                {
                    // Linie (Single-Track-Mode)
                    g.DrawLine(pen, margin.Left + posX.Center, margin.Top - TOP_GAP, margin.Left + posX.Center, height - margin.Bottom);
                }
                else
                {
                    // Linie (Multi-Track-Mode)
                    g.DrawLine(pen, margin.Left + posX.Left, margin.Top - TOP_GAP, margin.Left + posX.Left, height - margin.Bottom);
                    foreach (var trackX in posX.TrackOffsets)
                    {
                        g.DrawLine(pen, margin.Left + trackX.Value, margin.Top - TOP_GAP, margin.Left + trackX.Value, height - margin.Bottom);
                    }
                    g.DrawLine(pen, margin.Left + posX.Right, margin.Top - TOP_GAP, margin.Left + posX.Right, height - margin.Bottom);
                }

                if (!drawHeader)
                {
                    continue;
                }

                // Stationsnamen
                if (attrs.DrawHeader)
                {
                    var display = StationDisplay(sta);
                    var size    = g.MeasureString(stationFont, display);

                    if (attrs.StationVertical)
                    {
                        var matrix = g.Transform.Clone();

                        g.TranslateTransform(margin.Left + posX.Center + (size.Height / 2), margin.Top - 8 - verticalTrackOffset - size.Width);
                        g.RotateTransform(90);
                        g.DrawText(stationFont, brush, 0, 0, display);

                        g.Transform = matrix;
                    }
                    else
                    {
                        g.DrawText(stationFont, brush, margin.Left + posX.Center - (size.Width / 2), margin.Top - size.Height - verticalTrackOffset - TOP_GAP, display);
                    }

                    if (attrs.MultiTrack)
                    {
                        foreach (var track in posX.TrackOffsets)
                        {
                            var trackSize = g.MeasureString(stationFont, track.Key);
                            if (attrs.StationVertical)
                            {
                                var matrix = g.Transform.Clone();

                                g.TranslateTransform(margin.Left + track.Value + (trackSize.Height / 2), margin.Top - 8 - trackSize.Width);
                                g.RotateTransform(90);
                                g.DrawText(stationFont, brush, 0, 0, track.Key);

                                g.Transform = matrix;
                            }
                            else
                            {
                                g.DrawText(stationFont, brush, margin.Left + track.Value - (trackSize.Width / 2), margin.Top - trackSize.Height - TOP_GAP, track.Key);
                            }
                        }
                    }
                }
            }
            return(stationOffsets);
        }