Free cookie consent management tool by TermsFeed Policy Generator

source: branches/QAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/QAPView.cs @ 5811

Last change on this file since 5811 was 5811, checked in by abeham, 13 years ago

#1330

  • Adapted QAP to new problem base class structure
  • Fixed a bug in a view
  • Merged changes from Optimization plugin into branch
File size: 18.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Drawing;
24using System.Drawing.Drawing2D;
25using System.Drawing.Text;
26using System.Globalization;
27using System.Windows.Forms;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.PermutationEncoding;
32
33namespace HeuristicLab.Problems.QuadraticAssignment.Views {
34  public partial class QAPView : UserControl {
35    private Bitmap bitmap;
36    private Bitmap defaultBitmap;
37
38    #region Properties
39    private DoubleMatrix distances;
40    public DoubleMatrix Distances {
41      get { return distances; }
42      set {
43        DeregisterDistancesEvents();
44        distances = value;
45        RegisterDistancesEvents();
46        OnRedraw();
47      }
48    }
49
50    private DoubleMatrix weights;
51    public DoubleMatrix Weights {
52      get { return weights; }
53      set {
54        DeregisterWeightsEvents();
55        weights = value;
56        RegisterWeightsEvents();
57        OnRedraw();
58      }
59    }
60
61    private Permutation assignment;
62    public Permutation Assignment {
63      get { return assignment; }
64      set {
65        DeregisterAssignmentEvents();
66        assignment = value;
67        RegisterAssignmentEvents();
68        OnRedraw();
69      }
70    }
71    #endregion
72
73    #region Event Handling
74    private void DeregisterDistancesEvents() {
75      if (Distances != null) {
76        Distances.Reset -= new EventHandler(Redraw);
77        Distances.RowsChanged -= new EventHandler(Redraw);
78        Distances.ColumnsChanged -= new EventHandler(Redraw);
79        Distances.ItemChanged -= new EventHandler<EventArgs<int, int>>(Redraw);
80      }
81    }
82
83    private void RegisterDistancesEvents() {
84      if (Distances != null) {
85        Distances.Reset += new EventHandler(Redraw);
86        Distances.RowsChanged += new EventHandler(Redraw);
87        Distances.ColumnsChanged += new EventHandler(Redraw);
88        Distances.ItemChanged += new EventHandler<EventArgs<int, int>>(Redraw);
89      }
90    }
91
92    private void DeregisterWeightsEvents() {
93      if (Weights != null) {
94        Weights.Reset -= new EventHandler(Redraw);
95        Weights.RowsChanged -= new EventHandler(Redraw);
96        Weights.ColumnsChanged -= new EventHandler(Redraw);
97        Weights.ItemChanged -= new EventHandler<EventArgs<int, int>>(Redraw);
98      }
99    }
100
101    private void RegisterWeightsEvents() {
102      if (Weights != null) {
103        Weights.Reset += new EventHandler(Redraw);
104        Weights.RowsChanged += new EventHandler(Redraw);
105        Weights.ColumnsChanged += new EventHandler(Redraw);
106        Weights.ItemChanged += new EventHandler<EventArgs<int, int>>(Redraw);
107      }
108    }
109
110    private void DeregisterAssignmentEvents() {
111      if (Assignment != null) {
112        Assignment.Reset -= new EventHandler(Redraw);
113        Assignment.ItemChanged -= new EventHandler<EventArgs<int>>(Redraw);
114      }
115    }
116
117    private void RegisterAssignmentEvents() {
118      if (Assignment != null) {
119        Assignment.Reset += new EventHandler(Redraw);
120        Assignment.ItemChanged += new EventHandler<EventArgs<int>>(Redraw);
121      }
122    }
123
124    private void Redraw(object sender, EventArgs e) {
125      if (sender is RadioButton && !((RadioButton)sender).Checked)
126        return;
127      OnRedraw();
128    }
129
130    private void Redraw(object sender, EventArgs<int, int> e) {
131      OnRedraw();
132    }
133
134    private void pictureBox_SizeChanged(object sender, EventArgs e) {
135      SetupDefaultBitmap();
136      OnRedraw();
137    }
138    #endregion
139
140    public QAPView() {
141      InitializeComponent();
142      SetupDefaultBitmap();
143    }
144
145    private void SetupDefaultBitmap() {
146      if (defaultBitmap != null) {
147        defaultBitmap.Dispose();
148        defaultBitmap = null;
149      }
150      if (pictureBox.Width > 0 && pictureBox.Height > 0) {
151        defaultBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
152        WriteCenteredTextToBitmap(ref defaultBitmap, "No visualization available");
153      }
154    }
155
156    private void WriteCenteredTextToBitmap(ref Bitmap bitmap, string text) {
157      using (Graphics g = Graphics.FromImage(bitmap)) {
158        g.TextRenderingHint = TextRenderingHint.AntiAlias;
159        g.SmoothingMode = SmoothingMode.AntiAlias;
160
161        SizeF strSize = g.MeasureString(text, Font);
162        g.DrawString(text, Font, Brushes.Black, (float)(pictureBox.Width - strSize.Width) / 2.0f, (float)(pictureBox.Height - strSize.Height) / 2.0f);
163      }
164    }
165
166    private void OnRedraw() {
167      if (InvokeRequired) {
168        Invoke((Action)OnRedraw, null);
169      } else {
170        GenerateImage();
171      }
172    }
173
174    private void GenerateImage() {
175      Bitmap newBitmap = null;
176      stressLabel.Text = "-";
177      if (distancesRadioButton.Checked && Distances != null && Distances.Rows > 0
178        && Distances.Rows == Distances.Columns) {
179        if (Distances.Rows > 30) {
180          newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
181          WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
182        } else newBitmap = GenerateDistanceImage();
183      } else if (weightsRadioButton.Checked && Weights != null && Weights.Rows > 0
184        && Weights.Rows == Weights.Columns) {
185        if (Weights.Rows > 30) {
186          newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
187          WriteCenteredTextToBitmap(ref newBitmap, "Problem dimension too large for visualization.");
188        } else newBitmap = GenerateWeightsImage();
189      } else if (assignmentRadioButton.Checked
190        && Assignment != null && Assignment.Length > 0
191        && Weights != null && Weights.Rows > 0
192        && Distances != null && Distances.Rows > 0
193        && Weights.Rows == Weights.Columns
194        && Distances.Rows == Distances.Columns
195        && Assignment.Length == Weights.Rows
196        && Assignment.Length == Distances.Rows
197        && Assignment.Validate()) {
198        newBitmap = GenerateAssignmentImage();
199      }
200
201      pictureBox.Image = newBitmap != null ? newBitmap : defaultBitmap;
202      if (bitmap != null) bitmap.Dispose();
203      if (newBitmap != null) bitmap = newBitmap;
204      else bitmap = null;
205    }
206
207    #region Draw distances
208    private Bitmap GenerateDistanceImage() {
209      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
210        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
211
212        for (int i = 0; i < distances.Rows; i++) {
213          for (int j = i + 1; j < distances.Rows; j++)
214            if (distances[i, j] != distances[j, i]) {
215              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
216              return newBitmap;
217            }
218        }
219
220        double stress;
221        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
222        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
223        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
224        double maxDistance = double.MinValue;
225        for (int i = 0; i < coordinates.Rows; i++) {
226          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
227          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
228          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
229          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
230
231          for (int j = i + 1; j < coordinates.Rows; j++) {
232            if (distances[i, j] > maxDistance) maxDistance = distances[i, j];
233            if (distances[j, i] > maxDistance) maxDistance = distances[j, i];
234          }
235        }
236
237        int border = 20;
238        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
239        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
240
241        Point[] points = new Point[coordinates.Rows];
242        for (int i = 0; i < coordinates.Rows; i++)
243          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
244                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
245
246        Random rand = new Random();
247        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
248          graphics.SmoothingMode = SmoothingMode.AntiAlias;
249          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
250          graphics.DrawString("Showing locations spaced out according to their distances", Font, Brushes.Black, 5, 2);
251
252          for (int i = 0; i < coordinates.Rows - 1; i++) {
253            for (int j = i + 1; j < coordinates.Rows; j++) {
254              Point start = points[i], end = points[j];
255              string caption = String.Empty;
256              double d = Math.Max(distances[i, j], distances[j, i]);
257              float width = (float)Math.Ceiling(5.0 * d / maxDistance);
258              if (d > 0) {
259                graphics.DrawLine(new Pen(Color.IndianRed, width), start, end);
260                if (distances[i, j] != distances[j, i])
261                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat)
262                    + " / " + distances[j, i].ToString(CultureInfo.InvariantCulture.NumberFormat);
263                else
264                  caption = distances[i, j].ToString(CultureInfo.InvariantCulture.NumberFormat);
265              }
266              if (!String.IsNullOrEmpty(caption)) {
267                double r = rand.NextDouble();
268                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
269                float x = (float)(start.X + (end.X - start.X) * r + 5);
270                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
271                graphics.DrawString(caption, Font, Brushes.Black, x, y);
272              }
273            }
274          }
275
276          for (int i = 0; i < points.Length; i++) {
277            Point p = new Point(points[i].X - 3, points[i].Y - 3);
278            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
279            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
280          }
281        }
282        return newBitmap;
283      }
284      return null;
285    }
286    #endregion
287
288    #region Draw weights
289    private Bitmap GenerateWeightsImage() {
290      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
291        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
292
293        double maxWeight = double.MinValue;
294        for (int i = 0; i < weights.Rows; i++)
295          for (int j = i + 1; j < weights.Rows; j++) {
296            if (weights[i, j] > maxWeight)
297              maxWeight = weights[i, j] + weights[j, i];
298
299            if (weights[i, j] != weights[j, i]) {
300              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
301              return newBitmap;
302            }
303          }
304
305        DoubleMatrix distances = new DoubleMatrix(weights.Rows, weights.Columns);
306        for (int i = 0; i < distances.Rows; i++)
307          for (int j = 0; j < distances.Columns; j++) {
308            distances[i, j] = maxWeight + 1 - weights[i, j];
309          }
310
311        double stress;
312        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
313        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
314        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
315        for (int i = 0; i < coordinates.Rows; i++) {
316          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
317          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
318          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
319          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
320        }
321
322        int border = 20;
323        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
324        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
325
326        Point[] points = new Point[coordinates.Rows];
327        for (int i = 0; i < coordinates.Rows; i++)
328          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
329                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
330
331        Random rand = new Random();
332        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
333          graphics.SmoothingMode = SmoothingMode.AntiAlias;
334          graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
335          graphics.DrawString("Showing facilities spaced out according to their weights", Font, Brushes.Black, 5, 2);
336
337          for (int i = 0; i < coordinates.Rows - 1; i++) {
338            for (int j = i + 1; j < coordinates.Rows; j++) {
339              Point start = points[i], end = points[j];
340              string caption = String.Empty;
341              double d = Math.Max(distances[i, j], distances[j, i]);
342              double w = weights[i, j];
343              if (w > 0) {
344                float width = (float)Math.Ceiling(3.0 * w / maxWeight);
345                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
346                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
347              }
348              if (!String.IsNullOrEmpty(caption)) {
349                double r = rand.NextDouble();
350                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
351                float x = (float)(start.X + (end.X - start.X) * r + 5);
352                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
353                graphics.DrawString(caption, Font, Brushes.Black, x, y);
354              }
355            }
356          }
357          for (int i = 0; i < points.Length; i++) {
358            Point p = new Point(points[i].X - 3, points[i].Y - 3);
359            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
360            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
361          }
362        }
363        return newBitmap;
364      }
365      return null;
366    }
367    #endregion
368
369    #region Draw assignment
370    private Bitmap GenerateAssignmentImage() {
371      if ((pictureBox.Width > 0) && (pictureBox.Height > 0)) {
372        Bitmap newBitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
373
374        for (int i = 0; i < distances.Rows; i++) {
375          for (int j = i + 1; j < distances.Rows; j++) {
376            if (distances[i, j] != distances[j, i]) {
377              WriteCenteredTextToBitmap(ref newBitmap, "Distance matrix is not symmetric");
378              return newBitmap;
379            }
380            if (weights[i, j] != weights[j, i]) {
381              WriteCenteredTextToBitmap(ref newBitmap, "Weights matrix is not symmetric");
382            }
383          }
384        }
385
386        double stress;
387        DoubleMatrix coordinates = MultidimensionalScaling.MetricByDistance(distances, out stress);
388        stressLabel.Text = stress.ToString("0.00", CultureInfo.CurrentCulture.NumberFormat);
389        double xMin = double.MaxValue, yMin = double.MaxValue, xMax = double.MinValue, yMax = double.MinValue;
390        double maxWeight = double.MinValue;
391        for (int i = 0; i < coordinates.Rows; i++) {
392          if (xMin > coordinates[i, 0]) xMin = coordinates[i, 0];
393          if (yMin > coordinates[i, 1]) yMin = coordinates[i, 1];
394          if (xMax < coordinates[i, 0]) xMax = coordinates[i, 0];
395          if (yMax < coordinates[i, 1]) yMax = coordinates[i, 1];
396
397          for (int j = i + 1; j < coordinates.Rows; j++) {
398            if (weights[i, j] > maxWeight) maxWeight = weights[i, j];
399          }
400        }
401
402        int border = 20;
403        double xStep = xMax != xMin ? (pictureBox.Width - 2 * border) / (xMax - xMin) : 1;
404        double yStep = yMax != yMin ? (pictureBox.Height - 2 * border) / (yMax - yMin) : 1;
405
406        Point[] points = new Point[coordinates.Rows];
407        for (int i = 0; i < coordinates.Rows; i++)
408          points[i] = new Point(border + ((int)((coordinates[i, 0] - xMin) * xStep)),
409                                newBitmap.Height - (border + ((int)((coordinates[i, 1] - yMin) * yStep))));
410
411        Random rand = new Random();
412        using (Graphics graphics = Graphics.FromImage(newBitmap)) {
413          graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
414          graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
415
416          for (int i = 0; i < assignment.Length - 1; i++) {
417            for (int j = i + 1; j < assignment.Length; j++) {
418              Point start, end;
419              string caption = String.Empty;
420              double d = distances[i, j];
421              start = points[assignment[i]];
422              end = points[assignment[j]];
423              double w = weights[i, j];
424              if (w > 0) {
425                float width = (float)Math.Ceiling(4.0 * w / maxWeight);
426                graphics.DrawLine(new Pen(Color.MediumBlue, width), start, end);
427                caption = w.ToString(CultureInfo.InvariantCulture.NumberFormat);
428              }
429              if (!String.IsNullOrEmpty(caption)) {
430                double r = rand.NextDouble();
431                while (r < 0.2 || r > 0.8) r = rand.NextDouble();
432                float x = (float)(start.X + (end.X - start.X) * r + 5);
433                float y = (float)(start.Y + (end.Y - start.Y) * r + 5);
434                graphics.DrawString(caption, Font, Brushes.Black, x, y);
435              }
436            }
437          }
438
439          for (int i = 0; i < points.Length; i++) {
440            Point p = new Point(points[i].X - 3, points[i].Y - 3);
441            graphics.FillRectangle(Brushes.Black, p.X, p.Y, 8, 8);
442            graphics.DrawString(i.ToString(), Font, Brushes.Black, p.X, p.Y + 10);
443          }
444        }
445        return newBitmap;
446      }
447      return null;
448    }
449    #endregion
450
451    private void CustomDispose(bool disposing) {
452      DeregisterDistancesEvents();
453      DeregisterWeightsEvents();
454      DeregisterAssignmentEvents();
455      if (bitmap != null) bitmap.Dispose();
456      bitmap = null;
457      if (defaultBitmap != null) {
458        defaultBitmap.Dispose();
459        defaultBitmap = null;
460      }
461    }
462  }
463}
Note: See TracBrowser for help on using the repository browser.