Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GeneralizedQAP/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs @ 6650

Last change on this file since 6650 was 6375, checked in by mkommend, 13 years ago

#1549: Minor changes in SymbolicExpressionTreeNode and the SymbolicExpressionTreeChart that are necessary for the debugger visualizer to work correctly.

File size: 13.2 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.Collections.Generic;
24using System.Drawing;
25using System.Drawing.Imaging;
26using System.Windows.Forms;
27
28namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
29  public sealed partial class SymbolicExpressionTreeChart : UserControl {
30    private Image image;
31    private StringFormat stringFormat;
32    private Dictionary<ISymbolicExpressionTreeNode, VisualSymbolicExpressionTreeNode> visualTreeNodes;
33
34    public SymbolicExpressionTreeChart() {
35      InitializeComponent();
36      this.image = new Bitmap(Width, Height);
37      this.stringFormat = new StringFormat();
38      this.stringFormat.Alignment = StringAlignment.Center;
39      this.stringFormat.LineAlignment = StringAlignment.Center;
40      this.spacing = 5;
41      this.lineColor = Color.Black;
42      this.backgroundColor = Color.White;
43      this.textFont = new Font("Times New Roman", 8);
44    }
45
46    public SymbolicExpressionTreeChart(ISymbolicExpressionTree tree)
47      : this() {
48      this.Tree = tree;
49    }
50
51    private int spacing;
52    public int Spacing {
53      get { return this.spacing; }
54      set {
55        this.spacing = value;
56        this.Repaint();
57      }
58    }
59
60    private Color lineColor;
61    public Color LineColor {
62      get { return this.lineColor; }
63      set {
64        this.lineColor = value;
65        this.Repaint();
66      }
67    }
68
69    private Color backgroundColor;
70    public Color BackgroundColor {
71      get { return this.backgroundColor; }
72      set {
73        this.backgroundColor = value;
74        this.Repaint();
75      }
76    }
77
78    private Font textFont;
79    public Font TextFont {
80      get { return this.textFont; }
81      set {
82        this.textFont = value;
83        this.Repaint();
84      }
85    }
86
87    private ISymbolicExpressionTree tree;
88    public ISymbolicExpressionTree Tree {
89      get { return this.tree; }
90      set {
91        tree = value;
92        visualTreeNodes = new Dictionary<ISymbolicExpressionTreeNode, VisualSymbolicExpressionTreeNode>();
93        if (tree != null) {
94          foreach (SymbolicExpressionTreeNode node in tree.IterateNodesPrefix())
95            visualTreeNodes[node] = new VisualSymbolicExpressionTreeNode(node);
96        }
97        Repaint();
98      }
99    }
100
101    protected override void OnPaint(PaintEventArgs e) {
102      base.OnPaint(e);
103      e.Graphics.DrawImage(image, 0, 0);
104    }
105    protected override void OnResize(EventArgs e) {
106      base.OnResize(e);
107      if (this.Width <= 1 || this.Height <= 1)
108        this.image = new Bitmap(1, 1);
109      else
110        this.image = new Bitmap(Width, Height);
111      this.Repaint();
112    }
113
114    public void Repaint() {
115      this.GenerateImage();
116      this.Refresh();
117    }
118
119    private void GenerateImage() {
120      using (Graphics graphics = Graphics.FromImage(image)) {
121        graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
122        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
123        graphics.Clear(backgroundColor);
124        if (tree != null) {
125          int height = this.Height / tree.Depth;
126          DrawFunctionTree(tree, graphics, 0, 0, this.Width, height);
127        }
128      }
129    }
130
131    public VisualSymbolicExpressionTreeNode GetVisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) {
132      if (visualTreeNodes.ContainsKey(symbolicExpressionTreeNode))
133        return visualTreeNodes[symbolicExpressionTreeNode];
134      return null;
135    }
136
137    #region events
138    public event MouseEventHandler SymbolicExpressionTreeNodeClicked;
139    private void OnSymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
140      var clicked = SymbolicExpressionTreeNodeClicked;
141      if (clicked != null)
142        clicked(sender, e);
143    }
144
145    private void SymbolicExpressionTreeChart_MouseClick(object sender, MouseEventArgs e) {
146      VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
147      if (visualTreeNode != null)
148        OnSymbolicExpressionTreeNodeClicked(visualTreeNode, e);
149    }
150
151    public event MouseEventHandler SymbolicExpressionTreeNodeDoubleClicked;
152    private void OnSymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
153      var doubleClicked = SymbolicExpressionTreeNodeDoubleClicked;
154      if (doubleClicked != null)
155        doubleClicked(sender, e);
156    }
157
158    private void SymbolicExpressionTreeChart_MouseDoubleClick(object sender, MouseEventArgs e) {
159      VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
160      if (visualTreeNode != null)
161        OnSymbolicExpressionTreeNodeDoubleClicked(visualTreeNode, e);
162    }
163
164    public event ItemDragEventHandler SymbolicExpressionTreeNodeDrag;
165    private void OnSymbolicExpressionTreeNodeDragDrag(object sender, ItemDragEventArgs e) {
166      var dragged = SymbolicExpressionTreeNodeDrag;
167      if (dragged != null)
168        dragged(sender, e);
169    }
170
171    private VisualSymbolicExpressionTreeNode draggedSymbolicExpressionTree;
172    private MouseButtons dragButtons;
173    private void SymbolicExpressionTreeChart_MouseDown(object sender, MouseEventArgs e) {
174      this.dragButtons = e.Button;
175      this.draggedSymbolicExpressionTree = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
176    }
177    private void SymbolicExpressionTreeChart_MouseUp(object sender, MouseEventArgs e) {
178      this.draggedSymbolicExpressionTree = null;
179      this.dragButtons = MouseButtons.None;
180    }
181
182    private void SymbolicExpressionTreeChart_MouseMove(object sender, MouseEventArgs e) {
183      VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
184      if (draggedSymbolicExpressionTree != null &&
185        draggedSymbolicExpressionTree != visualTreeNode) {
186        OnSymbolicExpressionTreeNodeDragDrag(draggedSymbolicExpressionTree, new ItemDragEventArgs(dragButtons, draggedSymbolicExpressionTree));
187        draggedSymbolicExpressionTree = null;
188      } else if (draggedSymbolicExpressionTree == null &&
189        visualTreeNode != null) {
190        string tooltipText = visualTreeNode.ToolTip;
191        if (this.toolTip.GetToolTip(this) != tooltipText)
192          this.toolTip.SetToolTip(this, tooltipText);
193
194      } else if (visualTreeNode == null)
195        this.toolTip.SetToolTip(this, "");
196    }
197
198    private VisualSymbolicExpressionTreeNode FindVisualSymbolicExpressionTreeNodeAt(int x, int y) {
199      foreach (var visualTreeNode in visualTreeNodes.Values) {
200        if (x >= visualTreeNode.X && x <= visualTreeNode.X + visualTreeNode.Width &&
201            y >= visualTreeNode.Y && y <= visualTreeNode.Y + visualTreeNode.Height)
202          return visualTreeNode;
203      }
204      return null;
205    }
206    #endregion
207
208    #region methods for painting the symbolic expression tree
209    private void DrawFunctionTree(ISymbolicExpressionTree tree, Graphics graphics, int x, int y, int width, int height) {
210      DrawFunctionTree(tree.Root, graphics, x, y, width, height, Point.Empty);
211    }
212
213    /// <summary>
214    ///
215    /// </summary>
216    /// <param name="functionTree"> functiontree to draw</param>
217    /// <param name="graphics">graphics object to draw on</param>
218    /// <param name="x">x coordinate of drawing area</param>
219    /// <param name="y">y coordinate of drawing area</param>
220    /// <param name="width">width of drawing area</param>
221    /// <param name="height">height of drawing area</param>
222    private void DrawFunctionTree(ISymbolicExpressionTreeNode node, Graphics graphics, int x, int y, int width, int height, Point connectionPoint) {
223      VisualSymbolicExpressionTreeNode visualTreeNode = visualTreeNodes[node];
224      float center_x = x + width / 2;
225      float center_y = y + height / 2;
226      int actualWidth = width - spacing;
227      int actualHeight = height - spacing;
228
229      SolidBrush textBrush = new SolidBrush(visualTreeNode.TextColor);
230      Pen linePen = new Pen(this.lineColor);
231      Pen nodeLinePen = new Pen(visualTreeNode.LineColor);
232      SolidBrush nodeFillBrush = new SolidBrush(visualTreeNode.FillColor);
233
234      //calculate size of node
235      if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
236        visualTreeNode.Width = visualTreeNode.PreferredWidth;
237        visualTreeNode.Height = visualTreeNode.PreferredHeight;
238        visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
239        visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
240      }
241        //width too small to draw in desired sized
242      else if (actualWidth < visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
243        visualTreeNode.Width = actualWidth;
244        visualTreeNode.Height = visualTreeNode.PreferredHeight;
245        visualTreeNode.X = x;
246        visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
247      }
248        //height too small to draw in desired sized
249      else if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight < visualTreeNode.PreferredHeight) {
250        visualTreeNode.Width = visualTreeNode.PreferredWidth;
251        visualTreeNode.Height = actualHeight;
252        visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
253        visualTreeNode.Y = y;
254      }
255        //width and height too small to draw in desired size
256      else {
257        visualTreeNode.Width = actualWidth;
258        visualTreeNode.Height = actualHeight;
259        visualTreeNode.X = x;
260        visualTreeNode.Y = y;
261      }
262
263      //draw terminal node
264      if (node.SubtreesCount == 0) {
265        graphics.FillRectangle(nodeFillBrush, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
266        graphics.DrawRectangle(nodeLinePen, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
267      } else {
268        graphics.FillEllipse(nodeFillBrush, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
269        graphics.DrawEllipse(nodeLinePen, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
270      }
271
272      //draw name of symbol
273      var text = node.ToString();
274      graphics.DrawString(text, textFont, textBrush, new RectangleF(visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height), stringFormat);
275
276      //draw connection line to parent node
277      if (!connectionPoint.IsEmpty)
278        graphics.DrawLine(linePen, connectionPoint, new Point(visualTreeNode.X + visualTreeNode.Width / 2, visualTreeNode.Y));
279
280      //calculate areas for the subtrees according to their tree size and call drawFunctionTree
281      Point connectFrom = new Point(visualTreeNode.X + visualTreeNode.Width / 2, visualTreeNode.Y + visualTreeNode.Height);
282      int[] xBoundaries = new int[node.SubtreesCount + 1];
283      xBoundaries[0] = x;
284      for (int i = 0; i < node.SubtreesCount; i++) {
285        xBoundaries[i + 1] = (int)(xBoundaries[i] + (width * (double)node.GetSubtree(i).GetLength()) / (node.GetLength() - 1));
286        DrawFunctionTree(node.GetSubtree(i), graphics, xBoundaries[i], y + height,
287          xBoundaries[i + 1] - xBoundaries[i], height, connectFrom);
288      }
289    }
290    #endregion
291
292    #region save image
293    private void saveImageToolStripMenuItem_Click(object sender, EventArgs e) {
294      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
295        string filename = saveFileDialog.FileName.ToLower();
296        if (filename.EndsWith("bmp")) SaveImageAsBitmap(filename);
297        else if (filename.EndsWith("emf")) SaveImageAsEmf(filename);
298        else SaveImageAsBitmap(filename);
299      }
300    }
301
302    private void SaveImageAsBitmap(string filename) {
303      if (tree == null) return;
304      Image image = new Bitmap(Width, Height);
305      using (Graphics g = Graphics.FromImage(image)) {
306        int height = this.Height / tree.Depth;
307        DrawFunctionTree(tree, g, 0, 0, Width, height);
308      }
309      image.Save(filename);
310    }
311
312    private void SaveImageAsEmf(string filename) {
313      if (tree == null) return;
314      using (Graphics g = CreateGraphics()) {
315        using (Metafile file = new Metafile(filename, g.GetHdc())) {
316          using (Graphics emfFile = Graphics.FromImage(file)) {
317            int height = this.Height / tree.Depth;
318            DrawFunctionTree(tree, emfFile, 0, 0, Width, height);
319          }
320        }
321        g.ReleaseHdc();
322      }
323    }
324    #endregion
325  }
326}
Note: See TracBrowser for help on using the repository browser.