using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using System.Collections.ObjectModel;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
///
/// Represents a ticks provider for values.
///
public sealed class NumericTicksProvider : ITicksProvider
{
///
/// Initializes a new instance of the class.
///
public NumericTicksProvider()
{
minorProvider = new MinorNumericTicksProvider(this);
minorProvider.Changed += minorProvider_Changed;
minorProvider.Coeffs = new double[] { 0.3, 0.3, 0.3, 0.3, 0.6, 0.3, 0.3, 0.3, 0.3 };
}
private void minorProvider_Changed(object sender, EventArgs e)
{
Changed.Raise(this);
}
public event EventHandler Changed;
private void RaiseChangedEvent()
{
Changed.Raise(this);
}
private double minStep = 0.0;
///
/// Gets or sets the minimal step between ticks.
///
/// The min step.
public double MinStep
{
get { return minStep; }
set
{
Verify.IsTrue(value >= 0.0, "value");
if (minStep != value)
{
minStep = value;
RaiseChangedEvent();
}
}
}
private double[] ticks;
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
double step = RoundingHelper.Round(unroundedStep, stepLog);
if (step == 0)
{
stepLog--;
step = RoundingHelper.Round(unroundedStep, stepLog);
if (step == 0)
{
// step will not be rounded if attempts to be rounded to zero.
step = unroundedStep;
}
}
if (step < minStep)
step = minStep;
if (step != 0.0)
{
ticks = CreateTicks(start, finish, step);
}
else
{
ticks = new double[] { };
}
TicksInfo res = new TicksInfo { Info = log, Ticks = ticks };
return res;
}
private static double[] CreateTicks(double start, double finish, double step)
{
DebugVerify.Is(step != 0.0);
double x = step * Math.Floor(start / step);
if (x == x + step)
{
return new double[0];
}
List res = new List();
double increasedFinish = finish + step * 1.05;
while (x <= increasedFinish)
{
res.Add(x);
DebugVerify.Is(res.Count < 2000);
x += step;
}
return res.ToArray();
}
private static int[] tickCounts = new int[] { 20, 10, 5, 4, 2, 1 };
public const int DefaultPreferredTicksCount = 10;
public int DecreaseTickCount(int ticksCount)
{
return tickCounts.FirstOrDefault(tick => tick < ticksCount);
}
public int IncreaseTickCount(int ticksCount)
{
int newTickCount = tickCounts.Reverse().FirstOrDefault(tick => tick > ticksCount);
if (newTickCount == 0)
newTickCount = tickCounts[0];
return newTickCount;
}
private readonly MinorNumericTicksProvider minorProvider;
public ITicksProvider MinorProvider
{
get
{
if (ticks != null)
{
minorProvider.SetRanges(ticks.GetPairs());
}
return minorProvider;
}
}
public ITicksProvider MajorProvider
{
get { return null; }
}
}
}