Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Charts/LineGraph.cs @ 13834

Last change on this file since 13834 was 12503, checked in by aballeit, 10 years ago

#2283 added GUI and charts; fixed MCTS

File size: 8.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections.ObjectModel;
4using System.Collections.Specialized;
5using System.ComponentModel;
6using System.Diagnostics;
7using System.Globalization;
8using System.Linq;
9using System.Windows;
10using System.Windows.Media;
11using Microsoft.Research.DynamicDataDisplay.Charts;
12using Microsoft.Research.DynamicDataDisplay.Charts.Legend_items;
13using Microsoft.Research.DynamicDataDisplay.DataSources;
14using Microsoft.Research.DynamicDataDisplay.Filters;
15using System.Windows.Shapes;
16
17
18namespace Microsoft.Research.DynamicDataDisplay
19{
20  /// <summary>
21  /// Represents a series of points connected by one polyline.
22  /// </summary>
23  public class LineGraph : PointsGraphBase
24  {
25    static LineGraph()
26    {
27      Type thisType = typeof(LineGraph);
28
29      Legend.DescriptionProperty.OverrideMetadata(thisType, new FrameworkPropertyMetadata("LineGraph"));
30      Legend.LegendItemsBuilderProperty.OverrideMetadata(thisType, new FrameworkPropertyMetadata(new LegendItemsBuilder(DefaultLegendItemsBuilder)));
31    }
32
33    private static IEnumerable<FrameworkElement> DefaultLegendItemsBuilder(IPlotterElement plotterElement)
34    {
35      LineGraph lineGraph = (LineGraph)plotterElement;
36
37      Line line = new Line { X1 = 0, Y1 = 10, X2 = 20, Y2 = 0, Stretch = Stretch.Fill, DataContext = lineGraph };
38      line.SetBinding(Line.StrokeProperty, "Stroke");
39      line.SetBinding(Line.StrokeThicknessProperty, "StrokeThickness");
40      Legend.SetVisualContent(lineGraph, line);
41
42      var legendItem = LegendItemsHelper.BuildDefaultLegendItem(lineGraph);
43      yield return legendItem;
44    }
45
46    private readonly FilterCollection filters = new FilterCollection();
47
48    /// <summary>
49    /// Initializes a new instance of the <see cref="LineGraph"/> class.
50    /// </summary>
51    public LineGraph()
52    {
53      ManualTranslate = true;
54
55      filters.CollectionChanged += filters_CollectionChanged;
56    }
57
58    private void filters_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
59    {
60      filteredPoints = null;
61      Update();
62    }
63
64    /// <summary>
65    /// Initializes a new instance of the <see cref="LineGraph"/> class.
66    /// </summary>
67    /// <param name="pointSource">The point source.</param>
68    public LineGraph(IPointDataSource pointSource)
69      : this()
70    {
71      DataSource = pointSource;
72    }
73
74    /// <summary>Provides access to filters collection</summary>
75    public FilterCollection Filters
76    {
77      get { return filters; }
78    }
79
80    #region Pen
81
82    /// <summary>
83    /// Gets or sets the brush, using which polyline is plotted.
84    /// </summary>
85    /// <value>The line brush.</value>
86    public Brush Stroke
87    {
88      get { return LinePen.Brush; }
89      set
90      {
91        if (LinePen.Brush != value)
92        {
93          if (!LinePen.IsSealed)
94          {
95            LinePen.Brush = value;
96            InvalidateVisual();
97          }
98          else
99          {
100            Pen pen = LinePen.Clone();
101            pen.Brush = value;
102            LinePen = pen;
103          }
104
105          RaisePropertyChanged("Stroke");
106        }
107      }
108    }
109
110    /// <summary>
111    /// Gets or sets the line thickness.
112    /// </summary>
113    /// <value>The line thickness.</value>
114    public double StrokeThickness
115    {
116      get { return LinePen.Thickness; }
117      set
118      {
119        if (LinePen.Thickness != value)
120        {
121          if (!LinePen.IsSealed)
122          {
123            LinePen.Thickness = value; InvalidateVisual();
124          }
125          else
126          {
127            Pen pen = LinePen.Clone();
128            pen.Thickness = value;
129            LinePen = pen;
130          }
131
132          RaisePropertyChanged("StrokeThickness");
133        }
134      }
135    }
136
137    /// <summary>
138    /// Gets or sets the line pen.
139    /// </summary>
140    /// <value>The line pen.</value>
141    [NotNull]
142    public Pen LinePen
143    {
144      get { return (Pen)GetValue(LinePenProperty); }
145      set { SetValue(LinePenProperty, value); }
146    }
147
148    public static readonly DependencyProperty LinePenProperty =
149      DependencyProperty.Register(
150      "LinePen",
151      typeof(Pen),
152      typeof(LineGraph),
153      new FrameworkPropertyMetadata(
154        new Pen(Brushes.Blue, 1),
155        FrameworkPropertyMetadataOptions.AffectsRender
156        ),
157      OnValidatePen);
158
159    private static bool OnValidatePen(object value)
160    {
161      return value != null;
162    }
163
164    #endregion
165
166    protected override void OnOutputChanged(Rect newRect, Rect oldRect)
167    {
168      filteredPoints = null;
169      base.OnOutputChanged(newRect, oldRect);
170    }
171
172    protected override void OnDataChanged()
173    {
174      filteredPoints = null;
175      base.OnDataChanged();
176    }
177
178    protected override void OnDataSourceChanged(DependencyPropertyChangedEventArgs args)
179    {
180      filteredPoints = null;
181      base.OnDataSourceChanged(args);
182    }
183
184    protected override void OnVisibleChanged(DataRect newRect, DataRect oldRect)
185    {
186      if (newRect.Size != oldRect.Size)
187      {
188        filteredPoints = null;
189      }
190
191      base.OnVisibleChanged(newRect, oldRect);
192    }
193
194    private FakePointList filteredPoints;
195    protected FakePointList FilteredPoints
196    {
197      get { return filteredPoints; }
198      set { filteredPoints = value; }
199    }
200
201    protected override void UpdateCore()
202    {
203      if (DataSource == null) return;
204      if (Plotter == null) return;
205
206      Rect output = Viewport.Output;
207      var transform = GetTransform();
208
209      if (filteredPoints == null || !(transform.DataTransform is IdentityTransform))
210      {
211        IEnumerable<Point> points = GetPoints();
212
213        var bounds = BoundsHelper.GetViewportBounds(points, transform.DataTransform);
214        Viewport2D.SetContentBounds(this, bounds);
215
216        // getting new value of transform as it could change after calculating and setting content bounds.
217        transform = GetTransform();
218        List<Point> transformedPoints = transform.DataToScreenAsList(points);
219
220        // Analysis and filtering of unnecessary points
221        filteredPoints = new FakePointList(FilterPoints(transformedPoints),
222          output.Left, output.Right);
223
224        if (ProvideVisiblePoints)
225        {
226          List<Point> viewportPointsList = new List<Point>(transformedPoints.Count);
227          if (transform.DataTransform is IdentityTransform)
228          {
229            viewportPointsList.AddRange(points);
230          }
231          else
232          {
233            var viewportPoints = points.DataToViewport(transform.DataTransform);
234            viewportPointsList.AddRange(viewportPoints);
235          }
236
237          SetVisiblePoints(this, new ReadOnlyCollection<Point>(viewportPointsList));
238        }
239
240        Offset = new Vector();
241      }
242      else
243      {
244        double left = output.Left;
245        double right = output.Right;
246        double shift = Offset.X;
247        left -= shift;
248        right -= shift;
249
250        filteredPoints.SetXBorders(left, right);
251      }
252    }
253
254    StreamGeometry streamGeometry = new StreamGeometry();
255    protected override void OnRenderCore(DrawingContext dc, RenderState state)
256    {
257      if (DataSource == null) return;
258
259      if (filteredPoints.HasPoints)
260      {
261
262        using (StreamGeometryContext context = streamGeometry.Open())
263        {
264          context.BeginFigure(filteredPoints.StartPoint, false, false);
265          context.PolyLineTo(filteredPoints, true, smoothLinesJoin);
266        }
267
268        Brush brush = null;
269        Pen pen = LinePen;
270
271        bool isTranslated = IsTranslated;
272        if (isTranslated)
273        {
274          dc.PushTransform(new TranslateTransform(Offset.X, Offset.Y));
275        }
276        dc.DrawGeometry(brush, pen, streamGeometry);
277        if (isTranslated)
278        {
279          dc.Pop();
280        }
281
282#if __DEBUG
283        FormattedText text = new FormattedText(filteredPoints.Count.ToString(),
284          CultureInfo.InvariantCulture, FlowDirection.LeftToRight,
285          new Typeface("Arial"), 12, Brushes.Black);
286        dc.DrawText(text, Viewport.Output.GetCenter());
287#endif
288      }
289    }
290
291    private bool filteringEnabled = true;
292    public bool FilteringEnabled
293    {
294      get { return filteringEnabled; }
295      set
296      {
297        if (filteringEnabled != value)
298        {
299          filteringEnabled = value;
300          filteredPoints = null;
301          Update();
302        }
303      }
304    }
305
306    private bool smoothLinesJoin = true;
307    public bool SmoothLinesJoin
308    {
309      get { return smoothLinesJoin; }
310      set
311      {
312        smoothLinesJoin = value;
313        Update();
314      }
315    }
316
317    private List<Point> FilterPoints(List<Point> points)
318    {
319      if (!filteringEnabled)
320        return points;
321
322      var filteredPoints = filters.Filter(points, Viewport.Output);
323
324      return filteredPoints;
325    }
326  }
327}
Note: See TracBrowser for help on using the repository browser.