Ignore:
Timestamp:
07/07/14 16:55:50 (5 years ago)
Author:
gkronber
Message:

#2076,#2159, #2092
multi-ticket merge to stable:

Location:
stable
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views

  • stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs

    r10520 r11120  
    77namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    88  public class ReingoldTilfordLayoutEngine<T> : ILayoutEngine<T> where T : class {
    9     private readonly Dictionary<T, LayoutNode<T>> nodeMap; // provides a reverse mapping T => LayoutNode
    109    public int NodeWidth { get; set; }
    1110    public int NodeHeight { get; set; }
     
    2221    }
    2322
    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);
     23    private readonly Func<T, IEnumerable<T>> GetChildren;
     24
     25    public ReingoldTilfordLayoutEngine(Func<T, IEnumerable<T>> GetChildren) {
     26      this.GetChildren = GetChildren;
     27    }
     28
     29    public IEnumerable<VisualTreeNode<T>> CalculateLayout(T root) {
     30      return CalculateLayout(root, 0, 0);
     31    }
     32
     33    public IEnumerable<VisualTreeNode<T>> CalculateLayout(T root, float width, float height) {
     34      Dictionary<T, LayoutNode<T>> layoutNodeMap = new Dictionary<T, LayoutNode<T>>();
     35      var layoutRoot = new LayoutNode<T> { Content = root, Width = NodeWidth, Height = NodeHeight, };
     36      layoutRoot.Ancestor = layoutRoot;
     37      Expand(layoutRoot, layoutNodeMap);
     38
     39      FirstWalk(layoutRoot);
     40      SecondWalk(layoutRoot, -layoutRoot.Prelim);
     41      NormalizeCoordinates(layoutNodeMap.Values);
     42      if (height != 0 && width != 0) {
     43        FitToBounds(width, height, layoutNodeMap.Values);
     44        Center(width, height, layoutNodeMap.Values);
     45      }
     46
     47      return layoutNodeMap.Values.Select(x => new VisualTreeNode<T>(x.Content) {
     48        Width = (int)Math.Round(x.Width),
     49        Height = (int)Math.Round(x.Height),
     50        X = (int)Math.Round(x.X),
     51        Y = (int)Math.Round(x.Y)
     52      });
     53    }
     54
     55    private void Expand(LayoutNode<T> lRoot, Dictionary<T, LayoutNode<T>> map) {
     56      map.Add(lRoot.Content, lRoot);
    4957      var children = GetChildren(lRoot.Content).ToList();
    5058      if (!children.Any()) return;
     
    6169        node.Ancestor = node;
    6270        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     }
     71        Expand(node, map);
     72      }
     73    }
     74
    10875
    10976    /// <summary>
    11077    /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0)
    11178    /// </summary>
    112     private void NormalizeCoordinates() {
    113       var nodes = nodeMap.Values.ToList();
     79    private static void NormalizeCoordinates(IEnumerable<LayoutNode<T>> nodes) {
    11480      float xmin = 0, ymin = 0;
    11581      foreach (var node in nodes) {
     
    12389    }
    12490
    125     public void Center(float width, float height) {
     91    private void Center(float width, float height, IEnumerable<LayoutNode<T>> nodes) {
    12692      // center layout on screen
    127       var bounds = Bounds();
     93      var bounds = Bounds(nodes);
    12894      float dx = 0, dy = 0;
    12995      if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; }
    13096      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();
     97      foreach (var node in nodes) { node.Translate(dx, dy); }
     98    }
     99
     100    private void FitToBounds(float width, float height, IEnumerable<LayoutNode<T>> nodes) {
     101      var bounds = Bounds(nodes);
    136102      var myWidth = bounds.Width;
    137103      var myHeight = bounds.Height;
     
    139105      if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds
    140106
    141       var layers = nodeMap.Values.GroupBy(node => node.Level, node => node).ToList();
     107      var layers = nodes.GroupBy(node => node.Level, node => node).ToList();
    142108
    143109      if (myWidth > width) {
     
    150116        float spacing = minHorizontalSpacing * x;
    151117        foreach (var layer in layers) {
    152           var nodes = layer.ToList();
     118          var nodesLayer = layer.ToList();
    153119          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); }
     120          for (int i = 0; i < nodesLayer.Count - 1; ++i) { minWidth = Math.Min(minWidth, nodesLayer[i + 1].X - nodesLayer[i].X); }
    155121          float w = Math.Min(NodeWidth, minWidth - spacing);
    156           foreach (var node in nodes) {
     122          foreach (var node in nodesLayer) {
    157123            node.X += (node.Width - w) / 2f;
    158124            node.Width = w;
     
    178144    }
    179145
    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     }
    205146
    206147    /// <summary>
     
    208149    /// </summary>
    209150    /// <returns></returns>
    210     public RectangleF Bounds() {
     151    private RectangleF Bounds(IEnumerable<LayoutNode<T>> nodes) {
    211152      float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
    212       var list = nodeMap.Values.ToList();
    213       foreach (LayoutNode<T> node in list) {
     153      foreach (LayoutNode<T> node in nodes) {
    214154        float x = node.X, y = node.Y;
    215155        if (xmin > x) xmin = x;
Note: See TracChangeset for help on using the changeset viewer.