source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Tracking/FragmentGraphView.cs @ 10888

Last change on this file since 10888 was 10888, checked in by bburlacu, 8 years ago

#1772: Introduced separate class for FragmentNodes and adjusted tracing code. Fixed small bug creating the genealogy graph.

File size: 8.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.Linq;
26using HeuristicLab.Core.Views;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
29using HeuristicLab.EvolutionTracking;
30using HeuristicLab.MainForm;
31using HeuristicLab.Visualization;
32
33namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
34  [View("FragmentGraphView")]
35  [Content(typeof(FragmentGraph), IsDefaultView = true)]
36  public sealed partial class FragmentGraphView : ItemView {
37    private const int PreferredHorizontalSpacing = 10;
38    private const int PreferredVerticalSpacing = 25;
39
40    private ReingoldTilfordLayoutEngine<TileLayoutNode> layoutEngine;
41    private ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> symbolicExpressionEngine;
42
43    private Dictionary<FragmentNode, TileLayoutNode> tileDictionary;
44
45    private SymbolicExpressionTreeTile Root { get; set; }
46
47    public new FragmentGraph Content {
48      get { return (FragmentGraph)base.Content; }
49      set { base.Content = value; }
50    }
51
52    public FragmentGraphView() {
53      InitializeComponent();
54
55      layoutEngine = new ReingoldTilfordLayoutEngine<TileLayoutNode>(n => n.Children) {
56        HorizontalSpacing = PreferredHorizontalSpacing,
57        VerticalSpacing = PreferredVerticalSpacing,
58      };
59      symbolicExpressionEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>(n => n.Subtrees) {
60        HorizontalSpacing = PreferredHorizontalSpacing,
61        VerticalSpacing = PreferredVerticalSpacing,
62        NodeWidth = 80,
63        NodeHeight = 40
64      };
65      tileDictionary = new Dictionary<FragmentNode, TileLayoutNode>();
66    }
67
68    private void MakeTiles() {
69      var chart = symbolicExpressionChartControl.Chart;
70      tileDictionary.Clear();
71      foreach (var node in Content.Nodes) {
72        var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)node.Content;
73        var tile = new SymbolicExpressionTreeTile(chart);
74        tile.LayoutEngine = symbolicExpressionEngine;
75        tile.Label = "Generation " + node.Content.Rank + Environment.NewLine +
76                     "Quality " + String.Format("{0:0.000}", node.Content.Quality);
77        tile.Root = graphNode.Content.Root;
78        var tileNode = new TileLayoutNode { Tile = tile };
79        tileDictionary.Add(node, tileNode);
80      }
81      foreach (var node in Content.Nodes.Where(n => n.OutArcs.Any())) {
82        var layoutNode = tileDictionary[node];
83        layoutNode.Children = new List<TileLayoutNode>(node.OutArcs.Select(a => tileDictionary[(FragmentNode)a.Target]));
84      }
85    }
86
87    private void Draw() {
88      var chart = symbolicExpressionChartControl.Chart;
89      var nodes = Content.Nodes.ToList();
90      var root = nodes[0];
91      var fragmentRoot = tileDictionary[root];
92      int maxTileWidth = 0, maxTileHeight = 0;
93      var tiles = nodes.Select(x => tileDictionary[x].Tile).ToList();
94
95      foreach (var tile in tiles) {
96        var size = tile.Size;
97        if (maxTileWidth < size.Width) maxTileWidth = size.Width;
98        if (maxTileHeight < size.Height) maxTileHeight = size.Height;
99      }
100      layoutEngine.NodeWidth = maxTileWidth;
101      layoutEngine.NodeHeight = maxTileHeight;
102      layoutEngine.HorizontalSpacing = PreferredHorizontalSpacing;
103      layoutEngine.VerticalSpacing = PreferredVerticalSpacing;
104
105      var visualNodes = layoutEngine.CalculateLayout(fragmentRoot);
106
107      symbolicExpressionChartControl.UpdateEnabled = false;
108      foreach (var visualNode in visualNodes) {
109        var tile = visualNode.Content.Tile;
110        tile.Position = new Point(visualNode.X, visualNode.Y);
111        symbolicExpressionChartControl.Add(tile);
112      }
113
114      // add connections between the tiles
115      foreach (var node in nodes) {
116        var aTile = tileDictionary[node].Tile;
117        var aSize = aTile.Size;
118        var aPos = aTile.Position;
119        var graphNode = node.Content;
120
121        if (node.SubtreeIndex > 0) {
122          var subtree = graphNode.Content.Root.NodeAt(node.SubtreeIndex);
123          foreach (var s in subtree.IterateNodesPrefix()) {
124            var primitive = aTile.GetPrimitive(s);
125            if (primitive != null) {
126              var rpb = primitive as RectangularPrimitiveBase;
127              if (rpb != null) {
128                rpb.Pen = new Pen(Color.Black);
129              }
130            }
131          }
132        }
133        if (node.FragmentIndex > 0) {
134          var subtree = graphNode.Content.Root.NodeAt(node.FragmentIndex);
135          foreach (var s in subtree.IterateNodesPrefix()) {
136            var primitive = aTile.GetPrimitive(s);
137            if (primitive != null) {
138              var rpb = primitive as RectangularPrimitiveBase;
139              if (rpb != null) {
140                rpb.Brush = new SolidBrush(Color.LightGray);
141              }
142            }
143          }
144        }
145
146        if (node.InArcs.Any()) {
147          var parent = (FragmentNode)node.InArcs.First().Source;
148          if (parent.OutArcs.First().Target == node) {
149            var index = node.SubtreeIndex + (parent.FragmentIndex - parent.SubtreeIndex);
150            // some mutations create discontinuities which invalidate the index
151            if (index >= 0 && index < graphNode.Content.Length) {
152              var subtree = graphNode.Content.NodeAt(index);
153              var primitive = aTile.GetPrimitive(subtree);
154              primitive.Brush = new SolidBrush(Color.LightCoral);
155            }
156          }
157        }
158
159        foreach (var child in node.OutArcs.Select(x => (FragmentNode)x.Target)) {
160          var bTile = tileDictionary[child].Tile;
161          var bSize = bTile.Size;
162          var bPos = bTile.Position;
163
164          var line = new Line(chart, new PointD(aPos.X + aSize.Width / 2.0, aPos.Y + aSize.Height), new PointD(bPos.X + bSize.Width / 2.0, bPos.Y)) {
165            Pen = Pens.DimGray
166          };
167          symbolicExpressionChartControl.Add(line);
168        }
169      }
170      // center display on the root of the fragment graph
171      symbolicExpressionChartControl.Chart.Move(tileDictionary[root].Tile.Position.X, tileDictionary[root].Tile.Position.Y);
172      symbolicExpressionChartControl.UpdateEnabled = true;
173      symbolicExpressionChartControl.EnforceUpdate();
174    }
175
176    protected override void DeregisterContentEvents() {
177      // TODO: Deregister your event handlers here
178      base.DeregisterContentEvents();
179    }
180
181    protected override void RegisterContentEvents() {
182      base.RegisterContentEvents();
183      // TODO: Register your event handlers here
184    }
185
186    #region Event Handlers (Content)
187    // TODO: Put event handlers of the content here
188    protected override void OnContentChanged() {
189      base.OnContentChanged();
190      if (Content != null) {
191        MakeTiles();
192        Draw();
193      }
194    }
195    #endregion
196
197    protected override void SetEnabledStateOfControls() {
198      base.SetEnabledStateOfControls();
199      // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
200    }
201
202    #region Event Handlers (child controls)
203
204    // TODO: Put event handlers of child controls here.
205
206    #endregion
207  }
208
209  internal static class Util {
210    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
211      return NodeAt(tree.Root, position);
212    }
213    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
214      return root.IterateNodesPrefix().ElementAt(position);
215    }
216  }
217
218  internal class TileLayoutNode {
219    public SymbolicExpressionTreeTile Tile { get; set; }
220
221    private List<TileLayoutNode> children;
222    public IEnumerable<TileLayoutNode> Children {
223      get { return children ?? Enumerable.Empty<TileLayoutNode>(); }
224      set { children = value.ToList(); }
225    }
226  }
227}
Note: See TracBrowser for help on using the repository browser.