source: trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/BoxesLayoutEngine.cs @ 11065

Last change on this file since 11065 was 11065, checked in by gkronber, 5 years ago

#2076: minor changes to the code while reviewing / testing

File size: 4.9 KB
Line 
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
24using System;
25using System.Collections.Generic;
26using System.Linq;
27
28namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
29  public class BoxesLayoutEngine<T> : ILayoutEngine<T> where T : class {
30    public int NodeWidth { get; set; }
31    public int NodeHeight { get; set; }
32    public int HorizontalSpacing { get; set; }
33    public int VerticalSpacing { get; set; }
34
35    private readonly Func<T, IEnumerable<T>> GetChildren;
36    private readonly Func<T, int> GetLength;
37    private readonly Func<T, int> GetDepth;
38
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");
43
44      this.GetChildren = GetChildren;
45      this.GetLength = GetLength;
46      this.GetDepth = GetDepth;
47    }
48
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;
55    }
56
57    private void CreateVisualNodes(T root, Dictionary<T, VisualTreeNode<T>> map) {
58      var node = new VisualTreeNode<T>(root) {
59        PreferredWidth = NodeWidth,
60        PreferredHeight = NodeHeight
61      };
62
63      map.Add(root, node);
64      var children = GetChildren(root).ToList();
65      if (children.Any()) {
66        foreach (var child in children) {
67          CreateVisualNodes(child, map);
68        }
69      }
70    }
71
72    private void RecursiveLayout(Dictionary<T, VisualTreeNode<T>> nodeMap, VisualTreeNode<T> visualTreeNode, int x, int y, int width, int height) {
73      float center_x = x + width / 2;
74      float center_y = y + height / 2;
75      int actualWidth = width - HorizontalSpacing;
76      int actualHeight = height - VerticalSpacing;
77
78      //calculate size of node
79      if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
80        visualTreeNode.Width = visualTreeNode.PreferredWidth;
81        visualTreeNode.Height = visualTreeNode.PreferredHeight;
82        visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
83        visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
84      }
85        //width too small to draw in desired sized
86      else if (actualWidth < visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
87        visualTreeNode.Width = actualWidth;
88        visualTreeNode.Height = visualTreeNode.PreferredHeight;
89        visualTreeNode.X = x;
90        visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
91      }
92        //height too small to draw in desired sized
93      else if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight < visualTreeNode.PreferredHeight) {
94        visualTreeNode.Width = visualTreeNode.PreferredWidth;
95        visualTreeNode.Height = actualHeight;
96        visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
97        visualTreeNode.Y = y;
98      }
99        //width and height too small to draw in desired size
100      else {
101        visualTreeNode.Width = actualWidth;
102        visualTreeNode.Height = actualHeight;
103        visualTreeNode.X = x;
104        visualTreeNode.Y = y;
105      }
106      //calculate areas for the subtrees according to their tree size
107      var node = visualTreeNode.Content;
108      var children = GetChildren(node).ToList();
109      int[] xBoundaries = new int[children.Count + 1];
110      xBoundaries[0] = x;
111      for (int i = 0; i < children.Count; i++) {
112        xBoundaries[i + 1] = (int)(xBoundaries[i] + (width * (double)GetLength(children[i])) / (GetLength(node) - 1));
113        RecursiveLayout(nodeMap, nodeMap[children[i]], xBoundaries[i], y + height, xBoundaries[i + 1] - xBoundaries[i], height);
114      }
115    }
116  }
117}
Note: See TracBrowser for help on using the repository browser.