Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.EvolutionTracking.Views/3.4/GenealogyGraphChart.cs @ 10302

Last change on this file since 10302 was 10302, checked in by bburlacu, 10 years ago

#1772: - Added a ViewHost in the right side of the GenealogyGraphView which displays the encoding-specific content when a GenealogyGraphNode is clicked.

  • Migrated new SymbolicExpressionTreeChart (drawing the tree using the ReingoldTilfordLayoutEngine) to the new branch
  • Copied SymbolicDataAnalysisExpressionTreeMatching.cs and SymbolicDataAnalysisExpressionTreeSimilarityCalculator.cs to the new branch
File size: 10.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Drawing;
4using System.Drawing.Drawing2D;
5using System.Linq;
6using System.Windows.Forms;
7using HeuristicLab.Common;
8using HeuristicLab.Visualization;
9
10namespace HeuristicLab.EvolutionTracking.Views {
11  public partial class GenealogyGraphChart : ChartControl {
12    private IGenealogyGraph genealogyGraph;
13
14    private const double XIncrement = 30;
15    private const double YIncrement = 30;
16    private const double Diameter = 20;
17
18    public IGenealogyGraph GenealogyGraph {
19      get { return genealogyGraph; }
20      set {
21        if (value == null) return;
22        genealogyGraph = value;
23        Clear();
24        DrawGraph(XIncrement, YIncrement, Diameter);
25      }
26    }
27
28    private void Clear() {
29      if (nodeMap == null)
30        nodeMap = new Dictionary<IGenealogyGraphNode, VisualGenealogyGraphNode>();
31      else nodeMap.Clear();
32
33      if (arcMap == null)
34        arcMap = new Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc>();
35      else arcMap.Clear();
36
37      Chart.Group.Clear();
38    }
39
40    private Dictionary<IGenealogyGraphNode, VisualGenealogyGraphNode> nodeMap;
41    private Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc> arcMap;
42
43    public bool SimpleLineages { get; set; }
44    public bool LockGenealogy { get; set; }
45    private Visualization.Rectangle TargetRectangle { get; set; }
46
47    private VisualGenealogyGraphNode GetMappedNode(IGenealogyGraphNode node) {
48      VisualGenealogyGraphNode v;
49      nodeMap.TryGetValue(node, out v);
50      return v;
51    }
52
53    private VisualGenealogyGraphArc GetMappedArc(IGenealogyGraphNode source, IGenealogyGraphNode target) {
54      VisualGenealogyGraphNode visualSource, visualTarget;
55      nodeMap.TryGetValue(source, out visualSource);
56      nodeMap.TryGetValue(target, out visualTarget);
57
58      if (visualSource == null || visualTarget == null) return null;
59
60      VisualGenealogyGraphArc arc;
61      arcMap.TryGetValue(new Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>(visualSource, visualTarget), out arc);
62      return arc;
63    }
64    private bool DrawInProgress { get; set; } // do not try to update the chart while the drawing is not finished
65    private VisualGenealogyGraphNode SelectedVisualNode { get; set; }
66
67    public event MouseEventHandler GenealogyGraphNodeClicked;
68    private void OnGenealogyGraphNodeClicked(object sender, MouseEventArgs e) {
69      var clicked = GenealogyGraphNodeClicked;
70      if (clicked != null) clicked(sender, e);
71    }
72    public GenealogyGraphChart()
73      : base() {
74      InitializeComponent();
75    }
76    protected virtual void DrawGraph(double xIncrement, double yIncrement, double diameter) {
77      Chart.UpdateEnabled = false;
78      DrawInProgress = true;
79
80      var ranks = GenealogyGraph.Ranks.Select(t => new { Rank = t.Key, Nodes = t.Value }).OrderBy(p => p.Rank).ToList();
81      double x = 0;
82      double y = PreferredSize.Height + yIncrement + 2 * diameter;
83
84      foreach (var rank in ranks) {
85        var nodes = rank.Nodes.ToList();
86        nodes.Sort((a, b) => b.CompareTo(a)); // sort descending by quality
87        var nl = Environment.NewLine;
88
89        foreach (var node in nodes) {
90          var pen = new Pen(Color.LightGray);
91
92          var visualNode = new VisualGenealogyGraphNode(Chart, x, y, x + diameter, y + diameter, pen, null) {
93            Data = node,
94            ToolTipText = "Rank: " + node.Rank + nl +
95                          "Quality: " + String.Format("{0:0.0000}", node.Quality) + nl +
96                          "IsElite: " + node.IsElite
97          };
98          Chart.Group.Add(visualNode);
99          nodeMap.Add(node, visualNode);
100
101          x += xIncrement;
102        }
103        y -= yIncrement;
104        x = 0;
105      }
106
107      // add arcs
108      foreach (var node in GenealogyGraph.Nodes.Cast<IGenealogyGraphNode>()) {
109        if (node.InArcs == null) continue;
110        var visualNode = nodeMap[node];
111        if (visualNode == null) continue;
112        foreach (var arc in node.InArcs) {
113          var parent = arc.Source;
114          var visualParent = GetMappedNode(parent);
115          if (visualParent == null) continue;
116          var pen = new Pen(Color.Transparent);
117          var visualArc = AddArc(Chart, visualParent, visualNode, pen);
118          if (!arcMap.ContainsKey(Tuple.Create(visualParent, visualNode)))
119            arcMap.Add(Tuple.Create(visualParent, visualNode), visualArc);
120        }
121      }
122      // TODO: connect elites
123
124      Chart.UpdateEnabled = true;
125      Chart.EnforceUpdate();
126
127      DrawInProgress = false;
128    }
129    protected override void pictureBox_MouseMove(object sender, MouseEventArgs e) {
130      if (!DrawInProgress) {
131        switch (e.Button) {
132          case MouseButtons.Left:
133            Chart.Mode = ChartMode.Select;
134            Cursor = Cursors.Default;
135            break;
136          case MouseButtons.Middle:
137            Chart.Mode = ChartMode.Move;
138            Cursor = Cursors.Hand;
139            break;
140        }
141      }
142      base.pictureBox_MouseMove(sender, e);
143    }
144    protected override void pictureBox_MouseUp(object sender, MouseEventArgs e) {
145      Cursor = Cursors.Default;
146      if (Chart.Mode == ChartMode.Move) {
147        Chart.Mode = ChartMode.Select;
148        return;
149      }
150      if (Chart.Mode != ChartMode.Select) {
151        base.pictureBox_MouseUp(sender, e);
152        return;
153      }
154      var visualNodes = Chart.GetAllPrimitives(e.Location).Where(p => p is VisualGenealogyGraphNode).ToList();
155      if (visualNodes.Count <= 0) {
156        SelectedVisualNode = null;
157        return;
158      }
159      if (SelectedVisualNode == visualNodes[0]) return;
160      SelectedVisualNode = visualNodes[0] as VisualGenealogyGraphNode;
161      if (SelectedVisualNode == null) return;
162
163      if (!LockGenealogy) {
164        // new node has been selected, clean up
165        Chart.UpdateEnabled = false;
166        if (ModifierKeys != Keys.Shift)
167          // clear colors
168          ClearPrimitives();
169        // use a rectangle to highlight the currently selected genealogy graph node
170        var gNode = SelectedVisualNode.Data;
171        var visualNode = GetMappedNode(gNode);
172
173        DrawLineage(visualNode, n => SimpleLineages ? n.IncomingArcs.Take(1) : n.IncomingArcs, a => a.Source);
174        visualNode.Brush = null;
175        DrawLineage(visualNode, n => n.OutgoingArcs, a => a.Target);
176      }
177
178      MarkSelectedNode();
179
180      // update
181      Chart.UpdateEnabled = true;
182      Chart.EnforceUpdate();
183
184      if (SelectedVisualNode != null)
185        /* emit clicked event */
186        OnGenealogyGraphNodeClicked(SelectedVisualNode, e);
187
188      base.pictureBox_MouseUp(sender, e);
189    }
190    private void DrawLineage(VisualGenealogyGraphNode node, Func<VisualGenealogyGraphNode, IEnumerable<VisualGenealogyGraphArc>> arcSelector, Func<VisualGenealogyGraphArc, VisualGenealogyGraphNode> nodeSelector) {
191      if (node.Brush != null) return;
192      node.Brush = new SolidBrush(node.Data.GetColor());
193      var arcs = arcSelector(node);
194      if (arcs == null) return;
195
196      foreach (var arc in arcs) {
197        var source = arc.Source.Data;
198        var target = arc.Target.Data;
199        var start = new Point((int)arc.Start.X, (int)arc.Start.Y);
200        var end = new Point((int)arc.End.X, (int)arc.End.Y);
201        arc.Pen.Brush = new LinearGradientBrush(start, end, source.GetColor(), target.GetColor());
202        arc.Pen.Color = Color.Transparent;
203        //        arc.Pen.FontBrush = new SolidBrush(Color.DarkGray);
204        DrawLineage(nodeSelector(arc), arcSelector, nodeSelector);
205      }
206    }
207    void MarkSelectedNode() {
208      var center = SelectedVisualNode.Center;
209      var size = SelectedVisualNode.Size;
210      double x1 = center.X - size.Width / 2;
211      double x2 = x1 + size.Width;
212      double y1 = center.Y - size.Height / 2;
213      double y2 = y1 + size.Height;
214      if (TargetRectangle == null) {
215        TargetRectangle = new Visualization.Rectangle(Chart, x1, y1, x2, y2, new Pen(Color.Black), null);
216        Chart.Group.Add(TargetRectangle);
217      } else {
218        TargetRectangle.SetPosition(x1, y1, x2, y2);
219      }
220    }
221    private static VisualGenealogyGraphArc AddArc(IChart chart, VisualGenealogyGraphNode source, VisualGenealogyGraphNode target, Pen pen, Brush brush = null) {
222      var arc = new VisualGenealogyGraphArc(chart, source, target, pen) { Brush = brush };
223      arc.UpdatePosition();
224      source.OutgoingArcs.Add(arc);
225      target.IncomingArcs.Add(arc);
226      chart.Group.Add(arc);
227      return arc;
228    }
229    public virtual void ClearPrimitives() {
230      foreach (var primitive in Chart.Group.Primitives) {
231        if (primitive is VisualGenealogyGraphArc) {
232          primitive.Pen.Brush = new SolidBrush(Color.Transparent);
233        } else {
234          primitive.Brush = null;
235        }
236      }
237    }
238    public void HighlightNodes(IEnumerable<IGenealogyGraphNode> nodes) {
239      Chart.UpdateEnabled = false;
240      ClearPrimitives();
241      foreach (var node in nodes) {
242        GetMappedNode(node).Brush = new SolidBrush(node.GetColor());
243      }
244      Chart.UpdateEnabled = true;
245      Chart.EnforceUpdate();
246    }
247    public void HighlightAll() {
248      Chart.UpdateEnabled = false;
249      foreach (var visualNode in nodeMap.Values) {
250        visualNode.Brush = new SolidBrush(visualNode.Data.GetColor());
251      }
252      foreach (var arc in arcMap.Values) {
253        var source = arc.Source.Data;
254        var target = arc.Target.Data;
255        var start = new Point((int)arc.Start.X, (int)arc.Start.Y);
256        var end = new Point((int)arc.End.X, (int)arc.End.Y);
257        arc.Pen.Brush = new LinearGradientBrush(start, end, source.GetColor(), target.GetColor());
258      }
259      Chart.UpdateEnabled = true;
260      Chart.EnforceUpdate();
261    }
262  }
263  internal static class Util {
264    public static Color GetColor(this IGenealogyGraphNode node) {
265      var colorIndex = (int)(node.Quality * ColorGradient.Colors.Count);
266      return colorIndex < ColorGradient.Colors.Count ? ColorGradient.Colors[colorIndex] : Color.Transparent;
267    }
268  }
269}
Note: See TracBrowser for help on using the repository browser.