Changeset 10565 for trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs
- Timestamp:
- 03/07/14 16:23:41 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs
r10561 r10565 7 7 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views { 8 8 public class ReingoldTilfordLayoutEngine<T> : ILayoutEngine<T> where T : class { 9 private readonly Dictionary<T, LayoutNode<T>> nodeMap; // provides a reverse mapping T => LayoutNode10 9 public int NodeWidth { get; set; } 11 10 public int NodeHeight { get; set; } … … 22 21 } 23 22 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); 49 57 var children = GetChildren(lRoot.Content).ToList(); 50 58 if (!children.Any()) return; … … 61 69 node.Ancestor = node; 62 70 lRoot.Children.Add(node); 63 Expand(node); 64 } 65 } 66 67 public IEnumerable<T> GetContentNodes() { 68 return nodeMap.Keys; 69 } 70 71 public IEnumerable<VisualTreeNode<T>> GetVisualNodes() { 72 return nodeMap.Values.Select(x => new VisualTreeNode<T>(x.Content) { 73 Width = (int)Math.Round(x.Width), 74 Height = (int)Math.Round(x.Height), 75 X = (int)Math.Round(x.X), 76 Y = (int)Math.Round(x.Y) 77 }); 78 } 79 80 public IEnumerable<LayoutNode<T>> GetLayoutNodes() { 81 return nodeMap.Values; 82 } 83 84 public void AddNode(T content) { 85 if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); } 86 var node = new LayoutNode<T> { Content = content }; 87 nodeMap.Add(content, node); 88 } 89 90 public void AddNode(LayoutNode<T> node) { 91 var content = node.Content; 92 if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); } 93 nodeMap.Add(content, node); 94 } 95 96 public void AddNodes(IEnumerable<LayoutNode<T>> nodes) { 97 foreach (var node in nodes) 98 nodeMap.Add(node.Content, node); 99 } 100 101 public LayoutNode<T> GetNode(T content) { 102 LayoutNode<T> layoutNode; 103 nodeMap.TryGetValue(content, out layoutNode); 104 return layoutNode; 105 } 106 107 public void ResetCoordinates() { 108 foreach (var node in nodeMap.Values) { 109 node.ResetCoordinates(); 110 } 111 } 112 113 public Dictionary<T, PointF> GetCoordinates() { 114 return nodeMap.ToDictionary(x => x.Key, x => new PointF(x.Value.X, x.Value.Y)); 115 } 71 Expand(node, map); 72 } 73 } 74 116 75 117 76 /// <summary> 118 77 /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0) 119 78 /// </summary> 120 private void NormalizeCoordinates() { 121 var nodes = nodeMap.Values.ToList(); 79 private static void NormalizeCoordinates(IEnumerable<LayoutNode<T>> nodes) { 122 80 float xmin = 0, ymin = 0; 123 81 foreach (var node in nodes) { … … 131 89 } 132 90 133 p ublic void Center(float width, float height) {91 private void Center(float width, float height, IEnumerable<LayoutNode<T>> nodes) { 134 92 // center layout on screen 135 var bounds = Bounds( );93 var bounds = Bounds(nodes); 136 94 float dx = 0, dy = 0; 137 95 if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; } 138 96 if (height > bounds.Height) { dy = (height - bounds.Height) / 2f; } 139 foreach (var node in node Map.Values) { node.Translate(dx, dy); }140 } 141 142 p ublic void FitToBounds(float width, float height) {143 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); 144 102 var myWidth = bounds.Width; 145 103 var myHeight = bounds.Height; … … 147 105 if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds 148 106 149 var layers = node Map.Values.GroupBy(node => node.Level, node => node).ToList();107 var layers = nodes.GroupBy(node => node.Level, node => node).ToList(); 150 108 151 109 if (myWidth > width) { … … 158 116 float spacing = minHorizontalSpacing * x; 159 117 foreach (var layer in layers) { 160 var nodes = layer.ToList();118 var nodesLayer = layer.ToList(); 161 119 float minWidth = float.MaxValue; 162 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); } 163 121 float w = Math.Min(NodeWidth, minWidth - spacing); 164 foreach (var node in nodes ) {122 foreach (var node in nodesLayer) { 165 123 node.X += (node.Width - w) / 2f; 166 124 node.Width = w; … … 186 144 } 187 145 188 public void Clear() {189 layoutRoot = null;190 nodeMap.Clear();191 }192 193 public void Reset() {194 foreach (var layoutNode in nodeMap.Values) {195 // reset layout-related parameters196 layoutNode.Reset();197 // reset the width and height since they might have been affected by scaling198 layoutNode.Width = NodeWidth;199 layoutNode.Height = NodeHeight;200 }201 }202 203 public void CalculateLayout() {204 if (layoutRoot == null) throw new Exception("Layout layoutRoot cannot be null.");205 Reset(); // reset node parameters like Mod, Shift etc. and set coordinates to 0206 FirstWalk(layoutRoot);207 SecondWalk(layoutRoot, -layoutRoot.Prelim);208 NormalizeCoordinates();209 }210 211 public void CalculateLayout(float width, float height) {212 CalculateLayout();213 FitToBounds(width, height);214 Center(width, height);215 }216 146 217 147 /// <summary> … … 219 149 /// </summary> 220 150 /// <returns></returns> 221 p ublic RectangleF Bounds() {151 private RectangleF Bounds(IEnumerable<LayoutNode<T>> nodes) { 222 152 float xmin = 0, xmax = 0, ymin = 0, ymax = 0; 223 var list = nodeMap.Values.ToList(); 224 foreach (LayoutNode<T> node in list) { 153 foreach (LayoutNode<T> node in nodes) { 225 154 float x = node.X, y = node.Y; 226 155 if (xmin > x) xmin = x;
Note: See TracChangeset
for help on using the changeset viewer.