using System; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Windows.Forms; using TSP; namespace Plotter { public class TourPlot { public Tour Tour { get; set; } public PictureBox Canvas { get; set; } public Label WeightLabel { get; set; } public Label RuntimeLabel { get; set; } public TimeSpan RunTime { get; set; } public TourPlot(PictureBox canvas, Label weightLabel, Label runtimeLabel) { Canvas = canvas; WeightLabel = weightLabel; RuntimeLabel = runtimeLabel; } public void Render() { const int Scaler = 25; const int PlotSize = 100; using Bitmap bmp = new(Canvas.Width, Canvas.Height); using Graphics gfx = Graphics.FromImage(bmp); using Pen pen = new(Color.Black); using Pen gridPen = new(Color.LightGray); using Font font = new("Arial", 16); using Font gridFont = new("Arial", 10); using SolidBrush brush = new(Color.Black); using StringFormat stringFormat = new StringFormat(); gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.Clear(Color.White); for (int i = 0; i <= 100; i += 10) { Point left = ScaleLocation(new Coordinate(0, i)); Point right = ScaleLocation(new Coordinate(100, i)); gfx.DrawLine(gridPen, left, right); stringFormat.Alignment = StringAlignment.Far; stringFormat.LineAlignment = StringAlignment.Center; gfx.DrawString(i.ToString(), gridFont, brush, left, stringFormat); Point bottom = ScaleLocation(new Coordinate(i, 0)); Point top = ScaleLocation(new Coordinate(i, 100)); gfx.DrawLine(gridPen, bottom, top); stringFormat.Alignment = StringAlignment.Center; stringFormat.LineAlignment = StringAlignment.Near; gfx.DrawString(i.ToString(), gridFont, brush, bottom, stringFormat); } // iterate through each city and draw line from Location to parent.Location foreach (City city in Tour.Cities.Where(city => city.Parent != -1)) { City parent = Tour[city.Parent]; Point cityPoint = ScaleLocation(city.Location); Point parentPoint = ScaleLocation(parent.Location); gfx.DrawString(city.Id.ToString(), font, brush, cityPoint); gfx.DrawLine(pen, cityPoint, parentPoint); } // copy the bitmap to the picturebox (double buffered) Canvas.Image?.Dispose(); Canvas.Image = (Bitmap)bmp.Clone(); // set runtime and weight labels RuntimeLabel.Text = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", RunTime.Hours, RunTime.Minutes, RunTime.Seconds, RunTime.Milliseconds / 10); WeightLabel.Text = Tour.Weight.ToString("F3"); // helper function to unify the scaling of images Point ScaleLocation(Coordinate coordinate) { int x = Canvas.Width * (coordinate.X + Scaler / 2) / (Scaler + PlotSize); int y = Canvas.Height * ((coordinate.Y - PlotSize) * -1 + Scaler / 2) / (Scaler + PlotSize); return new Point(x, y); } } public void Save(string filename) => Canvas.Image.Save(filename); } }