using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary; namespace Microsoft.Research.DynamicDataDisplay.Charts.Axes { /// /// Represents a ticks provider for intefer values. /// public class IntegerTicksProvider : ITicksProvider { /// /// Initializes a new instance of the class. /// public IntegerTicksProvider() { } private int minStep = 0; /// /// Gets or sets the minimal step between ticks. /// /// The min step. public int MinStep { get { return minStep; } set { Verify.IsTrue(value >= 0, "value"); if (minStep != value) { minStep = value; RaiseChangedEvent(); } } } private int maxStep = Int32.MaxValue; /// /// Gets or sets the maximal step between ticks. /// /// The max step. public int MaxStep { get { return maxStep; } set { if (maxStep != value) { if (value < 0) throw new ArgumentOutOfRangeException("value", Strings.Exceptions.ParameterShouldBePositive); maxStep = value; RaiseChangedEvent(); } } } #region ITicksProvider Members /// /// Generates ticks for given range and preferred ticks count. /// /// The range. /// The ticks count. /// public ITicksInfo GetTicks(Range range, int ticksCount) { double start = range.Min; double finish = range.Max; double delta = finish - start; int log = (int)Math.Round(Math.Log10(delta)); double newStart = RoundingHelper.Round(start, log); double newFinish = RoundingHelper.Round(finish, log); if (newStart == newFinish) { log--; newStart = RoundingHelper.Round(start, log); newFinish = RoundingHelper.Round(finish, log); } // calculating step between ticks double unroundedStep = (newFinish - newStart) / ticksCount; int stepLog = log; // trying to round step int step = (int)RoundingHelper.Round(unroundedStep, stepLog); if (step == 0) { stepLog--; step = (int)RoundingHelper.Round(unroundedStep, stepLog); if (step == 0) { // step will not be rounded if attempts to be rounded to zero. step = (int)unroundedStep; } } if (step < minStep) step = minStep; if (step > maxStep) step = maxStep; if (step <= 0) step = 1; int[] ticks = CreateTicks(start, finish, step); TicksInfo res = new TicksInfo { Info = log, Ticks = ticks }; return res; } private static int[] CreateTicks(double start, double finish, int step) { DebugVerify.Is(step != 0); int x = (int)(step * Math.Floor(start / (double)step)); List res = new List(); checked { double increasedFinish = finish + step * 1.05; while (x <= increasedFinish) { res.Add(x); x += step; } } return res.ToArray(); } private static int[] tickCounts = new int[] { 20, 10, 5, 4, 2, 1 }; /// /// Decreases the tick count. /// Returned value should be later passed as ticksCount parameter to GetTicks method. /// /// The ticks count. /// Decreased ticks count. public int DecreaseTickCount(int ticksCount) { return tickCounts.FirstOrDefault(tick => tick < ticksCount); } /// /// Increases the tick count. /// Returned value should be later passed as ticksCount parameter to GetTicks method. /// /// The ticks count. /// Increased ticks count. public int IncreaseTickCount(int ticksCount) { int newTickCount = tickCounts.Reverse().FirstOrDefault(tick => tick > ticksCount); if (newTickCount == 0) newTickCount = tickCounts[0]; return newTickCount; } /// /// Gets the minor ticks provider, used to generate ticks between each two adjacent ticks. /// /// The minor provider. public ITicksProvider MinorProvider { get { return null; } } /// /// Gets the major provider, used to generate major ticks - for example, years for common ticks as months. /// /// The major provider. public ITicksProvider MajorProvider { get { return null; } } protected void RaiseChangedEvent() { Changed.Raise(this); } public event EventHandler Changed; #endregion } }