Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Charts/Axes/AxisBase.cs @ 14161

Last change on this file since 14161 was 12503, checked in by aballeit, 9 years ago

#2283 added GUI and charts; fixed MCTS

File size: 12.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Media;
8using System.Windows.Data;
9using System.Diagnostics;
10using System.ComponentModel;
11using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
12using Microsoft.Research.DynamicDataDisplay.Common;
13using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
14using System.Windows.Threading;
15
16namespace Microsoft.Research.DynamicDataDisplay.Charts
17{
18  /// <summary>
19  /// Represents a base class for all axes in ChartPlotter.
20  /// Contains a real UI representation of axis - AxisControl, and means to adjust number of ticks, algorythms of their generating and
21  /// look of ticks' labels.
22  /// </summary>
23  /// <typeparam name="T">Type of each tick's value</typeparam>
24  public abstract class AxisBase<T> : GeneralAxis, ITypedAxis<T>, IValueConversion<T>
25  {
26    /// <summary>
27    /// Initializes a new instance of the <see cref="AxisBase&lt;T&gt;"/> class.
28    /// </summary>
29    /// <param name="axisControl">The axis control.</param>
30    /// <param name="convertFromDouble">The convert from double.</param>
31    /// <param name="convertToDouble">The convert to double.</param>
32    protected AxisBase(AxisControl<T> axisControl, Func<double, T> convertFromDouble, Func<T, double> convertToDouble)
33    {
34      if (axisControl == null)
35        throw new ArgumentNullException("axisControl");
36      if (convertFromDouble == null)
37        throw new ArgumentNullException("convertFromDouble");
38      if (convertToDouble == null)
39        throw new ArgumentNullException("convertToDouble");
40
41      this.convertToDouble = convertToDouble;
42      this.convertFromDouble = convertFromDouble;
43
44      this.axisControl = axisControl;
45      axisControl.MakeDependent();
46      axisControl.ConvertToDouble = convertToDouble;
47      axisControl.ScreenTicksChanged += axisControl_ScreenTicksChanged;
48
49      Content = axisControl;
50      axisControl.SetBinding(Control.BackgroundProperty, new Binding("Background") { Source = this });
51
52      Focusable = false;
53
54      Loaded += OnLoaded;
55    }
56
57    public override void ForceUpdate()
58    {
59      axisControl.UpdateUI();
60    }
61
62    private void axisControl_ScreenTicksChanged(object sender, EventArgs e)
63    {
64      RaiseTicksChanged();
65    }
66
67    /// <summary>
68    /// Gets or sets a value indicating whether this axis is default axis.
69    /// ChartPlotter's AxisGrid gets axis ticks to display from two default axes - horizontal and vertical.
70    /// </summary>
71    /// <value>
72    ///   <c>true</c> if this instance is default axis; otherwise, <c>false</c>.
73    /// </value>
74    public bool IsDefaultAxis
75    {
76      get { return Microsoft.Research.DynamicDataDisplay.Plotter.GetIsDefaultAxis(this); }
77      set { Microsoft.Research.DynamicDataDisplay.Plotter.SetIsDefaultAxis(this, value); }
78    }
79
80    private void OnLoaded(object sender, RoutedEventArgs e)
81    {
82      RaiseTicksChanged();
83    }
84
85    /// <summary>
86    /// Gets or sets a value indicating whether to use smooth panning, when axis ticks are not being repainted after each chart panning.
87    /// </summary>
88    /// <value><c>true</c> if use smooth panning; otherwise, <c>false</c>.</value>
89    public override bool UseSmoothPanning
90    {
91      get { return axisControl.UseSmoothPanning; }
92      set { axisControl.UseSmoothPanning = value; }
93    }
94
95    /// <summary>
96    /// Gets the screen coordinates of axis ticks.
97    /// </summary>
98    /// <value>The screen ticks.</value>
99    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
100    [EditorBrowsable(EditorBrowsableState.Never)]
101    public override double[] ScreenTicks
102    {
103      get { return axisControl.ScreenTicks; }
104    }
105
106    /// <summary>
107    /// Gets the screen coordinates of minor ticks.
108    /// </summary>
109    /// <value>The minor screen ticks.</value>
110    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
111    [EditorBrowsable(EditorBrowsableState.Never)]
112    public override MinorTickInfo<double>[] MinorScreenTicks
113    {
114      get { return axisControl.MinorScreenTicks; }
115    }
116
117    private AxisControl<T> axisControl;
118    /// <summary>
119    /// Gets the axis control - actual UI representation of axis.
120    /// </summary>
121    /// <value>The axis control.</value>
122    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
123    public AxisControl<T> AxisControl
124    {
125      get { return axisControl; }
126    }
127
128    /// <summary>
129    /// Gets or sets the ticks provider, which is used to generate ticks in given range.
130    /// </summary>
131    /// <value>The ticks provider.</value>
132    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
133    public ITicksProvider<T> TicksProvider
134    {
135      get { return axisControl.TicksProvider; }
136      set { axisControl.TicksProvider = value; }
137    }
138
139    /// <summary>
140    /// Gets or sets the label provider, that is used to create UI look of axis ticks.
141    ///
142    /// Should not be null.
143    /// </summary>
144    /// <value>The label provider.</value>
145    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
146    [NotNull]
147    public LabelProviderBase<T> LabelProvider
148    {
149      get { return axisControl.LabelProvider; }
150      set { axisControl.LabelProvider = value; }
151    }
152
153    /// <summary>
154    /// Gets or sets the major label provider, which creates labels for major ticks.
155    /// If null, major labels will not be shown.
156    /// </summary>
157    /// <value>The major label provider.</value>
158    public LabelProviderBase<T> MajorLabelProvider
159    {
160      get { return axisControl.MajorLabelProvider; }
161      set { axisControl.MajorLabelProvider = value; }
162    }
163
164    /// <summary>
165    /// Gets or sets the label string format, used to create simple formats of each tick's label, such as
166    /// changing tick label from "1.2" to "$1.2".
167    /// Should be in format "*{0}*", where '*' is any number of any chars.
168    ///
169    /// If value is null, format string will not be used.
170    /// </summary>
171    /// <value>The label string format.</value>
172    public string LabelStringFormat
173    {
174      get { return LabelProvider.LabelStringFormat; }
175      set { LabelProvider.LabelStringFormat = value; }
176    }
177
178    /// <summary>
179    /// Gets or sets a value indicating whether to show minor ticks.
180    /// </summary>
181    /// <value><c>true</c> if show minor ticks; otherwise, <c>false</c>.</value>
182    public bool ShowMinorTicks
183    {
184      get { return axisControl.DrawMinorTicks; }
185      set { axisControl.DrawMinorTicks = value; }
186    }
187
188    /// <summary>
189    /// Gets or sets a value indicating whether to show major labels.
190    /// </summary>
191    /// <value><c>true</c> if show major labels; otherwise, <c>false</c>.</value>
192    public bool ShowMajorLabels
193    {
194      get { return axisControl.DrawMajorLabels; }
195      set { axisControl.DrawMajorLabels = value; }
196    }
197
198    protected override void OnPlotterAttached(Plotter2D plotter)
199    {
200      plotter.Viewport.PropertyChanged += OnViewportPropertyChanged;
201
202      Panel panel = GetPanelByPlacement(Placement);
203      if (panel != null)
204      {
205        int index = GetInsertionIndexByPlacement(Placement, panel);
206        panel.Children.Insert(index, this);
207      }
208
209      using (axisControl.OpenUpdateRegion(true))
210      {
211        UpdateAxisControl(plotter);
212      }
213    }
214
215    private void UpdateAxisControl(Plotter2D plotter2d)
216    {
217      axisControl.Transform = plotter2d.Viewport.Transform;
218      axisControl.Range = CreateRangeFromRect(plotter2d.Visible.ViewportToData(plotter2d.Viewport.Transform));
219    }
220
221    private int GetInsertionIndexByPlacement(AxisPlacement placement, Panel panel)
222    {
223      int index = panel.Children.Count;
224
225      switch (placement)
226      {
227        case AxisPlacement.Left:
228          index = 0;
229          break;
230        case AxisPlacement.Top:
231          index = 0;
232          break;
233        default:
234          break;
235      }
236
237      return index;
238    }
239
240    ExtendedPropertyChangedEventArgs visibleChangedEventArgs;
241    int viewportPropertyChangedEnters = 0;
242    DataRect prevDataRect = DataRect.Empty;
243    private void OnViewportPropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
244    {
245      //if (viewportPropertyChangedEnters > 4)
246      //{
247      //    if (e.PropertyName == "Visible")
248      //    {
249      //        visibleChangedEventArgs = e;
250      //    }
251      //    return;
252      //}
253
254      viewportPropertyChangedEnters++;
255
256      Viewport2D viewport = (Viewport2D)sender;
257
258      DataRect visible = viewport.Visible;
259
260      DataRect dataRect = visible.ViewportToData(viewport.Transform);
261      bool forceUpdate = dataRect != prevDataRect;
262      prevDataRect = dataRect;
263
264      Range<T> range = CreateRangeFromRect(dataRect);
265
266      using (axisControl.OpenUpdateRegion(false)) // todo was forceUpdate
267      {
268        axisControl.Range = range;
269        axisControl.Transform = viewport.Transform;
270      }
271
272      //OnViewportPropertyChanged(Plotter.Viewport, visibleChangedEventArgs);
273
274      //Dispatcher.BeginInvoke(() =>
275      //{
276      //    viewportPropertyChangedEnters--;
277      //    if (visibleChangedEventArgs != null)
278      //    {
279      //        OnViewportPropertyChanged(Plotter.Viewport, visibleChangedEventArgs);
280      //    }
281      //    visibleChangedEventArgs = null;
282      //}, DispatcherPriority.Render);
283    }
284
285    private Func<double, T> convertFromDouble;
286    /// <summary>
287    /// Gets or sets the delegate that is used to create each tick from double.
288    /// Is used to create typed range to display for internal AxisControl.
289    /// If changed, ConvertToDouble should be changed appropriately, too.
290    /// Should not be null.
291    /// </summary>
292    /// <value>The convert from double.</value>
293    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
294    [NotNull]
295    public Func<double, T> ConvertFromDouble
296    {
297      get { return convertFromDouble; }
298      set
299      {
300        if (value == null)
301          throw new ArgumentNullException("value");
302
303        if (convertFromDouble != value)
304        {
305          convertFromDouble = value;
306          if (ParentPlotter != null)
307          {
308            UpdateAxisControl(ParentPlotter);
309          }
310        }
311      }
312    }
313
314    private Func<T, double> convertToDouble;
315    /// <summary>
316    /// Gets or sets the delegate that is used to convert each tick to double.
317    /// Is used by internal AxisControl to convert tick to double to get tick's coordinates inside of viewport.
318    /// If changed, ConvertFromDouble should be changed appropriately, too.
319    /// Should not be null.
320    /// </summary>
321    /// <value>The convert to double.</value>
322    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
323    [NotNull]
324    public Func<T, double> ConvertToDouble
325    {
326      get { return convertToDouble; }
327      set
328      {
329        if (value == null)
330          throw new ArgumentNullException("value");
331
332        if (convertToDouble != value)
333        {
334          convertToDouble = value;
335          axisControl.ConvertToDouble = value;
336        }
337      }
338    }
339
340    /// <summary>
341    /// Sets conversions of axis - functions used to convert values of axis type to and from double values of viewport.
342    /// Sets both ConvertToDouble and ConvertFromDouble properties.
343    /// </summary>
344    /// <param name="min">The minimal viewport value.</param>
345    /// <param name="minValue">The value of axis type, corresponding to minimal viewport value.</param>
346    /// <param name="max">The maximal viewport value.</param>
347    /// <param name="maxValue">The value of axis type, corresponding to maximal viewport value.</param>
348    public virtual void SetConversion(double min, T minValue, double max, T maxValue)
349    {
350      throw new NotImplementedException();
351    }
352
353    private Range<T> CreateRangeFromRect(DataRect visible)
354    {
355      T min, max;
356
357      Range<T> range;
358      switch (Placement)
359      {
360        case AxisPlacement.Left:
361        case AxisPlacement.Right:
362          min = ConvertFromDouble(visible.YMin);
363          max = ConvertFromDouble(visible.YMax);
364          break;
365        case AxisPlacement.Top:
366        case AxisPlacement.Bottom:
367          min = ConvertFromDouble(visible.XMin);
368          max = ConvertFromDouble(visible.XMax);
369          break;
370        default:
371          throw new NotSupportedException();
372      }
373
374      TrySort(ref min, ref max);
375      range = new Range<T>(min, max);
376      return range;
377    }
378
379    private static void TrySort<TS>(ref TS min, ref TS max)
380    {
381      if (min is IComparable)
382      {
383        IComparable c1 = (IComparable)min;
384        // if min > max
385        if (c1.CompareTo(max) > 0)
386        {
387          TS temp = min;
388          min = max;
389          max = temp;
390        }
391      }
392    }
393
394    protected override void OnPlacementChanged(AxisPlacement oldPlacement, AxisPlacement newPlacement)
395    {
396      axisControl.Placement = Placement;
397      if (ParentPlotter != null)
398      {
399        Panel panel = GetPanelByPlacement(oldPlacement);
400        panel.Children.Remove(this);
401
402        Panel newPanel = GetPanelByPlacement(newPlacement);
403        int index = GetInsertionIndexByPlacement(newPlacement, newPanel);
404        newPanel.Children.Insert(index, this);
405      }
406    }
407
408    protected override void OnPlotterDetaching(Plotter2D plotter)
409    {
410      if (plotter == null)
411        return;
412
413      Panel panel = GetPanelByPlacement(Placement);
414      if (panel != null)
415      {
416        panel.Children.Remove(this);
417      }
418
419      plotter.Viewport.PropertyChanged -= OnViewportPropertyChanged;
420      axisControl.Transform = null;
421    }
422  }
423}
Note: See TracBrowser for help on using the repository browser.