Esempio n. 1
0
        /// <summary>
        /// Static all-in-one method to fit the splines and evaluate at X coordinates.
        /// </summary>
        /// <param name="x">Input. X coordinates to fit.</param>
        /// <param name="y">Input. Y coordinates to fit.</param>
        /// <param name="xs">Input. X coordinates to evaluate the fitted curve at.</param>
        /// <param name="startSlope">Optional slope constraint for the first point. Single.NaN means no constraint.</param>
        /// <param name="endSlope">Optional slope constraint for the final point. Single.NaN means no constraint.</param>
        /// <param name="debug">Turn on console output. Default is false.</param>
        /// <returns>The computed y values for each xs.</returns>
        public static float[] Compute(float[] x, float[] y, float[] xs, float startSlope = float.NaN, float endSlope = float.NaN, bool debug = false)
        {
            CubicSpline spline = new CubicSpline();

            return(spline.FitAndEval(x, y, xs, startSlope, endSlope, debug));
        }
Esempio n. 2
0
        /// <summary>
        /// Maps <see cref="MSHealthAPI.MSHealthActivity"/> instance to <see cref="NikePlusAPI.NikePlusActivity"/> instance.
        /// </summary>
        /// <param name="activityIn"><see cref="MSHealthAPI.MSHealthActivity"/> instance to map.</param>
        /// <returns><see cref="NikePlusAPI.NikePlusActivity"/> instance.</returns>
        public static NikePlusActivity ToNikePlusActicity(this MSHealthActivity activityIn)
        {
            NikePlusActivity loActivityOut = null;

            if (activityIn != null)
            {
                loActivityOut = new NikePlusActivity();
                // Distance
                double ldDistance = 0;
                if (activityIn.SplitDistance != null &&
                    activityIn.DistanceSummary != null &&
                    activityIn.DistanceSummary.TotalDistance != null)
                {
                    ldDistance = activityIn.DistanceSummary.TotalDistance.Value / activityIn.SplitDistance.Value;
                    if (activityIn.SplitDistance.Value == MSHealthActivity.SPLIT_DISTANCE_MILE)
                    {
                        ldDistance = ldDistance * 1.609344; //1609.344;
                    }
                    if (loActivityOut.MetricSummary == null)
                    {
                        loActivityOut.MetricSummary = new NikePlusMetricSummary();
                    }
                    loActivityOut.MetricSummary.Distance = ldDistance;
                }
                // Duration
                if (activityIn.Duration != null)
                {
                    loActivityOut.Duration = activityIn.Duration.Value.TotalMilliseconds;
                    if (loActivityOut.MetricSummary == null)
                    {
                        loActivityOut.MetricSummary = new NikePlusMetricSummary();
                    }
                    loActivityOut.MetricSummary.Duration = activityIn.Duration;
                }
                // Start Time
                if (activityIn.StartTime != null &&
                    activityIn.StartTime.HasValue)
                {
                    loActivityOut.StartTime = activityIn.StartTime.Value;
                }
                // Status
                loActivityOut.Status = NikePlusActivityStatus.COMPLETE;
                // Type
                switch (activityIn.Type)
                {
                case MSHealthActivityType.Run:
                    loActivityOut.Type = NikePlusActivityType.RUN;
                    break;

                case MSHealthActivityType.Bike:
                    loActivityOut.Type = NikePlusActivityType.CYCLE;
                    break;

                case MSHealthActivityType.Sleep:
                    loActivityOut.Type = NikePlusActivityType.SLEEPING;
                    break;

                default:
                    loActivityOut.Type = NikePlusActivityType.OTHER;
                    break;
                }
                // Calories
                if (activityIn.CaloriesBurnedSummary != null &&
                    activityIn.CaloriesBurnedSummary.TotalCalories != null)
                {
                    if (loActivityOut.MetricSummary == null)
                    {
                        loActivityOut.MetricSummary = new NikePlusMetricSummary();
                    }
                    loActivityOut.MetricSummary.Calories = activityIn.CaloriesBurnedSummary.TotalCalories;
                }
                // Device
                loActivityOut.DeviceType = NikePlusDeviceType.WATCH; // Nike doesn't recognize MSBand as valid device, so, set as WATCH
                                                                     // Get valid MapPoints (with Location Latitude and Longitude)
                IEnumerable <MSHealthMapPoint> loMapPoints = null;
                if (activityIn.MapPoints != null &&
                    activityIn.MapPoints.Any())
                {
                    loMapPoints = activityIn.MapPoints
                                  .Where(loMP => loMP.IsPaused != null &&
                                         !loMP.IsPaused.Value &&
                                         loMP.SecondsSinceStart != null)
                                  .OrderBy(loMP => loMP.Ordinal);
                }
                // Metrics
                List <NikePlusMetric> loMetrics        = new List <NikePlusMetric>();
                NikePlusMetric        loMetricDistance = new NikePlusMetric()
                {
                    Type = NikePlusMetricType.DISTANCE
                };
                NikePlusMetric loMetricHeartRate = new NikePlusMetric()
                {
                    Type = NikePlusMetricType.HEARTRATE
                };
                NikePlusMetric loMetricSpeed = new NikePlusMetric {
                    Type = NikePlusMetricType.SPEED
                };
                NikePlusMetric loMetricCalories = new NikePlusMetric {
                    Type = NikePlusMetricType.CALORIES
                };
                SortedDictionary <float, float> loDistanceToDurationNodes  = new SortedDictionary <float, float>();
                SortedDictionary <float, float> loHeartRateToDurationNodes = new SortedDictionary <float, float>();
                SortedDictionary <float, float> loSpeedToDurationNodes     = new SortedDictionary <float, float>();
                SortedDictionary <float, float> loCaloriesToDurationNodes  = new SortedDictionary <float, float>();
                SortedDictionary <float, float> loDurationToDistanceNodes  = new SortedDictionary <float, float>();
                double ldTotalDistance = 0;
                float  lfTotalSeconds  = 0;
                if (loMapPoints != null &&
                    loMapPoints.Any())
                {
                    foreach (MSHealthMapPoint loMapPoint in loMapPoints)
                    {
                        // Location
                        if (loMapPoint.Location != null)
                        {
                            // Latitude/Longitude
                            if (loMapPoint.Location.Latitude != null &&
                                loMapPoint.Location.Longitude != null)
                            {
                                if (loActivityOut.GPSData == null)
                                {
                                    loActivityOut.GPSData = new NikePlusGPS();
                                }
                                if (loActivityOut.GPSData.Waypoints == null)
                                {
                                    loActivityOut.GPSData.Waypoints = new List <NikePlusWaypoint>();
                                }
                                NikePlusWaypoint loWaypoint = new NikePlusWaypoint()
                                {
                                    Latitude  = loMapPoint.Location.Latitude.Value / MSHealthGPSPoint.LATITUDE_FACTOR,
                                    Longitude = loMapPoint.Location.Longitude.Value / MSHealthGPSPoint.LONGITUDE_FACTOR,
                                };
                                // Elevation
                                if (loMapPoint.Location.ElevationFromMeanSeaLevel != null)
                                {
                                    loWaypoint.Elevation = loMapPoint.Location.ElevationFromMeanSeaLevel.Value / MSHealthGPSPoint.ELEVATION_FACTOR;
                                }
                                loActivityOut.GPSData.Waypoints.Add(loWaypoint);
                            }
                        }
                        // Distance
                        if (loMapPoint.TotalDistance != null &&
                            loMapPoint.SecondsSinceStart != null)
                        {
                            ldDistance = loMapPoint.TotalDistance.Value / activityIn.SplitDistance.Value;
                            if (activityIn.SplitDistance.Value == MSHealthActivity.SPLIT_DISTANCE_MILE)
                            {
                                ldDistance = ldDistance * 1.609344;
                            }
                            if (!loDistanceToDurationNodes.ContainsKey(loMapPoint.SecondsSinceStart.Value))
                            {
                                loDistanceToDurationNodes.Add(loMapPoint.SecondsSinceStart.Value, (float)ldDistance);
                            }
                            if (!loDurationToDistanceNodes.ContainsKey((float)ldDistance))
                            {
                                loDurationToDistanceNodes.Add((float)ldDistance, loMapPoint.SecondsSinceStart.Value);
                            }
                            ldTotalDistance = ldDistance;
                            lfTotalSeconds  = loMapPoint.SecondsSinceStart.Value;
                        }
                        // Heart rate
                        if (loMapPoint.HeartRate != null)
                        {
                            if (!loHeartRateToDurationNodes.ContainsKey(loMapPoint.SecondsSinceStart.Value))
                            {
                                loHeartRateToDurationNodes.Add(loMapPoint.SecondsSinceStart.Value, loMapPoint.HeartRate.Value);
                            }
                        }
                        // Speed
                        if (loMapPoint.Speed != null)
                        {
                            // TODO: Determine if conversion is necessary
                            if (!loSpeedToDurationNodes.ContainsKey(loMapPoint.SecondsSinceStart.Value))
                            {
                                loSpeedToDurationNodes.Add(loMapPoint.SecondsSinceStart.Value, (float)loMapPoint.Speed.Value);
                            }
                        }
                    }
                    MSHealthMapPoint loLastMapPoint = loMapPoints.LastOrDefault();
                    if (loLastMapPoint != null &&
                        loLastMapPoint.SecondsSinceStart != null)
                    {
                        lfTotalSeconds = loLastMapPoint.SecondsSinceStart.Value;
                    }
                }
                else
                {
                    if (activityIn.MinuteSummaries != null &&
                        activityIn.MinuteSummaries.Any())
                    {
                        lfTotalSeconds  = 0;
                        ldTotalDistance = 0;
                        IEnumerable <MSHealthSummary> loSummaries = activityIn.MinuteSummaries.OrderBy(loSumm => loSumm.StartTime);
                        foreach (MSHealthSummary loSummary in loSummaries)
                        {
                            lfTotalSeconds += 60;
                            // Calories
                            if (loSummary.CaloriesBurnedSummary != null &&
                                loSummary.CaloriesBurnedSummary.TotalCalories != null)
                            {
                                if (!loCaloriesToDurationNodes.ContainsKey(lfTotalSeconds))
                                {
                                    loCaloriesToDurationNodes.Add(lfTotalSeconds, loSummary.CaloriesBurnedSummary.TotalCalories.Value);
                                }
                            }
                            // Heart Rate
                            if (loSummary.HeartRateSummary != null &&
                                loSummary.HeartRateSummary.AverageHeartRate != null)
                            {
                                if (!loHeartRateToDurationNodes.ContainsKey(lfTotalSeconds))
                                {
                                    loHeartRateToDurationNodes.Add(lfTotalSeconds, loSummary.HeartRateSummary.AverageHeartRate.Value);
                                }
                            }
                            // Distance
                            if (activityIn.SplitDistance != null &&
                                loSummary.DistanceSummary != null &&
                                loSummary.DistanceSummary.TotalDistance != null)
                            {
                                ldDistance = loSummary.DistanceSummary.TotalDistance.Value / activityIn.SplitDistance.Value;
                                if (activityIn.SplitDistance.Value == MSHealthActivity.SPLIT_DISTANCE_MILE)
                                {
                                    ldDistance = ldDistance * 1.609344;
                                }
                                ldTotalDistance += ldDistance;
                                if (!loDistanceToDurationNodes.ContainsKey(lfTotalSeconds))
                                {
                                    loDistanceToDurationNodes.Add(lfTotalSeconds, (float)ldTotalDistance);
                                }
                                if (!loDurationToDistanceNodes.ContainsKey((float)ldDistance))
                                {
                                    loDurationToDistanceNodes.Add((float)ldDistance, lfTotalSeconds);
                                }
                            }
                        }
                    }
                    loActivityOut.IsGPSActivity = false;
                }
                // Interpolate metrics to each 10 seconds.
                List <float> loIntervals = new List <float>();
                for (float lfInterval = 10; lfInterval < lfTotalSeconds; lfInterval += 10)
                {
                    loIntervals.Add(lfInterval);
                }
                CubicSpline loCubicSpline = null;
                float[]     loValues      = null;

                /*
                 * GPS
                 */
                if (loActivityOut.GPSData != null &&
                    loActivityOut.GPSData.Waypoints != null &&
                    loActivityOut.GPSData.Waypoints.Any())
                {
                    // Configure GPS Data
                    loActivityOut.IsGPSActivity          = true;
                    loActivityOut.GPSData.IntervalUnit   = NikePlusIntervalUnit.SEC;
                    loActivityOut.GPSData.IntervalMetric = Math.Floor((double)lfTotalSeconds / (double)loActivityOut.GPSData.Waypoints.Count);
                    // Elevation
                    if (activityIn.DistanceSummary != null)
                    {
                        if (activityIn.DistanceSummary.ElevationGain != null)
                        {
                            loActivityOut.GPSData.ElevationGain = activityIn.DistanceSummary.ElevationGain / MSHealthDistanceSummary.ELEVATION_FACTOR;
                        }
                        if (activityIn.DistanceSummary.ElevationLoss != null)
                        {
                            loActivityOut.GPSData.ElevationLoss = activityIn.DistanceSummary.ElevationLoss / MSHealthDistanceSummary.ELEVATION_FACTOR;
                        }
                        if (activityIn.DistanceSummary.MaxElevation != null)
                        {
                            loActivityOut.GPSData.ElevationMax = activityIn.DistanceSummary.MaxElevation / MSHealthDistanceSummary.ELEVATION_FACTOR;
                        }
                        if (activityIn.DistanceSummary.MinElevation != null)
                        {
                            loActivityOut.GPSData.ElevationMin = activityIn.DistanceSummary.MinElevation / MSHealthDistanceSummary.ELEVATION_FACTOR;
                        }
                    }
                    // GPS can be loaded using GPX format
                    try { loActivityOut.GPX = activityIn.ToGPX(); }
                    catch { /* Do nothing */ }
                }

                /*
                 * Metrics
                 */
                // Distance
                if (loDistanceToDurationNodes.Any())
                {
                    if (!loDistanceToDurationNodes.ContainsKey(0))
                    {
                        loDistanceToDurationNodes.Add(0, 0);
                    }
                    loCubicSpline = new CubicSpline(loDistanceToDurationNodes.Keys.ToArray(), loDistanceToDurationNodes.Values.ToArray());
                    loValues      = loCubicSpline.Eval(loIntervals.ToArray());
                    // Configure Metric Intervals and Values
                    loMetricDistance.Values         = (from lfValue in loValues select lfValue < 0 ? "0" : lfValue.ToString()).ToList();
                    loMetricDistance.IntervalUnit   = NikePlusIntervalUnit.SEC;
                    loMetricDistance.IntervalMetric = 10;
                    loMetrics.Add(loMetricDistance);
                }
                // Heart Rate
                if (loHeartRateToDurationNodes.Any())
                {
                    if (!loHeartRateToDurationNodes.ContainsKey(0))
                    {
                        loHeartRateToDurationNodes.Add(0, 0);
                    }
                    loCubicSpline = new CubicSpline(loHeartRateToDurationNodes.Keys.ToArray(), loHeartRateToDurationNodes.Values.ToArray());
                    loValues      = loCubicSpline.Eval(loIntervals.ToArray());
                    // Configure Metric Intervals and Values
                    loMetricHeartRate.Values         = (from lfValue in loValues select lfValue < 0 ? "0" : ((int)lfValue).ToString()).ToList();
                    loMetricHeartRate.IntervalUnit   = NikePlusIntervalUnit.SEC;
                    loMetricHeartRate.IntervalMetric = 10;
                    loMetrics.Add(loMetricHeartRate);
                }
                // Speed
                if (loSpeedToDurationNodes.Any())
                {
                    if (!loSpeedToDurationNodes.ContainsKey(0))
                    {
                        loSpeedToDurationNodes.Add(0, 0);
                    }
                    loCubicSpline = new CubicSpline(loSpeedToDurationNodes.Keys.ToArray(), loSpeedToDurationNodes.Values.ToArray());
                    loValues      = loCubicSpline.Eval(loIntervals.ToArray());
                    // Configure Metric Intervals and Values
                    loMetricSpeed.Values         = (from lfValue in loValues select lfValue < 0 ? "0" : lfValue.ToString()).ToList();
                    loMetricSpeed.IntervalUnit   = NikePlusIntervalUnit.SEC;
                    loMetricSpeed.IntervalMetric = 10;
                    //loMetrics.Add(loMetricSpeed);
                }
                // Calories
                if (loCaloriesToDurationNodes.Any())
                {
                    if (!loCaloriesToDurationNodes.ContainsKey(0))
                    {
                        loCaloriesToDurationNodes.Add(0, 0);
                    }
                    loCubicSpline = new CubicSpline(loCaloriesToDurationNodes.Keys.ToArray(), loCaloriesToDurationNodes.Values.ToArray());
                    loValues      = loCubicSpline.Eval(loIntervals.ToArray());
                    // Configure Metric Intervals and Values
                    loMetricCalories.Values         = (from lfValue in loValues select lfValue < 0 ? "0" : lfValue.ToString()).ToList();
                    loMetricCalories.IntervalUnit   = NikePlusIntervalUnit.SEC;
                    loMetricCalories.IntervalMetric = 10;
                    loMetrics.Add(loMetricCalories);
                }
                // Snapshots
                if (loDurationToDistanceNodes != null &&
                    loDurationToDistanceNodes.Any())
                {
                    loActivityOut.SummaryV2           = new NikePlusActivitySummaryV2();
                    loActivityOut.SummaryV2.Snapshots = new List <NikePlusSnapshotV2>();
                    NikePlusSnapshotV2 loSnapshot = null;
                    // Kilometers
                    int liTotalDistance = (int)(ldTotalDistance / 1d);
                    loIntervals = new List <float>();
                    for (float lfInterval = 1; lfInterval <= liTotalDistance; lfInterval++)
                    {
                        loIntervals.Add(lfInterval);
                    }
                    loCubicSpline = null;
                    loValues      = null;
                    if (!loDurationToDistanceNodes.ContainsKey(0))
                    {
                        loDurationToDistanceNodes.Add(0, 0);
                    }
                    loCubicSpline         = new CubicSpline(loDurationToDistanceNodes.Keys.ToArray(), loDurationToDistanceNodes.Values.ToArray());
                    loValues              = loCubicSpline.Eval(loIntervals.ToArray());
                    loSnapshot            = new NikePlusSnapshotV2();
                    loSnapshot.Name       = "kmSplit";
                    loSnapshot.DataSeries = new List <NikePlusDataSerieV2>();
                    for (int liValue = 0; liValue < loValues.Length; liValue++)
                    {
                        NikePlusDataSerieV2 loDataSerie = new NikePlusDataSerieV2();
                        loDataSerie.Metrics = new NikePlusMetricV2()
                        {
                            Distance = (liValue + 1),
                            Duration = loValues[liValue] * 1000, // Seconds to Milliseconds
                        };
                        loDataSerie.ObjectType = "dataPoint";
                        loSnapshot.DataSeries.Add(loDataSerie);
                    }
                    loActivityOut.SummaryV2.Snapshots.Add(loSnapshot);
                    // Miles (1.609344)
                    liTotalDistance = (int)(ldTotalDistance / 1.609344d);
                    loIntervals     = new List <float>();
                    for (float lfInterval = 1; lfInterval <= liTotalDistance; lfInterval++)
                    {
                        loIntervals.Add(lfInterval * 1.609344f);
                    }
                    loCubicSpline = null;
                    loValues      = null;
                    if (!loDurationToDistanceNodes.ContainsKey(0))
                    {
                        loDurationToDistanceNodes.Add(0, 0);
                    }
                    loCubicSpline         = new CubicSpline(loDurationToDistanceNodes.Keys.ToArray(), loDurationToDistanceNodes.Values.ToArray());
                    loValues              = loCubicSpline.Eval(loIntervals.ToArray());
                    loSnapshot            = new NikePlusSnapshotV2();
                    loSnapshot.Name       = "mileSplit";
                    loSnapshot.DataSeries = new List <NikePlusDataSerieV2>();
                    for (int liValue = 0; liValue < loValues.Length; liValue++)
                    {
                        NikePlusDataSerieV2 loDataSerie = new NikePlusDataSerieV2();
                        loDataSerie.Metrics = new NikePlusMetricV2()
                        {
                            Distance = (liValue + 1),
                            Duration = loValues[liValue] * 1000, // Seconds to Milliseconds
                        };
                        loDataSerie.ObjectType = "dataPoint";
                        loSnapshot.DataSeries.Add(loDataSerie);
                    }
                    loActivityOut.SummaryV2.Snapshots.Add(loSnapshot);
                }
                // Set metrics
                if (loMetrics != null &&
                    loMetrics.Any())
                {
                    loActivityOut.Metrics = loMetrics;
                }

                /*
                 *              Newtonsoft.Json.JsonSerializerSettings loSerializerSettings = null;
                 *              loSerializerSettings = new Newtonsoft.Json.JsonSerializerSettings();
                 *              loSerializerSettings.Converters.Add(new NikePlusActivityPostConverterV2());
                 *              string lsActivityOutJson = Newtonsoft.Json.JsonConvert.SerializeObject(loActivityOut, loSerializerSettings);
                 *              System.Diagnostics.Debug.WriteLine(lsActivityOutJson);
                 *              //loActivityOut = null;//*/
            }
            return(loActivityOut);
        }