Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1772: Added text labels to SymbolicExpressionTreeTiles so that the generation number is also displayed.

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