Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs @ 5956

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

#1464: Corrected behavior of ViewHost and SymbolicExpressionTreeChart.

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