/// <summary> /// Gets the cached track if available, or calculates from scratch if not available. /// </summary> /// <param name="activity">Activity to calculate</param> /// <param name="chartType">Which track to calculate</param> /// <param name="create">Cache the track if it doesn't exist. /// True will always return a track. /// False will return the cached track, or null if not already cached.</param> /// <returns>Cached track if available, or empty track if not found.</returns> private static INumericTimeDataSeries GetMeanMaxTrack(IActivity activity, Common.TrackType chartType, out INumericTimeDataSeries timeTrack, bool create) { if (activity == null) { timeTrack = new NumericTimeDataSeries(); return(new NumericTimeDataSeries()); } string id = activity.ReferenceId + chartType; if (tracks.ContainsKey(id)) { // Returned cached value from memory :) timeTrack = tracks[id + "T"]; return(tracks[id]); } else if (create) { // Not in cache, create a new mean-max track :( INumericTimeDataSeries track = new NumericTimeDataSeries(); timeTrack = null; switch (chartType) { case Common.TrackType.HR: { track = GetMeanMaxTrack(activity.HeartRatePerMinuteTrack, out timeTrack, activity.StartTime); break; } case Common.TrackType.Power: { track = GetMeanMaxTrack(activity.PowerWattsTrack, out timeTrack, activity.StartTime); break; } case Common.TrackType.Cadence: { track = GetMeanMaxTrack(activity.CadencePerMinuteTrack, out timeTrack, activity.StartTime); break; } } // Add data track and related 'T'ime track to cache for next time MeanMaxCache.AddTrack(track, id); MeanMaxCache.AddTrack(timeTrack, id + "T"); return(track); } else { // Not previously cached, AND requested not to create a new cached item. timeTrack = new NumericTimeDataSeries(); return(null); } }
/// <summary> /// Get critical value track. This is the full track of critical values for various activities over a date range until 'now'. /// /// </summary> /// <param name="activities">The list of activities to consider</param> /// <param name="trackType">Which data track to evaluate</param> /// <param name="seconds">The critical period, measured in seconds. Example, for 5 minute power this would be 300.</param> /// <returns>Returns a data track of values over a date range. 1 value per day.</returns> internal static INumericTimeDataSeries GetCriticalTrack(IEnumerable <IActivity> activities, Common.TrackType trackType, float seconds) { float criticalValue = 0; SortedList <DateTime, float> criticalData = new SortedList <DateTime, float>(); INumericTimeDataSeries criticalTrack = new NumericTimeDataSeries(); float i = 0, count = (activities as List <IActivity>).Count; // Populate activity data foreach (IActivity activity in activities) { Progress = (int)(i++ / count * 100f); Application.DoEvents(); // Filter bad data if (activity.StartTime.Year != 1) { criticalValue = MeanMaxCache.GetCriticalValue(activity, trackType, seconds); if (!float.IsNaN(criticalValue)) { DateTime activityDate = activity.StartTime.Add(activity.TimeZoneUtcOffset).Date; if (criticalData.ContainsKey(activityDate)) { // Handle days with multiple activities // Update with higher value criticalData[activityDate] = Math.Max(criticalValue, criticalData[activityDate]); } else if (criticalValue != 0) { // Add critical value to data set criticalData.Add(activityDate, criticalValue); } } } } // Construct critical data track DateTime firstDate; if (criticalData.Count > 0) { firstDate = criticalData.Keys[0]; criticalValue = criticalData[firstDate]; } else { firstDate = DateTime.Now; } float value; for (DateTime day = firstDate; day < DateTime.Now;) { // Decay the critical value first, value for 'today' //criticalValue = criticalValue - criticalValue / GlobalSettings.Instance.TCc; if (criticalData.TryGetValue(day.Date, out value)) { // TODO: Determine best way to incorporate decay values // Value recorded for today or previous (decayed) value //criticalValue = Math.Max(value, criticalValue); //criticalTrack.Add(day, criticalValue); criticalTrack.Add(day, value); } else { // Decayed value //criticalTrack.Add(day, criticalValue); } // Next day day = day.AddDays(1); } Progress = -1; return(criticalTrack); }