diff options
Diffstat (limited to 'src/Plotter/TourPlot.cs')
-rw-r--r-- | src/Plotter/TourPlot.cs | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/Plotter/TourPlot.cs b/src/Plotter/TourPlot.cs new file mode 100644 index 0000000..751fd2e --- /dev/null +++ b/src/Plotter/TourPlot.cs @@ -0,0 +1,114 @@ +using System; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using TSP; + +namespace Plotter +{ + public class TourPlot + { + public string GraphName { get; set; } + public string Type { get; set; } + 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(string graphName, string type, PictureBox canvas, Label weightLabel, Label runtimeLabel) + { + GraphName = graphName; + Type = type; + Canvas = canvas; + WeightLabel = weightLabel; + RuntimeLabel = runtimeLabel; + } + + public void Save(string filename) => + Save(filename, Canvas.Width, Canvas.Height); + + public void Save(string filename, int width, int height) + { + Draw(300, 300).Save(Path.Join(filename, $"{GraphName}_{Type}.png")); + File.AppendAllText(Path.Join(filename, $"data.csv"), $"{this}\n"); + } + + public void Render() + { + Draw(Canvas.Width, Canvas.Height); + + // copy the bitmap to the picturebox (double buffered) + Canvas.Image?.Dispose(); + Canvas.Image = Draw(Canvas.Width, Canvas.Height); + + // 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"); + } + + public Bitmap Draw(int width, int height) + { + const int Offset = 25; + const int PlotSize = 100; + + using Bitmap bmp = new(width, height); + using Graphics gfx = Graphics.FromImage(bmp); + using Pen pen = new(Color.Black); + using Pen gridPen = new(Color.LightGray); + using Font font = new("Arial", 12); + 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); + } + + return (Bitmap)bmp.Clone(); + + // helper function to unify the scaling of images + Point ScaleLocation(Coordinate coordinate) + { + int x = width * (coordinate.X + Offset / 2) / (Offset + PlotSize); + int y = height * ((coordinate.Y - PlotSize) * -1 + Offset / 2) / (Offset + PlotSize); + + return new Point(x, y); + } + + } + + public override string ToString() => $"{GraphName},{Type},{Runtime.TotalSeconds},{Tour}"; + } +} |