Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/24/14 16:56:18 (10 years ago)
Author:
bburlacu
Message:

#1772: Merged trunk changes (related to the ReingoldTilfordLayoutEngine).

Location:
branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views

  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/Formatters/SymbolicExpressionTreeLatexFormatter.cs

    r10520 r10649  
    2222using System;
    2323using System.Collections.Generic;
     24using System.Drawing;
    2425using System.Globalization;
    2526using System.Linq;
     
    3637      {"StartSymbol","RPB"}
    3738    };
    38     private readonly ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>();
     39
     40    private readonly ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> layoutEngine;
    3941
    4042    public SymbolicExpressionTreeLatexFormatter()
    4143      : base("LaTeX/PDF Formatter", "Formatter for symbolic expression trees for use with latex package tikz.") {
    42       layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
     44      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>(n => n.Subtrees) {
    4345        HorizontalSpacing = 2,
    4446        VerticalSpacing = 2,
     
    5759
    5860    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
    59       layoutEngine.Reset();
    6061      var root = symbolicExpressionTree.Root;
    6162      var actualRoot = root.SubtreeCount == 0 ? root.GetSubtree(0) : root;
    62       layoutEngine.Initialize(actualRoot, x => x.Subtrees);
    63       layoutEngine.CalculateLayout();
    64       var nodeCoordinates = layoutEngine.GetCoordinates();
     63      var nodeCoordinates = layoutEngine.CalculateLayout(actualRoot).ToDictionary(n => n.Content, n => new PointF(n.X, n.Y));
    6564      var sb = new StringBuilder();
    6665      var nl = Environment.NewLine;
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/BoxesLayoutEngine.cs

    r10520 r10649  
    1 
     1#region License Information
     2
     3/* HeuristicLab
     4 * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     5 *
     6 * This file is part of HeuristicLab.
     7 *
     8 * HeuristicLab is free software: you can redistribute it and/or modify
     9 * it under the terms of the GNU General Public License as published by
     10 * the Free Software Foundation, either version 3 of the License, or
     11 * (at your option) any later version.
     12 *
     13 * HeuristicLab is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 * GNU General Public License for more details.
     17 *
     18 * You should have received a copy of the GNU General Public License
     19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
     20 */
     21
     22#endregion
     23
    224using System;
    325using System.Collections.Generic;
    4 using System.Drawing;
    526using System.Linq;
    627
    728namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    829  public class BoxesLayoutEngine<T> : ILayoutEngine<T> where T : class {
    9     private readonly Dictionary<T, VisualTreeNode<T>> nodeMap;
    10 
    1130    public int NodeWidth { get; set; }
    1231    public int NodeHeight { get; set; }
    1332    public int HorizontalSpacing { get; set; }
    1433    public int VerticalSpacing { get; set; }
    15     private VisualTreeNode<T> layoutRoot;
    1634
    17     public int Width { get; private set; }
    18     public int Height { get; private set; }
     35    private readonly Func<T, IEnumerable<T>> GetChildren;
     36    private readonly Func<T, int> GetLength;
     37    private readonly Func<T, int> GetDepth;
    1938
    20     public Func<T, IEnumerable<T>> GetChildren { get; set; }
    21     public Func<T, int> GetLength { get; set; }
    22     public Func<T, int> GetDepth { get; set; }
     39    public BoxesLayoutEngine(Func<T, IEnumerable<T>> GetChildren, Func<T, int> GetLength, Func<T, int> GetDepth) {
     40      if (GetChildren == null) throw new ArgumentNullException("GetChildren");
     41      if (GetLength == null) throw new ArgumentNullException("GetLength");
     42      if (GetDepth == null) throw new ArgumentNullException("GetDepth");
    2343
    24     public BoxesLayoutEngine() {
    25       nodeMap = new Dictionary<T, VisualTreeNode<T>>();
     44      this.GetChildren = GetChildren;
     45      this.GetLength = GetLength;
     46      this.GetDepth = GetDepth;
    2647    }
    2748
    28     public void CalculateLayout() {
    29       throw new Exception("The BoxesLayoutEngine does not support arbitrary bounds. Please use method CalculateLayout(Width, Height)");
     49
     50    public IEnumerable<VisualTreeNode<T>> CalculateLayout(T root, float width, float height) {
     51      var nodeMap = new Dictionary<T, VisualTreeNode<T>>();
     52      CreateVisualNodes(root, nodeMap);
     53      RecursiveLayout(nodeMap, nodeMap[root], 0, 0, (int)Math.Round(width), (int)Math.Round(height) / GetDepth(root));
     54      return nodeMap.Values;
    3055    }
    3156
    32     public void CalculateLayout(float width, float height) {
    33       Width = (int)Math.Round(width);
    34       Height = (int)Math.Round(height);
    35       Reset();
    36       RecursiveLayout(layoutRoot, 0, 0, Width, Height / GetDepth(layoutRoot.Content));
    37     }
    38 
    39     public void Initialize(T root, Func<T, IEnumerable<T>> getChildren, Func<T, int> getLength, Func<T, int> getDepth) {
    40       if (getChildren == null || getLength == null || getDepth == null)
    41         throw new ArgumentNullException("The BoxesLayoutEngine requires all of the lambdas: (getChildren, getLength and getDepth) to be defined.");
    42       GetChildren = getChildren;
    43       GetLength = getLength;
    44       GetDepth = getDepth;
    45       Clear();
    46       Expand(root); // produce the nodeMap
    47       layoutRoot = nodeMap[root];
    48     }
    49 
    50     private void Expand(T root) {
     57    private void CreateVisualNodes(T root, Dictionary<T, VisualTreeNode<T>> map) {
    5158      var node = new VisualTreeNode<T>(root) {
    5259        PreferredWidth = NodeWidth,
    5360        PreferredHeight = NodeHeight
    5461      };
    55       nodeMap.Add(root, node);
     62
     63      map.Add(root, node);
    5664      var children = GetChildren(root).ToList();
    5765      if (children.Any()) {
    5866        foreach (var child in children) {
    59           Expand(child);
     67          CreateVisualNodes(child, map);
    6068        }
    6169      }
    6270    }
    6371
    64     public void Center(float width, float height) {
    65       // does nothing because the BoxesLayout centers the tree by default
    66     }
    67 
    68     public void Clear() {
    69       nodeMap.Clear();
    70       layoutRoot = null;
    71     }
    72 
    73     public void Reset() {
    74       foreach (var node in nodeMap.Values) {
    75         node.X = 0;
    76         node.Y = 0;
    77       }
    78     }
    79 
    80     public Dictionary<T, PointF> GetCoordinates() {
    81       return nodeMap.ToDictionary(x => x.Key, x => new PointF(x.Value.X, x.Value.Y));
    82     }
    83 
    84     public void FitToBounds(float width, float height) {
    85       // does nothing because the BoxesLayout is by default stretched on the whole drawing area
    86     }
    87 
    88     private void RecursiveLayout(VisualTreeNode<T> visualTreeNode, int x, int y, int width, int height) {
     72    private void RecursiveLayout(Dictionary<T, VisualTreeNode<T>> nodeMap, VisualTreeNode<T> visualTreeNode, int x, int y, int width, int height) {
    8973      float center_x = x + width / 2;
    9074      float center_y = y + height / 2;
     
    127111      for (int i = 0; i < children.Count; i++) {
    128112        xBoundaries[i + 1] = (int)(xBoundaries[i] + (width * (double)GetLength(children[i])) / (GetLength(node) - 1));
    129         RecursiveLayout(nodeMap[children[i]], xBoundaries[i], y + height, xBoundaries[i + 1] - xBoundaries[i], height);
     113        RecursiveLayout(nodeMap, nodeMap[children[i]], xBoundaries[i], y + height, xBoundaries[i + 1] - xBoundaries[i], height);
    130114      }
    131     }
    132 
    133     public IEnumerable<VisualTreeNode<T>> GetVisualNodes() {
    134       return nodeMap.Values;
    135115    }
    136116  }
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ILayoutEngine.cs

    r10520 r10649  
    1 
    2 using System;
     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
     21#endregion
     22
    323using System.Collections.Generic;
    4 using System.Drawing;
    524
    625namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
     
    1130    int VerticalSpacing { get; set; }
    1231
    13     void CalculateLayout();
    14     void CalculateLayout(float width, float height);
    15     void Initialize(T root, Func<T, IEnumerable<T>> getChildren, Func<T, int> getLength = null, Func<T, int> getDepth = null);
    16     void Clear();
    17     void Reset();
    18 
    19     // function members necessary to navigate the tree structure
    20     Func<T, IEnumerable<T>> GetChildren { get; set; }
    21     Func<T, int> GetLength { get; set; }
    22     Func<T, int> GetDepth { get; set; }
    23 
    24     IEnumerable<VisualTreeNode<T>> GetVisualNodes();
    25     Dictionary<T, PointF> GetCoordinates();
     32    IEnumerable<VisualTreeNode<T>> CalculateLayout(T root, float width, float height);
    2633  }
    2734}
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs

    r10520 r10649  
    2525
    2626namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    27   public class LayoutNode<T> : object where T : class {
     27  internal class LayoutNode<T> : object where T : class {
    2828    public float Width { get; set; }
    2929    public float Height { get; set; }
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs

    r10520 r10649  
    1 
     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
    222using System;
    323using System.Collections.Generic;
     
    727namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    828  public class ReingoldTilfordLayoutEngine<T> : ILayoutEngine<T> where T : class {
    9     private readonly Dictionary<T, LayoutNode<T>> nodeMap; // provides a reverse mapping T => LayoutNode
    1029    public int NodeWidth { get; set; }
    1130    public int NodeHeight { get; set; }
     
    2241    }
    2342
    24     public Func<T, IEnumerable<T>> GetChildren { get; set; }
    25     public Func<T, int> GetLength { get; set; }
    26     public Func<T, int> GetDepth { get; set; }
    27     private LayoutNode<T> layoutRoot;
    28 
    29     public ReingoldTilfordLayoutEngine() {
    30       nodeMap = new Dictionary<T, LayoutNode<T>>();
    31     }
    32 
    33     public ReingoldTilfordLayoutEngine(T root, Func<T, IEnumerable<T>> childrenFunc)
    34       : this() {
    35       Initialize(root, childrenFunc);
    36     }
    37 
    38     public void Initialize(T root, Func<T, IEnumerable<T>> getChildren, Func<T, int> getLength = null, Func<T, int> getDepth = null) {
    39       GetChildren = getChildren;
    40       Clear();
    41       var node = new LayoutNode<T> { Content = root, Width = NodeWidth, Height = NodeHeight };
    42       node.Ancestor = node;
    43       layoutRoot = node;
    44       Expand(node);
    45     }
    46 
    47     private void Expand(LayoutNode<T> lRoot) {
    48       nodeMap.Add(lRoot.Content, lRoot);
     43    private readonly Func<T, IEnumerable<T>> GetChildren;
     44
     45    public ReingoldTilfordLayoutEngine(Func<T, IEnumerable<T>> GetChildren) {
     46      this.GetChildren = GetChildren;
     47    }
     48
     49    public IEnumerable<VisualTreeNode<T>> CalculateLayout(T root) {
     50      return CalculateLayout(root, 0, 0);
     51    }
     52
     53    public IEnumerable<VisualTreeNode<T>> CalculateLayout(T root, float width, float height) {
     54      Dictionary<T, LayoutNode<T>> layoutNodeMap = new Dictionary<T, LayoutNode<T>>();
     55      var layoutRoot = new LayoutNode<T> { Content = root, Width = NodeWidth, Height = NodeHeight, };
     56      layoutRoot.Ancestor = layoutRoot;
     57      Expand(layoutRoot, layoutNodeMap);
     58
     59      FirstWalk(layoutRoot);
     60      SecondWalk(layoutRoot, -layoutRoot.Prelim);
     61      NormalizeCoordinates(layoutNodeMap.Values);
     62      if (height != 0 && width != 0) {
     63        FitToBounds(width, height, layoutNodeMap.Values);
     64        Center(width, height, layoutNodeMap.Values);
     65      }
     66
     67      return layoutNodeMap.Values.Select(x => new VisualTreeNode<T>(x.Content) {
     68        Width = (int)Math.Round(x.Width),
     69        Height = (int)Math.Round(x.Height),
     70        X = (int)Math.Round(x.X),
     71        Y = (int)Math.Round(x.Y)
     72      });
     73    }
     74
     75    private void Expand(LayoutNode<T> lRoot, Dictionary<T, LayoutNode<T>> map) {
     76      map.Add(lRoot.Content, lRoot);
    4977      var children = GetChildren(lRoot.Content).ToList();
    5078      if (!children.Any()) return;
     
    6189        node.Ancestor = node;
    6290        lRoot.Children.Add(node);
    63         Expand(node);
    64       }
    65     }
    66 
    67     public IEnumerable<VisualTreeNode<T>> GetVisualNodes() {
    68       return nodeMap.Values.Select(x => new VisualTreeNode<T>(x.Content) {
    69         Width = (int)Math.Round(x.Width),
    70         Height = (int)Math.Round(x.Height),
    71         X = (int)Math.Round(x.X),
    72         Y = (int)Math.Round(x.Y)
    73       });
    74     }
    75 
    76     public void AddNode(T content) {
    77       if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); }
    78       var node = new LayoutNode<T> { Content = content };
    79       nodeMap.Add(content, node);
    80     }
    81 
    82     public void AddNode(LayoutNode<T> node) {
    83       var content = node.Content;
    84       if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); }
    85       nodeMap.Add(content, node);
    86     }
    87 
    88     public void AddNodes(IEnumerable<LayoutNode<T>> nodes) {
    89       foreach (var node in nodes)
    90         nodeMap.Add(node.Content, node);
    91     }
    92 
    93     public LayoutNode<T> GetNode(T content) {
    94       LayoutNode<T> layoutNode;
    95       nodeMap.TryGetValue(content, out layoutNode);
    96       return layoutNode;
    97     }
    98 
    99     public void ResetCoordinates() {
    100       foreach (var node in nodeMap.Values) {
    101         node.ResetCoordinates();
    102       }
    103     }
    104 
    105     public Dictionary<T, PointF> GetCoordinates() {
    106       return nodeMap.ToDictionary(x => x.Key, x => new PointF(x.Value.X, x.Value.Y));
    107     }
     91        Expand(node, map);
     92      }
     93    }
     94
    10895
    10996    /// <summary>
    11097    /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0)
    11198    /// </summary>
    112     private void NormalizeCoordinates() {
    113       var nodes = nodeMap.Values.ToList();
     99    private static void NormalizeCoordinates(IEnumerable<LayoutNode<T>> nodes) {
    114100      float xmin = 0, ymin = 0;
    115101      foreach (var node in nodes) {
     
    123109    }
    124110
    125     public void Center(float width, float height) {
     111    private void Center(float width, float height, IEnumerable<LayoutNode<T>> nodes) {
    126112      // center layout on screen
    127       var bounds = Bounds();
     113      var bounds = Bounds(nodes);
    128114      float dx = 0, dy = 0;
    129115      if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; }
    130116      if (height > bounds.Height) { dy = (height - bounds.Height) / 2f; }
    131       foreach (var node in nodeMap.Values) { node.Translate(dx, dy); }
    132     }
    133 
    134     public void FitToBounds(float width, float height) {
    135       var bounds = Bounds();
     117      foreach (var node in nodes) { node.Translate(dx, dy); }
     118    }
     119
     120    private void FitToBounds(float width, float height, IEnumerable<LayoutNode<T>> nodes) {
     121      var bounds = Bounds(nodes);
    136122      var myWidth = bounds.Width;
    137123      var myHeight = bounds.Height;
     
    139125      if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds
    140126
    141       var layers = nodeMap.Values.GroupBy(node => node.Level, node => node).ToList();
     127      var layers = nodes.GroupBy(node => node.Level, node => node).ToList();
    142128
    143129      if (myWidth > width) {
     
    150136        float spacing = minHorizontalSpacing * x;
    151137        foreach (var layer in layers) {
    152           var nodes = layer.ToList();
     138          var nodesLayer = layer.ToList();
    153139          float minWidth = float.MaxValue;
    154           for (int i = 0; i < nodes.Count - 1; ++i) { minWidth = Math.Min(minWidth, nodes[i + 1].X - nodes[i].X); }
     140          for (int i = 0; i < nodesLayer.Count - 1; ++i) { minWidth = Math.Min(minWidth, nodesLayer[i + 1].X - nodesLayer[i].X); }
    155141          float w = Math.Min(NodeWidth, minWidth - spacing);
    156           foreach (var node in nodes) {
     142          foreach (var node in nodesLayer) {
    157143            node.X += (node.Width - w) / 2f;
    158144            node.Width = w;
     
    178164    }
    179165
    180     public void Clear() {
    181       layoutRoot = null;
    182       nodeMap.Clear();
    183     }
    184 
    185     public void Reset() {
    186       foreach (var layoutNode in nodeMap.Values) {
    187         // reset layout-related parameters
    188         layoutNode.Reset();
    189       }
    190     }
    191 
    192     public void CalculateLayout() {
    193       if (layoutRoot == null) throw new Exception("Layout layoutRoot cannot be null.");
    194       Reset(); // reset node parameters like Mod, Shift etc. and set coordinates to 0
    195       FirstWalk(layoutRoot);
    196       SecondWalk(layoutRoot, -layoutRoot.Prelim);
    197       NormalizeCoordinates();
    198     }
    199 
    200     public void CalculateLayout(float width, float height) {
    201       CalculateLayout();
    202       FitToBounds(width, height);
    203       Center(width, height);
    204     }
    205166
    206167    /// <summary>
     
    208169    /// </summary>
    209170    /// <returns></returns>
    210     public RectangleF Bounds() {
     171    private RectangleF Bounds(IEnumerable<LayoutNode<T>> nodes) {
    211172      float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
    212       var list = nodeMap.Values.ToList();
    213       foreach (LayoutNode<T> node in list) {
     173      foreach (LayoutNode<T> node in nodes) {
    214174        float x = node.X, y = node.Y;
    215175        if (xmin > x) xmin = x;
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs

    r10524 r10649  
    105105
    106106      var tree = new SymbolicExpressionTree(new SymbolicExpressionTreeNode(Symbol));
    107       symbolicExpressionTreeChart.SuspendRepaint = true;
    108107      if (Grammar.GetMaximumSubtreeCount(Symbol) > 0) {
    109108        for (int i = 0; i < Grammar.GetMaximumSubtreeCount(Symbol); i++) {
     
    118117      }
    119118      symbolicExpressionTreeChart.Tree = tree;
    120 
     119      symbolicExpressionTreeChart.SuspendRepaint = true;
    121120      foreach (var subtreeNode in tree.Root.Subtrees) {
    122121        foreach (var allowedChildNode in subtreeNode.Subtrees) {
     
    144143        }
    145144      }
    146 
    147145      symbolicExpressionTreeChart.SuspendRepaint = false;
    148146      UpdateSelectedSymbolicExpressionTreeNodes();
     
    155153        else visualNode.FillColor = Color.LightSteelBlue;
    156154      }
    157       symbolicExpressionTreeChart.Repaint();
     155      symbolicExpressionTreeChart.RepaintNodes();
    158156    }
    159157
  • branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs

    r10524 r10649  
    2727using System.Linq;
    2828using System.Windows.Forms;
    29 using Point = System.Drawing.Point;
     29
    3030
    3131namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
     
    5050      this.backgroundColor = Color.White;
    5151      this.textFont = new Font(FontFamily.GenericSansSerif, 12);
    52       //      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
    53       layoutEngine = new BoxesLayoutEngine<ISymbolicExpressionTreeNode> {
     52
     53      visualTreeNodes = new Dictionary<ISymbolicExpressionTreeNode, VisualTreeNode<ISymbolicExpressionTreeNode>>();
     54      visualLines = new Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualTreeNodeConnection>();
     55
     56      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>(n => n.Subtrees) {
    5457        NodeWidth = preferredNodeWidth,
    5558        NodeHeight = preferredNodeHeight,
     
    5760        VerticalSpacing = minVerticalDistance
    5861      };
    59     }
     62      reingoldTilfordToolStripMenuItem.Checked = true;
     63    }
     64
     65    //private ILayoutEngine<ISymbolicExpressionTreeNode> TreeLayoutEngine {
     66    //  get { return layoutEngine; }
     67    //  set {
     68    //    layoutEngine = value;
     69    //    InitializeLayout();
     70    //    Repaint();
     71    //  }
     72    //}
    6073
    6174    public SymbolicExpressionTreeChart(ISymbolicExpressionTree tree)
     
    106119      set {
    107120        tree = value;
    108         if (tree != null) {
    109           Repaint();
    110         }
     121        Repaint();
    111122      }
    112123    }
     
    127138      if (this.Width <= 1 || this.Height <= 1)
    128139        this.image = new Bitmap(1, 1);
    129       else
     140      else {
    130141        this.image = new Bitmap(Width, Height);
     142      }
    131143      this.Repaint();
     144    }
     145
     146    public event EventHandler Repainted;//expose this event to notify the parent control that the tree was repainted
     147    protected virtual void OnRepaint(object sender, EventArgs e) {
     148      var repainted = Repainted;
     149      if (repainted != null) {
     150        repainted(sender, e);
     151      }
    132152    }
    133153
     
    136156        this.GenerateImage();
    137157        this.Refresh();
     158        OnRepaint(this, EventArgs.Empty);
    138159      }
    139160    }
     
    146167          foreach (var visualNode in visualTreeNodes.Values) {
    147168            DrawTreeNode(graphics, visualNode);
     169            if (visualNode.Content.SubtreeCount > 0) {
     170              foreach (var visualSubtree in visualNode.Content.Subtrees.Select(s => visualTreeNodes[s])) {
     171                DrawLine(graphics, visualNode, visualSubtree);
     172              }
     173            }
    148174          }
    149175        }
     
    169195        graphics.Clear(backgroundColor);
    170196        if (tree != null) {
    171           DrawFunctionTree(tree, graphics, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
     197          DrawFunctionTree(graphics, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
    172198        }
    173199      }
     
    260286    #endregion
    261287
    262     #region methods for painting the symbolic expression tree
    263     private void DrawFunctionTree(ISymbolicExpressionTree symbExprTree, Graphics graphics, int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {
    264       var root = symbExprTree.Root;
    265       var actualRoot = root.SubtreeCount == 1 ? root.GetSubtree(0) : root;
     288    private void CalculateLayout(int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {
    266289      layoutEngine.NodeWidth = preferredWidth;
    267290      layoutEngine.NodeHeight = preferredHeight;
    268291      layoutEngine.HorizontalSpacing = minHDistance;
    269292      layoutEngine.VerticalSpacing = minVDistance;
    270       layoutEngine.Initialize(actualRoot, n => n.Subtrees, n => n.GetLength(), n => n.GetDepth());
    271       layoutEngine.CalculateLayout(Width, Height);
    272 
    273       var visualNodes = layoutEngine.GetVisualNodes().ToList();
     293
     294      var actualRoot = tree.Root;
     295      if (actualRoot.Symbol is ProgramRootSymbol && actualRoot.SubtreeCount == 1) {
     296        actualRoot = tree.Root.GetSubtree(0);
     297      }
     298
     299      var visualNodes = layoutEngine.CalculateLayout(actualRoot, Width, Height).ToList();
    274300      visualTreeNodes = visualNodes.ToDictionary(x => x.Content, x => x);
    275301      visualLines = new Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualTreeNodeConnection>();
     
    279305        }
    280306      }
    281       // draw nodes and connections
     307    }
     308
     309    #region methods for painting the symbolic expression tree
     310    private void DrawFunctionTree(Graphics graphics, int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {
     311      CalculateLayout(preferredWidth, preferredHeight, minHDistance, minVDistance);
     312      var visualNodes = visualTreeNodes.Values;
     313      //draw nodes and connections
    282314      foreach (var visualNode in visualNodes) {
    283315        DrawTreeNode(visualNode);
     
    325357      }
    326358    }
     359
     360    protected void DrawLine(Graphics graphics, VisualTreeNode<ISymbolicExpressionTreeNode> startNode, VisualTreeNode<ISymbolicExpressionTreeNode> endNode) {
     361      var origin = new Point(startNode.X + startNode.Width / 2, startNode.Y + startNode.Height);
     362      var target = new Point(endNode.X + endNode.Width / 2, endNode.Y);
     363      graphics.Clip = new Region(new Rectangle(Math.Min(origin.X, target.X), origin.Y, Math.Max(origin.X, target.X), target.Y));
     364      var visualLine = GetVisualSymbolicExpressionTreeNodeConnection(startNode.Content, endNode.Content);
     365      using (var linePen = new Pen(visualLine.LineColor)) {
     366        linePen.DashStyle = visualLine.DashStyle;
     367        graphics.DrawLine(linePen, origin, target);
     368      }
     369    }
    327370    #endregion
    328371    #region save image
     
    340383      Image image = new Bitmap(Width, Height);
    341384      using (Graphics g = Graphics.FromImage(image)) {
    342         DrawFunctionTree(tree, g, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
     385        DrawFunctionTree(g, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
    343386      }
    344387      image.Save(filename);
     
    350393        using (Metafile file = new Metafile(filename, g.GetHdc())) {
    351394          using (Graphics emfFile = Graphics.FromImage(file)) {
    352             DrawFunctionTree(tree, emfFile, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
     395            DrawFunctionTree(emfFile, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
    353396          }
    354397        }
     
    369412
    370413    private void reingoldTilfordToolStripMenuItem_Click(object sender, EventArgs e) {
    371       layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
     414      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>(n => n.Subtrees) {
    372415        NodeWidth = preferredNodeWidth,
    373416        NodeHeight = preferredNodeHeight,
     
    375418        VerticalSpacing = minVerticalDistance
    376419      };
     420      reingoldTilfordToolStripMenuItem.Checked = true;
     421      boxesToolStripMenuItem.Checked = false;
    377422      Repaint();
    378423    }
    379424
    380425    private void boxesToolStripMenuItem_Click(object sender, EventArgs e) {
    381       layoutEngine = new BoxesLayoutEngine<ISymbolicExpressionTreeNode> {
     426      layoutEngine = new BoxesLayoutEngine<ISymbolicExpressionTreeNode>(n => n.Subtrees, n => n.GetLength(), n => n.GetDepth()) {
    382427        NodeWidth = preferredNodeWidth,
    383428        NodeHeight = preferredNodeHeight,
     
    385430        VerticalSpacing = minVerticalDistance
    386431      };
     432      reingoldTilfordToolStripMenuItem.Checked = false;
     433      boxesToolStripMenuItem.Checked = true;
    387434      Repaint();
    388435    }
Note: See TracChangeset for help on using the changeset viewer.