Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 10285 was 10285, checked in by bburlacu, 11 years ago

#1772: Added SymbolicDataAnalysisGenealogyView, updated generic analyzer and operators.

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