PageRenderTime 19ms CodeModel.GetById 1ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 1ms

/Main/src/DynamicDataDisplay/Charts/Axes/Numeric/NumericTicksProvider.cs

#
C# | 167 lines | 128 code | 26 blank | 13 comment | 19 complexity | 50b207a79bda5dacb64269c296978fc4 MD5 | raw file
  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}