Changeset 10649 for branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines
- Timestamp:
- 03/24/14 16:56:18 (11 years ago)
- Location:
- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views
- Property svn:mergeinfo changed
/trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views merged: 10531,10561,10565
- Property svn:mergeinfo changed
-
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 2 24 using System; 3 25 using System.Collections.Generic; 4 using System.Drawing;5 26 using System.Linq; 6 27 7 28 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views { 8 29 public class BoxesLayoutEngine<T> : ILayoutEngine<T> where T : class { 9 private readonly Dictionary<T, VisualTreeNode<T>> nodeMap;10 11 30 public int NodeWidth { get; set; } 12 31 public int NodeHeight { get; set; } 13 32 public int HorizontalSpacing { get; set; } 14 33 public int VerticalSpacing { get; set; } 15 private VisualTreeNode<T> layoutRoot;16 34 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; 19 38 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"); 23 43 24 public BoxesLayoutEngine() { 25 nodeMap = new Dictionary<T, VisualTreeNode<T>>(); 44 this.GetChildren = GetChildren; 45 this.GetLength = GetLength; 46 this.GetDepth = GetDepth; 26 47 } 27 48 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; 30 55 } 31 56 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) { 51 58 var node = new VisualTreeNode<T>(root) { 52 59 PreferredWidth = NodeWidth, 53 60 PreferredHeight = NodeHeight 54 61 }; 55 nodeMap.Add(root, node); 62 63 map.Add(root, node); 56 64 var children = GetChildren(root).ToList(); 57 65 if (children.Any()) { 58 66 foreach (var child in children) { 59 Expand(child);67 CreateVisualNodes(child, map); 60 68 } 61 69 } 62 70 } 63 71 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) { 89 73 float center_x = x + width / 2; 90 74 float center_y = y + height / 2; … … 127 111 for (int i = 0; i < children.Count; i++) { 128 112 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); 130 114 } 131 }132 133 public IEnumerable<VisualTreeNode<T>> GetVisualNodes() {134 return nodeMap.Values;135 115 } 136 116 } -
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 3 23 using System.Collections.Generic; 4 using System.Drawing;5 24 6 25 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views { … … 11 30 int VerticalSpacing { get; set; } 12 31 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); 26 33 } 27 34 } -
branches/HeuristicLab.EvolutionTracking/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs
r10520 r10649 25 25 26 26 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views { 27 publicclass LayoutNode<T> : object where T : class {27 internal class LayoutNode<T> : object where T : class { 28 28 public float Width { get; set; } 29 29 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 2 22 using System; 3 23 using System.Collections.Generic; … … 7 27 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views { 8 28 public class ReingoldTilfordLayoutEngine<T> : ILayoutEngine<T> where T : class { 9 private readonly Dictionary<T, LayoutNode<T>> nodeMap; // provides a reverse mapping T => LayoutNode10 29 public int NodeWidth { get; set; } 11 30 public int NodeHeight { get; set; } … … 22 41 } 23 42 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); 49 77 var children = GetChildren(lRoot.Content).ToList(); 50 78 if (!children.Any()) return; … … 61 89 node.Ancestor = node; 62 90 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 108 95 109 96 /// <summary> 110 97 /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0) 111 98 /// </summary> 112 private void NormalizeCoordinates() { 113 var nodes = nodeMap.Values.ToList(); 99 private static void NormalizeCoordinates(IEnumerable<LayoutNode<T>> nodes) { 114 100 float xmin = 0, ymin = 0; 115 101 foreach (var node in nodes) { … … 123 109 } 124 110 125 p ublic void Center(float width, float height) {111 private void Center(float width, float height, IEnumerable<LayoutNode<T>> nodes) { 126 112 // center layout on screen 127 var bounds = Bounds( );113 var bounds = Bounds(nodes); 128 114 float dx = 0, dy = 0; 129 115 if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; } 130 116 if (height > bounds.Height) { dy = (height - bounds.Height) / 2f; } 131 foreach (var node in node Map.Values) { node.Translate(dx, dy); }132 } 133 134 p ublic 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); 136 122 var myWidth = bounds.Width; 137 123 var myHeight = bounds.Height; … … 139 125 if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds 140 126 141 var layers = node Map.Values.GroupBy(node => node.Level, node => node).ToList();127 var layers = nodes.GroupBy(node => node.Level, node => node).ToList(); 142 128 143 129 if (myWidth > width) { … … 150 136 float spacing = minHorizontalSpacing * x; 151 137 foreach (var layer in layers) { 152 var nodes = layer.ToList();138 var nodesLayer = layer.ToList(); 153 139 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); } 155 141 float w = Math.Min(NodeWidth, minWidth - spacing); 156 foreach (var node in nodes ) {142 foreach (var node in nodesLayer) { 157 143 node.X += (node.Width - w) / 2f; 158 144 node.Width = w; … … 178 164 } 179 165 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 parameters188 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 0195 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 }205 166 206 167 /// <summary> … … 208 169 /// </summary> 209 170 /// <returns></returns> 210 p ublic RectangleF Bounds() {171 private RectangleF Bounds(IEnumerable<LayoutNode<T>> nodes) { 211 172 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) { 214 174 float x = node.X, y = node.Y; 215 175 if (xmin > x) xmin = x;
Note: See TracChangeset
for help on using the changeset viewer.