/Main/src/DynamicDataDisplay/Charts/Axes/DateTime/TimePeriodTicksProvider.cs
C# | 269 lines | 227 code | 42 blank | 0 comment | 31 complexity | 054b8516de9405c9f146f9c0d261b0ff 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; 6 7namespace Microsoft.Research.DynamicDataDisplay.Charts 8{ 9 internal abstract class TimePeriodTicksProvider<T> : ITicksProvider<T> 10 { 11 public event EventHandler Changed; 12 protected void RaiseChanged() 13 { 14 if (Changed != null) 15 { 16 Changed(this, EventArgs.Empty); 17 } 18 } 19 20 protected abstract T RoundUp(T time, DifferenceIn diff); 21 protected abstract T RoundDown(T time, DifferenceIn diff); 22 23 private bool differenceInited = false; 24 private DifferenceIn difference; 25 protected DifferenceIn Difference 26 { 27 get 28 { 29 if (!differenceInited) 30 { 31 difference = GetDifferenceCore(); 32 differenceInited = true; 33 } 34 return difference; 35 } 36 } 37 protected abstract DifferenceIn GetDifferenceCore(); 38 39 private int[] tickCounts = null; 40 protected int[] TickCounts 41 { 42 get 43 { 44 if (tickCounts == null) 45 tickCounts = GetTickCountsCore(); 46 return tickCounts; 47 } 48 } 49 protected abstract int[] GetTickCountsCore(); 50 51 public int DecreaseTickCount(int ticksCount) 52 { 53 if (ticksCount > TickCounts[0]) return TickCounts[0]; 54 55 for (int i = 0; i < TickCounts.Length; i++) 56 if (ticksCount > TickCounts[i]) 57 return TickCounts[i]; 58 59 return TickCounts.Last(); 60 } 61 62 public int IncreaseTickCount(int ticksCount) 63 { 64 if (ticksCount >= TickCounts[0]) return TickCounts[0]; 65 66 for (int i = TickCounts.Length - 1; i >= 0; i--) 67 if (ticksCount < TickCounts[i]) 68 return TickCounts[i]; 69 70 return TickCounts.Last(); 71 } 72 73 protected abstract int GetSpecificValue(T start, T dt); 74 protected abstract T GetStart(T start, int value, int step); 75 protected abstract bool IsMinDate(T dt); 76 protected abstract T AddStep(T dt, int step); 77 78 public ITicksInfo<T> GetTicks(Range<T> range, int ticksCount) 79 { 80 T start = range.Min; 81 T end = range.Max; 82 DifferenceIn diff = Difference; 83 start = RoundDown(start, end); 84 end = RoundUp(start, end); 85 86 RoundingInfo bounds = RoundingHelper.CreateRoundedRange( 87 GetSpecificValue(start, start), 88 GetSpecificValue(start, end)); 89 90 int delta = (int)(bounds.Max - bounds.Min); 91 if (delta == 0) 92 return new TicksInfo<T> { Ticks = new T[] { start } }; 93 94 int step = delta / ticksCount; 95 96 if (step == 0) step = 1; 97 98 T tick = GetStart(start, (int)bounds.Min, step); 99 bool isMinDateTime = IsMinDate(tick) && step != 1; 100 if (isMinDateTime) 101 step--; 102 103 List<T> ticks = new List<T>(); 104 T finishTick = AddStep(range.Max, step); 105 while (Continue(tick, finishTick)) 106 { 107 ticks.Add(tick); 108 tick = AddStep(tick, step); 109 if (isMinDateTime) 110 { 111 isMinDateTime = false; 112 step++; 113 } 114 } 115 116 ticks = Trim(ticks, range); 117 118 TicksInfo<T> res = new TicksInfo<T> { Ticks = ticks.ToArray(), Info = diff }; 119 return res; 120 } 121 122 protected abstract bool Continue(T current, T end); 123 124 protected abstract T RoundUp(T start, T end); 125 126 protected abstract T RoundDown(T start, T end); 127 128 protected abstract List<T> Trim(List<T> ticks, Range<T> range); 129 130 public ITicksProvider<T> MinorProvider 131 { 132 get { throw new NotSupportedException(); } 133 } 134 135 public ITicksProvider<T> MajorProvider 136 { 137 get { throw new NotSupportedException(); } 138 } 139 } 140 141 internal abstract class DatePeriodTicksProvider : TimePeriodTicksProvider<DateTime> 142 { 143 protected sealed override bool Continue(DateTime current, DateTime end) 144 { 145 return current < end; 146 } 147 148 protected sealed override List<DateTime> Trim(List<DateTime> ticks, Range<DateTime> range) 149 { 150 int startIndex = 0; 151 for (int i = 0; i < ticks.Count - 1; i++) 152 { 153 if (ticks[i] <= range.Min && range.Min <= ticks[i + 1]) 154 { 155 startIndex = i; 156 break; 157 } 158 } 159 160 int endIndex = ticks.Count - 1; 161 for (int i = ticks.Count - 1; i >= 1; i--) 162 { 163 if (ticks[i] >= range.Max && range.Max > ticks[i - 1]) 164 { 165 endIndex = i; 166 break; 167 } 168 } 169 170 List<DateTime> res = new List<DateTime>(endIndex - startIndex + 1); 171 for (int i = startIndex; i <= endIndex; i++) 172 { 173 res.Add(ticks[i]); 174 } 175 176 return res; 177 } 178 179 protected sealed override DateTime RoundUp(DateTime start, DateTime end) 180 { 181 bool isPositive = (end - start).Ticks > 0; 182 return isPositive ? SafelyRoundUp(end) : RoundDown(end, Difference); 183 } 184 185 private DateTime SafelyRoundUp(DateTime dt) 186 { 187 if (AddStep(dt, 1) == DateTime.MaxValue) 188 return DateTime.MaxValue; 189 190 return RoundUp(dt, Difference); 191 } 192 193 protected sealed override DateTime RoundDown(DateTime start, DateTime end) 194 { 195 bool isPositive = (end - start).Ticks > 0; 196 return isPositive ? RoundDown(start, Difference) : SafelyRoundUp(start); 197 } 198 199 protected sealed override DateTime RoundDown(DateTime time, DifferenceIn diff) 200 { 201 DateTime res = time; 202 203 switch (diff) 204 { 205 case DifferenceIn.Year: 206 res = new DateTime(time.Year, 1, 1); 207 break; 208 case DifferenceIn.Month: 209 res = new DateTime(time.Year, time.Month, 1); 210 break; 211 case DifferenceIn.Day: 212 res = time.Date; 213 break; 214 case DifferenceIn.Hour: 215 res = time.Date.AddHours(time.Hour); 216 break; 217 case DifferenceIn.Minute: 218 res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute); 219 break; 220 case DifferenceIn.Second: 221 res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second); 222 break; 223 case DifferenceIn.Millisecond: 224 res = time.Date.AddHours(time.Hour).AddMinutes(time.Minute).AddSeconds(time.Second).AddMilliseconds(time.Millisecond); 225 break; 226 default: 227 break; 228 } 229 230 DebugVerify.Is(res <= time); 231 232 return res; 233 } 234 235 protected override DateTime RoundUp(DateTime dateTime, DifferenceIn diff) 236 { 237 DateTime res = RoundDown(dateTime, diff); 238 239 switch (diff) 240 { 241 case DifferenceIn.Year: 242 res = res.AddYears(1); 243 break; 244 case DifferenceIn.Month: 245 res = res.AddMonths(1); 246 break; 247 case DifferenceIn.Day: 248 res = res.AddDays(1); 249 break; 250 case DifferenceIn.Hour: 251 res = res.AddHours(1); 252 break; 253 case DifferenceIn.Minute: 254 res = res.AddMinutes(1); 255 break; 256 case DifferenceIn.Second: 257 res = res.AddSeconds(1); 258 break; 259 case DifferenceIn.Millisecond: 260 res = res.AddMilliseconds(1); 261 break; 262 default: 263 break; 264 } 265 266 return res; 267 } 268 } 269}