private ComboUsageInfo GetMostUsedGearValue(RangeInfoCacheWrapper range) { if (range.ActivityPauselessCadenceTrack.Count > 0) { ITimeDataSeries <SprocketCombo> rangeSprockets = GetRangeSprocketsTrack(range); IList <SprocketComboInfo> sprocketInfo = GetSprocketComboInfo(range, rangeSprockets); SprocketCombo mostUsedCombo = null; TimeSpan mostUsedDuration = new TimeSpan(0); foreach (SprocketComboInfo comboInfo in sprocketInfo) { TimeSpan currentComboDuration = new TimeSpan(0); foreach (IValueRange <DateTime> times in comboInfo.Times) { currentComboDuration += (times.Upper - times.Lower); } if (mostUsedCombo == null || mostUsedDuration < currentComboDuration) { mostUsedCombo = comboInfo.SprocketCombo; mostUsedDuration = currentComboDuration; } } return(new ComboUsageInfo(mostUsedCombo, mostUsedDuration)); } return(null); }
public IList <SprocketComboInfo> CalculateSprocketComboInfo(IActivity activity) { if (activity != null) { bool retrieveInfo = true; SprocketComboInfoCacheItem cachedItem = null; if (m_InfoCache.ContainsKey(activity) && !m_InfoCache[activity].m_Dirty) { retrieveInfo = false; } if (retrieveInfo) { ITimeDataSeries <SprocketCombo> sprocketTrack = ActivityGearTrackCache.Instance.CalculateSprocketTrack(activity); IList <SprocketComboInfo> sprocketInfo = Common.Data.Calculate(activity, sprocketTrack); UpdateCachedInfo(activity, sprocketInfo); } cachedItem = m_InfoCache[activity]; return(cachedItem.m_ComboInfo); } return(null); }
public ITimeDataSeries <SprocketCombo> CalculateSprocketTrack(IActivity activity) { if (activity != null) { bool retrieveInfo = true; ActivityGearTrackCacheItem cachedItem = null; if (m_InfoCache.ContainsKey(activity) && m_InfoCache[activity].m_SprocketTrack != null) { retrieveInfo = false; } if (retrieveInfo) { ITimeDataSeries <SprocketCombo> sprocketTrack = Common.Data.GetSprocketTrack(activity); UpdateCachedSprocketTrack(activity, sprocketTrack); } cachedItem = m_InfoCache[activity]; return(cachedItem.m_SprocketTrack); } return(null); }
private void InsertValue(DateTime atime, ITimeDataSeries <T> track, ITimeDataSeries <T> source) { if (atime >= this.startTime && atime <= this.endTime && !ZoneFiveSoftware.Common.Data.Algorithm.DateTimeRangeSeries.IsPaused(atime, this.pauses)) { TrackUtil.InsertValue <T>(atime, track, source); } }
//ST interpolate is not handling subseconds, interpolate better if possible internal static T getValFromDateTimeIndex <T>(ITimeDataSeries <T> track, DateTime time, int i) { T dist; if (i < 0 || i >= track.Count || track.Count <= 1) { //index out of bound //Note that the distance track may not start at result StartTime, then this will report result at 0 sec Debug.Assert(true, "index out of bounds"); i = Math.Max(i, 0); i = Math.Min(i, track.Count - 1); dist = track[i].Value; } else if (time == track.EntryDateTime(track[i])) { //Exact time, no interpolation dist = track[i].Value; } else { if (i == 0) { i = 1; } float elapsed = (float)((time - track.StartTime).TotalSeconds); float f = (elapsed - track[i - 1].ElapsedSeconds) / (float)(track[i].ElapsedSeconds - track[i - 1].ElapsedSeconds); dist = track[i - 1].Value; //assignment for compiler if (dist is float) { float v0 = (float)(object)(track[i - 1].Value); float v1 = (float)(object)(track[i].Value); dist = (T)(object)(v0 + (v1 - v0) * f); } else if (dist is IGPSPoint) { IGPSPoint v0 = (IGPSPoint)(object)(track[i - 1].Value); IGPSPoint v1 = (IGPSPoint)(object)(track[i].Value); float lat = (v0.LatitudeDegrees + (v1.LatitudeDegrees - v0.LatitudeDegrees) * f); float lon = (v0.LongitudeDegrees + (v1.LongitudeDegrees - v0.LongitudeDegrees) * f); float ele = (v0.ElevationMeters + (v1.ElevationMeters - v0.ElevationMeters) * f); dist = (T)(object)(new GPSPoint(lat, lon, ele)); } else { //Added to satisfy compiler - not possible to configure Debug.Assert(true, "Unexpected ITimeDataSeries"); dist = default(T); } } return(dist); }
/// <summary> /// Caculate basic stats for each sprocket. This mostly allows to know the times during which we used a given gear /// </summary> /// <param name="activity"></param> /// <param name="sprocketTrack"></param> /// <returns>Returns an IList<SprocketComboInfo> of the sprocket combo info</returns> public static IList <SprocketComboInfo> Calculate(IActivity activity, ITimeDataSeries <SprocketCombo> sprocketTrack) { List <SprocketCombo> sprockets = GetSprocketCombos(activity); List <SprocketComboInfo> result = new List <SprocketComboInfo>(sprockets.Count + 1); SprocketCombo lastItemSprocket = null; DateTime sectionStartTime = sprocketTrack.StartTime; // Create the results for each zone foreach (SprocketCombo combo in sprockets) { result.Add(new SprocketComboInfo(combo)); } // Go through and find the corresponding sprocket combo for each point foreach (ITimeValueEntry <SprocketCombo> item in sprocketTrack) { // We found a change in gear, add section to times if (lastItemSprocket != item.Value) { DateTime currentItemTime = sprocketTrack.EntryDateTime(item); // First item, ignore it if (lastItemSprocket != null) { int index = sprockets.IndexOf(lastItemSprocket); result[index].Times.Add(new ValueRange <DateTime>(sectionStartTime, currentItemTime)); } sectionStartTime = currentItemTime; lastItemSprocket = item.Value; } } // Add last section if (lastItemSprocket != null && sprocketTrack.Count > 0) { int index = sprockets.IndexOf(lastItemSprocket); DateTime endTime = sprocketTrack.EntryDateTime(sprocketTrack[sprocketTrack.Count - 1]); result[index].Times.Add(new ValueRange <DateTime>(sectionStartTime, endTime)); // There is also a "totals" when Calculate is used in ST, add it although it's a bit useless for now SprocketComboInfo totals = new SprocketComboInfo(null); totals.Times.Add(new ValueRange <DateTime>(sprocketTrack.StartTime, endTime)); result.Add(totals); } return(result); }
private void UpdateCachedSprocketTrack(IActivity activity, ITimeDataSeries <SprocketCombo> sprocketTrack) { ActivityGearTrackCacheItem newCacheItem = new ActivityGearTrackCacheItem(activity); if (!m_InfoCache.ContainsKey(activity)) { m_InfoCache.Add(activity, null); activity.PropertyChanged += new PropertyChangedEventHandler(OnActivityDataChanged); } m_InfoCache[activity] = newCacheItem; m_InfoCache[activity].m_SprocketTrack = sprocketTrack; }
private ComboUsageInfo GetMostUsedGearValue(List <RangeInfoCacheWrapper> allRanges) { if (allRanges.Count > 0 && allRanges[0].ActivityPauselessCadenceTrack.Count > 0) { List <ComboUsageInfo> allRangesUsageInfo = new List <ComboUsageInfo>(); foreach (RangeInfoCacheWrapper range in allRanges) { ITimeDataSeries <SprocketCombo> rangeSprockets = GetRangeSprocketsTrack(range); IList <SprocketComboInfo> sprocketInfo = GetSprocketComboInfo(range, rangeSprockets); for (int i = 0; i < sprocketInfo.Count; ++i) { TimeSpan currentComboDuration = new TimeSpan(0); foreach (IValueRange <DateTime> times in sprocketInfo[i].Times) { currentComboDuration += (times.Upper - times.Lower); } if (allRangesUsageInfo.Count <= i) { allRangesUsageInfo.Add(new ComboUsageInfo(sprocketInfo[i].SprocketCombo, currentComboDuration)); } else { allRangesUsageInfo[i].m_UsageDuration += currentComboDuration; } } } SprocketCombo mostUsedCombo = null; TimeSpan mostUsedDuration = new TimeSpan(0); foreach (ComboUsageInfo comboInfo in allRangesUsageInfo) { if (mostUsedCombo == null || mostUsedDuration < comboInfo.m_UsageDuration) { mostUsedCombo = comboInfo.m_Combo; mostUsedDuration = comboInfo.m_UsageDuration; } } return(new ComboUsageInfo(mostUsedCombo, mostUsedDuration)); } return(null); }
public static void InsertValue <T>(DateTime atime, ITimeDataSeries <T> track, ITimeDataSeries <T> source) { //Interpolation is down to seconds //TBD: Inefficient, source.IndexOf often fails #if ST_3_1_5314_BUG //http://www.zonefivesoftware.com/sporttracks/forums/viewtopic.php?p=84638#p84638 //System.Exception: FindPosOnOrBefore: Didn't find element properly. try { #endif ITimeValueEntry <T> interpolatedP = source.GetInterpolatedValue(atime); if (interpolatedP != null) { int index = source.IndexOf(interpolatedP); T val = interpolatedP.Value; if (index >= 0) { val = TrackUtil.getValFromDateTimeIndex(source, atime, index); } else { } try { #if !NO_ST_INSERT_START_TIME //ST bug: not inserted in order if ms differs for start if (Math.Abs((atime - track.StartTime).TotalSeconds) < 1) { track.RemoveAt(0); } #endif track.Add(atime, val); //T val2 = track.GetInterpolatedValue(atime).Value; } catch { } } #if ST_3_1_5314_BUG } catch (Exception e) { } #endif }
/// <summary> /// Create gear guess selection chart based on gear ratios /// </summary> /// <param name="input">Pre-calculated raw data to estimate from. This should already be smoothed or filtered if desired.</param> /// <returns>Gear guess NumericTimeDataSeries</returns> public static NumericTimeDataSeries GuessGears(INumericTimeDataSeries input, List <SprocketCombo> sprockets) { ITimeDataSeries <SprocketCombo> guessSprockets = GuessSprockets(input, sprockets); NumericTimeDataSeries guessSeries = new NumericTimeDataSeries(); DateTime lastTime = input.StartTime; // Iterate through entire data series, recreating the result foreach (ITimeValueEntry <SprocketCombo> item in guessSprockets) { float ratio = 0; if (item.Value != null) { ratio = item.Value.GearRatio; } guessSeries.Add(guessSprockets.EntryDateTime(item), ratio); } return(guessSeries); }
/****************************************************/ //Before ST 3_0_4205 points was not always inserted in order //For some reason this occasionally occurs in Trails 1.2.821 too public static bool ResortTrack <T>(ITimeDataSeries <T> track) { bool reSort = false; #if !NO_ST_RESORT_TRACKS if (track.Count > 0) { for (int i = 1; i < track.Count; i++) { if (track[i - 1].ElapsedSeconds > track[i].ElapsedSeconds) { reSort = true; break; } } if (reSort) { SortedDictionary <uint, ITimeValueEntry <T> > dic = new SortedDictionary <uint, ITimeValueEntry <T> >(); foreach (ITimeValueEntry <T> g in track) { if (!dic.ContainsKey(g.ElapsedSeconds)) { dic.Add(g.ElapsedSeconds, g); } } DateTime startTimeTrack = track.StartTime; track.Clear(); foreach (KeyValuePair <uint, ITimeValueEntry <T> > g in dic) { track.Add(startTimeTrack.AddSeconds(g.Value.ElapsedSeconds), g.Value.Value); } } } #endif return(reSort); }
public ITimeDataSeries <SprocketCombo> GetRangeSprocketsTrack(RangeInfoCacheWrapper range) { ITimeDataSeries <SprocketCombo> result = null; if (range.ContainsStoredInfo(m_SprocketTrackStoredInfoId) && range.RetrieveStoredInfo(m_SprocketTrackStoredInfoId) != null) { result = range.RetrieveStoredInfo(m_SprocketTrackStoredInfoId) as ITimeDataSeries <SprocketCombo>; } else { INumericTimeDataSeries gears = ActivityGearTrackCache.Instance.CalculateGearTrack(range.Activity); gears = Utils.Utils.RemovePausedTimesInTrack(gears, range.Activity); NumericTimeDataSeries tempResult = new NumericTimeDataSeries(); Utils.Utils.ExtractRangeFromDataTrack(gears, range.PauselessRange, tempResult); result = GearChart.UI.GearUtils.GuessSprockets(tempResult, Common.Data.GetSprocketCombos(range.Activity)); range.SaveStoredInfo(m_SprocketTrackStoredInfoId, result); } return(result); }
/// <summary> /// Insert values at borders: Start, stop, pauses, trailpoints /// </summary> /// <param name="track"></param> /// <param name="source"></param> public void insertValues(ITimeDataSeries <T> track, ITimeDataSeries <T> source) { //Insert points around pauses and points //This is needed to get the track match the cut-up activity //(otherwise for instance start point need to be added) IList <DateTime> dates = new List <DateTime>(); //start/end should be included from points, but prepare for changes... InsertValue(startTime, track, source); InsertValue(endTime, track, source); dates.Add(startTime); dates.Add(endTime); foreach (IValueRange <DateTime> p in pauses) { if (p.Lower > startTime) { InsertValue(p.Lower.AddSeconds(-1), track, source); dates.Add(p.Lower.AddSeconds(-1)); } if (p.Upper < endTime) { InsertValue(p.Upper.AddSeconds(1), track, source); dates.Add(p.Upper.AddSeconds(1)); } } if (this.points != null) { foreach (TrailResultPoint t in points) { DateTime dateTime = t.Time; if (dateTime > startTime && dateTime < endTime) { //Adding an extra point will change averages etc //InsertValue(dateTime.AddSeconds(-1), track, source); InsertValue(dateTime, track, source); dates.Add(dateTime); } } } //((List<DateTime>)dates).Sort(); //kolla avrundning av elapsed både då starttime.ms och entry.ms //int j = 0; //double elapsedDate = (dates[j] - source.StartTime).TotalSeconds; //for (int i = 0; i < source.Count - 1; i++) //{ // uint elapsedSrc = source[i].ElapsedSeconds; // while (j < dates.Count && (dates[j] < source.StartTime || // elapsedDate < elapsedSrc)) // { // j++; // if (j < dates.Count) // { // elapsedDate = (dates[j] - source.StartTime).TotalSeconds; // } // } // if (j >= dates.Count || elapsedDate > source.TotalElapsedSeconds) // { // //No more dates // break; // } // if (elapsedDate >= elapsedSrc) // { // // } //} //ST bug: track could be out of order (due to insert at least) TrackUtil.ResortTrack(track); }
public IList <SprocketComboInfo> GetSprocketComboInfo(RangeInfoCacheWrapper range, ITimeDataSeries <SprocketCombo> sprocketTrack) { IList <SprocketComboInfo> result; if (range.ContainsStoredInfo(m_SprocketStoredInfoId) && range.RetrieveStoredInfo(m_SprocketStoredInfoId) != null) { result = range.RetrieveStoredInfo(m_SprocketStoredInfoId) as IList <SprocketComboInfo>; } else { result = Common.Data.Calculate(range.Activity, sprocketTrack); // Remove totals row result.RemoveAt(result.Count - 1); range.SaveStoredInfo(m_SprocketStoredInfoId, result); } return(result); }