/Main/src/DynamicDataDisplay/Charts/Axes/Numeric/NumericTicksProvider.cs
C# | 167 lines | 128 code | 26 blank | 13 comment | 19 complexity | 50b207a79bda5dacb64269c296978fc4 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text; 5using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary; 6using System.Collections.ObjectModel; 7 8namespace Microsoft.Research.DynamicDataDisplay.Charts 9{ 10 /// <summary> 11 /// Represents a ticks provider for <see cref="System.Double"/> values. 12 /// </summary> 13 public sealed class NumericTicksProvider : ITicksProvider<double> 14 { 15 /// <summary> 16 /// Initializes a new instance of the <see cref="NumericTicksProvider"/> class. 17 /// </summary> 18 public NumericTicksProvider() 19 { 20 minorProvider = new MinorNumericTicksProvider(this); 21 minorProvider.Changed += minorProvider_Changed; 22 minorProvider.Coeffs = new double[] { 0.3, 0.3, 0.3, 0.3, 0.6, 0.3, 0.3, 0.3, 0.3 }; 23 } 24 25 private void minorProvider_Changed(object sender, EventArgs e) 26 { 27 Changed.Raise(this); 28 } 29 30 public event EventHandler Changed; 31 private void RaiseChangedEvent() 32 { 33 Changed.Raise(this); 34 } 35 36 private double minStep = 0.0; 37 /// <summary> 38 /// Gets or sets the minimal step between ticks. 39 /// </summary> 40 /// <value>The min step.</value> 41 public double MinStep 42 { 43 get { return minStep; } 44 set 45 { 46 Verify.IsTrue(value >= 0.0, "value"); 47 if (minStep != value) 48 { 49 minStep = value; 50 RaiseChangedEvent(); 51 } 52 } 53 } 54 55 private double[] ticks; 56 public ITicksInfo<double> GetTicks(Range<double> range, int ticksCount) 57 { 58 double start = range.Min; 59 double finish = range.Max; 60 61 double delta = finish - start; 62 63 int log = (int)Math.Round(Math.Log10(delta)); 64 65 double newStart = RoundingHelper.Round(start, log); 66 double newFinish = RoundingHelper.Round(finish, log); 67 if (newStart == newFinish) 68 { 69 log--; 70 newStart = RoundingHelper.Round(start, log); 71 newFinish = RoundingHelper.Round(finish, log); 72 } 73 74 // calculating step between ticks 75 double unroundedStep = (newFinish - newStart) / ticksCount; 76 int stepLog = log; 77 // trying to round step 78 double step = RoundingHelper.Round(unroundedStep, stepLog); 79 if (step == 0) 80 { 81 stepLog--; 82 step = RoundingHelper.Round(unroundedStep, stepLog); 83 if (step == 0) 84 { 85 // step will not be rounded if attempts to be rounded to zero. 86 step = unroundedStep; 87 } 88 } 89 90 if (step < minStep) 91 step = minStep; 92 93 if (step != 0.0) 94 { 95 ticks = CreateTicks(start, finish, step); 96 } 97 else 98 { 99 ticks = new double[] { }; 100 } 101 102 TicksInfo<double> res = new TicksInfo<double> { Info = log, Ticks = ticks }; 103 104 return res; 105 } 106 107 private static double[] CreateTicks(double start, double finish, double step) 108 { 109 DebugVerify.Is(step != 0.0); 110 111 double x = step * Math.Floor(start / step); 112 113 if (x == x + step) 114 { 115 return new double[0]; 116 } 117 118 List<double> res = new List<double>(); 119 120 double increasedFinish = finish + step * 1.05; 121 while (x <= increasedFinish) 122 { 123 res.Add(x); 124 DebugVerify.Is(res.Count < 2000); 125 x += step; 126 } 127 return res.ToArray(); 128 } 129 130 private static int[] tickCounts = new int[] { 20, 10, 5, 4, 2, 1 }; 131 132 public const int DefaultPreferredTicksCount = 10; 133 134 public int DecreaseTickCount(int ticksCount) 135 { 136 return tickCounts.FirstOrDefault(tick => tick < ticksCount); 137 } 138 139 public int IncreaseTickCount(int ticksCount) 140 { 141 int newTickCount = tickCounts.Reverse().FirstOrDefault(tick => tick > ticksCount); 142 if (newTickCount == 0) 143 newTickCount = tickCounts[0]; 144 145 return newTickCount; 146 } 147 148 private readonly MinorNumericTicksProvider minorProvider; 149 public ITicksProvider<double> MinorProvider 150 { 151 get 152 { 153 if (ticks != null) 154 { 155 minorProvider.SetRanges(ticks.GetPairs()); 156 } 157 158 return minorProvider; 159 } 160 } 161 162 public ITicksProvider<double> MajorProvider 163 { 164 get { return null; } 165 } 166 } 167}