Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeTile.cs @ 10884

Last change on this file since 10884 was 10884, checked in by bburlacu, 10 years ago

#1772: Added license headers where they were missing. Introduced an id map to the DirectedGraph to get graph vertices based on the id injected in the scopes by the genealogy analyzer.

File size: 9.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 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.Drawing2D;
26using System.Drawing.Text;
27using System.Linq;
28using HeuristicLab.Common;
29using HeuristicLab.Visualization;
30using Rectangle = HeuristicLab.Visualization.Rectangle;
31
32namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
33  /// <summary>
34  /// The SymbolicExpressionTreeTile will display either a full tree or just a subtree (case in which the SymbolicExpressionTreeProperty remains unset).
35  /// By setting the Root property, the user can use the SymbolicExpressionTreeTile to layout and display arbitrary subtrees.
36  /// </summary>
37  public class SymbolicExpressionTreeTile : Group {
38    public int PreferredNodeWidth { get; set; }
39    public int PreferredNodeHeight { get; set; }
40
41    private const int labelHeight = 60;
42
43    private readonly SolidBrush defaultBrush;
44    private readonly Pen defaultPen;
45    private readonly Font defaultFont;
46
47    public ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> LayoutEngine { get; set; }
48    private readonly Dictionary<IPrimitive, ISymbolicExpressionTreeNode> primitivesToNodes;
49    private readonly Dictionary<ISymbolicExpressionTreeNode, IPrimitive> nodesToPrimitives;
50
51    private string label;
52    public string Label {
53      get { return label; }
54      set { label = value; }
55    }
56
57    private Size size;
58    public Size Size {
59      private set { size = value; }
60      get { return size; }
61    }
62
63    private Point position;
64    public Point Position {
65      get { return position; }
66      set {
67        var oldpos = position;
68        position = value;
69        int ox = position.X - oldpos.X;
70        int oy = position.Y - oldpos.Y;
71        // translate all primitives to the new position
72        foreach (var p in Primitives) {
73          var rpb = p as RectangularPrimitiveBase;
74          if (rpb != null) {
75            var lowerLeft = new Point((int)Math.Floor(rpb.LowerLeft.X) + ox, (int)Math.Floor(rpb.LowerLeft.Y + oy));
76            var upperRight = new PointD(lowerLeft.X + rpb.Size.Width, lowerLeft.Y + rpb.Size.Height);
77            rpb.SetPosition(lowerLeft, upperRight);
78          }
79          var line = p as LinearPrimitiveBase;
80          if (line != null) {
81            var start = new Point((int)Math.Floor(line.Start.X) + ox, (int)Math.Floor(line.Start.Y) + oy);
82            var end = new Point(start.X + (int)line.Size.Width, start.Y + (int)line.Size.Height);
83            line.SetPosition(start, end);
84          }
85        }
86      }
87    }
88
89    public IPrimitive GetPrimitive(ISymbolicExpressionTreeNode node) {
90      IPrimitive primitive;
91      nodesToPrimitives.TryGetValue(node, out primitive);
92      return primitive;
93    }
94
95    public ISymbolicExpressionTreeNode GetExpressionTreeNode(IPrimitive primitive) {
96      ISymbolicExpressionTreeNode node;
97      primitivesToNodes.TryGetValue(primitive, out node);
98      return node;
99    }
100
101    private ISymbolicExpressionTree symbolicExpressionTree;
102    public ISymbolicExpressionTree SymbolicExpressionTree {
103      get { return symbolicExpressionTree; }
104      set {
105        symbolicExpressionTree = value;
106        Root = symbolicExpressionTree.Root;
107      }
108    }
109
110    new private void Clear() {
111      Group.Clear();
112      primitivesToNodes.Clear();
113      nodesToPrimitives.Clear();
114    }
115
116    private ISymbolicExpressionTreeNode root;
117    public ISymbolicExpressionTreeNode Root {
118      get { return root; }
119      set {
120        root = value;
121        GeneratePrimitives(PreferredNodeWidth, PreferredNodeHeight);
122      }
123    }
124
125    public SymbolicExpressionTreeTile(IChart chart)
126      : base(chart) {
127      primitivesToNodes = new Dictionary<IPrimitive, ISymbolicExpressionTreeNode>();
128      nodesToPrimitives = new Dictionary<ISymbolicExpressionTreeNode, IPrimitive>();
129      PreferredNodeWidth = 80;
130      PreferredNodeHeight = 40;
131      Group = new Group(chart);
132
133      defaultBrush = new SolidBrush(Color.Transparent);
134      defaultPen = new Pen(Color.DimGray);
135      defaultFont = new Font(FontFamily.GenericSansSerif, 12, GraphicsUnit.Pixel);
136    }
137    public SymbolicExpressionTreeTile(IChart chart, ISymbolicExpressionTree tree)
138      : this(chart) {
139      SymbolicExpressionTree = tree;
140    }
141    private void GeneratePrimitives(double preferredNodeWidth, double preferredNodeHeight) {
142      Clear();
143      var actualRoot = Root;
144      //      if (Root.Symbol is ProgramRootSymbol && Root.SubtreeCount == 1) { actualRoot = Root.GetSubtree(0).GetSubtree(0); }
145
146      LayoutEngine.NodeWidth = PreferredNodeWidth;
147      LayoutEngine.NodeHeight = PreferredNodeHeight;
148
149      var visualNodes = LayoutEngine.CalculateLayout(actualRoot).ToList();
150
151      var visualNodeMap = visualNodes.ToDictionary(x => x.Content, x => x);
152
153      foreach (var visualNode in visualNodes) {
154        var lowerLeft = new PointD(visualNode.X, visualNode.Y);
155        var upperRight = new PointD(visualNode.X + preferredNodeWidth, visualNode.Y + preferredNodeHeight);
156        var node = visualNode.Content;
157
158        RectangularPrimitiveBase rectangularPrimitive;
159        var shortenedLabel = ShortenLabel(node);
160        if (node.SubtreeCount == 0) {
161          rectangularPrimitive = new Rectangle(Chart, lowerLeft, upperRight) {
162            Font = defaultFont, Text = shortenedLabel, Brush = defaultBrush, Pen = defaultPen, MaximumFontSize = 12f
163          };
164        } else {
165          rectangularPrimitive = new Ellipse(Chart, lowerLeft, upperRight) {
166            Font = defaultFont, Text = shortenedLabel, Brush = defaultBrush, Pen = defaultPen, MaximumFontSize = 12f
167          };
168        }
169
170        primitivesToNodes.Add(rectangularPrimitive, node); // to be able to retrieve nodes via primitives
171        nodesToPrimitives.Add(node, rectangularPrimitive);
172        this.Add(rectangularPrimitive);
173
174        if (rectangularPrimitive.Size.Width.IsAlmost(0) || rectangularPrimitive.Size.Height.IsAlmost(0)) {
175          throw new Exception("Primitive size cannot be zero.");
176        }
177      }
178
179      foreach (var node in visualNodes.Where(n => n.Content.SubtreeCount > 0)) {
180        var parent = node.Content;
181        foreach (var child in parent.Subtrees.Select(x => visualNodeMap[x])) {
182          var start = new PointD(node.X + preferredNodeWidth / 2, node.Y + preferredNodeHeight);
183          var end = new PointD(child.X + preferredNodeWidth / 2, child.Y);
184          var line = new Line(this.Chart, start, end) { Pen = defaultPen };
185          this.Add(line);
186        }
187      }
188      int xmin = 0, ymin = 0, xmax = 0, ymax = 0;
189      foreach (var rpb in Primitives.OfType<RectangularPrimitiveBase>()) {
190        if (xmin > rpb.LowerLeft.X) xmin = (int)Math.Floor(rpb.LowerLeft.X);
191        if (xmax < rpb.UpperRight.X) xmax = (int)Math.Ceiling(rpb.UpperRight.X);
192        if (ymin > rpb.LowerLeft.Y) ymin = (int)Math.Floor(rpb.LowerLeft.Y);
193        if (ymax < rpb.UpperRight.Y) ymax = (int)Math.Ceiling(rpb.UpperRight.Y);
194      }
195      int width = xmax - xmin;
196      int height = ymax - ymin;
197
198      // draw a primitive to display the label
199      var labelRect = new Rectangle(this.Chart, new PointD(0, height), new PointD(width, height + labelHeight)) {
200        Pen = defaultPen,
201        Brush = defaultBrush,
202        Text = Label,
203        Font = defaultFont
204      };
205      this.Add(labelRect);
206
207      // draw a rectangle to mark the countour of this tile
208      Size = new Size(width, height + labelHeight);
209
210      var rectangle = new Rectangle(this.Chart, new PointD(0, 0), new PointD(Size.Width, Size.Height)) {
211        Pen = defaultPen,
212        Brush = defaultBrush
213      };
214      this.Add(rectangle);
215
216      // flip primitives vertically
217      foreach (var primitive in Primitives) {
218        var rpb = primitive as RectangularPrimitiveBase;
219        if (rpb != null) {
220          rpb.SetPosition(rpb.LowerLeft.X, Size.Height - rpb.UpperRight.Y, rpb.UpperRight.X, Size.Height - rpb.LowerLeft.Y);
221
222        } else {
223          var line = primitive as LinearPrimitiveBase;
224          if (line != null) {
225            line.SetPosition(line.Start.X, Size.Height - line.Start.Y, line.End.X, Size.Height - line.End.Y);
226          }
227        }
228      }
229    }
230
231    public override void Draw(Graphics graphics) {
232      graphics.SmoothingMode = SmoothingMode.HighQuality;
233      graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
234      base.Draw(graphics);
235    }
236
237    private string ShortenLabel(ISymbolicExpressionTreeNode node) {
238      var term = node as SymbolicExpressionTreeTerminalNode;
239      if (term != null) {
240        var parts = term.ToString().Split(' '); // split by space
241        return parts.Length == 1 ? string.Format("{0:0.000}", double.Parse(parts[0])) : string.Format("{0:0.000} {1}", double.Parse(parts[0]), parts[1]);
242      }
243      return node.Symbol.ToString().Substring(0, 3);
244    }
245  }
246}
Note: See TracBrowser for help on using the repository browser.