Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/Formatters/SymbolicExpressionTreeLatexFormatter.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/Formatters/SymbolicExpressionTreeLatexFormatter.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/Formatters/SymbolicExpressionTreeLatexFormatter.cs (revision 11120)
@@ -0,0 +1,101 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ [Item("LaTeX/PDF Formatter", "Formatter for symbolic expression trees for use with latex package tikz.")]
+ public class SymbolicExpressionTreeLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
+ private readonly static Dictionary symbolNameMap = new Dictionary
+ {
+ {"ProgramRootSymbol", "Prog"},
+ {"StartSymbol","RPB"}
+ };
+
+ private readonly ReingoldTilfordLayoutEngine layoutEngine;
+
+ public SymbolicExpressionTreeLatexFormatter()
+ : base("LaTeX/PDF Formatter", "Formatter for symbolic expression trees for use with latex package tikz.") {
+ layoutEngine = new ReingoldTilfordLayoutEngine(n => n.Subtrees) {
+ HorizontalSpacing = 2,
+ VerticalSpacing = 2,
+ NodeWidth = 8,
+ NodeHeight = 4
+ };
+ }
+
+ protected SymbolicExpressionTreeLatexFormatter(SymbolicExpressionTreeLatexFormatter original, Cloner cloner)
+ : base(original, cloner) {
+ }
+
+ public override IDeepCloneable Clone(Cloner cloner) {
+ return new SymbolicExpressionTreeLatexFormatter(this, cloner);
+ }
+
+ public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
+ var root = symbolicExpressionTree.Root;
+ var actualRoot = root.SubtreeCount == 0 ? root.GetSubtree(0) : root;
+ var nodeCoordinates = layoutEngine.CalculateLayout(actualRoot).ToDictionary(n => n.Content, n => new PointF(n.X, n.Y));
+ var sb = new StringBuilder();
+ var nl = Environment.NewLine;
+ double ws = 1;
+ double hs = 0.7;
+
+ sb.Append("\\documentclass[class=minimal,border=0pt]{standalone}" + nl +
+ "\\usepackage{tikz}" + nl +
+ "\\begin{document}" + nl +
+ "\\begin{tikzpicture}" + nl +
+ "\\def\\ws{1}" + nl +
+ "\\def\\hs{0.7}" + nl);
+
+ var nodeIndices = new Dictionary();
+ var nodes = symbolicExpressionTree.IterateNodesBreadth().ToList();
+ for (int i = 0; i < nodes.Count; ++i) {
+ var node = nodes[i];
+ nodeIndices.Add(node, i);
+ var coord = nodeCoordinates[node];
+ var nodeName = symbolNameMap.ContainsKey(node.Symbol.Name) ? symbolNameMap[node.Symbol.Name] : node.ToString();
+ sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\node ({0}) at (\\ws*{1},\\hs*{2}) {{{3}}};", i, ws * coord.X, -hs * coord.Y, EscapeLatexString(nodeName)));
+ }
+
+ for (int i = 0; i < nodes.Count; ++i) {
+ foreach (var s in nodes[i].Subtrees) {
+ sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\draw ({0}) -- ({1});", i, nodeIndices[s]));
+ }
+ }
+
+ sb.Append("\\end{tikzpicture}" + nl +
+ "\\end{document}" + nl);
+ return sb.ToString();
+ }
+
+ private static string EscapeLatexString(string s) {
+ return s.Replace("\\", "\\\\").Replace("{", "\\{").Replace("}", "\\}").Replace("_", "\\_");
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/GraphicalSymbolicExpressionTreeView.Designer.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/GraphicalSymbolicExpressionTreeView.Designer.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/GraphicalSymbolicExpressionTreeView.Designer.cs (revision 11120)
@@ -19,4 +19,6 @@
*/
#endregion
+
+using System.Drawing;
namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
@@ -59,5 +61,5 @@
this.symbolicExpressionTreeChart.Spacing = 5;
this.symbolicExpressionTreeChart.TabIndex = 0;
- this.symbolicExpressionTreeChart.TextFont = new System.Drawing.Font("Times New Roman", 6F);
+ this.symbolicExpressionTreeChart.TextFont = new System.Drawing.Font(FontFamily.GenericSerif, 8F);
//
// FunctionTreeView
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4.csproj
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4.csproj (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4.csproj (revision 11120)
@@ -110,4 +110,9 @@
+
+
+
+
+
@@ -160,6 +165,6 @@
SymbolicExpressionView.cs
-
-
+
+
@@ -276,5 +281,5 @@
-->
- set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+ set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
set ProjectDir=$(ProjectDir)
set SolutionDir=$(SolutionDir)
@@ -283,5 +288,5 @@
call PreBuildEvent.cmd
-
+
export ProjectDir=$(ProjectDir)
export SolutionDir=$(SolutionDir)
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/BoxesLayoutEngine.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/BoxesLayoutEngine.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/BoxesLayoutEngine.cs (revision 11120)
@@ -0,0 +1,117 @@
+#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ public class BoxesLayoutEngine : ILayoutEngine where T : class {
+ public int NodeWidth { get; set; }
+ public int NodeHeight { get; set; }
+ public int HorizontalSpacing { get; set; }
+ public int VerticalSpacing { get; set; }
+
+ private readonly Func> GetChildren;
+ private readonly Func GetLength;
+ private readonly Func GetDepth;
+
+ public BoxesLayoutEngine(Func> GetChildren, Func GetLength, Func GetDepth) {
+ if (GetChildren == null) throw new ArgumentNullException("GetChildren");
+ if (GetLength == null) throw new ArgumentNullException("GetLength");
+ if (GetDepth == null) throw new ArgumentNullException("GetDepth");
+
+ this.GetChildren = GetChildren;
+ this.GetLength = GetLength;
+ this.GetDepth = GetDepth;
+ }
+
+
+ public IEnumerable> CalculateLayout(T root, float width, float height) {
+ var nodeMap = new Dictionary>();
+ CreateVisualNodes(root, nodeMap);
+ RecursiveLayout(nodeMap, nodeMap[root], 0, 0, (int)Math.Round(width), (int)Math.Round(height) / GetDepth(root));
+ return nodeMap.Values;
+ }
+
+ private void CreateVisualNodes(T root, Dictionary> map) {
+ var node = new VisualTreeNode(root) {
+ PreferredWidth = NodeWidth,
+ PreferredHeight = NodeHeight
+ };
+
+ map.Add(root, node);
+ var children = GetChildren(root).ToList();
+ if (children.Any()) {
+ foreach (var child in children) {
+ CreateVisualNodes(child, map);
+ }
+ }
+ }
+
+ private void RecursiveLayout(Dictionary> nodeMap, VisualTreeNode visualTreeNode, int x, int y, int width, int height) {
+ float center_x = x + width / 2;
+ float center_y = y + height / 2;
+ int actualWidth = width - HorizontalSpacing;
+ int actualHeight = height - VerticalSpacing;
+
+ //calculate size of node
+ if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
+ visualTreeNode.Width = visualTreeNode.PreferredWidth;
+ visualTreeNode.Height = visualTreeNode.PreferredHeight;
+ visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
+ visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
+ }
+ //width too small to draw in desired sized
+ else if (actualWidth < visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
+ visualTreeNode.Width = actualWidth;
+ visualTreeNode.Height = visualTreeNode.PreferredHeight;
+ visualTreeNode.X = x;
+ visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
+ }
+ //height too small to draw in desired sized
+ else if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight < visualTreeNode.PreferredHeight) {
+ visualTreeNode.Width = visualTreeNode.PreferredWidth;
+ visualTreeNode.Height = actualHeight;
+ visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
+ visualTreeNode.Y = y;
+ }
+ //width and height too small to draw in desired size
+ else {
+ visualTreeNode.Width = actualWidth;
+ visualTreeNode.Height = actualHeight;
+ visualTreeNode.X = x;
+ visualTreeNode.Y = y;
+ }
+ //calculate areas for the subtrees according to their tree size
+ var node = visualTreeNode.Content;
+ var children = GetChildren(node).ToList();
+ int[] xBoundaries = new int[children.Count + 1];
+ xBoundaries[0] = x;
+ for (int i = 0; i < children.Count; i++) {
+ xBoundaries[i + 1] = (int)(xBoundaries[i] + (width * (double)GetLength(children[i])) / (GetLength(node) - 1));
+ RecursiveLayout(nodeMap, nodeMap[children[i]], xBoundaries[i], y + height, xBoundaries[i + 1] - xBoundaries[i], height);
+ }
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ILayoutEngine.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ILayoutEngine.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ILayoutEngine.cs (revision 11120)
@@ -0,0 +1,35 @@
+#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ interface ILayoutEngine where T : class {
+ int NodeWidth { get; set; }
+ int NodeHeight { get; set; }
+ int HorizontalSpacing { get; set; }
+ int VerticalSpacing { get; set; }
+
+ IEnumerable> CalculateLayout(T root, float width, float height);
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/LayoutNode.cs (revision 11120)
@@ -0,0 +1,108 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ internal class LayoutNode : object where T : class {
+ public float Width { get; set; }
+ public float Height { get; set; }
+
+ public LayoutNode NextLeft {
+ get {
+ return Children == null ? Thread : Children.First();
+ }
+ }
+ public LayoutNode NextRight {
+ get {
+ return Children == null ? Thread : Children.Last();
+ }
+ }
+ public LayoutNode LeftSibling {
+ get {
+ if (Parent == null) return null;
+ return Number == 0 ? null : Parent.Children[Number - 1];
+ }
+ }
+ public LayoutNode LeftmostSibling {
+ get {
+ if (Parent == null) return null;
+ return Number == 0 ? null : Parent.Children[0];
+ }
+ }
+
+ public LayoutNode Thread { get; set; }
+ public LayoutNode Ancestor { get; set; }
+ public LayoutNode Parent { get; set; }
+ public List> Children { get; set; }
+ public float Mod { get; set; }
+ public float Prelim { get; set; }
+ public float Change { get; set; }
+ public float Shift { get; set; }
+ public int Number { get; set; }
+ public int Level { get; set; }
+ public float X { get; set; }
+ public float Y { get; set; }
+
+ public bool IsLeaf {
+ get { return Children == null || Children.Count == 0; }
+ }
+
+ private T content;
+ public T Content {
+ get { return content; }
+ set {
+ if (value == null)
+ throw new ArgumentNullException("LayoutNode: Content cannot be null.");
+ content = value;
+ }
+ }
+ ///
+ /// Translate the position of the layout node according to the given offsets
+ ///
+ ///
+ ///
+ public void Translate(float dx, float dy) {
+ X += dx;
+ Y += dy;
+ }
+
+ public void ResetCoordinates() {
+ X = 0;
+ Y = 0;
+ }
+
+ ///
+ /// Reset layout-related parameters
+ ///
+ public void Reset() {
+ Ancestor = this;
+ Thread = null;
+ Change = 0;
+ Shift = 0;
+ Prelim = 0;
+ Mod = 0;
+ ResetCoordinates();
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/LayoutEngines/ReingoldTilfordLayoutEngine.cs (revision 11120)
@@ -0,0 +1,273 @@
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ public class ReingoldTilfordLayoutEngine : ILayoutEngine where T : class {
+ public int NodeWidth { get; set; }
+ public int NodeHeight { get; set; }
+ private int minHorizontalSpacing = 5;
+ public int HorizontalSpacing {
+ get { return minHorizontalSpacing; }
+ set { minHorizontalSpacing = value; }
+ }
+
+ private int minVerticalSpacing = 5;
+ public int VerticalSpacing {
+ get { return minVerticalSpacing; }
+ set { minVerticalSpacing = value; }
+ }
+
+ private readonly Func> GetChildren;
+
+ public ReingoldTilfordLayoutEngine(Func> GetChildren) {
+ this.GetChildren = GetChildren;
+ }
+
+ public IEnumerable> CalculateLayout(T root) {
+ return CalculateLayout(root, 0, 0);
+ }
+
+ public IEnumerable> CalculateLayout(T root, float width, float height) {
+ Dictionary> layoutNodeMap = new Dictionary>();
+ var layoutRoot = new LayoutNode { Content = root, Width = NodeWidth, Height = NodeHeight, };
+ layoutRoot.Ancestor = layoutRoot;
+ Expand(layoutRoot, layoutNodeMap);
+
+ FirstWalk(layoutRoot);
+ SecondWalk(layoutRoot, -layoutRoot.Prelim);
+ NormalizeCoordinates(layoutNodeMap.Values);
+ if (height != 0 && width != 0) {
+ FitToBounds(width, height, layoutNodeMap.Values);
+ Center(width, height, layoutNodeMap.Values);
+ }
+
+ return layoutNodeMap.Values.Select(x => new VisualTreeNode(x.Content) {
+ Width = (int)Math.Round(x.Width),
+ Height = (int)Math.Round(x.Height),
+ X = (int)Math.Round(x.X),
+ Y = (int)Math.Round(x.Y)
+ });
+ }
+
+ private void Expand(LayoutNode lRoot, Dictionary> map) {
+ map.Add(lRoot.Content, lRoot);
+ var children = GetChildren(lRoot.Content).ToList();
+ if (!children.Any()) return;
+ lRoot.Children = new List>(children.Count);
+ for (int i = 0; i < children.Count; ++i) {
+ var node = new LayoutNode {
+ Content = children[i],
+ Number = i,
+ Parent = lRoot,
+ Level = lRoot.Level + 1,
+ Width = NodeWidth,
+ Height = NodeHeight
+ };
+ node.Ancestor = node;
+ lRoot.Children.Add(node);
+ Expand(node, map);
+ }
+ }
+
+
+ ///
+ /// Transform LayoutNode coordinates so that all coordinates are positive and start from (0,0)
+ ///
+ private static void NormalizeCoordinates(IEnumerable> nodes) {
+ float xmin = 0, ymin = 0;
+ foreach (var node in nodes) {
+ if (xmin > node.X) xmin = node.X;
+ if (ymin > node.Y) ymin = node.Y;
+ }
+ foreach (var node in nodes) {
+ node.X -= xmin;
+ node.Y -= ymin;
+ }
+ }
+
+ private void Center(float width, float height, IEnumerable> nodes) {
+ // center layout on screen
+ var bounds = Bounds(nodes);
+ float dx = 0, dy = 0;
+ if (width > bounds.Width) { dx = (width - bounds.Width) / 2f; }
+ if (height > bounds.Height) { dy = (height - bounds.Height) / 2f; }
+ foreach (var node in nodes) { node.Translate(dx, dy); }
+ }
+
+ private void FitToBounds(float width, float height, IEnumerable> nodes) {
+ var bounds = Bounds(nodes);
+ var myWidth = bounds.Width;
+ var myHeight = bounds.Height;
+
+ if (myWidth <= width && myHeight <= height) return; // no need to fit since we are within bounds
+
+ var layers = nodes.GroupBy(node => node.Level, node => node).ToList();
+
+ if (myWidth > width) {
+ // need to scale horizontally
+ float x = width / myWidth;
+ foreach (var node in layers.SelectMany(g => g)) {
+ node.X *= x;
+ node.Width *= x;
+ }
+ float spacing = minHorizontalSpacing * x;
+ foreach (var layer in layers) {
+ var nodesLayer = layer.ToList();
+ float minWidth = float.MaxValue;
+ for (int i = 0; i < nodesLayer.Count - 1; ++i) { minWidth = Math.Min(minWidth, nodesLayer[i + 1].X - nodesLayer[i].X); }
+ float w = Math.Min(NodeWidth, minWidth - spacing);
+ foreach (var node in nodesLayer) {
+ node.X += (node.Width - w) / 2f;
+ node.Width = w;
+ //this is a simple solution to ensure that the leftmost and rightmost nodes are not drawn partially offscreen due to scaling and offset
+ //this should work well enough 99.9% of the time with no noticeable visual difference
+ if (node.X < 0) {
+ node.Width += node.X;
+ node.X = 0;
+ } else if (node.X + node.Width > width) {
+ node.Width = width - node.X;
+ }
+ }
+ }
+ }
+ if (myHeight > height) {
+ // need to scale vertically
+ float x = height / myHeight;
+ foreach (var node in layers.SelectMany(g => g)) {
+ node.Y *= x;
+ node.Height *= x;
+ }
+ }
+ }
+
+
+ ///
+ /// Returns the bounding box for this layout. When the layout is normalized, the rectangle should be [0,0,xmin,xmax].
+ ///
+ ///
+ private RectangleF Bounds(IEnumerable> nodes) {
+ float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
+ foreach (LayoutNode node in nodes) {
+ float x = node.X, y = node.Y;
+ if (xmin > x) xmin = x;
+ if (xmax < x) xmax = x;
+ if (ymin > y) ymin = y;
+ if (ymax < y) ymax = y;
+ }
+ return new RectangleF(xmin, ymin, xmax + minHorizontalSpacing + NodeWidth, ymax + minVerticalSpacing + NodeHeight);
+ }
+
+ #region methods specific to the reingold-tilford layout algorithm
+ private void FirstWalk(LayoutNode v) {
+ LayoutNode w;
+ if (v.IsLeaf) {
+ w = v.LeftSibling;
+ if (w != null) {
+ v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
+ }
+ } else {
+ var defaultAncestor = v.Children[0]; // leftmost child
+
+ foreach (var child in v.Children) {
+ FirstWalk(child);
+ Apportion(child, ref defaultAncestor);
+ }
+ ExecuteShifts(v);
+ var leftmost = v.Children.First();
+ var rightmost = v.Children.Last();
+ float midPoint = (leftmost.Prelim + rightmost.Prelim) / 2;
+ w = v.LeftSibling;
+ if (w != null) {
+ v.Prelim = w.Prelim + minHorizontalSpacing + NodeWidth;
+ v.Mod = v.Prelim - midPoint;
+ } else {
+ v.Prelim = midPoint;
+ }
+ }
+ }
+
+ private void SecondWalk(LayoutNode v, float m) {
+ v.X = v.Prelim + m;
+ v.Y = v.Level * (minVerticalSpacing + NodeHeight);
+ if (v.IsLeaf) return;
+ foreach (var child in v.Children) {
+ SecondWalk(child, m + v.Mod);
+ }
+ }
+
+ private void Apportion(LayoutNode v, ref LayoutNode defaultAncestor) {
+ var w = v.LeftSibling;
+ if (w == null) return;
+ LayoutNode vip = v;
+ LayoutNode vop = v;
+ LayoutNode vim = w;
+ LayoutNode vom = vip.LeftmostSibling;
+
+ float sip = vip.Mod;
+ float sop = vop.Mod;
+ float sim = vim.Mod;
+ float som = vom.Mod;
+
+ while (vim.NextRight != null && vip.NextLeft != null) {
+ vim = vim.NextRight;
+ vip = vip.NextLeft;
+ vom = vom.NextLeft;
+ vop = vop.NextRight;
+ vop.Ancestor = v;
+ float shift = (vim.Prelim + sim) - (vip.Prelim + sip) + minHorizontalSpacing + NodeWidth;
+ if (shift > 0) {
+ var ancestor = Ancestor(vim, v) ?? defaultAncestor;
+ MoveSubtree(ancestor, v, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim.Mod;
+ sip += vip.Mod;
+ som += vom.Mod;
+ sop += vop.Mod;
+ }
+ if (vim.NextRight != null && vop.NextRight == null) {
+ vop.Thread = vim.NextRight;
+ vop.Mod += (sim - sop);
+ }
+ if (vip.NextLeft != null && vom.NextLeft == null) {
+ vom.Thread = vip.NextLeft;
+ vom.Mod += (sip - som);
+ defaultAncestor = v;
+ }
+ }
+
+ private void MoveSubtree(LayoutNode wm, LayoutNode wp, float shift) {
+ int subtrees = wp.Number - wm.Number; // TODO: Investigate possible bug (if the value ever happens to be zero) - happens when the tree is actually a graph (but that's outside the use case of this algorithm which only works with trees)
+ if (subtrees == 0) throw new Exception("MoveSubtree failed: check if object is really a tree (no cycles)");
+ wp.Change -= shift / subtrees;
+ wp.Shift += shift;
+ wm.Change += shift / subtrees;
+ wp.Prelim += shift;
+ wp.Mod += shift;
+ }
+
+ private void ExecuteShifts(LayoutNode v) {
+ if (v.IsLeaf) return;
+ float shift = 0;
+ float change = 0;
+ for (int i = v.Children.Count - 1; i >= 0; --i) {
+ var w = v.Children[i];
+ w.Prelim += shift;
+ w.Mod += shift;
+ change += w.Change;
+ shift += (w.Shift + change);
+ }
+ }
+
+ private LayoutNode Ancestor(LayoutNode u, LayoutNode v) {
+ var ancestor = u.Ancestor;
+ if (ancestor == null) return null;
+ return ancestor.Parent == v.Parent ? ancestor : null;
+ }
+ #endregion
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionGrammarAllowedChildSymbolsControl.cs (revision 11120)
@@ -29,4 +29,6 @@
using HeuristicLab.PluginInfrastructure;
+using VisualSymbolicExpressionTreeNode = HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views.VisualTreeNode;
+
namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
public sealed partial class SymbolicExpressionGrammarAllowedChildSymbolsControl : UserControl {
@@ -103,5 +105,4 @@
var tree = new SymbolicExpressionTree(new SymbolicExpressionTreeNode(Symbol));
- symbolicExpressionTreeChart.SuspendRepaint = true;
if (Grammar.GetMaximumSubtreeCount(Symbol) > 0) {
for (int i = 0; i < Grammar.GetMaximumSubtreeCount(Symbol); i++) {
@@ -116,5 +117,5 @@
}
symbolicExpressionTreeChart.Tree = tree;
-
+ symbolicExpressionTreeChart.SuspendRepaint = true;
foreach (var subtreeNode in tree.Root.Subtrees) {
foreach (var allowedChildNode in subtreeNode.Subtrees) {
@@ -142,5 +143,4 @@
}
}
-
symbolicExpressionTreeChart.SuspendRepaint = false;
UpdateSelectedSymbolicExpressionTreeNodes();
@@ -153,5 +153,5 @@
else visualNode.FillColor = Color.LightSteelBlue;
}
- symbolicExpressionTreeChart.Repaint();
+ symbolicExpressionTreeChart.RepaintNodes();
}
@@ -162,5 +162,5 @@
VisualSymbolicExpressionTreeNode clickedNode = (VisualSymbolicExpressionTreeNode)sender;
- var selectedNode = clickedNode.SymbolicExpressionTreeNode;
+ var selectedNode = clickedNode.Content;
if (selectedNode.SubtreeCount == 0) {
if (!selectedSymbolicExpressionTreeNodes.Contains(selectedNode))
@@ -207,5 +207,5 @@
var visualNode = symbolicExpressionTreeChart.FindVisualSymbolicExpressionTreeNodeAt(coordinates.X, coordinates.Y);
if (visualNode != null) {
- var node = visualNode.SymbolicExpressionTreeNode;
+ var node = visualNode.Content;
var root = symbolicExpressionTreeChart.Tree.Root;
if (node == root || node.Parent == root) e.Effect = DragDropEffects.Copy;
@@ -223,5 +223,5 @@
var symbols = data as IEnumerable;
- if (node.SymbolicExpressionTreeNode == root) {
+ if (node.Content == root) {
if (symbol != null)
Grammar.AddAllowedChildSymbol(root.Symbol, symbol);
@@ -229,5 +229,5 @@
foreach (var s in symbols) Grammar.AddAllowedChildSymbol(root.Symbol, s);
} else {
- int argumentIndex = root.IndexOfSubtree(node.SymbolicExpressionTreeNode);
+ int argumentIndex = root.IndexOfSubtree(node.Content);
if (symbol != null)
Grammar.AddAllowedChildSymbol(root.Symbol, symbol, argumentIndex);
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.Designer.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.Designer.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.Designer.cs (revision 11120)
@@ -49,4 +49,8 @@
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.saveImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.exportPgfLaTeXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.layoutEngineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.reingoldTilfordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.boxesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.contextMenuStrip.SuspendLayout();
@@ -56,24 +60,56 @@
//
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.saveImageToolStripMenuItem});
+ this.saveImageToolStripMenuItem,
+ this.exportPgfLaTeXToolStripMenuItem,
+ this.layoutEngineToolStripMenuItem});
this.contextMenuStrip.Name = "contextMenuStrip";
- this.contextMenuStrip.Size = new System.Drawing.Size(135, 26);
+ this.contextMenuStrip.Size = new System.Drawing.Size(166, 70);
//
// saveImageToolStripMenuItem
//
this.saveImageToolStripMenuItem.Name = "saveImageToolStripMenuItem";
- this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(134, 22);
+ this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(165, 22);
this.saveImageToolStripMenuItem.Text = "Save Image";
this.saveImageToolStripMenuItem.Click += new System.EventHandler(this.saveImageToolStripMenuItem_Click);
+ //
+ // exportPgfLaTeXToolStripMenuItem
+ //
+ this.exportPgfLaTeXToolStripMenuItem.Name = "exportPgfLaTeXToolStripMenuItem";
+ this.exportPgfLaTeXToolStripMenuItem.Size = new System.Drawing.Size(165, 22);
+ this.exportPgfLaTeXToolStripMenuItem.Text = "Export Pgf/LaTeX";
+ this.exportPgfLaTeXToolStripMenuItem.Click += new System.EventHandler(this.exportLatexToolStripMenuItem_Click);
+ //
+ // layoutEngineToolStripMenuItem
+ //
+ this.layoutEngineToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.reingoldTilfordToolStripMenuItem,
+ this.boxesToolStripMenuItem});
+ this.layoutEngineToolStripMenuItem.Name = "layoutEngineToolStripMenuItem";
+ this.layoutEngineToolStripMenuItem.Size = new System.Drawing.Size(165, 22);
+ this.layoutEngineToolStripMenuItem.Text = "Layout Engine:";
+ //
+ // reingoldTilfordToolStripMenuItem
+ //
+ this.reingoldTilfordToolStripMenuItem.Name = "reingoldTilfordToolStripMenuItem";
+ this.reingoldTilfordToolStripMenuItem.Size = new System.Drawing.Size(161, 22);
+ this.reingoldTilfordToolStripMenuItem.Text = "Reingold-Tilford";
+ this.reingoldTilfordToolStripMenuItem.Click += new System.EventHandler(this.reingoldTilfordToolStripMenuItem_Click);
+ //
+ // boxesToolStripMenuItem
+ //
+ this.boxesToolStripMenuItem.Name = "boxesToolStripMenuItem";
+ this.boxesToolStripMenuItem.Size = new System.Drawing.Size(161, 22);
+ this.boxesToolStripMenuItem.Text = "Boxes";
+ this.boxesToolStripMenuItem.Click += new System.EventHandler(this.boxesToolStripMenuItem_Click);
//
// saveFileDialog
//
this.saveFileDialog.Filter = "Bitmap (*.bmp)|*.bmp|EMF (*.emf)|*.emf";
- this.saveFileDialog.FilterIndex = 1;
+ //
// SymbolicExpressionTreeChart
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ContextMenuStrip = this.contextMenuStrip;
+ this.DoubleBuffered = true;
this.Name = "SymbolicExpressionTreeChart";
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.SymbolicExpressionTreeChart_MouseClick);
@@ -93,4 +129,8 @@
protected System.Windows.Forms.ToolStripMenuItem saveImageToolStripMenuItem;
protected System.Windows.Forms.SaveFileDialog saveFileDialog;
+ private System.Windows.Forms.ToolStripMenuItem exportPgfLaTeXToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem layoutEngineToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem reingoldTilfordToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem boxesToolStripMenuItem;
}
}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionTreeChart.cs (revision 11120)
@@ -24,12 +24,21 @@
using System.Drawing;
using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
using System.Windows.Forms;
+
namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
public partial class SymbolicExpressionTreeChart : UserControl {
private Image image;
- private StringFormat stringFormat;
- private Dictionary visualTreeNodes;
- private Dictionary, VisualSymbolicExpressionTreeNodeConnection> visualLines;
+ private readonly StringFormat stringFormat;
+ private Dictionary> visualTreeNodes;
+ private Dictionary, VisualTreeNodeConnection> visualLines;
+ private ILayoutEngine layoutEngine;
+
+ private const int preferredNodeWidth = 70;
+ private const int preferredNodeHeight = 46;
+ private int minHorizontalDistance = 30;
+ private int minVerticalDistance = 30;
public SymbolicExpressionTreeChart() {
@@ -40,5 +49,16 @@
this.lineColor = Color.Black;
this.backgroundColor = Color.White;
- this.textFont = new Font("Times New Roman", 8);
+ this.textFont = new Font(FontFamily.GenericSansSerif, 12);
+
+ visualTreeNodes = new Dictionary>();
+ visualLines = new Dictionary, VisualTreeNodeConnection>();
+
+ layoutEngine = new ReingoldTilfordLayoutEngine(n => n.Subtrees) {
+ NodeWidth = preferredNodeWidth,
+ NodeHeight = preferredNodeHeight,
+ HorizontalSpacing = minHorizontalDistance,
+ VerticalSpacing = minVerticalDistance
+ };
+ reingoldTilfordToolStripMenuItem.Checked = true;
}
@@ -48,4 +68,5 @@
}
+ #region Public properties
private int spacing;
public int Spacing {
@@ -89,12 +110,4 @@
set {
tree = value;
- visualTreeNodes = new Dictionary();
- visualLines = new Dictionary, VisualSymbolicExpressionTreeNodeConnection>();
- if (tree != null) {
- foreach (ISymbolicExpressionTreeNode node in tree.IterateNodesPrefix()) {
- visualTreeNodes[node] = new VisualSymbolicExpressionTreeNode(node);
- if (node.Parent != null) visualLines[Tuple.Create(node.Parent, node)] = new VisualSymbolicExpressionTreeNodeConnection();
- }
- }
Repaint();
}
@@ -106,4 +119,5 @@
set { suspendRepaint = value; }
}
+ #endregion
protected override void OnPaint(PaintEventArgs e) {
@@ -115,7 +129,16 @@
if (this.Width <= 1 || this.Height <= 1)
this.image = new Bitmap(1, 1);
- else
+ else {
this.image = new Bitmap(Width, Height);
+ }
this.Repaint();
+ }
+
+ public event EventHandler Repainted;//expose this event to notify the parent control that the tree was repainted
+ protected virtual void OnRepaint(object sender, EventArgs e) {
+ var repainted = Repainted;
+ if (repainted != null) {
+ repainted(sender, e);
+ }
}
@@ -124,4 +147,5 @@
this.GenerateImage();
this.Refresh();
+ OnRepaint(this, EventArgs.Empty);
}
}
@@ -134,4 +158,9 @@
foreach (var visualNode in visualTreeNodes.Values) {
DrawTreeNode(graphics, visualNode);
+ if (visualNode.Content.SubtreeCount > 0) {
+ foreach (var visualSubtree in visualNode.Content.Subtrees.Select(s => visualTreeNodes[s])) {
+ DrawLine(graphics, visualNode, visualSubtree);
+ }
+ }
}
}
@@ -140,5 +169,5 @@
}
- public void RepaintNode(VisualSymbolicExpressionTreeNode visualNode) {
+ public void RepaintNode(VisualTreeNode visualNode) {
if (!suspendRepaint) {
using (var graphics = Graphics.FromImage(image)) {
@@ -157,11 +186,10 @@
graphics.Clear(backgroundColor);
if (tree != null) {
- int height = this.Height / tree.Depth;
- DrawFunctionTree(tree, graphics, 0, 0, this.Width, height);
- }
- }
- }
-
- public VisualSymbolicExpressionTreeNode GetVisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) {
+ DrawFunctionTree(graphics, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
+ }
+ }
+ }
+
+ public VisualTreeNode GetVisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) {
if (visualTreeNodes.ContainsKey(symbolicExpressionTreeNode))
return visualTreeNodes[symbolicExpressionTreeNode];
@@ -169,8 +197,8 @@
}
- public VisualSymbolicExpressionTreeNodeConnection GetVisualSymbolicExpressionTreeNodeConnection(ISymbolicExpressionTreeNode parent, ISymbolicExpressionTreeNode child) {
+ public VisualTreeNodeConnection GetVisualSymbolicExpressionTreeNodeConnection(ISymbolicExpressionTreeNode parent, ISymbolicExpressionTreeNode child) {
if (child.Parent != parent) throw new ArgumentException();
var key = Tuple.Create(parent, child);
- VisualSymbolicExpressionTreeNodeConnection connection = null;
+ VisualTreeNodeConnection connection = null;
visualLines.TryGetValue(key, out connection);
return connection;
@@ -186,5 +214,5 @@
protected virtual void SymbolicExpressionTreeChart_MouseClick(object sender, MouseEventArgs e) {
- VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
+ var visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
if (visualTreeNode != null) {
OnSymbolicExpressionTreeNodeClicked(visualTreeNode, e);
@@ -200,5 +228,5 @@
protected virtual void SymbolicExpressionTreeChart_MouseDoubleClick(object sender, MouseEventArgs e) {
- VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
+ VisualTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
if (visualTreeNode != null)
OnSymbolicExpressionTreeNodeDoubleClicked(visualTreeNode, e);
@@ -212,5 +240,5 @@
}
- private VisualSymbolicExpressionTreeNode draggedSymbolicExpressionTree;
+ private VisualTreeNode draggedSymbolicExpressionTree;
private MouseButtons dragButtons;
private void SymbolicExpressionTreeChart_MouseDown(object sender, MouseEventArgs e) {
@@ -224,5 +252,5 @@
private void SymbolicExpressionTreeChart_MouseMove(object sender, MouseEventArgs e) {
- VisualSymbolicExpressionTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
+ VisualTreeNode visualTreeNode = FindVisualSymbolicExpressionTreeNodeAt(e.X, e.Y);
if (draggedSymbolicExpressionTree != null &&
draggedSymbolicExpressionTree != visualTreeNode) {
@@ -239,5 +267,5 @@
}
- public VisualSymbolicExpressionTreeNode FindVisualSymbolicExpressionTreeNodeAt(int x, int y) {
+ public VisualTreeNode FindVisualSymbolicExpressionTreeNodeAt(int x, int y) {
foreach (var visualTreeNode in visualTreeNodes.Values) {
if (x >= visualTreeNode.X && x <= visualTreeNode.X + visualTreeNode.Width &&
@@ -249,103 +277,51 @@
#endregion
+ private void CalculateLayout(int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {
+ layoutEngine.NodeWidth = preferredWidth;
+ layoutEngine.NodeHeight = preferredHeight;
+ layoutEngine.HorizontalSpacing = minHDistance;
+ layoutEngine.VerticalSpacing = minVDistance;
+
+ var actualRoot = tree.Root;
+ if (actualRoot.Symbol is ProgramRootSymbol && actualRoot.SubtreeCount == 1) {
+ actualRoot = tree.Root.GetSubtree(0);
+ }
+
+ var visualNodes = layoutEngine.CalculateLayout(actualRoot, Width, Height).ToList();
+ visualTreeNodes = visualNodes.ToDictionary(x => x.Content, x => x);
+ visualLines = new Dictionary, VisualTreeNodeConnection>();
+ foreach (var node in visualNodes.Select(n => n.Content)) {
+ foreach (var subtree in node.Subtrees) {
+ visualLines.Add(new Tuple(node, subtree), new VisualTreeNodeConnection());
+ }
+ }
+ }
+
#region methods for painting the symbolic expression tree
- private void DrawFunctionTree(ISymbolicExpressionTree tree, Graphics graphics, int x, int y, int width, int height) {
- DrawFunctionTree(tree.Root, graphics, x, y, width, height, Point.Empty);
- }
-
- ///
- ///
- ///
- /// function tree to draw
- /// graphics object to draw on
- /// x coordinate of drawing area
- /// y coordinate of drawing area
- /// width of drawing area
- /// height of drawing area
- private void DrawFunctionTree(ISymbolicExpressionTreeNode node, Graphics graphics, int x, int y, int width, int height, Point connectionPoint) {
- VisualSymbolicExpressionTreeNode visualTreeNode = visualTreeNodes[node];
- float center_x = x + width / 2;
- float center_y = y + height / 2;
- int actualWidth = width - spacing;
- int actualHeight = height - spacing;
-
- using (var textBrush = new SolidBrush(visualTreeNode.TextColor))
- using (var nodeLinePen = new Pen(visualTreeNode.LineColor))
- using (var nodeFillBrush = new SolidBrush(visualTreeNode.FillColor)) {
-
- //calculate size of node
- if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
- visualTreeNode.Width = visualTreeNode.PreferredWidth;
- visualTreeNode.Height = visualTreeNode.PreferredHeight;
- visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
- visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
- }
- //width too small to draw in desired sized
- else if (actualWidth < visualTreeNode.PreferredWidth && actualHeight >= visualTreeNode.PreferredHeight) {
- visualTreeNode.Width = actualWidth;
- visualTreeNode.Height = visualTreeNode.PreferredHeight;
- visualTreeNode.X = x;
- visualTreeNode.Y = (int)center_y - visualTreeNode.Height / 2;
- }
- //height too small to draw in desired sized
- else if (actualWidth >= visualTreeNode.PreferredWidth && actualHeight < visualTreeNode.PreferredHeight) {
- visualTreeNode.Width = visualTreeNode.PreferredWidth;
- visualTreeNode.Height = actualHeight;
- visualTreeNode.X = (int)center_x - visualTreeNode.Width / 2;
- visualTreeNode.Y = y;
- }
- //width and height too small to draw in desired size
- else {
- visualTreeNode.Width = actualWidth;
- visualTreeNode.Height = actualHeight;
- visualTreeNode.X = x;
- visualTreeNode.Y = y;
- }
-
- //draw terminal node
- if (node.SubtreeCount == 0) {
- graphics.FillRectangle(nodeFillBrush, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
- graphics.DrawRectangle(nodeLinePen, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
- } else {
- graphics.FillEllipse(nodeFillBrush, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
- graphics.DrawEllipse(nodeLinePen, visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height);
- }
-
- //draw name of symbol
- var text = node.ToString();
- graphics.DrawString(text, textFont, textBrush, new RectangleF(visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width, visualTreeNode.Height), stringFormat);
-
- //draw connection line to parent node
- if (!connectionPoint.IsEmpty && node.Parent != null) {
- var visualLine = GetVisualSymbolicExpressionTreeNodeConnection(node.Parent, node);
- using (Pen linePen = new Pen(visualLine.LineColor)) {
+ private void DrawFunctionTree(Graphics graphics, int preferredWidth, int preferredHeight, int minHDistance, int minVDistance) {
+ CalculateLayout(preferredWidth, preferredHeight, minHDistance, minVDistance);
+ var visualNodes = visualTreeNodes.Values;
+ //draw nodes and connections
+ foreach (var visualNode in visualNodes) {
+ DrawTreeNode(graphics, visualNode);
+ var node = visualNode.Content;
+ foreach (var subtree in node.Subtrees) {
+ var visualLine = GetVisualSymbolicExpressionTreeNodeConnection(node, subtree);
+ var visualSubtree = visualTreeNodes[subtree];
+ var origin = new Point(visualNode.X + visualNode.Width / 2, visualNode.Y + visualNode.Height);
+ var target = new Point(visualSubtree.X + visualSubtree.Width / 2, visualSubtree.Y);
+ graphics.Clip = new Region(new Rectangle(Math.Min(origin.X, target.X), origin.Y, Math.Max(origin.X, target.X), target.Y));
+ using (var linePen = new Pen(visualLine.LineColor)) {
linePen.DashStyle = visualLine.DashStyle;
- graphics.DrawLine(linePen, connectionPoint, new Point(visualTreeNode.X + visualTreeNode.Width / 2, visualTreeNode.Y));
+ graphics.DrawLine(linePen, origin, target);
}
}
-
- //calculate areas for the subtrees according to their tree size and call drawFunctionTree
- Point connectFrom = new Point(visualTreeNode.X + visualTreeNode.Width / 2, visualTreeNode.Y + visualTreeNode.Height);
- int[] xBoundaries = new int[node.SubtreeCount + 1];
- xBoundaries[0] = x;
- for (int i = 0; i < node.SubtreeCount; i++) {
- xBoundaries[i + 1] = (int)(xBoundaries[i] + (width * (double)node.GetSubtree(i).GetLength()) / (node.GetLength() - 1));
- DrawFunctionTree(node.GetSubtree(i), graphics, xBoundaries[i], y + height, xBoundaries[i + 1] - xBoundaries[i], height, connectFrom);
- }
- }
- }
-
- protected void DrawTreeNode(VisualSymbolicExpressionTreeNode visualTreeNode) {
- using (var graphics = Graphics.FromImage(image)) {
- graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
- graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
- DrawTreeNode(graphics, visualTreeNode);
- }
- }
-
- protected void DrawTreeNode(Graphics graphics, VisualSymbolicExpressionTreeNode visualTreeNode) {
+ }
+ }
+
+ protected void DrawTreeNode(Graphics graphics, VisualTreeNode visualTreeNode) {
graphics.Clip = new Region(new Rectangle(visualTreeNode.X, visualTreeNode.Y, visualTreeNode.Width + 1, visualTreeNode.Height + 1));
graphics.Clear(backgroundColor);
- var node = visualTreeNode.SymbolicExpressionTreeNode;
+ var node = visualTreeNode.Content;
using (var textBrush = new SolidBrush(visualTreeNode.TextColor))
using (var nodeLinePen = new Pen(visualTreeNode.LineColor))
@@ -364,6 +340,16 @@
}
}
+
+ protected void DrawLine(Graphics graphics, VisualTreeNode startNode, VisualTreeNode endNode) {
+ var origin = new Point(startNode.X + startNode.Width / 2, startNode.Y + startNode.Height);
+ var target = new Point(endNode.X + endNode.Width / 2, endNode.Y);
+ graphics.Clip = new Region(new Rectangle(Math.Min(origin.X, target.X), origin.Y, Math.Max(origin.X, target.X), target.Y));
+ var visualLine = GetVisualSymbolicExpressionTreeNodeConnection(startNode.Content, endNode.Content);
+ using (var linePen = new Pen(visualLine.LineColor)) {
+ linePen.DashStyle = visualLine.DashStyle;
+ graphics.DrawLine(linePen, origin, target);
+ }
+ }
#endregion
-
#region save image
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e) {
@@ -380,6 +366,5 @@
Image image = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(image)) {
- int height = this.Height / tree.Depth;
- DrawFunctionTree(tree, g, 0, 0, Width, height);
+ DrawFunctionTree(g, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
}
image.Save(filename);
@@ -391,6 +376,5 @@
using (Metafile file = new Metafile(filename, g.GetHdc())) {
using (Graphics emfFile = Graphics.FromImage(file)) {
- int height = this.Height / tree.Depth;
- DrawFunctionTree(tree, emfFile, 0, 0, Width, height);
+ DrawFunctionTree(emfFile, preferredNodeWidth, preferredNodeHeight, minHorizontalDistance, minVerticalDistance);
}
}
@@ -399,4 +383,44 @@
}
#endregion
+ #region export pgf/tikz
+ private void exportLatexToolStripMenuItem_Click(object sender, EventArgs e) {
+ var t = Tree;
+ if (t == null) return;
+ using (var dialog = new SaveFileDialog { Filter = "Tex (*.tex)|*.tex" }) {
+ if (dialog.ShowDialog() != DialogResult.OK) return;
+ string filename = dialog.FileName.ToLower();
+ var formatter = new SymbolicExpressionTreeLatexFormatter();
+ File.WriteAllText(filename, formatter.Format(t));
+ }
+ }
+ #endregion
+
+ private void reingoldTilfordToolStripMenuItem_Click(object sender, EventArgs e) {
+ minHorizontalDistance = 30;
+ minVerticalDistance = 30;
+ layoutEngine = new ReingoldTilfordLayoutEngine(n => n.Subtrees) {
+ NodeWidth = preferredNodeWidth,
+ NodeHeight = preferredNodeHeight,
+ HorizontalSpacing = minHorizontalDistance,
+ VerticalSpacing = minVerticalDistance
+ };
+ reingoldTilfordToolStripMenuItem.Checked = true;
+ boxesToolStripMenuItem.Checked = false;
+ Repaint();
+ }
+
+ private void boxesToolStripMenuItem_Click(object sender, EventArgs e) {
+ minHorizontalDistance = 5;
+ minVerticalDistance = 5;
+ layoutEngine = new BoxesLayoutEngine(n => n.Subtrees, n => n.GetLength(), n => n.GetDepth()) {
+ NodeWidth = preferredNodeWidth,
+ NodeHeight = preferredNodeHeight,
+ HorizontalSpacing = minHorizontalDistance,
+ VerticalSpacing = minVerticalDistance
+ };
+ reingoldTilfordToolStripMenuItem.Checked = false;
+ boxesToolStripMenuItem.Checked = true;
+ Repaint();
+ }
}
}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.Designer.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.Designer.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.Designer.cs (revision 11120)
@@ -52,8 +52,9 @@
// textBox
//
- this.textBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.textBox.BackColor = System.Drawing.Color.White;
+ this.textBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textBox.Location = new System.Drawing.Point(3, 30);
this.textBox.Multiline = true;
@@ -66,6 +67,6 @@
// formattersComboBox
//
- this.formattersComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
+ this.formattersComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.formattersComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.formattersComboBox.FormattingEnabled = true;
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.cs (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/SymbolicExpressionView.cs (revision 11120)
@@ -78,4 +78,5 @@
UpdateTextbox();
}
+
}
}
Index: able/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualSymbolicExpressionTreeNode.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualSymbolicExpressionTreeNode.cs (revision 11119)
+++ (revision )
@@ -1,129 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see .
- */
-#endregion
-
-using System.Drawing;
-
-namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
- public class VisualSymbolicExpressionTreeNode : object {
- private static readonly Color defaultLineColor = Color.Black;
- private static readonly Color defaultTextColor = Color.Black;
- private static readonly Color defaultFillColor = Color.White;
- private const int defaultPreferredWidth = 70;
- private const int defaultPreferredHeight = 46;
-
- public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode) :
- this(symbolicExpressionTreeNode, defaultLineColor) {
- }
-
- public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor) :
- this(symbolicExpressionTreeNode, lineColor, defaultTextColor) {
- }
-
- public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor) :
- this(symbolicExpressionTreeNode, lineColor, textColor, defaultFillColor) {
- }
-
- public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor, Color fillColor) :
- this(symbolicExpressionTreeNode, lineColor, textColor, fillColor, defaultPreferredWidth, defaultPreferredHeight) {
- }
-
- public VisualSymbolicExpressionTreeNode(ISymbolicExpressionTreeNode symbolicExpressionTreeNode, Color lineColor, Color textColor, Color fillColor, int width, int height) {
- this.symbolicExpressionTreeNode = symbolicExpressionTreeNode;
- this.lineColor = lineColor;
- this.textColor = textColor;
- this.fillColor = fillColor;
- this.preferredWidth = width;
- this.preferredHeight = height;
- this.ToolTip = symbolicExpressionTreeNode.ToString();
- }
-
- #region members for internal use only
- private int x;
- public int X {
- get { return x; }
- internal set { this.x = value; }
- }
-
- private int y;
- public int Y {
- get { return y; }
- internal set { this.y = value; }
- }
-
- private int width;
- public int Width {
- get { return this.width; }
- internal set { this.width = value; }
- }
-
- private int height;
- public int Height {
- get { return this.height; }
- internal set { this.height = value; }
- }
- #endregion
-
- private ISymbolicExpressionTreeNode symbolicExpressionTreeNode;
- public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode {
- get { return this.symbolicExpressionTreeNode; }
- set {
- symbolicExpressionTreeNode = value;
- ToolTip = SymbolicExpressionTreeNode.ToString();
- }
- }
-
- private int preferredWidth;
- public int PreferredWidth {
- get { return this.preferredWidth; }
- set { this.preferredWidth = value; }
- }
-
- private int preferredHeight;
- public int PreferredHeight {
- get { return this.preferredHeight; }
- set { this.preferredHeight = value; }
- }
-
- private Color lineColor;
- public Color LineColor {
- get { return this.lineColor; }
- set { this.lineColor = value; }
- }
-
- private Color textColor;
- public Color TextColor {
- get { return this.textColor; }
- set { this.textColor = value; }
- }
-
- private Color fillColor;
- public Color FillColor {
- get { return this.fillColor; }
- set { this.fillColor = value; }
- }
-
- private string toolTip;
- public string ToolTip {
- get { return toolTip; }
- set { toolTip = value; }
- }
- }
-}
Index: able/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualSymbolicExpressionTreeNodeConnection.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualSymbolicExpressionTreeNodeConnection.cs (revision 11119)
+++ (revision )
@@ -1,48 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see .
- */
-#endregion
-
-using System.Drawing;
-using System.Drawing.Drawing2D;
-
-namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
- public class VisualSymbolicExpressionTreeNodeConnection : object {
- private static readonly Color defaultLineColor = Color.Black;
- private static readonly DashStyle defaultDashStyle = DashStyle.Solid;
-
- private Color lineColor;
- public Color LineColor {
- get { return lineColor; }
- set { lineColor = value; }
- }
-
- private DashStyle dashStyle;
- public DashStyle DashStyle {
- get { return dashStyle; }
- set { dashStyle = value; }
- }
-
- public VisualSymbolicExpressionTreeNodeConnection()
- : base() {
- lineColor = defaultLineColor;
- dashStyle = defaultDashStyle;
- }
- }
-}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNode.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNode.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNode.cs (revision 11120)
@@ -0,0 +1,129 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System.Drawing;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ public class VisualTreeNode where T : class {
+ private static readonly Color defaultLineColor = Color.Black;
+ private static readonly Color defaultTextColor = Color.Black;
+ private static readonly Color defaultFillColor = Color.White;
+ private const int defaultPreferredWidth = 70;
+ private const int defaultPreferredHeight = 46;
+
+ public VisualTreeNode(T content) :
+ this(content, defaultLineColor) {
+ }
+
+ public VisualTreeNode(T content, Color lineColor) :
+ this(content, lineColor, defaultTextColor) {
+ }
+
+ public VisualTreeNode(T content, Color lineColor, Color textColor) :
+ this(content, lineColor, textColor, defaultFillColor) {
+ }
+
+ public VisualTreeNode(T content, Color lineColor, Color textColor, Color fillColor) :
+ this(content, lineColor, textColor, fillColor, defaultPreferredWidth, defaultPreferredHeight) {
+ }
+
+ public VisualTreeNode(T content, Color lineColor, Color textColor, Color fillColor, int width, int height) {
+ this.content = content;
+ this.lineColor = lineColor;
+ this.textColor = textColor;
+ this.fillColor = fillColor;
+ this.preferredWidth = width;
+ this.preferredHeight = height;
+ this.ToolTip = content.ToString();
+ }
+
+ #region members for internal use only
+ private int x;
+ public int X {
+ get { return x; }
+ internal set { this.x = value; }
+ }
+
+ private int y;
+ public int Y {
+ get { return y; }
+ internal set { this.y = value; }
+ }
+
+ private int width;
+ public int Width {
+ get { return this.width; }
+ internal set { this.width = value; }
+ }
+
+ private int height;
+ public int Height {
+ get { return this.height; }
+ internal set { this.height = value; }
+ }
+ #endregion
+
+ private T content;
+ public T Content {
+ get { return this.content; }
+ set {
+ content = value;
+ ToolTip = Content.ToString();
+ }
+ }
+
+ private int preferredWidth;
+ public int PreferredWidth {
+ get { return this.preferredWidth; }
+ set { this.preferredWidth = value; }
+ }
+
+ private int preferredHeight;
+ public int PreferredHeight {
+ get { return this.preferredHeight; }
+ set { this.preferredHeight = value; }
+ }
+
+ private Color lineColor;
+ public Color LineColor {
+ get { return this.lineColor; }
+ set { this.lineColor = value; }
+ }
+
+ private Color textColor;
+ public Color TextColor {
+ get { return this.textColor; }
+ set { this.textColor = value; }
+ }
+
+ private Color fillColor;
+ public Color FillColor {
+ get { return this.fillColor; }
+ set { this.fillColor = value; }
+ }
+
+ private string toolTip;
+ public string ToolTip {
+ get { return toolTip; }
+ set { toolTip = value; }
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNodeConnection.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNodeConnection.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views/3.4/VisualTreeNodeConnection.cs (revision 11120)
@@ -0,0 +1,48 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+#endregion
+
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views {
+ public class VisualTreeNodeConnection {
+ private static readonly Color defaultLineColor = Color.Black;
+ private static readonly DashStyle defaultDashStyle = DashStyle.Solid;
+
+ private Color lineColor;
+ public Color LineColor {
+ get { return lineColor; }
+ set { lineColor = value; }
+ }
+
+ private DashStyle dashStyle;
+ public DashStyle DashStyle {
+ get { return dashStyle; }
+ set { dashStyle = value; }
+ }
+
+ public VisualTreeNodeConnection()
+ : base() {
+ lineColor = defaultLineColor;
+ dashStyle = defaultDashStyle;
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Formatters/SymbolicExpressionTreeHierarchicalFormatter.cs
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Formatters/SymbolicExpressionTreeHierarchicalFormatter.cs (revision 11120)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Formatters/SymbolicExpressionTreeHierarchicalFormatter.cs (revision 11120)
@@ -0,0 +1,93 @@
+#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see .
+ */
+
+#endregion
+
+using System.IO;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
+ [Item("Hierarchical Formatter", "Formatter for symbolic expression trees that uses special characters for drawing a tree in text-mode.")]
+ public sealed class SymbolicExpressionTreeHierarchicalFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
+ private SymbolicExpressionTreeHierarchicalFormatter(SymbolicExpressionTreeHierarchicalFormatter original, Cloner cloner)
+ : base(original, cloner) {
+ }
+ public override IDeepCloneable Clone(Cloner cloner) {
+ return new SymbolicExpressionTreeHierarchicalFormatter(this, cloner);
+ }
+
+ public SymbolicExpressionTreeHierarchicalFormatter() :
+ base("Hierarchical Formatter", "Formatter for symbolic expression trees that uses special characters for drawing a tree in text-mode.") { }
+
+ public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
+ var sw = new StringWriter();
+ RenderTree(sw, symbolicExpressionTree);
+ return sw.ToString();
+ }
+
+ private static void RenderTree(TextWriter writer, ISymbolicExpressionTree tree) {
+ RenderNode(writer, tree.Root, string.Empty);
+ }
+
+ public static void RenderNode(TextWriter writer, ISymbolicExpressionTreeNode node, string prefix) {
+ string label = node.ToString();
+ writer.Write(label);
+ if (node.SubtreeCount > 0) {
+ var padding = prefix + new string(' ', label.Length);
+ for (int i = 0; i != node.SubtreeCount; ++i) {
+ char connector, extender = ' ';
+ if (i == 0) {
+ if (node.SubtreeCount > 1) {
+ connector = RenderChars.JunctionDown;
+ extender = RenderChars.VerticalLine;
+ } else {
+ connector = RenderChars.HorizontalLine;
+ extender = ' ';
+ }
+ } else {
+ writer.Write(padding);
+ if (i == node.SubtreeCount - 1) {
+ connector = RenderChars.CornerRight;
+ extender = ' ';
+ } else {
+ connector = RenderChars.JunctionRight;
+ extender = RenderChars.VerticalLine;
+ }
+ }
+ writer.Write(string.Concat(connector, RenderChars.HorizontalLine));
+ var newPrefix = string.Concat(padding, extender, ' ');
+ RenderNode(writer, node.GetSubtree(i), newPrefix);
+ }
+ } else
+ writer.WriteLine();
+ }
+
+ // helper class providing characters for displaying a tree in the console
+ public static class RenderChars {
+ public const char JunctionDown = '┬';
+ public const char HorizontalLine = '─';
+ public const char VerticalLine = '│';
+ public const char JunctionRight = '├';
+ public const char CornerRight = '└';
+ }
+ }
+}
Index: /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj
===================================================================
--- /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj (revision 11119)
+++ /stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj (revision 11120)
@@ -135,4 +135,5 @@
+
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs (revision 11119)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs (revision 11120)
@@ -52,4 +52,5 @@
Content.ModelChanged += Content_Changed;
Content.ProblemDataChanged += Content_Changed;
+ treeChart.Repainted += treeChart_Repainted;
}
protected override void DeregisterContentEvents() {
@@ -57,4 +58,5 @@
Content.ModelChanged -= Content_Changed;
Content.ProblemDataChanged -= Content_Changed;
+ treeChart.Repainted -= treeChart_Repainted;
}
@@ -68,4 +70,9 @@
UpdateView();
viewHost.Content = this.Content;
+ }
+
+ private void treeChart_Repainted(object sender, EventArgs e) {
+ if (nodeImpacts != null && nodeImpacts.Count > 0)
+ PaintNodeImpacts();
}
@@ -96,21 +103,18 @@
private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) {
- var visualNode = (VisualSymbolicExpressionTreeNode)sender;
- var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.SymbolicExpressionTreeNode;
- if (symbExprTreeNode == null) return;
- var tree = Content.Model.SymbolicExpressionTree;
+ var visualNode = (VisualTreeNode)sender;
+ if (visualNode.Content == null) { throw new Exception("Visual node content cannot be null."); }
+ var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.Content;
+ if (!foldedNodes.ContainsKey(symbExprTreeNode)) return; // constant nodes cannot be folded
var parent = symbExprTreeNode.Parent;
int indexOfSubtree = parent.IndexOfSubtree(symbExprTreeNode);
- if (foldedNodes.ContainsKey(symbExprTreeNode)) {
- // undo node folding
- SwitchNodeWithReplacementNode(parent, indexOfSubtree);
- }
- UpdateModel(tree);
+ SwitchNodeWithReplacementNode(parent, indexOfSubtree);
+ UpdateModel(Content.Model.SymbolicExpressionTree);
}
private void SwitchNodeWithReplacementNode(ISymbolicExpressionTreeNode parent, int subTreeIndex) {
ISymbolicExpressionTreeNode subTree = parent.GetSubtree(subTreeIndex);
- parent.RemoveSubtree(subTreeIndex);
if (foldedNodes.ContainsKey(subTree)) {
+ parent.RemoveSubtree(subTreeIndex);
var replacementNode = foldedNodes[subTree];
parent.InsertSubtree(subTreeIndex, replacementNode);
@@ -125,8 +129,9 @@
double max = impacts.Max();
double min = impacts.Min();
- foreach (ISymbolicExpressionTreeNode treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
- VisualSymbolicExpressionTreeNode visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
+ foreach (var treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {
+ VisualTreeNode visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode);
if (!(treeNode is ConstantTreeNode) && nodeImpacts.ContainsKey(treeNode)) {
+ visualTree.ToolTip = visualTree.Content.ToString(); // to avoid duplicate tooltips
double impact = nodeImpacts[treeNode];
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs (revision 11119)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs (revision 11120)
@@ -33,5 +33,5 @@
internal sealed partial class InteractiveSymbolicExpressionTreeChart : SymbolicExpressionTreeChart {
private ISymbolicExpressionTreeNode tempNode; // node in clipboard (to be cut/copy/pasted etc)
- private VisualSymbolicExpressionTreeNode currSelected; // currently selected node
+ private VisualTreeNode currSelected; // currently selected node
private enum EditOp { NoOp, CopySubtree, CutSubtree }
private EditOp lastOp = EditOp.NoOp;
@@ -65,5 +65,5 @@
pasteToolStripMenuItem.Visible = false;
} else {
- var node = currSelected.SymbolicExpressionTreeNode;
+ var node = currSelected.Content;
insertNodeToolStripMenuItem.Visible = true;
changeNodeToolStripMenuItem.Visible = true;
@@ -77,10 +77,10 @@
pasteToolStripMenuItem.Enabled = tempNode != null && insertNodeToolStripMenuItem.Enabled
&& !(lastOp == EditOp.CutSubtree
- && tempNode.IterateNodesBreadth().Contains(currSelected.SymbolicExpressionTreeNode));
+ && tempNode.IterateNodesBreadth().Contains(currSelected.Content));
}
}
protected override void OnSymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs e) {
- currSelected = (VisualSymbolicExpressionTreeNode)sender; ;
+ currSelected = (VisualTreeNode)sender; ;
if (currSelected != null) {
currSelected.LineColor = Color.FromArgb(130, currSelected.LineColor);
@@ -104,6 +104,6 @@
private void insertNodeToolStripMenuItem_Click(object sender, EventArgs e) {
- if (currSelected == null || currSelected.SymbolicExpressionTreeNode is SymbolicExpressionTreeTerminalNode) return;
- var parent = currSelected.SymbolicExpressionTreeNode;
+ if (currSelected == null || currSelected.Content is SymbolicExpressionTreeTerminalNode) return;
+ var parent = currSelected.Content;
using (var dialog = new InsertNodeDialog()) {
@@ -138,6 +138,6 @@
if (currSelected == null) return;
- var node = (ISymbolicExpressionTreeNode)currSelected.SymbolicExpressionTreeNode.Clone();
- var originalNode = currSelected.SymbolicExpressionTreeNode;
+ var node = (ISymbolicExpressionTreeNode)currSelected.Content.Clone();
+ var originalNode = currSelected.Content;
ISymbolicExpressionTreeNode newNode = null;
@@ -180,5 +180,5 @@
}
}
- tempNode = currSelected.SymbolicExpressionTreeNode;
+ tempNode = currSelected.Content;
foreach (var node in tempNode.IterateNodesPostfix()) {
var visualNode = GetVisualSymbolicExpressionTreeNode(node);
@@ -194,5 +194,5 @@
}
private void removeNodeToolStripMenuItem_Click(object sender, EventArgs e) {
- var node = currSelected.SymbolicExpressionTreeNode;
+ var node = currSelected.Content;
if (node == tempNode) tempNode = null;
ModifyTree(Tree, node.Parent, node, null, removeSubtree: false);
@@ -200,5 +200,5 @@
}
private void removeSubtreeToolStripMenuItem_Click(object sender, EventArgs e) {
- var node = currSelected.SymbolicExpressionTreeNode;
+ var node = currSelected.Content;
if (node.IterateNodesPostfix().Contains(tempNode)) tempNode = null;
ModifyTree(Tree, node.Parent, node, null, removeSubtree: true);
@@ -209,5 +209,5 @@
if (!(lastOp == EditOp.CopySubtree || lastOp == EditOp.CutSubtree)) return;
// check if the copied/cut node (stored in the tempNode) can be inserted as a child of the current selected node
- var node = currSelected.SymbolicExpressionTreeNode;
+ var node = currSelected.Content;
if (node is ConstantTreeNode || node is VariableTreeNode) return;
// check if the currently selected node can accept the copied node as a child
@@ -218,5 +218,5 @@
if (tempNode.IterateNodesBreadth().Contains(node))
throw new ArgumentException();// cannot cut/paste a node into itself
- ModifyTree(Tree, tempNode.Parent, tempNode, null); //remove node from its original parent
+ ModifyTree(Tree, tempNode.Parent, tempNode, null); //remove node from its original parent
ModifyTree(Tree, node, null, tempNode); //insert it as a child to the new parent
break;
Index: /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TextualSymbolicDataAnalysisModelView.designer.cs
===================================================================
--- /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TextualSymbolicDataAnalysisModelView.designer.cs (revision 11119)
+++ /stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TextualSymbolicDataAnalysisModelView.designer.cs (revision 11120)
@@ -48,5 +48,5 @@
this.SuspendLayout();
//
- // expressionTreeView
+ // symbolicExpressionTreeView
//
this.symbolicExpressionTreeView.AllowDrop = true;
@@ -55,16 +55,15 @@
this.symbolicExpressionTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
this.symbolicExpressionTreeView.Location = new System.Drawing.Point(0, 0);
- this.symbolicExpressionTreeView.Name = "expressionTreeView";
+ this.symbolicExpressionTreeView.Name = "symbolicExpressionTreeView";
this.symbolicExpressionTreeView.ReadOnly = false;
this.symbolicExpressionTreeView.Size = new System.Drawing.Size(352, 413);
this.symbolicExpressionTreeView.TabIndex = 0;
//
- // SymbolicExpressionModelView
+ // TextualSymbolicDataAnalysisModelView
//
this.AllowDrop = true;
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.symbolicExpressionTreeView);
- this.Name = "SymbolicExpressionModelView";
+ this.Name = "TextualSymbolicDataAnalysisModelView";
this.Size = new System.Drawing.Size(352, 413);
this.ResumeLayout(false);