#region License Information /* HeuristicLab * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Windows.Forms; using HeuristicLab.Core.Views; using HeuristicLab.Data; using HeuristicLab.Encodings.PermutationEncoding; using HeuristicLab.MainForm; namespace HeuristicLab.Problems.QuadraticAssignment.Views { /// /// The base class for visual representations of a path tour for a TSP. /// [View("QAPAssignment View")] [Content(typeof(QAPAssignment), true)] public sealed partial class QAPAssignmentView : ItemView { private Bitmap bitmap; public new QAPAssignment Content { get { return (QAPAssignment)base.Content; } set { base.Content = value; } } /// /// Initializes a new instance of . /// public QAPAssignmentView() { InitializeComponent(); } protected override void DeregisterContentEvents() { Content.PropertyChanged -= new PropertyChangedEventHandler(Content_PropertyChanged); base.DeregisterContentEvents(); } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.PropertyChanged += new PropertyChangedEventHandler(Content_PropertyChanged); } protected override void OnContentChanged() { base.OnContentChanged(); if (Content == null) { qualityViewHost.Content = null; pictureBox.Image = null; assignmentViewHost.Content = null; } else { qualityViewHost.Content = Content.Quality; GenerateImage(); assignmentViewHost.Content = Content.Assignment; } } protected override void SetEnabledStateOfControls() { base.SetEnabledStateOfControls(); qualityGroupBox.Enabled = Content != null; pictureBox.Enabled = Content != null; assignmentGroupBox.Enabled = Content != null; } private void GenerateImage() { if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) { if (Content == null) { pictureBox.Image = null; if (bitmap != null) bitmap.Dispose(); bitmap = null; } else { Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height); bool drawDistances = distancesRadioButton.Checked; DoubleMatrix coordinates = Content.Coordinates; DoubleMatrix distances = Content.Distances; if ((coordinates == null || coordinates.Rows == 0) && (distances == null || distances.Rows == 0)) { using (Graphics g = Graphics.FromImage(newBitmap)) { string str = "No coordinates and no distance matrix specified."; SizeF strSize = g.MeasureString(str, Font); g.DrawString(str, Font, Brushes.Black, (float)(newBitmap.Width - strSize.Width) / 2.0f, (float)(newBitmap.Height - strSize.Height) / 2.0f); } } else { if ((coordinates == null || coordinates.Rows == 0) && Content.ViewCoordinates == null) { coordinates = new DoubleMatrix(distances.Rows, 2); double rad = (2 * Math.PI) / coordinates.Rows; for (int i = 0; i < coordinates.Rows; i++) { coordinates[i, 0] = 10 * Math.Cos(rad * i); coordinates[i, 1] = 10 * Math.Sin(rad * i); } Content.ViewCoordinates = coordinates; } else if ((coordinates == null || coordinates.Rows == 0) && Content.ViewCoordinates != null) { coordinates = Content.ViewCoordinates; } DoubleMatrix weights = Content.Weights; Permutation assignment = Content.Assignment; double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue; double maxWeight = double.MinValue, maxDistance = double.MinValue; for (int i = 0; i < coordinates.Rows; i++) { if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0]; if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1]; if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0]; if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1]; for (int j = i + 1; j < coordinates.Rows; j++) { if (weights[i, j] + weights[j, i] > maxWeight) maxWeight = weights[i, j] + weights[j, i]; if (distances[i, j] > maxDistance) maxDistance = distances[i, j]; else if (distances[j, i] > maxDistance) maxDistance = distances[j, i]; } } int border = 20; double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1; double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1; Point[] points = new Point[coordinates.Rows]; for (int i = 0; i < coordinates.Rows; i++) points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)), newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep)))); Random rand = new Random(); using (Graphics graphics = Graphics.FromImage(newBitmap)) { graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; if ((assignment != null) && (assignment.Length == coordinates.Rows) && (assignment.Validate())) { for (int i = 0; i < assignment.Length - 1; i++) { for (int j = i + 1; j < assignment.Length; j++) { Point start = points[assignment[i]], end = points[assignment[j]]; string caption = String.Empty; double d = Math.Max(distances[i, j], distances[j, i]); if (drawDistances) { float width = (float)Math.Ceiling(5.0 * d / maxDistance); graphics.DrawLine(new Pen(Color.IndianRed, width), start, end); if (distances[i, j] != distances[j, i]) caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat) + " / " + distances[j, i].ToString(CultureInfo.InvariantCulture.NumberFormat); else caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat); } else { double w = weights[i, j] + weights[j, i]; if (w > 0) { float width = (float)Math.Ceiling(5.0 * w / maxWeight); graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end); caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat); } if (!String.IsNullOrEmpty(caption)) { double r = rand.NextDouble(); while (r < 0.2 || r > 0.8) r = rand.NextDouble(); float x = (float)(start.X + (end.X - start.X) * r + 5); float y = (float)(start.Y + (end.Y - start.Y) * r + 5); graphics.DrawString(caption, Font, Brushes.Black, x, y); } } } } } for (int i = 0; i < points.Length; i++) { Point p = new Point(points[assignment[i]].X - 3, points[assignment[i]].Y - 3); graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8); graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10); } } } pictureBox.Image = newBitmap; if (bitmap != null) bitmap.Dispose(); bitmap = newBitmap; } } } private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (InvokeRequired) Invoke(new PropertyChangedEventHandler(Content_PropertyChanged), sender, e); else { switch (e.PropertyName) { case "Coordinates": case "Distances": case "Weights": GenerateImage(); break; case "Assignment": GenerateImage(); assignmentViewHost.Content = Content.Assignment; break; case "Quality": break; default: break; } } } private void pictureBox_SizeChanged(object sender, EventArgs e) { GenerateImage(); } private void radioButton_CheckedChanged(object sender, EventArgs e) { GenerateImage(); } } }