private static Record GetDistancePaceRecord(IActivity activity, RecordCategory category) { float fastestSpeed = 0; float currentSpeed; float currentDistance = 0; if (activity.GPSRoute != null && activity.GPSRoute.TotalElapsedSeconds > 0 && ActivityInfoCache.Instance.GetInfo(activity).DistanceMetersMoving >= category.Meters) { int recordStart = 0, recordEnd = 0, startIndex, endIndex = 0; List <double> p2pDistance = new List <double>(); // Go through each starting point for (startIndex = 0; startIndex < activity.GPSRoute.Count; startIndex++) { // Find end GPS point that's the proper distance away while (currentDistance <= category.Meters) { endIndex += 1; // Typical return point. End has exceeded route. Construct and return record for this activity/category. if (endIndex >= activity.GPSRoute.Count) { // Construct record GPS route GPSRoute recordGPS = new GPSRoute(); NumericTimeDataSeries recordHRTrack = new NumericTimeDataSeries(); NumericTimeDataSeries pwrTrack = new NumericTimeDataSeries(); NumericTimeDataSeries elevTrack = new NumericTimeDataSeries(); NumericTimeDataSeries cadTrack = new NumericTimeDataSeries(); DistanceDataTrack distTrack = new DistanceDataTrack(); for (int i = recordStart; i <= recordEnd; i++) { // Record information/statistics DateTime time = activity.GPSRoute.EntryDateTime(activity.GPSRoute[i]); recordGPS.Add(time, activity.GPSRoute[i].Value); if (activity.HeartRatePerMinuteTrack != null && activity.HeartRatePerMinuteTrack.StartTime <= time && activity.HeartRatePerMinuteTrack.StartTime.AddSeconds(activity.HeartRatePerMinuteTrack.TotalElapsedSeconds) >= time) { recordHRTrack.Add(time, activity.HeartRatePerMinuteTrack.GetInterpolatedValue(time).Value); } if (activity.PowerWattsTrack != null && activity.PowerWattsTrack.StartTime <= time && activity.PowerWattsTrack.StartTime.AddSeconds(activity.PowerWattsTrack.TotalElapsedSeconds) >= time) { pwrTrack.Add(time, activity.PowerWattsTrack.GetInterpolatedValue(time).Value); } if (activity.CadencePerMinuteTrack != null && activity.CadencePerMinuteTrack.StartTime <= time && activity.CadencePerMinuteTrack.StartTime.AddSeconds(activity.CadencePerMinuteTrack.TotalElapsedSeconds) >= time) { cadTrack.Add(time, activity.CadencePerMinuteTrack.GetInterpolatedValue(time).Value); } if (activity.DistanceMetersTrack != null && activity.DistanceMetersTrack.StartTime <= time && activity.DistanceMetersTrack.StartTime.AddSeconds(activity.DistanceMetersTrack.TotalElapsedSeconds) >= time) { distTrack.Add(time, activity.DistanceMetersTrack.GetInterpolatedValue(time).Value); } if (activity.ElevationMetersTrack != null && activity.ElevationMetersTrack.StartTime <= time && activity.ElevationMetersTrack.StartTime.AddSeconds(activity.ElevationMetersTrack.TotalElapsedSeconds) >= time) { elevTrack.Add(time, activity.ElevationMetersTrack.GetInterpolatedValue(time).Value); } } // Return record Record record = new Record(activity, category, recordGPS, recordHRTrack, pwrTrack, cadTrack, distTrack, elevTrack); return(record); } else { // Add to end of route until category distance is found currentDistance += activity.GPSRoute[endIndex].Value.DistanceMetersToPoint(activity.GPSRoute[endIndex - 1].Value); } } // In meters / second currentSpeed = currentDistance / (activity.GPSRoute[endIndex].ElapsedSeconds - activity.GPSRoute[startIndex].ElapsedSeconds); // Store fastest info (in meters / second) if (fastestSpeed < currentSpeed) { fastestSpeed = currentSpeed; recordStart = startIndex; recordEnd = endIndex; } // Remove first point from routeDistance, and go to next starting point. currentDistance -= activity.GPSRoute[startIndex].Value.DistanceMetersToPoint(activity.GPSRoute[startIndex + 1].Value); } } // Activity does not contain GPS data or not long enough return(null); }
/// <summary> /// Used to generate the record properties of the supplied activity /// </summary> /// <param name="activity">The full activity for the record</param> /// <param name="category">The Record Category for this record</param> /// <param name="gpsTrack">The GPS route of the actual record</param> /// <param name="hrTrack">The HR track of the actual record</param> /// <param name="pwrTrack">The power track of the actual record</param> /// <param name="cadTrack">The cadence track of the actual record</param> public Record(IActivity activity, RecordCategory category, IGPSRoute gpsTrack, INumericTimeDataSeries hrTrack, INumericTimeDataSeries pwrTrack, INumericTimeDataSeries cadTrack, IDistanceDataTrack distTrack, INumericTimeDataSeries elevTrack, DateTime activityStartTime) { // Create new activity from template IActivity recActivity = (IActivity)Activator.CreateInstance(activity.GetType()); // HACK: Manually Clone 'activity' until a better way is found recActivity.Category = activity.Category; recActivity.DistanceMetersTrack = distTrack; recActivity.ElevationMetersTrack = elevTrack; recActivity.GPSRoute = gpsTrack; recActivity.HasStartTime = activity.HasStartTime; recActivity.HeartRatePerMinuteTrack = hrTrack; recActivity.Intensity = activity.Intensity; recActivity.Location = activity.Location; recActivity.Name = activity.Name; recActivity.PowerWattsTrack = pwrTrack; recActivity.CadencePerMinuteTrack = cadTrack; recActivity.Weather.Conditions = activity.Weather.Conditions; recActivity.Weather.CurentDirectionDegrees = activity.Weather.CurentDirectionDegrees; recActivity.Weather.CurentSpeedKilometersPerHour = activity.Weather.CurentSpeedKilometersPerHour; recActivity.Weather.HumidityPercent = activity.Weather.HumidityPercent; recActivity.Weather.TemperatureCelsius = activity.Weather.TemperatureCelsius; recActivity.Weather.WindDirectionDegrees = activity.Weather.WindDirectionDegrees; recActivity.Weather.WindSpeedKilometersPerHour = activity.Weather.WindSpeedKilometersPerHour; // Set the start time for the record activity recActivity.StartTime = activityStartTime; // Set up the activity info for pulling summary data ActivityInfo info = ActivityInfoCache.Instance.GetInfo(recActivity); // Set the record category this.category = category; // Max and Min elevation seen over the route float maxE = float.NegativeInfinity; float minE = float.PositiveInfinity; if (activity.GPSRoute != null && activity.GPSRoute.Count > 0) { GPSRoute startRoute = new GPSRoute(); for (int i = 0; i < activity.GPSRoute.Count; i++) { GPSPoint p = (GPSPoint)activity.GPSRoute[i].Value; if (p.ElevationMeters > maxE) { maxE = p.ElevationMeters; } if (p.ElevationMeters < minE) { minE = p.ElevationMeters; } if (gpsTrack.Count == 0) { break; } if (p.Equals((GPSPoint)gpsTrack[0].Value)) { break; } else { startRoute.Add(activity.GPSRoute.EntryDateTime(activity.GPSRoute[i]), p); } } startDistance = startRoute.TotalDistanceMeters; } else if (activity.ElevationMetersTrack != null) { for (int i = 0; i < activity.ElevationMetersTrack.Count; i++) { if (activity.ElevationMetersTrack[i].Value > maxE) { maxE = activity.ElevationMetersTrack[i].Value; } if (activity.ElevationMetersTrack[i].Value < maxE) { minE = activity.ElevationMetersTrack[i].Value; } } startDistance = 0; } this.maxElevation = maxE; this.minElevation = minE; this.trueStartDate = activity.StartTime; this.activity = recActivity; }
//public IDistanceDataTrack GetSmoothedDistanceTrack(int seconds, out float min, out float max) //{ // IDistanceDataTrack distanceTrack; // if (record.Activity.DistanceMetersTrack != null) // { // // #1 Use Distance track from activity // distanceTrack = record.Activity.DistanceMetersTrack; // } // else // { // if (record.Activity.GPSRoute != null) // { // // #2 Otherwise create a distance track from GPS // distanceTrack = Utilities.CreateDistanceDataTrack(record.Activity); // return Utilities.STSmooth(distanceTrack, seconds, min, max); // } // else // { // // Else, no distance track, and cannot create one. // distanceTrack = new DistanceDataTrack(); // } // } //} //public INumericTimeDataSeries GetSmoothedGradeTrack(int seconds, out float min, out float max) //{ // NumericTimeDataSeries gradeTrack = new NumericTimeDataSeries(); // for (int i = 0; i < record.Activity.ElevationMetersTrack.Count; i++) // { // if (i == 0) // { // gradeTrack.Add(record.Activity.ElevationMetersTrack[i].ElapsedSeconds, 0); // } // } //} #region Constructors public Feature(IActivity activity, feature_type type, DateTime inStartTime, DateTime inEndTime) { startTime = inStartTime; endTime = inEndTime; added = false; hillNumber = 0; _feature_type = type; masterActivityID = activity.ReferenceId; // Default fill and line color fillColor = Color.FromArgb(125, 146, 94, 9); lineColor = Color.FromArgb(255, 146, 94, 9); lineWidth = 1; selectedColor = Color.Empty; routeWidth = PluginMain.GetApplication().SystemPreferences.RouteSettings.RouteWidth; IGPSRoute recordGPS = new GPSRoute(); INumericTimeDataSeries recordHRTrack = new NumericTimeDataSeries(); INumericTimeDataSeries pwrTrack = new NumericTimeDataSeries(); INumericTimeDataSeries elevTrack = new NumericTimeDataSeries(); INumericTimeDataSeries cadTrack = new NumericTimeDataSeries(); IDistanceDataTrack distTrack = new DistanceDataTrack(); RecordCategory category = new RecordCategory(); ActivityInfo ai = ActivityInfoCache.Instance.GetInfo(activity); DateTime start = activity.StartTime; if (activity.GPSRoute != null) { // Check and make sure the route has points if (activity.GPSRoute.Count > 0) { // If the time passed in is before the start of the gps track, get the first value if (activity.GPSRoute.StartTime > inStartTime) { startPoint = activity.GPSRoute[0].Value; } else { // Set the start point ITimeValueEntry <IGPSPoint> sPoint = activity.GPSRoute.GetInterpolatedValue(inStartTime); if (sPoint != null) { startPoint = sPoint.Value; } } // If the time passed in is after the end of the gps track, get the last value if (activity.GPSRoute.StartTime.AddSeconds(activity.GPSRoute[activity.GPSRoute.Count - 1].ElapsedSeconds) < inEndTime) { endPoint = activity.GPSRoute[activity.GPSRoute.Count - 1].Value; } else { // Set the end point ITimeValueEntry <IGPSPoint> ePoint = activity.GPSRoute.GetInterpolatedValue(inEndTime); if (ePoint != null) { endPoint = ePoint.Value; } } } // Create the GPSRoute for (int i = 0; i < activity.GPSRoute.Count; i++) { if (activity.GPSRoute.StartTime.AddSeconds(activity.GPSRoute[i].ElapsedSeconds) >= inStartTime && activity.GPSRoute.StartTime.AddSeconds(activity.GPSRoute[i].ElapsedSeconds) <= inEndTime) { recordGPS.Add(activity.GPSRoute.StartTime.AddSeconds(activity.GPSRoute[i].ElapsedSeconds), activity.GPSRoute[i].Value); } } } // Create the Distance Track INumericTimeDataSeries allDistanceTrack = ai.MovingDistanceMetersTrack; // Utilities.GetDistanceTrack(activity); INumericTimeDataSeries allElevationTrack = ai.SmoothedElevationTrack; // Utilities.GetElevationTrack(activity); // Work your way through the moving meters track to create all others if (allDistanceTrack != null) { for (int i = 0; i < allDistanceTrack.Count; i++) { DateTime time = allDistanceTrack.StartTime.AddSeconds(allDistanceTrack[i].ElapsedSeconds); if (time >= inStartTime && time <= inEndTime) { // Add the distance point distTrack.Add(time, allDistanceTrack[i].Value); ITimeValueEntry <float> point = null; // Find the elevation point at this time and add it if (allElevationTrack != null && allElevationTrack.Count > 0) { point = allElevationTrack.GetInterpolatedValue(time); if (point != null) { elevTrack.Add(time, point.Value); } } // Find the HR point at this time and add it if (activity.HeartRatePerMinuteTrack != null && activity.HeartRatePerMinuteTrack.Count > 0) { point = activity.HeartRatePerMinuteTrack.GetInterpolatedValue(time); if (point != null) { recordHRTrack.Add(time, point.Value); } } // Find the power point at this time and add it if (activity.PowerWattsTrack != null && activity.PowerWattsTrack.Count > 0) { point = activity.PowerWattsTrack.GetInterpolatedValue(time); if (point != null) { pwrTrack.Add(time, point.Value); } } // Find the cadence point at this time and add it if (activity.CadencePerMinuteTrack != null && activity.CadencePerMinuteTrack.Count > 0) { point = activity.CadencePerMinuteTrack.GetInterpolatedValue(time); if (point != null) { cadTrack.Add(time, point.Value); } } } else if (allDistanceTrack.StartTime.AddSeconds(allDistanceTrack[i].ElapsedSeconds) > inEndTime) { break; } } } // Get the start/end distance if (distTrack != null && distTrack.Count > 0) { startDistance = distTrack[0].Value; endDistance = distTrack[distTrack.Count - 1].Value; } else { startDistance = 0; endDistance = 0; } // Get the start/end elevation if (elevTrack != null && elevTrack.Count > 0) { startElevation = elevTrack[0].Value; endElevation = elevTrack[elevTrack.Count - 1].Value; } else { startElevation = 0; endElevation = 0; } // Build the record record = new Record(activity, category, recordGPS, recordHRTrack, pwrTrack, cadTrack, distTrack, elevTrack, inStartTime); // Create a reference id for this hill refId = Guid.NewGuid().ToString("D"); double distanceX = endDistance - startDistance; distance = distanceX; double elev = endElevation - startElevation; elevGain = elev; // Find the start percents from the distance track if (allDistanceTrack != null && allDistanceTrack.Count > 0) { startPercentDistance = startDistance / allDistanceTrack[allDistanceTrack.Count - 1].Value; endPercentDistance = endDistance / allDistanceTrack[allDistanceTrack.Count - 1].Value; startPercentTime = ((inStartTime - allDistanceTrack.StartTime).TotalSeconds / allDistanceTrack[allDistanceTrack.Count - 1].ElapsedSeconds); endPercentTime = ((inEndTime - allDistanceTrack.StartTime).TotalSeconds / allDistanceTrack[allDistanceTrack.Count - 1].ElapsedSeconds); } // Calculate the VAM (Velocity Ascended, Meters per hour) // Calculate the W/kg (Relative power) vam = 0; wKg = 0; if (elevGain > 0) { vam = (elevGain * 60f * 60f) / record.TotalTime.TotalSeconds; wKg = vam / ((2 + (avgGrade * 10f)) * 100f); } ActivityInfo aiRec = ActivityInfoCache.Instance.GetInfo(record.Activity); stoppedTime = aiRec.TimeNotMoving; }
// Use the GPS track as a base when creating the TrackPoints. // Use heartbeat data if available private TrackPoint[] GetTrackPointsFromGPSTrack(IActivity activity) { if (activity.GPSRoute == null) return null; List<TrackPoint> tps = new List<TrackPoint>(); double accDistance = 0; ITimeValueEntry<IGPSPoint> prevPoint = null; // Removing GPS points at identical time is a workaround for the funbeat server not being able to handle them // Ought to be fixed on the server side IGPSRoute ActGPSRoute = new GPSRoute(activity.GPSRoute); ActGPSRoute.AllowMultipleAtSameTime = false; foreach (ITimeValueEntry<IGPSPoint> p in ActGPSRoute) { TrackPoint tp = new TrackPoint(); if (p == ActGPSRoute[0]) tp.isStartPoint = true; tp.TimeStamp = ConvertToLocalTime(ActGPSRoute.StartTime.AddSeconds(p.ElapsedSeconds)); DateTime actualTime = ActGPSRoute.StartTime.AddSeconds(p.ElapsedSeconds); // Get heartrate track if (activity.HeartRatePerMinuteTrack != null) { if (actualTime < activity.HeartRatePerMinuteTrack.StartTime) actualTime = activity.HeartRatePerMinuteTrack.StartTime; ITimeValueEntry<float> interpolatedHR = activity.HeartRatePerMinuteTrack.GetInterpolatedValue(actualTime); if (interpolatedHR != null) { float heartRate = interpolatedHR.Value; tp.HR = Convert.ToInt32(heartRate); } else { tp.HR = null; } } else { tp.HR = null; } // Get cadence track if (activity.CadencePerMinuteTrack != null) { if (actualTime < activity.CadencePerMinuteTrack.StartTime) actualTime = activity.CadencePerMinuteTrack.StartTime; ITimeValueEntry<float> interpolatedCadence = activity.CadencePerMinuteTrack.GetInterpolatedValue(actualTime); if (interpolatedCadence != null) { float cadence = interpolatedCadence.Value; tp.Cad = Convert.ToInt32(cadence); if (double.IsNaN((double)tp.Cad)) { tp.Cad = null; } } else { tp.Cad = null; } } else { tp.Cad = null; } tp.Latitude = Convert.ToDouble(p.Value.LatitudeDegrees); tp.Longitude = Convert.ToDouble(p.Value.LongitudeDegrees); tp.Altitude = Convert.ToDouble(p.Value.ElevationMeters); if (double.IsNaN((double)tp.Altitude)) { tp.Altitude = null; } if (prevPoint != null) accDistance += p.Value.DistanceMetersToPoint(prevPoint.Value); tp.Distance = accDistance / 1000; tps.Add(tp); prevPoint = p; } return tps.ToArray(); }