Initial Commit

This commit is contained in:
2024-02-23 00:46:06 -05:00
commit 2bbedc0178
470 changed files with 46035 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents a horizontal axis with values of <see cref="TimeSpan"/> type.
/// </summary>
public class HorizontalTimeSpanAxis : TimeSpanAxis
{
/// <summary>
/// Initializes a new instance of the <see cref="HorizontalTimeSpanAxis"/> class, placed on the bottom of <see cref="ChartPlotter"/>.
/// </summary>
public HorizontalTimeSpanAxis()
{
Placement = AxisPlacement.Bottom;
}
protected override void ValidatePlacement(AxisPlacement newPlacement)
{
if (newPlacement == AxisPlacement.Left || newPlacement == AxisPlacement.Right)
throw new ArgumentException(Strings.Exceptions.HorizontalAxisCannotBeVertical);
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal sealed class MinorTimeSpanTicksProvider : MinorTimeProviderBase<TimeSpan>
{
public MinorTimeSpanTicksProvider(ITicksProvider<TimeSpan> owner) : base(owner) { }
protected override bool IsInside(TimeSpan value, Range<TimeSpan> range)
{
return range.Min < value && value < range.Max;
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents axis with values of type TimeSpan.
/// </summary>
public class TimeSpanAxis : AxisBase<TimeSpan>
{
/// <summary>
/// Initializes a new instance of the <see cref="TimeSpanAxis"/> class with default values conversion.
/// </summary>
public TimeSpanAxis()
: base(new TimeSpanAxisControl(),
DoubleToTimeSpan, TimeSpanToDouble)
{ }
private static readonly long minTicks = TimeSpan.MinValue.Ticks;
private static readonly long maxTicks = TimeSpan.MaxValue.Ticks;
private static TimeSpan DoubleToTimeSpan(double value)
{
long ticks = (long)(value * 10000000000L);
// todo should we throw an exception if number of ticks is too big or small?
if (ticks < minTicks)
ticks = minTicks;
else if (ticks > maxTicks)
ticks = maxTicks;
return new TimeSpan(ticks);
}
private static double TimeSpanToDouble(TimeSpan time)
{
return time.Ticks / 10000000000.0;
}
/// <summary>
/// Sets conversions of axis - functions used to convert values of axis type to and from double values of viewport.
/// Sets both ConvertToDouble and ConvertFromDouble properties.
/// </summary>
/// <param name="min">The minimal viewport value.</param>
/// <param name="minValue">The value of axis type, corresponding to minimal viewport value.</param>
/// <param name="max">The maximal viewport value.</param>
/// <param name="maxValue">The value of axis type, corresponding to maximal viewport value.</param>
public override void SetConversion(double min, TimeSpan minValue, double max, TimeSpan maxValue)
{
var conversion = new TimeSpanToDoubleConversion(min, minValue, max, maxValue);
ConvertToDouble = conversion.ToDouble;
ConvertFromDouble = conversion.FromDouble;
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class TimeSpanAxisControl : AxisControl<TimeSpan>
{
public TimeSpanAxisControl()
{
LabelProvider = new TimeSpanLabelProvider();
TicksProvider = new TimeSpanTicksProvider();
ConvertToDouble = time => time.Ticks;
Range = new Range<TimeSpan>(new TimeSpan(), new TimeSpan(1, 0, 0));
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class TimeSpanLabelProvider : LabelProviderBase<TimeSpan>
{
public override UIElement[] CreateLabels(ITicksInfo<TimeSpan> ticksInfo)
{
object info = ticksInfo.Info;
var ticks = ticksInfo.Ticks;
LabelTickInfo<TimeSpan> tickInfo = new LabelTickInfo<TimeSpan>();
UIElement[] res = new UIElement[ticks.Length];
for (int i = 0; i < ticks.Length; i++)
{
tickInfo.Tick = ticks[i];
tickInfo.Info = info;
string tickText = GetString(tickInfo);
UIElement label = new TextBlock { Text = tickText, ToolTip = ticks[i] };
res[i] = label;
}
return res;
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class TimeSpanTicksProvider : TimeTicksProviderBase<TimeSpan>
{
static TimeSpanTicksProvider()
{
Providers.Add(DifferenceIn.Year, new DayTimeSpanProvider());
Providers.Add(DifferenceIn.Month, new DayTimeSpanProvider());
Providers.Add(DifferenceIn.Day, new DayTimeSpanProvider());
Providers.Add(DifferenceIn.Hour, new HourTimeSpanProvider());
Providers.Add(DifferenceIn.Minute, new MinuteTimeSpanProvider());
Providers.Add(DifferenceIn.Second, new SecondTimeSpanProvider());
Providers.Add(DifferenceIn.Millisecond, new MillisecondTimeSpanProvider());
MinorProviders.Add(DifferenceIn.Year, new MinorTimeSpanTicksProvider(new DayTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Month, new MinorTimeSpanTicksProvider(new DayTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Day, new MinorTimeSpanTicksProvider(new DayTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Hour, new MinorTimeSpanTicksProvider(new HourTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Minute, new MinorTimeSpanTicksProvider(new MinuteTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Second, new MinorTimeSpanTicksProvider(new SecondTimeSpanProvider()));
MinorProviders.Add(DifferenceIn.Millisecond, new MinorTimeSpanTicksProvider(new MillisecondTimeSpanProvider()));
}
protected override TimeSpan GetDifference(TimeSpan start, TimeSpan end)
{
return end - start;
}
}
}

View File

@@ -0,0 +1,319 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal abstract class TimeSpanTicksProviderBase : TimePeriodTicksProvider<TimeSpan>
{
protected sealed override bool Continue(TimeSpan current, TimeSpan end)
{
return current < end;
}
protected sealed override TimeSpan RoundDown(TimeSpan start, TimeSpan end)
{
return RoundDown(start, Difference);
}
protected sealed override TimeSpan RoundUp(TimeSpan start, TimeSpan end)
{
return RoundUp(end, Difference);
}
protected static TimeSpan Shift(TimeSpan span, DifferenceIn diff)
{
TimeSpan res = span;
TimeSpan shift = new TimeSpan();
switch (diff)
{
case DifferenceIn.Year:
case DifferenceIn.Month:
case DifferenceIn.Day:
shift = TimeSpan.FromDays(1);
break;
case DifferenceIn.Hour:
shift = TimeSpan.FromHours(1);
break;
case DifferenceIn.Minute:
shift = TimeSpan.FromMinutes(1);
break;
case DifferenceIn.Second:
shift = TimeSpan.FromSeconds(1);
break;
case DifferenceIn.Millisecond:
shift = TimeSpan.FromMilliseconds(1);
break;
default:
break;
}
res = res.Add(shift);
return res;
}
protected sealed override TimeSpan RoundDown(TimeSpan timeSpan, DifferenceIn diff)
{
TimeSpan res = timeSpan;
if (timeSpan.Ticks < 0)
{
res = RoundUp(timeSpan.Duration(), diff).Negate();
}
else
{
switch (diff)
{
case DifferenceIn.Year:
case DifferenceIn.Month:
case DifferenceIn.Day:
res = TimeSpan.FromDays(timeSpan.Days);
break;
case DifferenceIn.Hour:
res = TimeSpan.FromDays(timeSpan.Days).
Add(TimeSpan.FromHours(timeSpan.Hours));
break;
case DifferenceIn.Minute:
res = TimeSpan.FromDays(timeSpan.Days).
Add(TimeSpan.FromHours(timeSpan.Hours)).
Add(TimeSpan.FromMinutes(timeSpan.Minutes));
break;
case DifferenceIn.Second:
res = TimeSpan.FromDays(timeSpan.Days).
Add(TimeSpan.FromHours(timeSpan.Hours)).
Add(TimeSpan.FromMinutes(timeSpan.Minutes)).
Add(TimeSpan.FromSeconds(timeSpan.Seconds));
break;
case DifferenceIn.Millisecond:
res = timeSpan;
break;
default:
break;
}
}
return res;
}
protected sealed override TimeSpan RoundUp(TimeSpan dateTime, DifferenceIn diff)
{
TimeSpan res = RoundDown(dateTime, diff);
res = Shift(res, diff);
return res;
}
protected override List<TimeSpan> Trim(List<TimeSpan> ticks, Range<TimeSpan> range)
{
int startIndex = 0;
for (int i = 0; i < ticks.Count - 1; i++)
{
if (ticks[i] <= range.Min && range.Min <= ticks[i + 1])
{
startIndex = i;
break;
}
}
int endIndex = ticks.Count - 1;
for (int i = ticks.Count - 1; i >= 1; i--)
{
if (ticks[i] >= range.Max && range.Max > ticks[i - 1])
{
endIndex = i;
break;
}
}
List<TimeSpan> res = new List<TimeSpan>(endIndex - startIndex + 1);
for (int i = startIndex; i <= endIndex; i++)
{
res.Add(ticks[i]);
}
return res;
}
protected sealed override bool IsMinDate(TimeSpan dt)
{
return false;
}
}
internal sealed class DayTimeSpanProvider : TimeSpanTicksProviderBase
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Day;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 20, 10, 5, 2, 1 };
}
protected override int GetSpecificValue(TimeSpan start, TimeSpan dt)
{
return (dt - start).Days;
}
protected override TimeSpan GetStart(TimeSpan start, int value, int step)
{
double days = start.TotalDays;
double newDays = ((int)(days / step)) * step;
if (newDays > days) {
newDays -= step;
}
return TimeSpan.FromDays(newDays);
//return TimeSpan.FromDays(start.Days);
}
protected override TimeSpan AddStep(TimeSpan dt, int step)
{
return dt.Add(TimeSpan.FromDays(step));
}
}
internal sealed class HourTimeSpanProvider : TimeSpanTicksProviderBase
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Hour;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 24, 12, 6, 4, 3, 2, 1 };
}
protected override int GetSpecificValue(TimeSpan start, TimeSpan dt)
{
return (int)(dt - start).TotalHours;
}
protected override TimeSpan GetStart(TimeSpan start, int value, int step)
{
double hours = start.TotalHours;
double newHours = ((int)(hours / step)) * step;
if (newHours > hours)
{
newHours -= step;
}
return TimeSpan.FromHours(newHours);
//return TimeSpan.FromDays(start.Days);
}
protected override TimeSpan AddStep(TimeSpan dt, int step)
{
return dt.Add(TimeSpan.FromHours(step));
}
}
internal sealed class MinuteTimeSpanProvider : TimeSpanTicksProviderBase
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Minute;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 60, 30, 20, 15, 10, 5, 4, 3, 2 };
}
protected override int GetSpecificValue(TimeSpan start, TimeSpan dt)
{
return (int)(dt - start).TotalMinutes;
}
protected override TimeSpan GetStart(TimeSpan start, int value, int step)
{
double minutes = start.TotalMinutes;
double newMinutes = ((int)(minutes / step)) * step;
if (newMinutes > minutes)
{
newMinutes -= step;
}
return TimeSpan.FromMinutes(newMinutes);
}
protected override TimeSpan AddStep(TimeSpan dt, int step)
{
return dt.Add(TimeSpan.FromMinutes(step));
}
}
internal sealed class SecondTimeSpanProvider : TimeSpanTicksProviderBase
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Second;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 60, 30, 20, 15, 10, 5, 4, 3, 2 };
}
protected override int GetSpecificValue(TimeSpan start, TimeSpan dt)
{
return (int)(dt - start).TotalSeconds;
}
protected override TimeSpan GetStart(TimeSpan start, int value, int step)
{
double seconds = start.TotalSeconds;
double newSeconds = ((int)(seconds / step)) * step;
if (newSeconds > seconds) {
newSeconds -= step;
}
return TimeSpan.FromSeconds(newSeconds);
//return new TimeSpan(start.Days, start.Hours, start.Minutes, 0);
}
protected override TimeSpan AddStep(TimeSpan dt, int step)
{
return dt.Add(TimeSpan.FromSeconds(step));
}
}
internal sealed class MillisecondTimeSpanProvider : TimeSpanTicksProviderBase
{
protected override DifferenceIn GetDifferenceCore()
{
return DifferenceIn.Millisecond;
}
protected override int[] GetTickCountsCore()
{
return new int[] { 100, 50, 40, 25, 20, 10, 5, 4, 2 };
}
protected override int GetSpecificValue(TimeSpan start, TimeSpan dt)
{
return (int)(dt - start).TotalMilliseconds;
}
protected override TimeSpan GetStart(TimeSpan start, int value, int step)
{
double millis = start.TotalMilliseconds;
double newMillis = ((int)(millis / step)) * step;
if (newMillis > millis) {
newMillis -= step;
}
return TimeSpan.FromMilliseconds(newMillis);
//return start;
}
protected override TimeSpan AddStep(TimeSpan dt, int step)
{
return dt.Add(TimeSpan.FromMilliseconds(step));
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
internal sealed class TimeSpanToDoubleConversion
{
public TimeSpanToDoubleConversion(TimeSpan minSpan, TimeSpan maxSpan)
: this(0, minSpan, 1, maxSpan)
{ }
public TimeSpanToDoubleConversion(double min, TimeSpan minSpan, double max, TimeSpan maxSpan)
{
this.min = min;
this.length = max - min;
this.ticksMin = minSpan.Ticks;
this.ticksLength = maxSpan.Ticks - ticksMin;
}
private double min;
private double length;
private long ticksMin;
private long ticksLength;
internal TimeSpan FromDouble(double d)
{
double ratio = (d - min) / length;
long ticks = (long)(ticksMin + ticksLength * ratio);
ticks = MathHelper.Clamp(ticks, TimeSpan.MinValue.Ticks, TimeSpan.MaxValue.Ticks);
return new TimeSpan(ticks);
}
internal double ToDouble(TimeSpan span)
{
double ratio = (span.Ticks - ticksMin) / (double)ticksLength;
return min + ratio * length;
}
}
}

View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public abstract class TimeTicksProviderBase<T> : ITicksProvider<T>
{
public event EventHandler Changed;
protected void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
private static readonly Dictionary<DifferenceIn, ITicksProvider<T>> providers =
new Dictionary<DifferenceIn, ITicksProvider<T>>();
protected static Dictionary<DifferenceIn, ITicksProvider<T>> Providers
{
get { return TimeTicksProviderBase<T>.providers; }
}
private static readonly Dictionary<DifferenceIn, ITicksProvider<T>> minorProviders =
new Dictionary<DifferenceIn, ITicksProvider<T>>();
protected static Dictionary<DifferenceIn, ITicksProvider<T>> MinorProviders
{
get { return TimeTicksProviderBase<T>.minorProviders; }
}
protected abstract TimeSpan GetDifference(T start, T end);
#region ITicksProvider<T> Members
private IDateTimeTicksStrategy strategy = new DefaultDateTimeTicksStrategy();
public IDateTimeTicksStrategy Strategy
{
get { return strategy; }
set
{
if (strategy != value)
{
strategy = value;
RaiseChanged();
}
}
}
private ITicksInfo<T> result;
private DifferenceIn diff;
public ITicksInfo<T> GetTicks(Range<T> range, int ticksCount)
{
Verify.IsTrue(ticksCount > 0);
T start = range.Min;
T end = range.Max;
TimeSpan length = GetDifference(start, end);
diff = strategy.GetDifference(length);
TicksInfo<T> result = new TicksInfo<T> { Info = diff };
if (providers.ContainsKey(diff))
{
ITicksInfo<T> innerResult = providers[diff].GetTicks(range, ticksCount);
T[] ticks = ModifyTicksGuard(innerResult.Ticks, diff);
result.Ticks = ticks;
this.result = result;
return result;
}
throw new InvalidOperationException(Strings.Exceptions.UnsupportedRangeInAxis);
}
private T[] ModifyTicksGuard(T[] ticks, object info)
{
var result = ModifyTicks(ticks, info);
if (result == null)
throw new ArgumentNullException("ticks");
return result;
}
protected virtual T[] ModifyTicks(T[] ticks, object info)
{
return ticks;
}
/// <summary>
/// Decreases the tick count.
/// </summary>
/// <param name="tickCount">The tick count.</param>
/// <returns></returns>
public int DecreaseTickCount(int ticksCount)
{
if (providers.ContainsKey(diff))
return providers[diff].DecreaseTickCount(ticksCount);
int res = ticksCount / 2;
if (res < 2) res = 2;
return res;
}
/// <summary>
/// Increases the tick count.
/// </summary>
/// <param name="ticksCount">The tick count.</param>
/// <returns></returns>
public int IncreaseTickCount(int ticksCount)
{
DebugVerify.Is(ticksCount < 2000);
if (providers.ContainsKey(diff))
return providers[diff].IncreaseTickCount(ticksCount);
return ticksCount * 2;
}
public ITicksProvider<T> MinorProvider
{
get
{
DifferenceIn smallerDiff = DifferenceIn.Smallest;
if (strategy.TryGetLowerDiff(diff, out smallerDiff) && minorProviders.ContainsKey(smallerDiff))
{
var minorProvider = (MinorTimeProviderBase<T>)minorProviders[smallerDiff];
minorProvider.SetTicks(result.Ticks);
return minorProvider;
}
return null;
// todo What to do if this already is the smallest provider?
}
}
public ITicksProvider<T> MajorProvider
{
get
{
DifferenceIn biggerDiff = DifferenceIn.Smallest;
if (strategy.TryGetBiggerDiff(diff, out biggerDiff))
{
return providers[biggerDiff];
}
return null;
// todo What to do if this already is the biggest provider?
}
}
#endregion
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
/// <summary>
/// Represents a vertical axis with values of <see cref="TimeSpan"/> type.
/// </summary>
public class VerticalTimeSpanAxis : TimeSpanAxis
{
/// <summary>
/// Initializes a new instance of the <see cref="VerticalTimeSpanAxis"/> class, placed (by default) on the left side of <see cref="ChartPlotter"/>.
/// </summary>
public VerticalTimeSpanAxis()
{
Placement = AxisPlacement.Left;
}
/// <summary>
/// Validates the placement - e.g., vertical axis should not be placed from top or bottom, etc.
/// If proposed placement is wrong, throws an ArgumentException.
/// </summary>
/// <param name="newPlacement">The new placement.</param>
protected override void ValidatePlacement(AxisPlacement newPlacement)
{
if (newPlacement == AxisPlacement.Bottom || newPlacement == AxisPlacement.Top)
throw new ArgumentException(Strings.Exceptions.VerticalAxisCannotBeHorizontal);
}
}
}