Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.ReingoldTilfordTreeLayout/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs @ 9852

Last change on this file since 9852 was 9852, checked in by bburlacu, 11 years ago

#2076: Created new branch as the old one was crashing subversion:

  • Restructured branch contents, created HeuristicLab.TreeLayout solution.
  • Merged HeuristicLab.Encodings.SymbolicExpressionTreeEncoding and HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views from the trunk
  • Renamed TreeLayout to ReingoldTilfordLayoutEngine and moved it to HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/LayoutEngines
  • Added SymbolicExpressionTreeLatexFormatter and modified the SymbolicExpressionTreeChart to allow the export of tree in pgf/latex format (using the formatter and the layout engine).
File size: 9.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 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;
26
27namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
28  class Node {
29    public Node Thread;
30    public Node Ancestor;
31
32    public float Mod; // position modifier
33    public float Prelim;
34    public float Change;
35    public float Shift;
36    public int Number;
37
38    public float X;
39    public float Y;
40
41    public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode;
42
43    public bool IsLeaf {
44      get { return SymbolicExpressionTreeNode.SubtreeCount == 0; }
45    }
46  }
47
48  public class ReingoldTilfordLayoutEngine {
49    private float distance = 5;
50    public float Distance {
51      get { return distance; }
52      set { distance = value; }
53    }
54
55    private ISymbolicExpressionTree symbolicExpressionTree;
56    public ISymbolicExpressionTree SymbolicExpressionTree {
57      get { return symbolicExpressionTree; }
58      set {
59        symbolicExpressionTree = value;
60        nodes.Clear();
61        var treeNodes = SymbolicExpressionTree.IterateNodesBreadth().ToList();
62        foreach (var treeNode in treeNodes) {
63          var node = new Node { SymbolicExpressionTreeNode = treeNode };
64          node.Ancestor = node;
65          nodes.Add(treeNode, node);
66        }
67        // assign a number to each node, representing its position among its siblings (parent.IndexOfSubtree)
68        foreach (var treeNode in treeNodes.Where(x => x.SubtreeCount > 0)) {
69          for (int i = 0; i != treeNode.SubtreeCount; ++i) {
70            nodes[treeNode.GetSubtree(i)].Number = i;
71          }
72        }
73        var r = nodes[symbolicExpressionTree.Root];
74        FirstWalk(r);
75        SecondWalk(r, -r.Prelim);
76        NormalizeCoordinates();
77      }
78    }
79
80    /// <summary>
81    /// Returns a map of coordinates for each node in the symbolic expression tree.
82    /// </summary>
83    /// <returns></returns>
84    public Dictionary<ISymbolicExpressionTreeNode, PointF> GetNodeCoordinates() {
85      var dict = new Dictionary<ISymbolicExpressionTreeNode, PointF>();
86      if (nodes == null || nodes.Count == 0) return dict;
87      foreach (var node in nodes.Values) {
88        dict.Add(node.SymbolicExpressionTreeNode, new PointF { X = node.X, Y = node.Y });
89      }
90      return dict;
91    }
92
93    /// <summary>
94    /// Returns the bounding box for this layout. When the layout is normalized, the rectangle should be [0,0,xmin,xmax].
95    /// </summary>
96    /// <returns></returns>
97    public RectangleF Bounds() {
98      float xmin, xmax, ymin, ymax; xmin = xmax = ymin = ymax = 0;
99      var list = nodes.Values.ToList();
100      for (int i = 0; i != list.Count; ++i) {
101        float x = list[i].X, y = list[i].Y;
102        if (xmin > x) xmin = x;
103        if (xmax < x) xmax = x;
104        if (ymin > y) ymin = y;
105        if (ymax < y) ymax = y;
106      }
107      return new RectangleF(xmin, ymin, xmax + distance, ymax + distance);
108    }
109
110    /// <summary>
111    /// Returns a string containing all the coordinates (useful for debugging).
112    /// </summary>
113    /// <returns></returns>
114    public string DumpCoordinates() {
115      if (nodes == null || nodes.Count == 0) return string.Empty;
116      return nodes.Values.Aggregate("", (current, node) => current + (node.X + " " + node.Y + Environment.NewLine));
117    }
118
119    private readonly Dictionary<ISymbolicExpressionTreeNode, Node> nodes;
120
121    public ReingoldTilfordLayoutEngine() {
122      nodes = new Dictionary<ISymbolicExpressionTreeNode, Node>();
123    }
124
125    /// <summary>
126    /// Transform node coordinates so that all coordinates are positive and start from 0.
127    /// </summary>
128    private void NormalizeCoordinates() {
129      var list = nodes.Values.ToList();
130      float xmin = 0, ymin = 0;
131      for (int i = 0; i != list.Count; ++i) {
132        if (xmin > list[i].X) xmin = list[i].X;
133        if (ymin > list[i].Y) ymin = list[i].Y;
134      }
135      for (int i = 0; i != list.Count; ++i) {
136        list[i].X -= xmin;
137        list[i].Y -= ymin;
138      }
139    }
140
141    private void FirstWalk(Node v) {
142      Node w;
143      if (v.IsLeaf) {
144        w = LeftSibling(v);
145        if (w != null) {
146          v.Prelim = w.Prelim + distance;
147        }
148      } else {
149        var symbExprNode = v.SymbolicExpressionTreeNode;
150        var defaultAncestor = nodes[symbExprNode.GetSubtree(0)]; // let defaultAncestor be the leftmost child of v
151        for (int i = 0; i != symbExprNode.SubtreeCount; ++i) {
152          var s = symbExprNode.GetSubtree(i);
153          w = nodes[s];
154          FirstWalk(w);
155          Apportion(w, ref defaultAncestor);
156        }
157        ExecuteShifts(v);
158        int c = symbExprNode.SubtreeCount;
159        var leftmost = nodes[symbExprNode.GetSubtree(0)];
160        var rightmost = nodes[symbExprNode.GetSubtree(c - 1)];
161        float midPoint = (leftmost.Prelim + rightmost.Prelim) / 2;
162        w = LeftSibling(v);
163        if (w != null) {
164          v.Prelim = w.Prelim + distance;
165          v.Mod = v.Prelim - midPoint;
166        } else {
167          v.Prelim = midPoint;
168        }
169      }
170    }
171
172    private void SecondWalk(Node v, float m) {
173      v.X = v.Prelim + m;
174      v.Y = symbolicExpressionTree.Root.GetBranchLevel(v.SymbolicExpressionTreeNode) * distance;
175      var symbExprNode = v.SymbolicExpressionTreeNode;
176      foreach (var s in symbExprNode.Subtrees) {
177        SecondWalk(nodes[s], m + v.Mod);
178      }
179    }
180
181    private void Apportion(Node v, ref Node defaultAncestor) {
182      var w = LeftSibling(v);
183      if (w == null) return;
184      Node vip = v;
185      Node vop = v;
186      Node vim = w;
187      Node vom = LeftmostSibling(vip);
188
189      float sip = vip.Mod;
190      float sop = vop.Mod;
191      float sim = vim.Mod;
192      float som = vom.Mod;
193
194      while (NextRight(vim) != null && NextLeft(vip) != null) {
195        vim = NextRight(vim);
196        vip = NextLeft(vip);
197        vom = NextLeft(vom);
198        vop = NextRight(vop);
199        vop.Ancestor = v;
200        float shift = (vim.Prelim + sim) - (vip.Prelim + sip) + distance;
201        if (shift > 0) {
202          var ancestor = Ancestor(vim, v) ?? defaultAncestor;
203          MoveSubtree(ancestor, v, shift);
204          sip += shift;
205          sop += shift;
206        }
207        sim += vim.Mod;
208        sip += vip.Mod;
209        som += vom.Mod;
210        sop += vop.Mod;
211      }
212      if (NextRight(vim) != null && NextRight(vop) == null) {
213        vop.Thread = NextRight(vim);
214        vop.Mod += (sim - sop);
215      }
216      if (NextLeft(vip) != null && NextLeft(vom) == null) {
217        vom.Thread = NextLeft(vip);
218        vom.Mod += (sip - som);
219        defaultAncestor = v;
220      }
221    }
222
223    private void MoveSubtree(Node wm, Node wp, float shift) {
224      int subtrees = wp.Number - wm.Number;
225      wp.Change -= shift / subtrees;
226      wp.Shift += shift;
227      wm.Change += shift / subtrees;
228      wp.Prelim += shift;
229      wp.Mod += shift;
230    }
231
232    private void ExecuteShifts(Node v) {
233      if (v.IsLeaf) return;
234      float shift = 0;
235      float change = 0;
236      for (int i = v.SymbolicExpressionTreeNode.SubtreeCount - 1; i >= 0; --i) {
237        var subtree = v.SymbolicExpressionTreeNode.GetSubtree(i);
238        var w = nodes[subtree];
239        w.Prelim += shift;
240        w.Mod += shift;
241        change += w.Change;
242        shift += (w.Shift + change);
243      }
244    }
245
246    #region Helper functions
247    private Node Ancestor(Node vi, Node v) {
248      var ancestor = vi.Ancestor;
249      return ancestor.SymbolicExpressionTreeNode.Parent == v.SymbolicExpressionTreeNode.Parent ? ancestor : null;
250    }
251
252    private Node NextLeft(Node v) {
253      int c = v.SymbolicExpressionTreeNode.SubtreeCount;
254      return c == 0 ? v.Thread : nodes[v.SymbolicExpressionTreeNode.GetSubtree(0)]; // return leftmost child
255    }
256
257    private Node NextRight(Node v) {
258      int c = v.SymbolicExpressionTreeNode.SubtreeCount;
259      return c == 0 ? v.Thread : nodes[v.SymbolicExpressionTreeNode.GetSubtree(c - 1)]; // return rightmost child
260    }
261
262    private Node LeftSibling(Node n) {
263      var parent = n.SymbolicExpressionTreeNode.Parent;
264      if (parent == null) return null;
265      int i = parent.IndexOfSubtree(n.SymbolicExpressionTreeNode);
266      if (i == 0) return null;
267      return nodes[parent.GetSubtree(i - 1)];
268    }
269
270    private Node LeftmostSibling(Node n) {
271      var parent = n.SymbolicExpressionTreeNode.Parent;
272      if (parent == null) return null;
273      int i = parent.IndexOfSubtree(n.SymbolicExpressionTreeNode);
274      if (i == 0) return null;
275      return nodes[parent.GetSubtree(0)];
276    }
277    #endregion
278  }
279}
Note: See TracBrowser for help on using the repository browser.