Changeset 10520


Ignore:
Timestamp:
02/28/14 11:56:15 (5 years ago)
Author:
bburlacu
Message:

#2076: Got rid of layout adapters. Extracted the previous drawing code and made it into another layout engine called the BoxesLayoutEngine (because it divides the areas necessary for each subtree into boxes and recursively applies the layout). Simplified usage of layout engine so that most of the things are handled internally, and the user just has to provide some lambdas telling the engine how to navigate the original tree. Added context option in the SymbolicExpressionTreeChart to choose which layout engine to use for tree drawing. Moved the SymbolicExpressionTreeLatexFormatter to the HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views assembly because it depends on the layout engine.

Location:
trunk/sources
Files:
3 added
2 deleted
7 edited
4 moved

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/Formatters/SymbolicExpressionTreeLatexFormatter.cs

    r10500 r10520  
    2828using HeuristicLab.Core;
    2929
    30 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
     30namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    3131  [Item("LaTeX/PDF Formatter", "Formatter for symbolic expression trees for use with latex package tikz.")]
    3232  public class SymbolicExpressionTreeLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
     
    3737    };
    3838    private readonly ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>();
    39     private readonly SymbolicExpressionTreeLayoutAdapter layoutAdapter = new SymbolicExpressionTreeLayoutAdapter();
    4039
    4140    public SymbolicExpressionTreeLatexFormatter()
    4241      : base("LaTeX/PDF Formatter", "Formatter for symbolic expression trees for use with latex package tikz.") {
    43       layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>();
     42      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
     43        HorizontalSpacing = 2,
     44        VerticalSpacing = 2,
     45        NodeWidth = 8,
     46        NodeHeight = 4
     47      };
    4448    }
    4549
     
    5458    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
    5559      layoutEngine.Reset();
    56       var layoutNodes = layoutAdapter.Convert(symbolicExpressionTree).ToList();
    57       layoutEngine.Root = layoutNodes[0];
    58       layoutEngine.AddNodes(layoutNodes);
     60      var root = symbolicExpressionTree.Root;
     61      var actualRoot = root.SubtreeCount == 0 ? root.GetSubtree(0) : root;
     62      layoutEngine.Initialize(actualRoot, x => x.Subtrees);
    5963      layoutEngine.CalculateLayout();
    60       var nodeCoordinates = layoutEngine.GetNodeCoordinates();
     64      var nodeCoordinates = layoutEngine.GetCoordinates();
    6165      var sb = new StringBuilder();
    6266      var nl = Environment.NewLine;
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4.csproj

    r8600 r10520  
    110110  </ItemGroup>
    111111  <ItemGroup>
     112    <Compile Include="Formatters\SymbolicExpressionTreeLatexFormatter.cs" />
     113    <Compile Include="LayoutEngines\BoxesLayoutEngine.cs" />
     114    <Compile Include="LayoutEngines\ILayoutEngine.cs" />
     115    <Compile Include="LayoutEngines\LayoutNode.cs" />
     116    <Compile Include="LayoutEngines\ReingoldTilfordLayoutEngine.cs" />
    112117    <Compile Include="Plugin.cs" />
    113118    <Compile Include="SymbolicExpressionGrammarAllowedChildSymbolsControl.cs">
     
    160165      <DependentUpon>SymbolicExpressionView.cs</DependentUpon>
    161166    </Compile>
    162     <Compile Include="VisualSymbolicExpressionTreeNode.cs" />
    163     <Compile Include="VisualSymbolicExpressionTreeNodeConnection.cs" />
     167    <Compile Include="VisualTreeNode.cs" />
     168    <Compile Include="VisualTreeNodeConnection.cs" />
    164169  </ItemGroup>
    165170  <ItemGroup>
     
    267272    </BootstrapperPackage>
    268273  </ItemGroup>
     274  <ItemGroup />
    269275  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    270276  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
     
    276282  -->
    277283  <PropertyGroup>
    278    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
     284    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
    279285set ProjectDir=$(ProjectDir)
    280286set SolutionDir=$(SolutionDir)
     
    283289call PreBuildEvent.cmd
    284290</PreBuildEvent>
    285 <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
     291    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
    286292export ProjectDir=$(ProjectDir)
    287293export SolutionDir=$(SolutionDir)
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs

    r10471 r10520  
    2424using System.Linq;
    2525
    26 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
    27   public class LayoutNode<T> where T : class {
     26namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
     27  public class LayoutNode<T> : object where T : class {
     28    public float Width { get; set; }
     29    public float Height { get; set; }
     30
    2831    public LayoutNode<T> NextLeft {
    2932      get {
     
    7578      }
    7679    }
     80    /// <summary>
     81    /// Translate the position of the layout node according to the given offsets
     82    /// </summary>
     83    /// <param name="dx"></param>
     84    /// <param name="dy"></param>
     85    public void Translate(float dx, float dy) {
     86      X += dx;
     87      Y += dy;
     88    }
     89
     90    public void ResetCoordinates() {
     91      X = 0;
     92      Y = 0;
     93    }
     94
     95    /// <summary>
     96    /// Reset layout-related parameters
     97    /// </summary>
     98    public void Reset() {
     99      Ancestor = this;
     100      Thread = null;
     101      Change = 0;
     102      Shift = 0;
     103      Prelim = 0;
     104      Mod = 0;
     105      ResetCoordinates();
     106    }
    77107  }
    78108}
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs

    r10471 r10520  
    55using System.Linq;
    66
    7 namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
    8   public class ReingoldTilfordLayoutEngine<T> where T : class {
     7namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
     8  public class ReingoldTilfordLayoutEngine<T> : ILayoutEngine<T> where T : class {
    99    private readonly Dictionary<T, LayoutNode<T>> nodeMap; // provides a reverse mapping T => LayoutNode
     10    public int NodeWidth { get; set; }
     11    public int NodeHeight { get; set; }
     12    private int minHorizontalSpacing = 5;
     13    public int HorizontalSpacing {
     14      get { return minHorizontalSpacing; }
     15      set { minHorizontalSpacing = value; }
     16    }
     17
     18    private int minVerticalSpacing = 5;
     19    public int VerticalSpacing {
     20      get { return minVerticalSpacing; }
     21      set { minVerticalSpacing = value; }
     22    }
     23
     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;
    1028
    1129    public ReingoldTilfordLayoutEngine() {
     
    1331    }
    1432
    15     public Dictionary<T, LayoutNode<T>> NodeMap { get { return nodeMap; } }
     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);
     49      var children = GetChildren(lRoot.Content).ToList();
     50      if (!children.Any()) return;
     51      lRoot.Children = new List<LayoutNode<T>>(children.Count);
     52      for (int i = 0; i < children.Count; ++i) {
     53        var node = new LayoutNode<T> {
     54          Content = children[i],
     55          Number = i,
     56          Parent = lRoot,
     57          Level = lRoot.Level + 1,
     58          Width = NodeWidth,
     59          Height = NodeHeight
     60        };
     61        node.Ancestor = node;
     62        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    }
    1675
    1776    public void AddNode(T content) {
    18       if (nodeMap.ContainsKey(content)) {
    19         throw new ArgumentException("Content already present in the dictionary.");
    20       }
     77      if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); }
    2178      var node = new LayoutNode<T> { Content = content };
    2279      nodeMap.Add(content, node);
     
    2582    public void AddNode(LayoutNode<T> node) {
    2683      var content = node.Content;
    27       if (nodeMap.ContainsKey(content)) {
    28         throw new ArgumentException("Content already present in the dictionary.");
    29       }
     84      if (nodeMap.ContainsKey(content)) { throw new ArgumentException("Content already present in the dictionary."); }
    3085      nodeMap.Add(content, node);
    3186    }
     
    4297    }
    4398
    44     private float minHorizontalSpacing = 5;
    45     public float MinHorizontalSpacing {
    46       get { return minHorizontalSpacing; }
    47       set { minHorizontalSpacing = value; }
    48     }
    49 
    50     private float minVerticalSpacing = 5;
    51     public float MinVerticalSpacing {
    52       get { return minVerticalSpacing; }
    53       set { minVerticalSpacing = value; }
    54     }
    55 
    56     private LayoutNode<T> root;
    57     public LayoutNode<T> Root {
    58       get { return root; }
    59       set {
    60         root = value;
    61       }
    62     }
    63 
    6499    public void ResetCoordinates() {
    65100      foreach (var node in nodeMap.Values) {
    66         node.X = 0;
    67         node.Y = 0;
    68       }
     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));
    69107    }
    70108
    71109    /// <summary>
    72     /// Transform LayoutNode coordinates so that all coordinates are positive and start from 0.
     110    /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0)
    73111    /// </summary>
    74112    private void NormalizeCoordinates() {
    75       var list = nodeMap.Values.ToList();
     113      var nodes = nodeMap.Values.ToList();
    76114      float xmin = 0, ymin = 0;
    77       for (int i = 0; i < list.Count; ++i) {
    78         if (xmin > list[i].X) xmin = list[i].X;
    79         if (ymin > list[i].Y) ymin = list[i].Y;
    80       }
    81       for (int i = 0; i < list.Count; ++i) {
    82         list[i].X -= xmin;
    83         list[i].Y -= ymin;
    84       }
     115      foreach (var node in nodes) {
     116        if (xmin > node.X) xmin = node.X;
     117        if (ymin > node.Y) ymin = node.Y;
     118      }
     119      foreach (var node in nodes) {
     120        node.X -= xmin;
     121        node.Y -= ymin;
     122      }
     123    }
     124
     125    public void Center(float width, float height) {
     126      // center layout on screen
     127      var bounds = Bounds();
     128      float dx = 0, dy = 0;
     129      if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; }
     130      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();
     136      var myWidth = bounds.Width;
     137      var myHeight = bounds.Height;
     138
     139      if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds
     140
     141      var layers = nodeMap.Values.GroupBy(node => node.Level, node => node).ToList();
     142
     143      if (myWidth > width) {
     144        // need to scale horizontally
     145        float x = width / myWidth;
     146        foreach (var node in layers.SelectMany(g => g)) {
     147          node.X *= x;
     148          node.Width *= x;
     149        }
     150        float spacing = minHorizontalSpacing * x;
     151        foreach (var layer in layers) {
     152          var nodes = layer.ToList();
     153          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); }
     155          float w = Math.Min(NodeWidth, minWidth - spacing);
     156          foreach (var node in nodes) {
     157            node.X += (node.Width - w) / 2f;
     158            node.Width = w;
     159            //this is a simple solution to ensure that the leftmost and rightmost nodes are not drawn partially offscreen due to scaling and offset
     160            //this should work well enough 99.9% of the time with no noticeable visual difference
     161            if (node.X < 0) {
     162              node.Width += node.X;
     163              node.X = 0;
     164            } else if (node.X + node.Width > width) {
     165              node.Width = width - node.X;
     166            }
     167          }
     168        }
     169      }
     170      if (myHeight > height) {
     171        // need to scale vertically
     172        float x = height / myHeight;
     173        foreach (var node in layers.SelectMany(g => g)) {
     174          node.Y *= x;
     175          node.Height *= x;
     176        }
     177      }
     178    }
     179
     180    public void Clear() {
     181      layoutRoot = null;
     182      nodeMap.Clear();
    85183    }
    86184
    87185    public void Reset() {
    88       root = null;
    89       nodeMap.Clear();
    90     }
    91 
    92     public void ResetParameters() {
    93186      foreach (var layoutNode in nodeMap.Values) {
    94187        // reset layout-related parameters
    95         layoutNode.Ancestor = layoutNode;
    96         layoutNode.Thread = null;
    97         layoutNode.Change = 0;
    98         layoutNode.Shift = 0;
    99         layoutNode.Prelim = 0;
    100         layoutNode.Mod = 0;
     188        layoutNode.Reset();
    101189      }
    102190    }
    103191
    104192    public void CalculateLayout() {
    105       if (root == null)
    106         throw new Exception("Root cannot be null.");
    107       ResetCoordinates(); // reset node X,Y coordinates
    108       ResetParameters(); // reset node parameters like Mod, Shift etc.
    109       FirstWalk(root);
    110       SecondWalk(root, -root.Prelim);
     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);
    111197      NormalizeCoordinates();
    112198    }
    113199
    114     /// <summary>
    115     /// Returns a map of coordinates for each LayoutNode in the symbolic expression tree.
    116     /// </summary>
    117     /// <returns></returns>
    118     public Dictionary<T, PointF> GetNodeCoordinates() {
    119       return nodeMap.ToDictionary(x => x.Key, x => new PointF(x.Value.X, x.Value.Y));
     200    public void CalculateLayout(float width, float height) {
     201      CalculateLayout();
     202      FitToBounds(width, height);
     203      Center(width, height);
    120204    }
    121205
     
    125209    /// <returns></returns>
    126210    public RectangleF Bounds() {
    127       float xmin, xmax, ymin, ymax; xmin = xmax = ymin = ymax = 0;
     211      float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
    128212      var list = nodeMap.Values.ToList();
    129       for (int i = 0; i < list.Count; ++i) {
    130         float x = list[i].X, y = list[i].Y;
     213      foreach (LayoutNode<T> node in list) {
     214        float x = node.X, y = node.Y;
    131215        if (xmin > x) xmin = x;
    132216        if (xmax < x) xmax = x;
     
    134218        if (ymax < y) ymax = y;
    135219      }
    136       return new RectangleF(xmin, ymin, xmax + minHorizontalSpacing, ymax + minVerticalSpacing);
    137     }
    138 
     220      return new RectangleF(xmin, ymin, xmax + minHorizontalSpacing + NodeWidth, ymax + minVerticalSpacing + NodeHeight);
     221    }
     222
     223    #region methods specific to the reingold-tilford layout algorithm
    139224    private void FirstWalk(LayoutNode<T> v) {
    140225      LayoutNode<T> w;
     
    142227        w = v.LeftSibling;
    143228        if (w != null) {
    144           v.Prelim = w.Prelim + minHorizontalSpacing;
     229          v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
    145230        }
    146231      } else {
     
    157242        w = v.LeftSibling;
    158243        if (w != null) {
    159           v.Prelim = w.Prelim + minHorizontalSpacing;
     244          v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
    160245          v.Mod = v.Prelim - midPoint;
    161246        } else {
     
    167252    private void SecondWalk(LayoutNode<T> v, float m) {
    168253      v.X = v.Prelim + m;
    169       v.Y = v.Level * minVerticalSpacing;
     254      v.Y = v.Level * (minVerticalSpacing + NodeHeight);
    170255      if (v.IsLeaf) return;
    171256      foreach (var child in v.Children) {
     
    193278        vop = vop.NextRight;
    194279        vop.Ancestor = v;
    195         float shift = (vim.Prelim + sim) - (vip.Prelim + sip) + minHorizontalSpacing;
     280        float shift = (vim.Prelim + sim) - (vip.Prelim + sip) + minHorizontalSpacing + NodeWidth;
    196281        if (shift > 0) {
    197282          var ancestor = Ancestor(vim, v) ?? defaultAncestor;
     
    244329      return ancestor.Parent == v.Parent ? ancestor : null;
    245330    }
     331    #endregion
    246332  }
    247333}
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs

    r9456 r10520  
    2929using HeuristicLab.PluginInfrastructure;
    3030
     31using VisualSymbolicExpressionTreeNode = HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views.VisualTreeNode<HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode>;
     32
    3133namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    3234  public sealed partial class SymbolicExpressionGrammarAllowedChildSymbolsControl : UserControl {
     
    162164
    163165      VisualSymbolicExpressionTreeNode clickedNode = (VisualSymbolicExpressionTreeNode)sender;
    164       var selectedNode = clickedNode.SymbolicExpressionTreeNode;
     166      var selectedNode = clickedNode.Content;
    165167      if (selectedNode.SubtreeCount == 0) {
    166168        if (!selectedSymbolicExpressionTreeNodes.Contains(selectedNode))
     
    207209        var visualNode = symbolicExpressionTreeChart.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
    208210        if (visualNode != null) {
    209           var node = visualNode.SymbolicExpressionTreeNode;
     211          var node = visualNode.Content;
    210212          var root = symbolicExpressionTreeChart.Tree.Root;
    211213          if (node == root || node.Parent == root) e.Effect = DragDropEffects.Copy;
     
    223225      var symbols = data as IEnumerable<ISymbol>;
    224226
    225       if (node.SymbolicExpressionTreeNode == root) {
     227      if (node.Content == root) {
    226228        if (symbol != null)
    227229          Grammar.AddAllowedChildSymbol(root.Symbol, symbol);
     
    229231          foreach (var s in symbols) Grammar.AddAllowedChildSymbol(root.Symbol, s);
    230232      } else {
    231         int argumentIndex = root.IndexOfSubtree(node.SymbolicExpressionTreeNode);
     233        int argumentIndex = root.IndexOfSubtree(node.Content);
    232234        if (symbol != null)
    233235          Grammar.AddAllowedChildSymbol(root.Symbol, symbol, argumentIndex);
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.Designer.cs

    r10496 r10520  
    4949      this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
    5050      this.saveImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
     51      this.exportPgfLaTeXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
     52      this.layoutEngineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
     53      this.reingoldTilfordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
     54      this.boxesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    5155      this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
    52       this.exportPgfLaTeXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    5356      this.contextMenuStrip.SuspendLayout();
    5457      this.SuspendLayout();
     
    5861      this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    5962            this.saveImageToolStripMenuItem,
    60             this.exportPgfLaTeXToolStripMenuItem});
     63            this.exportPgfLaTeXToolStripMenuItem,
     64            this.layoutEngineToolStripMenuItem});
    6165      this.contextMenuStrip.Name = "contextMenuStrip";
    6266      this.contextMenuStrip.Size = new System.Drawing.Size(166, 70);
     
    6569      //
    6670      this.saveImageToolStripMenuItem.Name = "saveImageToolStripMenuItem";
    67       this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
     71      this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(165, 22);
    6872      this.saveImageToolStripMenuItem.Text = "Save Image";
    6973      this.saveImageToolStripMenuItem.Click += new System.EventHandler(this.saveImageToolStripMenuItem_Click);
    70       //
    71       // saveFileDialog
    72       //
    73       this.saveFileDialog.Filter = "Bitmap (*.bmp)|*.bmp|EMF (*.emf)|*.emf";
    7474      //
    7575      // exportPgfLaTeXToolStripMenuItem
     
    7979      this.exportPgfLaTeXToolStripMenuItem.Text = "Export Pgf/LaTeX";
    8080      this.exportPgfLaTeXToolStripMenuItem.Click += new System.EventHandler(this.exportLatexToolStripMenuItem_Click);
     81      //
     82      // layoutEngineToolStripMenuItem
     83      //
     84      this.layoutEngineToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
     85            this.reingoldTilfordToolStripMenuItem,
     86            this.boxesToolStripMenuItem});
     87      this.layoutEngineToolStripMenuItem.Name = "layoutEngineToolStripMenuItem";
     88      this.layoutEngineToolStripMenuItem.Size = new System.Drawing.Size(165, 22);
     89      this.layoutEngineToolStripMenuItem.Text = "Layout Engine:";
     90      //
     91      // reingoldTilfordToolStripMenuItem
     92      //
     93      this.reingoldTilfordToolStripMenuItem.Name = "reingoldTilfordToolStripMenuItem";
     94      this.reingoldTilfordToolStripMenuItem.Size = new System.Drawing.Size(161, 22);
     95      this.reingoldTilfordToolStripMenuItem.Text = "Reingold-Tilford";
     96      this.reingoldTilfordToolStripMenuItem.Click += new System.EventHandler(this.reingoldTilfordToolStripMenuItem_Click);
     97      //
     98      // boxesToolStripMenuItem
     99      //
     100      this.boxesToolStripMenuItem.Name = "boxesToolStripMenuItem";
     101      this.boxesToolStripMenuItem.Size = new System.Drawing.Size(161, 22);
     102      this.boxesToolStripMenuItem.Text = "Boxes";
     103      this.boxesToolStripMenuItem.Click += new System.EventHandler(this.boxesToolStripMenuItem_Click);
     104      //
     105      // saveFileDialog
     106      //
     107      this.saveFileDialog.Filter = "Bitmap (*.bmp)|*.bmp|EMF (*.emf)|*.emf";
    81108      //
    82109      // SymbolicExpressionTreeChart
     
    103130    protected System.Windows.Forms.SaveFileDialog saveFileDialog;
    104131    private System.Windows.Forms.ToolStripMenuItem exportPgfLaTeXToolStripMenuItem;
     132    private System.Windows.Forms.ToolStripMenuItem layoutEngineToolStripMenuItem;
     133    private System.Windows.Forms.ToolStripMenuItem reingoldTilfordToolStripMenuItem;
     134    private System.Windows.Forms.ToolStripMenuItem boxesToolStripMenuItem;
    105135  }
    106136}
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs

    r10499 r10520  
    3333    private Image image;
    3434    private readonly StringFormat stringFormat;
    35     private Dictionary<ISymbolicExpressionTreeNode, VisualSymbolicExpressionTreeNode> visualTreeNodes;
    36     private Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualSymbolicExpressionTreeNodeConnection> visualLines;
    37     private readonly ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> layoutEngine;
    38     private readonly SymbolicExpressionTreeLayoutAdapter layoutAdapter;
     35    private Dictionary<ISymbolicExpressionTreeNode, VisualTreeNode<ISymbolicExpressionTreeNode>> visualTreeNodes;
     36    private Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualTreeNodeConnection> visualLines;
     37    private ILayoutEngine<ISymbolicExpressionTreeNode> layoutEngine;
    3938
    4039    private const int preferredNodeWidth = 70;
    4140    private const int preferredNodeHeight = 46;
    42     private const int minHorizontalDistance = 20;
    43     private const int minVerticalDistance = 20;
    44 
     41    private const int minHorizontalDistance = 30;
     42    private const int minVerticalDistance = 30;
    4543
    4644    public SymbolicExpressionTreeChart() {
     
    5250      this.backgroundColor = Color.White;
    5351      this.textFont = new Font(FontFamily.GenericSansSerif, 12);
    54       layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>();
    55       layoutAdapter = new SymbolicExpressionTreeLayoutAdapter();
     52      //      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
     53      layoutEngine = new BoxesLayoutEngine<ISymbolicExpressionTreeNode> {
     54        NodeWidth = preferredNodeWidth,
     55        NodeHeight = preferredNodeHeight,
     56        HorizontalSpacing = minHorizontalDistance,
     57        VerticalSpacing = minVerticalDistance
     58      };
    5659    }
    5760
    5861    public SymbolicExpressionTreeChart(ISymbolicExpressionTree tree)
    5962      : this() {
    60       layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>();
    61       layoutAdapter = new SymbolicExpressionTreeLayoutAdapter();
    6263      this.Tree = tree;
    6364    }
     
    105106      set {
    106107        tree = value;
    107         visualTreeNodes = new Dictionary<ISymbolicExpressionTreeNode, VisualSymbolicExpressionTreeNode>();
    108         visualLines = new Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualSymbolicExpressionTreeNodeConnection>();
    109108        if (tree != null) {
    110           IEnumerable<ISymbolicExpressionTreeNode> nodes;
    111           if (tree.Root.SubtreeCount == 1) nodes = tree.Root.GetSubtree(0).IterateNodesPrefix();
    112           else nodes = tree.Root.IterateNodesPrefix();
    113           foreach (ISymbolicExpressionTreeNode node in nodes) {
    114             visualTreeNodes[node] = new VisualSymbolicExpressionTreeNode(node);
    115             if (node.Parent != null) visualLines[Tuple.Create(node.Parent, node)] = new VisualSymbolicExpressionTreeNodeConnection();
    116           }
    117         }
    118         Repaint();
     109          Repaint();
     110        }
    119111      }
    120112    }
     
    160152    }
    161153
    162     public void RepaintNode(VisualSymbolicExpressionTreeNode visualNode) {
     154    public void RepaintNode(VisualTreeNode<ISymbolicExpressionTreeNode> visualNode) {
    163155      if (!suspendRepaint) {
    164156        using (var graphics = Graphics.FromImage(image)) {
     
    182174    }
    183175
    184     public VisualSymbolicExpressionTreeNode GetVisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) {
     176    public VisualTreeNode<ISymbolicExpressionTreeNode> GetVisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) {
    185177      if (visualTreeNodes.ContainsKey(symbolicExpressionTreeNode))
    186178        return visualTreeNodes[symbolicExpressionTreeNode];
     
    188180    }
    189181
    190     public VisualSymbolicExpressionTreeNodeConnection GetVisualSymbolicExpressionTreeNodeConnection(ISymbolicExpressionTreeNode parent, ISymbolicExpressionTreeNode child) {
     182    public VisualTreeNodeConnection GetVisualSymbolicExpressionTreeNodeConnection(ISymbolicExpressionTreeNode parent, ISymbolicExpressionTreeNode child) {
    191183      if (child.Parent != parent) throw new ArgumentException();
    192184      var key = Tuple.Create(parent, child);
    193       VisualSymbolicExpressionTreeNodeConnection connection = null;
     185      VisualTreeNodeConnection connection = null;
    194186      visualLines.TryGetValue(key, out connection);
    195187      return connection;
     
    205197
    206198    protected virtual void SymbolicExpressionTreeChart_MouseClick(object sender, MouseEventArgs e) {
    207       VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
     199      var visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
    208200      if (visualTreeNode != null) {
    209201        OnSymbolicExpressionTreeNodeClicked(visualTreeNode, e);
     
    219211
    220212    protected virtual void SymbolicExpressionTreeChart_MouseDoubleClick(object sender, MouseEventArgs e) {
    221       VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
     213      VisualTreeNode<ISymbolicExpressionTreeNode> visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
    222214      if (visualTreeNode != null)
    223215        OnSymbolicExpressionTreeNodeDoubleClicked(visualTreeNode, e);
     
    231223    }
    232224
    233     private VisualSymbolicExpressionTreeNode draggedSymbolicExpressionTree;
     225    private VisualTreeNode<ISymbolicExpressionTreeNode> draggedSymbolicExpressionTree;
    234226    private MouseButtons dragButtons;
    235227    private void SymbolicExpressionTreeChart_MouseDown(object sender, MouseEventArgs e) {
     
    243235
    244236    private void SymbolicExpressionTreeChart_MouseMove(object sender, MouseEventArgs e) {
    245       VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
     237      VisualTreeNode<ISymbolicExpressionTreeNode> visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
    246238      if (draggedSymbolicExpressionTree != null &&
    247239        draggedSymbolicExpressionTree != visualTreeNode) {
     
    258250    }
    259251
    260     public VisualSymbolicExpressionTreeNode FindVisualSymbolicExpressionTreeNodeAt(int x, int y) {
     252    public VisualTreeNode<ISymbolicExpressionTreeNode> FindVisualSymbolicExpressionTreeNodeAt(int x, int y) {
    261253      foreach (var visualTreeNode in visualTreeNodes.Values) {
    262254        if (x >= visualTreeNode.X && x <= visualTreeNode.X + visualTreeNode.Width &&
     
    269261
    270262    #region methods for painting the symbolic expression tree
    271     private void DrawFunctionTree(ISymbolicExpressionTree symbolicExpressionTree, Graphics graphics, int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {     
    272       var layoutNodes = layoutAdapter.Convert(symbolicExpressionTree).ToList();
    273       if(symbolicExpressionTree.Root.SubtreeCount==1) layoutNodes.RemoveAt(0);
    274       layoutEngine.Reset();
    275       layoutEngine.Root = layoutNodes[0];
    276       layoutEngine.AddNodes(layoutNodes);
    277       layoutEngine.MinHorizontalSpacing = (preferredWidth + minHDistance);
    278       layoutEngine.MinVerticalSpacing = (preferredHeight + minVDistance);
    279       layoutEngine.CalculateLayout();
    280       var bounds = layoutEngine.Bounds();
    281 
    282       double verticalScalingFactor = 1.0;
    283       double layoutHeight = (bounds.Height + preferredHeight);
    284       if (this.Height < layoutHeight)
    285         verticalScalingFactor = this.Height / layoutHeight;
    286 
    287       double horizontalScalingFactor = 1.0;
    288       double layoutWidth = (bounds.Width + preferredWidth);
    289       if (this.Width < layoutWidth)
    290         horizontalScalingFactor = this.Width / layoutWidth;
    291 
    292       double horizontalOffset;
    293       if (this.Width > layoutWidth)
    294         horizontalOffset = (this.Width - layoutWidth) / 2.0;
    295       else
    296         horizontalOffset = preferredWidth / 2.0;
    297 
    298       var levels = layoutNodes.GroupBy(n => n.Level, n => n).ToList();
    299       for (int i = levels.Count - 1; i >= 0; --i) {
    300         var nodes = levels[i].ToList();
    301 
    302         double minSpacing = double.MaxValue;
    303         if (nodes.Count > 1) {
    304           for (int j = 1; j < nodes.Count() - 1; ++j) {
    305             var distance = nodes[j].X - nodes[j - 1].X; // guaranteed to be > 0
    306             if (minSpacing > distance) minSpacing = distance;
    307           }
    308         }
    309         minSpacing *= horizontalScalingFactor;
    310 
    311         int minWidth = (int)Math.Round(preferredWidth * horizontalScalingFactor);
    312         int width = (int)Math.Min(minSpacing, preferredWidth) - 2; // leave some pixels so that node margins don't overlap
    313 
    314         foreach (var layoutNode in nodes) {
    315           var visualNode = visualTreeNodes[layoutNode.Content];
    316           visualNode.Width = width;
    317           visualNode.Height = (int)Math.Round(preferredHeight * verticalScalingFactor);
    318           visualNode.X = (int)Math.Round((layoutNode.X + horizontalOffset) * horizontalScalingFactor + (minWidth - width) / 2.0);
    319           visualNode.Y = (int)Math.Round(layoutNode.Y * verticalScalingFactor);
    320           DrawTreeNode(graphics, visualNode);
    321         }
    322       }
    323       // draw node connections
    324       foreach (var visualNode in visualTreeNodes.Values) {
    325         var node = visualNode.SymbolicExpressionTreeNode;
     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;
     266      layoutEngine.NodeWidth = preferredWidth;
     267      layoutEngine.NodeHeight = preferredHeight;
     268      layoutEngine.HorizontalSpacing = minHDistance;
     269      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();
     274      visualTreeNodes = visualNodes.ToDictionary(x => x.Content, x => x);
     275      visualLines = new Dictionary<Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>, VisualTreeNodeConnection>();
     276      foreach (var node in visualNodes.Select(n => n.Content)) {
     277        foreach (var subtree in node.Subtrees) {
     278          visualLines.Add(new Tuple<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(node, subtree), new VisualTreeNodeConnection());
     279        }
     280      }
     281      // draw nodes and connections
     282      foreach (var visualNode in visualNodes) {
     283        DrawTreeNode(visualNode);
     284        var node = visualNode.Content;
    326285        foreach (var subtree in node.Subtrees) {
    327286          var visualLine = GetVisualSymbolicExpressionTreeNodeConnection(node, subtree);
     
    338297    }
    339298
    340     protected void DrawTreeNode(VisualSymbolicExpressionTreeNode visualTreeNode) {
     299    protected void DrawTreeNode(VisualTreeNode<ISymbolicExpressionTreeNode> visualTreeNode) {
    341300      using (var graphics = Graphics.FromImage(image)) {
    342301        graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
     
    346305    }
    347306
    348     protected void DrawTreeNode(Graphics graphics, VisualSymbolicExpressionTreeNode visualTreeNode) {
     307    protected void DrawTreeNode(Graphics graphics, VisualTreeNode<ISymbolicExpressionTreeNode> visualTreeNode) {
    349308      graphics.Clip = new Region(new Rectangle(visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width + 1, visualTreeNode.Height + 1));
    350309      graphics.Clear(backgroundColor);
    351       var node = visualTreeNode.SymbolicExpressionTreeNode;
     310      var node = visualTreeNode.Content;
    352311      using (var textBrush = new SolidBrush(visualTreeNode.TextColor))
    353312      using (var nodeLinePen = new Pen(visualTreeNode.LineColor))
     
    408367    }
    409368    #endregion
     369
     370    private void reingoldTilfordToolStripMenuItem_Click(object sender, EventArgs e) {
     371      layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode> {
     372        NodeWidth = preferredNodeWidth,
     373        NodeHeight = preferredNodeHeight,
     374        HorizontalSpacing = minHorizontalDistance,
     375        VerticalSpacing = minVerticalDistance
     376      };
     377      Repaint();
     378    }
     379
     380    private void boxesToolStripMenuItem_Click(object sender, EventArgs e) {
     381      layoutEngine = new BoxesLayoutEngine<ISymbolicExpressionTreeNode> {
     382        NodeWidth = preferredNodeWidth,
     383        NodeHeight = preferredNodeHeight,
     384        HorizontalSpacing = minHorizontalDistance,
     385        VerticalSpacing = minVerticalDistance
     386      };
     387      Repaint();
     388    }
    410389  }
    411390}
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNode.cs

    r10500 r10520  
    2323
    2424namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    25   public class VisualSymbolicExpressionTreeNode : object {
     25  public class VisualTreeNode<T> where T : class {
    2626    private static readonly Color defaultLineColor = Color.Black;
    2727    private static readonly Color defaultTextColor = Color.Black;
     
    3030    private const int defaultPreferredHeight = 46;
    3131
    32     public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) :
    33       this(symbolicExpressionTreeNode, defaultLineColor) {
     32    public VisualTreeNode(T content) :
     33      this(content, defaultLineColor) {
    3434    }
    3535
    36     public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor) :
    37       this(symbolicExpressionTreeNode, lineColor, defaultTextColor) {
     36    public VisualTreeNode(T content, Color lineColor) :
     37      this(content, lineColor, defaultTextColor) {
    3838    }
    3939
    40     public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor) :
    41       this(symbolicExpressionTreeNode, lineColor, textColor, defaultFillColor) {
     40    public VisualTreeNode(T content, Color lineColor, Color textColor) :
     41      this(content, lineColor, textColor, defaultFillColor) {
    4242    }
    4343
    44     public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor, Color fillColor) :
    45       this(symbolicExpressionTreeNode, lineColor, textColor, fillColor, defaultPreferredWidth, defaultPreferredHeight) {
     44    public VisualTreeNode(T content, Color lineColor, Color textColor, Color fillColor) :
     45      this(content, lineColor, textColor, fillColor, defaultPreferredWidth, defaultPreferredHeight) {
    4646    }
    4747
    48     public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor, Color fillColor, int width, int height) {
    49       this.symbolicExpressionTreeNode = symbolicExpressionTreeNode;
     48    public VisualTreeNode(T content, Color lineColor, Color textColor, Color fillColor, int width, int height) {
     49      this.content = content;
    5050      this.lineColor = lineColor;
    5151      this.textColor = textColor;
     
    5353      this.preferredWidth = width;
    5454      this.preferredHeight = height;
    55       this.ToolTip = symbolicExpressionTreeNode.ToString();
     55      this.ToolTip = content.ToString();
    5656    }
    5757
     
    8282    #endregion
    8383
    84     private ISymbolicExpressionTreeNode symbolicExpressionTreeNode;
    85     public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode {
    86       get { return this.symbolicExpressionTreeNode; }
     84    private T content;
     85    public T Content {
     86      get { return this.content; }
    8787      set {
    88         symbolicExpressionTreeNode = value;
    89         ToolTip = SymbolicExpressionTreeNode.ToString();
     88        content = value;
     89        ToolTip = Content.ToString();
    9090      }
    9191    }
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNodeConnection.cs

    r10500 r10520  
    2424
    2525namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
    26   public class VisualSymbolicExpressionTreeNodeConnection : object {
     26  public class VisualTreeNodeConnection : object {
    2727    private static readonly Color defaultLineColor = Color.Black;
    2828    private static readonly DashStyle defaultDashStyle = DashStyle.Solid;
     
    4040    }
    4141
    42     public VisualSymbolicExpressionTreeNodeConnection()
     42    public VisualTreeNodeConnection()
    4343      : base() {
    4444      lineColor = defaultLineColor;
  • trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj

    r10496 r10520  
    135135    <Compile Include="Creators\RampedHalfAndHalfTreeCreator.cs" />
    136136    <Compile Include="Formatters\SymbolicExpressionTreeGraphvizFormatter.cs" />
    137     <Compile Include="Formatters\SymbolicExpressionTreeLatexFormatter.cs" />
    138     <Compile Include="Interfaces\ILayoutAdapter.cs" />
    139137    <Compile Include="Interfaces\IReadOnlySymbol.cs" />
    140138    <Compile Include="Interfaces\ISymbolicExpressionGrammar.cs" />
     
    156154    <Compile Include="Interfaces\ISymbolicExpressionTreeStringFormatter.cs" />
    157155    <Compile Include="Interfaces\Operators\ISymbolicExpressionTreeSizeConstraintOperator.cs" />
    158     <Compile Include="LayoutEngines\LayoutNode.cs" />
    159     <Compile Include="LayoutEngines\ReingoldTilfordLayoutEngine.cs" />
    160     <Compile Include="LayoutEngines\SymbolicExpressionTreeLayoutAdapter.cs" />
    161156    <Compile Include="Manipulators\ChangeNodeTypeManipulation.cs" />
    162157    <Compile Include="Interfaces\Operators\ISymbolicExpressionTreeManipulator.cs" />
Note: See TracChangeset for help on using the changeset viewer.