Example #1
0
 /// <summary>
 /// Constructor to cloan a MatchingFeature
 /// </summary>
 /// <param name="inMatchingFeature">MatchingFeature to clone</param>
 public MatchingFeature(MatchingFeature inMatchingFeature)
 {
     this.totalDistanceMeters         = inMatchingFeature.totalDistanceMeters;
     this.avgGrade                    = inMatchingFeature.avgGrade;
     this.totalTime                   = inMatchingFeature.totalTime;
     this.startPoint                  = inMatchingFeature.startPoint;
     this.endPoint                    = inMatchingFeature.endPoint;
     this.hillScoreClimbByBike        = inMatchingFeature.hillScoreClimbByBike;
     this.hillScoreCycle2Max          = inMatchingFeature.hillScoreCycle2Max;
     this.hillScoreFiets              = inMatchingFeature.hillScoreFiets;
     this.hillScoreCourseScoreRunning = inMatchingFeature.hillScoreCourseScoreRunning;
     this.hillScoreCourseScoreCycling = inMatchingFeature.hillScoreCourseScoreCycling;
     this.id               = inMatchingFeature.id;
     this.activityFact     = inMatchingFeature.activityFact;
     this.featureStartTime = inMatchingFeature.featureStartTime;
 }
Example #2
0
        public static float DistanceMetersToPointGpsSimple(IGPSPoint point, IGPSPoint point2)
        {
#if NO_SIMPLE_DISTANCE
            return(point.DistanceMetersToPoint(point2));
#else
            float _cosmean = (float)Math.Cos(point2.LatitudeDegrees * DegToRad);
            float dlat     = point.LatitudeDegrees - point2.LatitudeDegrees;
            float dlon     = point.LongitudeDegrees - point2.LongitudeDegrees;
            float result   = dlat * dlat + dlon * dlon * _cosmean;

#if SQUARE_DISTANCE
            return(result);
#else
            return(EarthRadius * DegToRad * (float)Math.Sqrt(result));
#endif
#endif
        }
Example #3
0
        static public TrailResultInfo ResultInfoFromSelection(IActivity activity, ZoneFiveSoftware.Common.Visuals.Fitness.IItemTrackSelectionInfo selInfo)
        {
            TrailResultInfo indexes = new TrailResultInfo(activity, false);
            DateTime        time    = selInfo.MarkedTimes[0].Lower;
            IGPSPoint       p       = Utils.TrackUtil.getGpsLoc(activity, time);

            if (p != null)
            {
                indexes.Points.Add(new TrailResultPoint(new TrailGPSLocation(p), time));
            }
            time = selInfo.MarkedTimes[0].Upper;
            p    = Utils.TrackUtil.getGpsLoc(activity, time);
            if (p != null)
            {
                indexes.Points.Add(new TrailResultPoint(new TrailGPSLocation(p), time));
            }
            return(indexes);
        }
Example #4
0
        //Note: Faster to keep this static then
        public static float DistanceMetersToPointSimple(TrailGPSLocation trailp, IGPSPoint point)
        {
#if NO_SIMPLE_DISTANCE
            return(trailp.DistanceMetersToPoint(point));
#else
            //Use the trailp lat instead of average lat
            if (trailp._cosmean == invalidLatLon)
            {
                trailp._cosmean = (float)Math.Cos(trailp.latitudeDegrees * DegToRad);
            }
            float dlat   = point.LatitudeDegrees - trailp.latitudeDegrees;
            float dlon   = point.LongitudeDegrees - trailp.longitudeDegrees;
            float result = dlat * dlat + dlon * dlon * trailp._cosmean;

#if SQUARE_DISTANCE
            return(result);
#else
            return(EarthRadius * DegToRad * (float)Math.Sqrt(result));
#endif
#endif
        }
Example #5
0
        public void Draw(IMapDrawContext drawContext)
        {
            if (m_CaptureSelectedGPSLocations)
            {
                m_CaptureSelectedGPSLocations = false;
                if (m_SelectedGPSLocations.Count != MapControl.Selected.Count)
                {
                    m_SelectedGPSLocations = getSelectedGPSLocations(drawContext);
                    SelectedGPSLocationsChanged(this, new System.EventArgs());
                }
            }

            if (_showPage)
            {
                //drawContext.Center

                IGPSLocation loc1           = drawContext.Projection.PixelToGPS(drawContext.Center, drawContext.ZoomLevel, new Point(0, 0));
                IGPSLocation loc2           = drawContext.Projection.PixelToGPS(drawContext.Center, drawContext.ZoomLevel, new Point(0, 100));
                IGPSPoint    point1         = Utils.GPS.LocationToPoint(loc1);
                IGPSPoint    point2         = Utils.GPS.LocationToPoint(loc2);
                float        meters         = point1.DistanceMetersToPoint(point2) / 100;
                float        radiusInPixels = m_highlightRadius / meters;

                foreach (TrailGPSLocation gpsLocation in m_TrailPoints)
                {
                    Point point = drawContext.Projection.GPSToPixel(drawContext.Center, drawContext.ZoomLevel, gpsLocation.GpsLocation);
                    Pen   pen   = new Pen(Color.Red, 5.0F);

                    drawContext.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    float X = point.X + (drawContext.DrawRectangle.Width / 2) - radiusInPixels;
                    float Y = point.Y + (drawContext.DrawRectangle.Height / 2) - radiusInPixels;
                    if (X > 0 && X < 1000 && Y > 0 && Y < 1000)
                    {
                        //Prevent crashes at large elipses
                        drawContext.Graphics.DrawEllipse(pen, X, Y, radiusInPixels * 2, radiusInPixels * 2);
                    }
                }
            }
        }
Example #6
0
        //Get the data in a generic Globalsat format, to separate ST
        public static IList <GhPacketBase.Train> ToGlobTrack(GlobalsatProtocol device, IList <IActivity> activities)
        {
            IList <GhPacketBase.Train> result = new List <GhPacketBase.Train>();

            foreach (IActivity activity in activities)
            {
                IGPSRoute          gpsRoute = activity.GPSRoute;
                GhPacketBase.Train train    = new GhPacketBase.Train();
                train.StartTime           = activity.StartTime;
                train.TotalTime           = TimeSpan.FromSeconds(gpsRoute.TotalElapsedSeconds);
                train.TotalDistanceMeters = (Int32)Math.Round(gpsRoute.TotalDistanceMeters);
                train.LapCount            = 1;

                train.TotalCalories = (Int16)activity.TotalCalories;
                if (train.MaximumSpeed == 0 && train.TotalTime.TotalSeconds >= 1)
                {
                    //Better than 0(?) - Info() could be used
                    train.MaximumSpeed = train.TotalDistanceMeters / train.TotalTime.TotalSeconds;
                }
                train.MaximumHeartRate = (byte)activity.MaximumHeartRatePerMinuteEntered;
                train.AverageHeartRate = (byte)activity.AverageHeartRatePerMinuteEntered;
                train.TotalAscend      = (Int16)activity.TotalAscendMetersEntered;
                train.TotalDescend     = (Int16)activity.TotalDescendMetersEntered;
                train.AverageCadence   = (Int16)activity.AverageCadencePerMinuteEntered;
                train.MaximumCadence   = (Int16)activity.MaximumCadencePerMinuteEntered;
                train.AveragePower     = (Int16)activity.AveragePowerWattsEntered;
                train.MaximumPower     = (Int16)activity.MaximumPowerWattsEntered;
                //Some protocols send laps in separate header
                //Use common code instead of overiding this method

                //Laps are not implemented when sending, one lap hardcoded

                for (int j = 0; j < gpsRoute.Count; j++)
                {
                    IGPSPoint point = gpsRoute[j].Value;
                    GhPacketBase.TrackPoint trackpoint = new GhPacketBase.TrackPoint();
                    trackpoint.Latitude  = point.LatitudeDegrees;
                    trackpoint.Longitude = point.LongitudeDegrees;
                    trackpoint.Altitude  = (Int32)point.ElevationMeters;
                    if (j == 0)
                    {
                        trackpoint.IntervalTime = 0;
                    }
                    else
                    {
#if ST_2_1
                        int intTime = gpsRoute[j].ElapsedSeconds - gpsRoute[j - 1].ElapsedSeconds;
#else
                        uint intTime = gpsRoute[j].ElapsedSeconds - gpsRoute[j - 1].ElapsedSeconds;
#endif
                        float dist = gpsRoute[j].Value.DistanceMetersToPoint(gpsRoute[j - 1].Value);
                        if (intTime > 0)
                        {
                            trackpoint.IntervalTime = intTime;
                            trackpoint.Speed        = dist / intTime;
                        }
                        else
                        {
                            //Time is not really used - could probably be empty
                            //The alternative would be to drop the points
                            trackpoint.IntervalTime = 1;
                        }
                    }
                    train.TrackPoints.Add(trackpoint);
                }
                train.TrackPointCount = (short)train.TrackPoints.Count;

                result.Add(train);
            }

            return(result);
        }
Example #7
0
        public static TrailResultInfo TrailResultInfoFromSplits(IActivity activity, bool onlyActiveLaps)
        {
            TrailResultInfo results = new TrailResultInfo(activity, false);

            if (activity == null)
            {
                //summary result
                return(results);
            }

            //Get around a problem with only Rest laps
            if (onlyActiveLaps)
            {
                onlyActiveLaps = false;
                for (int j = 0; j < activity.Laps.Count; j++)
                {
                    if (!activity.Laps[j].Rest)
                    {
                        onlyActiveLaps = true;
                        break;
                    }
                }
            }

            bool lastIsRestlap = false;

            if (null == activity.Laps || 0 == activity.Laps.Count)
            {
                //Use MovingDistanceMetersTrack rather than ActualDistanceMetersTrack, assume similar activities have similar pauses/slow parts
                IDistanceDataTrack track = ActivityInfoCache.Instance.GetInfo(activity).MovingDistanceMetersTrack;
                if (track != null && track.Max > 0)
                {
                    //Create some kind of points - could be dependent on length
                    const float cDist = 1000;
                    float       dist  = 0;
                    while (dist < track.Max)
                    {
                        DateTime  time = track.GetTimeAtDistanceMeters(dist);
                        IGPSPoint p    = Utils.TrackUtil.getGpsLoc(activity, time);
                        if (p != null)
                        {
                            results.Points.Add(new TrailResultPoint(new TrailGPSLocation(p), time));
                        }
                        else
                        {
                            if (activity.GPSRoute == null || activity.GPSRoute.Count == 0)
                            {
                                results.Points.Add(new TrailResultPoint(new TrailGPSLocation(activity.Name, true), time, track.TotalElapsedSeconds));
                            }
                            else
                            {
                                System.Diagnostics.Debug.Assert(false, "out of GPS");
                                if (results.Points.Count > 0)
                                {
                                    //end insert
                                    break;
                                }
                            }
                        }
                        dist = Math.Min(track.Max, dist + cDist);
                    }
                }
                else
                {
                    DateTime  time = ActivityInfoCache.Instance.GetInfo(activity).ActualTrackStart;
                    IGPSPoint p    = Utils.TrackUtil.getGpsLoc(activity, time);
                    if (p != null)
                    {
                        results.Points.Add(new TrailResultPoint(new TrailGPSLocation(p), time));
                    }
                }
            }
            else
            {
                int subresultIndex = 1;
                for (int j = 0; j < activity.Laps.Count; j++)
                {
                    ILapInfo l = activity.Laps[j];
                    if (!onlyActiveLaps || !l.Rest || j > 0 && !activity.Laps[j - 1].Rest)
                    {
                        string name = l.Notes;
                        if (string.IsNullOrEmpty(name))
                        {
                            name = "#" + (results.Points.Count + 1);
                        }
                        DateTime d = l.StartTime;
                        if (activity.GPSRoute == null || activity.GPSRoute.Count == 0)
                        {
                            results.Points.Add(new TrailResultPoint(new TrailGPSLocation(name, !l.Rest), d, l.TotalTime, l));
                        }
                        else
                        {
                            IGPSPoint t = Utils.TrackUtil.getGpsLoc(activity, d);
                            if (t != null)
                            {
                                results.Points.Add(new TrailResultPoint(new TrailGPSLocation(t, name, !l.Rest), d, l.TotalTime, l));
                            }
                        }
                        if (//All swim related have at least one PoolLength for each lap
                            l.PoolLengths != null && (l.PoolLengths.Count > 0))
                        {
                            TrailResultPoint tp = results.Points[results.Points.Count - 1];
                            foreach (IPoolLengthInfo p in l.PoolLengths)
                            {
                                DateTime        d2 = p.StartTime;
                                IPoolLengthInfo p1 = PoolLengthInfo.GetPoolLength(p);
                                tp.SubPoints.Add(new TrailResultPoint(new TrailGPSLocation(null, !l.Rest), d2, p.TotalTime, p1, subresultIndex++));
                            }
                            //Need (dummy) last point
                            IPoolLengthInfo p2 = tp.SubPoints[tp.SubPoints.Count - 1].PoolLengthInfo;
                            tp.SubPoints.Add(new TrailResultPoint(new TrailGPSLocation(null, !l.Rest), p2.StartTime + p2.TotalTime, TimeSpan.Zero, p2, subresultIndex));
                        }
                    }
                }
                lastIsRestlap = activity.Laps[activity.Laps.Count - 1].Rest;
            }

            //Add end point, except if last is a rest lap (where last already is added)
            if (!onlyActiveLaps || !lastIsRestlap)
            {
                DateTime d = ActivityInfoCache.Instance.GetInfo(activity).ActualTrackEnd;
                if (activity.GPSRoute == null || activity.GPSRoute.Count == 0)
                {
                    results.Points.Add(new TrailResultPoint(new TrailGPSLocation(activity.Name, !lastIsRestlap), d));
                }
                else
                {
                    IGPSPoint t = Utils.TrackUtil.getGpsLoc(activity, d);
                    if (t != null)
                    {
                        results.Points.Add(new TrailResultPoint(new TrailGPSLocation(t, activity.Name, !lastIsRestlap), d));
                    }
                }
            }

            //Special for activities without any GPS info
            if (results.Count == 0 && activity.HasStartTime)
            {
                results.Points.Add(new TrailResultPoint(new TrailGPSLocation(activity.Name, true), activity.StartTime));
                results.Points.Add(new TrailResultPoint(new TrailGPSLocation(activity.Name, true), activity.StartTime + activity.TotalTimeEntered));
            }

            //A trail created from splits should not define elevation points
            foreach (TrailGPSLocation t in results.Points)
            {
                t.SetElevation(float.NaN);
            }

            return(results);
        }
Example #8
0
        //Get a close enough point, not necessarily the closest or best match
        public int getClosePoint(IGPSPoint point)
        {
            IList<int> result = new List<int>();
            int x = (int)Math.Floor(point.LongitudeDegrees / m_lngWidth);
            int y = (int)Math.Floor(point.LatitudeDegrees / m_latWidth);
            foreach (int i in new int[] { x, x - 1, x + 1 })
            {
                if (m_Grid.ContainsKey(i))
                {
                    foreach (int j in new int[] { y, y - 1, y + 1 })
                    {
                        if (m_Grid[i].ContainsKey(j))
                        {
                            foreach (int p in m_Grid[i][j])
                            {
                                IGPSPoint pointInGrid = m_Route[p].Value;
                                double diffDist = point.DistanceMetersToPoint(pointInGrid);
                                if (diffDist < m_Distance)
                                {
                                    return p;
                                }
                            }
                        }
                    }
                }
            }

            return -1;
        }
Example #9
0
        //Get all points close to the asking point, but merge in "stretches" to let caller find best match
        public IList<IndexDiffDist> getAllCloseStretch(IGPSPoint point)
        {
            const int boxsize = 2;
            IList<IndexDiffDist> result = new List<IndexDiffDist>();
            int x = (int)Math.Floor(point.LongitudeDegrees / m_lngWidth);
            int y = (int)Math.Floor(point.LatitudeDegrees / m_latWidth);
            for (int i = x - boxsize; i <= x + boxsize; i++)
            {
                if (m_Grid.ContainsKey(i))
                {
                    for (int j = y - boxsize; j <= y + boxsize; j++)
                    {
                        if (m_Grid[i].ContainsKey(j))
                        {
                            foreach (int p in m_Grid[i][j])
                            {
                                IGPSPoint pointInGrid = m_Route[p].Value;
                                double diffDist = point.DistanceMetersToPoint(pointInGrid);
                                if (diffDist < m_Distance)
                                {
                                    double totDist = double.MaxValue;
                                    if (null != m_Dist)
                                    {
                                        totDist = m_Dist[p].Value;
                                    }
                                    IndexDiffDist t = new IndexDiffDist(p, p, p, diffDist, totDist);
                                    result.Add(t);
                                }
                            }
                        }
                    }
                }
            }

            //Group the results with local minimums in "stretches"
            //Only directly adjacent stretches are merged now, so single points out of the box will split stretches
            if (result.Count > 0)
            {
                for (int i = 0; i < result.Count; i++)
                {
                    for (int j = 0; j < result.Count; j++)
                    {
                        if (i != j && result[i].Index > -1 && result[j].Index > -1)
                        {
                            int k = Math.Min(i, j);
                            int l = Math.Max(i, j);
                            //Try merge with lower
                            if ((result[k].high + 1 >= result[l].low && result[k].high <= result[l].high) ||
                                Math.Abs(result[k].Dist - result[l].Dist) < m_Distance)
                            {
                                int tmp;
                                if (result[k].Diff < result[l].Diff)
                                {
                                    //Use lower also at equal
                                    tmp = k;
                                    result[l].Index = -1;
                                }
                                else
                                {
                                    tmp = l;
                                    result[k].Index = -1;
                                }
                                result[tmp].low = Math.Min(result[i].low, result[j].low);
                                result[tmp].high = Math.Max(result[i].high, result[j].high);
                            }
                        }
                    }
                }
                for (int i = result.Count-1; i >= 0; i--)
                {
                    if (result[i].Index == -1)
                    {
                        result.RemoveAt(i);
                    }
                }
            }
            return result;
        }
Example #10
0
        //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;
        }
Example #11
0
        protected void AddActivities(IImportResults importResults, IList <GlobalsatPacket.Train> trains, bool importSpeedTrackAsDistance, int detectPauses, int verbose)
        {
            foreach (GlobalsatPacket.Train train in trains)
            {
                DateTime  pointTime = train.StartTime;
                IActivity activity  = importResults.AddActivity(pointTime);
                activity.Metadata.Source            = string.Format(CommonResources.Text.Devices.ImportJob_ActivityImportSource, sourceDescription);
                activity.TotalTimeEntered           = train.TotalTime;
                activity.TotalDistanceMetersEntered = train.TotalDistanceMeters;
                activity.TotalCalories = train.TotalCalories;
                activity.MaximumHeartRatePerMinuteEntered = train.MaximumHeartRate;
                activity.AverageHeartRatePerMinuteEntered = train.AverageHeartRate;
                activity.MaximumCadencePerMinuteEntered   = train.MaximumCadence;
                activity.AverageCadencePerMinuteEntered   = train.AverageCadence;
                activity.MaximumPowerWattsEntered         = train.MaximumPower;
                activity.AveragePowerWattsEntered         = train.AveragePower;
                activity.TotalAscendMetersEntered         = train.TotalAscend;
                activity.TotalDescendMetersEntered        = -train.TotalDescend;
                activity.Notes += train.Comment;

                bool foundGPSPoint     = false;
                bool foundCadencePoint = false;
                bool foundPowerPoint   = false;

                activity.GPSRoute = new GPSRoute();
                activity.HeartRatePerMinuteTrack = new NumericTimeDataSeries();
                activity.CadencePerMinuteTrack   = new NumericTimeDataSeries();
                activity.PowerWattsTrack         = new NumericTimeDataSeries();
                activity.TemperatureCelsiusTrack = new NumericTimeDataSeries();
                activity.ElevationMetersTrack    = new NumericTimeDataSeries();
                activity.DistanceMetersTrack     = new DistanceDataTrack();

                float  pointDist    = 0;
                double pointElapsed = 0;
                //As interval to first is not zero, add point
                activity.DistanceMetersTrack.Add(pointTime, pointDist);

                //Fix for (GB-580 only?) recording problem with interval 10 or larger (in fw before 2012-09)
                double?fixInterval = null;
                if (train.TrackPoints.Count > 1)
                {
                    //All points except last has 0.1s interval
                    double testIntervall = (train.TotalTime.TotalSeconds - train.TrackPoints[train.TrackPoints.Count - 1].IntervalTime) / (train.TrackPointCount - 1 - 1);
                    if (testIntervall > 9.6)
                    {
                        fixInterval = testIntervall;
                    }
                }

                DateTime pointTimePrev    = System.DateTime.Now;
                DateTime pointTimeNext    = System.DateTime.Now;
                bool     insertPauseFirst = false;
                bool     insertPauseLast  = false;
                foreach (GhPacketBase.TrackPoint point in train.TrackPoints)
                {
                    double time = point.IntervalTime;
                    if (time < 0.11 && fixInterval != null)
                    {
                        time = (double)fixInterval;
                    }
                    pointElapsed += time;
                    //Note: There is an intervall time to the first point, also if TGP says it is 0
                    pointTime = pointTime.AddSeconds(time);

                    float dist = (float)(point.Speed * time);
                    pointDist += dist;

                    // TODO: How are GPS points indicated in indoor activities?
                    //It seems like all are the same
                    IGPSPoint gpsPoint = new GPSPoint((float)point.Latitude, (float)point.Longitude, point.Altitude);

                    //There are no pause markers in the Globalsat protocol
                    //Insert pauses when estimated/listed distance differs "too much"
                    //Guess pauses - no info of real pause, but this can at least be marked in the track
                    //Share setting with global split
                    if (foundGPSPoint && activity.GPSRoute.Count > 0)
                    {
                        //estimated time for the pause
                        double estimatedSec = 0;
                        string info         = "";

                        //speed & cadence method
                        if (detectPauses == 2 && !float.IsNaN(point.Cadence))
                        {
                            if (activity.GPSRoute.Count > 0)
                            {
                                float gpsDist = gpsPoint.DistanceMetersToPoint(activity.GPSRoute[activity.GPSRoute.Count - 1].Value);
                                //Some limit on when to include pause
                                //gpsDist must be higher than (all) GPS errors
                                if (point.Cadence == 0 && point.Speed == 0 && gpsDist > 0 && insertPauseFirst == false)
                                {
                                    insertPauseFirst = true;
                                    //We cannot know the true time for the expected pause, just set time between as pause to show on map
                                    estimatedSec  = time;
                                    pointTimePrev = pointTime;
                                }
                                else if (point.Cadence != 0 && point.Speed != 0 && insertPauseFirst)
                                {
                                    //last point
                                    insertPauseLast = true;
                                    pointTimeNext   = pointTime;
                                }
                            }

                            if (insertPauseLast)
                            {
                                insertPauseFirst = false;
                                insertPauseLast  = false;

                                //Only add rounded pauses, ST only handles complete seconds
                                activity.TimerPauses.Add(new ValueRange <DateTime>(
                                                             pointTimePrev.AddMilliseconds(-pointTimePrev.Millisecond),
                                                             pointTimeNext.AddMilliseconds(-pointTimeNext.Millisecond)));
                                if (verbose >= 10)
                                {
                                    //TODO: Remove remark when stable
                                    activity.Notes += string.Format("Added pause from {0} to {1} (dist:{2}, elapsedSec:{3} {4}) ",
                                                                    pointTimePrev.ToLocalTime(), pointTimeNext.ToLocalTime(), dist, pointTimeNext.Subtract(pointTimePrev).TotalSeconds, info) +
                                                      System.Environment.NewLine;
                                }
                            }
                        }
                        else if (detectPauses == 1)
                        {   //distance method
                            bool insertPause = false;
                            //how far from the first point
                            double perc = 0;

                            //This code previously had code to detect pauses from HR too
                            if (activity.GPSRoute.Count > 0)
                            {
                                float gpsDist = gpsPoint.DistanceMetersToPoint(activity.GPSRoute[activity.GPSRoute.Count - 1].Value);
                                //Some limit on when to include pause
                                //gpsDist must be higher than (all) GPS errors
                                if (gpsDist > 100 && gpsDist > 3 * dist)
                                {
                                    insertPause = true;
                                    //We cannot know the true time for the expected pause, just set time between as pause to show on map
                                    estimatedSec = time;

                                    if (gpsDist > 0)
                                    {
                                        perc = dist / gpsDist;
                                    }
                                    info += "gps: " + gpsDist;
                                }
                            }

                            if (insertPause)
                            {
                                //Use complete seconds only - pause is estimated, ST handles sec internally and this must be synced to laps
                                estimatedSec = Math.Round(estimatedSec);
                                IGPSPoint newPoint = (new GPSPoint.ValueInterpolator()).Interpolate(
                                    activity.GPSRoute[activity.GPSRoute.Count - 1].Value, gpsPoint, perc);

                                if (point == train.TrackPoints[train.TrackPoints.Count - 1])
                                {
                                    //Last point is incorrect, adjust (added normally)
                                    gpsPoint = newPoint;
                                }
                                else
                                {
                                    if (estimatedSec <= time + 1)
                                    {
                                        pointTimePrev = pointTime.AddSeconds(-time);
                                        pointTimeNext = pointTime;
                                    }
                                    else
                                    {
                                        //Add extra point
                                        activity.DistanceMetersTrack.Add(pointTime, pointDist);

                                        if (point.Latitude != 0 || point.Longitude != 0)
                                        {
                                            activity.GPSRoute.Add(pointTime, newPoint);
                                        }
                                        else if (device.FitnessDevice.HasElevationTrack && !float.IsNaN(newPoint.ElevationMeters))
                                        {
                                            activity.ElevationMetersTrack.Add(pointTime, newPoint.ElevationMeters);
                                        }
                                        pointTimePrev = pointTime;
                                        pointTimeNext = pointTime.AddSeconds((int)(estimatedSec - time));
                                        pointTime     = pointTimeNext;
                                    }
                                    //Only add rounded pauses, ST only handles complete seconds
                                    activity.TimerPauses.Add(new ValueRange <DateTime>(
                                                                 pointTimePrev.AddMilliseconds(-pointTimePrev.Millisecond + 1000),
                                                                 pointTimeNext.AddMilliseconds(-pointTimeNext.Millisecond - 9000)));
                                    if (verbose >= 10)
                                    {
                                        //TODO: Remove remark when stable
                                        activity.Notes += string.Format("Added pause from {0} to {1} (dist:{2}, elapsedSec:{3}, per:{4} {5}) ",
                                                                        pointTimePrev.ToLocalTime(), pointTimeNext.ToLocalTime(), dist, time, perc, info) +
                                                          System.Environment.NewLine;
                                    }
                                }
                            }
                        }
                    }
                    activity.DistanceMetersTrack.Add(pointTime, pointDist);

                    //lat/lon is 0 if a device has never had a fix
                    if (point.Latitude != 0 || point.Longitude != 0)
                    {
                        activity.GPSRoute.Add(pointTime, gpsPoint);

                        //Check if lat/lon ever change (ignore altitude), GlobalSat reports last known location without a fix
                        if (point.Latitude != train.TrackPoints[0].Latitude || point.Longitude != train.TrackPoints[0].Longitude)
                        {
                            foundGPSPoint = true;
                        }
                    }
                    if (device.FitnessDevice.HasElevationTrack && !float.IsNaN(point.Altitude))
                    {
                        activity.ElevationMetersTrack.Add(pointTime, point.Altitude);
                    }

                    //zero HR is invalid reading - drop
                    if (point.HeartRate > 0)
                    {
                        activity.HeartRatePerMinuteTrack.Add(pointTime, point.HeartRate);
                    }

                    //Zero Cadence/Power may be valid values, if there are any values (no way to detect lost communication)
                    activity.CadencePerMinuteTrack.Add(pointTime, point.Cadence);
                    if (point.Cadence > 0)
                    {
                        foundCadencePoint = true;
                    }

                    activity.PowerWattsTrack.Add(pointTime, point.Power);
                    if (point.Power > 0)
                    {
                        foundPowerPoint = true;
                    }

                    if (point.Temperature != 0x7fff)
                    {
                        activity.TemperatureCelsiusTrack.Add(pointTime, point.Temperature / 10.0F);
                    }
                }

                TimeSpan lapElapsed    = TimeSpan.Zero;
                int      totalDistance = 0;
                foreach (GlobalsatPacket.Lap lapPacket in train.Laps)
                {
                    DateTime lapTime = ZoneFiveSoftware.Common.Data.Algorithm.DateTimeRangeSeries.AddTimeAndPauses(activity.StartTime, lapElapsed, activity.TimerPauses);
                    lapElapsed += lapPacket.LapTime; //Same as lapPacket.EndTime for unpaused
                    ILapInfo lap = activity.Laps.Add(lapTime, lapPacket.LapTime);
                    //Adding Distance would previously make ST fail to add new laps. The distance is needed only when there is no GPS (Markers added)
                    if (activity.TotalDistanceMetersEntered > 0)
                    {
                        lap.TotalDistanceMeters = lapPacket.LapDistanceMeters;
                    }
                    if (lapPacket.LapCalories > 0)
                    {
                        lap.TotalCalories = lapPacket.LapCalories;
                    }
                    if (lapPacket.AverageHeartRate > 0)
                    {
                        lap.AverageHeartRatePerMinute = lapPacket.AverageHeartRate;
                    }
                    if (lapPacket.AverageCadence > 0)
                    {
                        lap.AverageCadencePerMinute = lapPacket.AverageCadence;
                    }
                    if (lapPacket.AveragePower > 0)
                    {
                        lap.AveragePowerWatts = lapPacket.AveragePower;
                    }
                    if (!foundGPSPoint && activity.ElevationMetersTrack != null && activity.ElevationMetersTrack.Count > 1)
                    {
                        //Limitation in ST: lap elevation not auto calc without GPS, lap preferred to elevation
                        DateTime lapEnd            = ZoneFiveSoftware.Common.Data.Algorithm.DateTimeRangeSeries.AddTimeAndPauses(activity.StartTime, lapElapsed, activity.TimerPauses);
                        ITimeValueEntry <float> p1 = activity.ElevationMetersTrack.GetInterpolatedValue(lapTime);
                        ITimeValueEntry <float> p2 = activity.ElevationMetersTrack.GetInterpolatedValue(lapEnd);
                        if (p1 != null && p2 != null)
                        {
                            lap.ElevationChangeMeters = p2.Value - p1.Value;
                        }
                    }
                    if (verbose >= 5)
                    {
                        //TODO: Localise outputs?
                        lap.Notes = string.Format("MaxSpeed:{0:0.##}m/s MaxHr:{1} MinAlt:{2}m MaxAlt:{3}m",
                                                  lapPacket.MaximumSpeed, lapPacket.MaximumHeartRate, lapPacket.MinimumAltitude, lapPacket.MaximumAltitude);
                        //Not adding Power/Cadence - not available
                        //lap.Notes = string.Format("MaxSpeed={0} MaxHr={1} MinAlt={2} MaxAlt={3} MaxCadence={4} MaxPower={5}",
                        //    lapPacket.MaximumSpeed, lapPacket.MaximumHeartRate, lapPacket.MinimumAltitude, lapPacket.MaximumAltitude, lapPacket.MaximumCadence, lapPacket.MaximumPower);
                    }
                    //Add distance markers from Globalsat. Will for sure be incorrect after pause insertion
                    totalDistance += lapPacket.LapDistanceMeters;
                    activity.DistanceMarkersMeters.Add(totalDistance);
                }

                if (!foundGPSPoint)
                {
                    if (activity.GPSRoute.Count > 0)
                    {
                        activity.Notes += string.Format("No GPS. Last known latitude:{0}, longitude:{1}",
                                                        activity.GPSRoute[0].Value.LatitudeDegrees, activity.GPSRoute[0].Value.LongitudeDegrees);
                    }
                    activity.GPSRoute = null;
                }
                //Keep elevation only if the device (may) record elevation separately from GPS
                //It may be used also if the user drops GPS if points have been recorded.
                //(ST may have partial use of elevation together with GPS on other parts in the future?)
                if (!device.FitnessDevice.HasElevationTrack || activity.ElevationMetersTrack.Count == 0)
                {
                    activity.ElevationMetersTrack = null;
                }

                //Barometric devices occasionally have bad points last
                if (activity.ElevationMetersTrack != null && activity.ElevationMetersTrack.Count > 1 &&
                    Math.Abs(activity.ElevationMetersTrack[activity.ElevationMetersTrack.Count - 1].Value -
                             activity.ElevationMetersTrack[activity.ElevationMetersTrack.Count - 2].Value) > 1)
                {
                    if (activity.GPSRoute != null &&
                        activity.ElevationMetersTrack.StartTime.AddSeconds(activity.ElevationMetersTrack.TotalElapsedSeconds) ==
                        activity.GPSRoute.StartTime.AddSeconds(activity.GPSRoute.TotalElapsedSeconds))
                    {
                        IGPSPoint g = activity.GPSRoute[activity.GPSRoute.Count - 1].Value;
                        activity.GPSRoute.SetValueAt(activity.GPSRoute.Count - 1, new GPSPoint(g.LatitudeDegrees, g.LongitudeDegrees, float.NaN));
                    }
                    activity.ElevationMetersTrack.RemoveAt(activity.ElevationMetersTrack.Count - 1);
                }
                if (activity.HeartRatePerMinuteTrack.Count == 0)
                {
                    activity.HeartRatePerMinuteTrack = null;
                }
                if (!foundCadencePoint)
                {
                    activity.CadencePerMinuteTrack = null;
                }
                if (!foundPowerPoint)
                {
                    activity.PowerWattsTrack = null;
                }
                if (activity.TemperatureCelsiusTrack.Count == 0)
                {
                    activity.TemperatureCelsiusTrack = null;
                }
                if (pointDist == 0 || !importSpeedTrackAsDistance && foundGPSPoint)
                {
                    activity.DistanceMetersTrack = null;
                }
#if DISTANCETRACK_FIX
                //attempt to fix import of distance track in 3.1.4515 - to be updated when rereleased
                //for now import distance track, to keep compatibility(?)
                try
                {
                    activity.CalcSpeedFromDistanceTrack = importSpeedTrackAsDistance;
                }
                catch
                {
                    //older than 3.1.4515, disable
                    if (!importSpeedTrackAsDistance && !foundGPSPoint)
                    {
                        activity.DistanceMetersTrack = null;
                    }
                }
#endif
            }
        }
Example #12
0
		public static IGPSLocation PointToLocation(IGPSPoint point) {
			return new GPSLocation(point.LatitudeDegrees, point.LongitudeDegrees);
		}
		public float DistanceMetersToPoint(IGPSPoint point) {
			GPSPoint thisPoint = new GPSPoint(
				this.LatitudeDegrees,
				this.LongitudeDegrees,
				0);
            if (point == null)
            {
                return float.MaxValue;
            }
			return point.DistanceMetersToPoint(thisPoint);
		}
Example #14
0
 public TrailGPSLocation(IGPSPoint gpsLoc) :
     this(gpsLoc, "", true)
 {
 }
Example #15
0
 public TrailGPSLocation(IGPSPoint gpsLoc, string name, bool required)
     : this(gpsLoc.LatitudeDegrees, gpsLoc.LongitudeDegrees, gpsLoc.ElevationMeters, name, required, defaultRadius)
 {
 }
Example #16
0
        public static float checkPass(float radius, IGPSPoint r1, float dt1, IGPSPoint r2, float dt2, TrailGPSLocation trailp, out float d)
        {
#if SQUARE_DISTANCE
            const int sqrt2 = 2;
#else
            //Optimise, accuracy is down to percent
            const float sqrt2 = 1.4142135623730950488016887242097F;
#endif
            d = float.MaxValue;
            float factor = -1;
            if (r1 == null || r2 == null || trailp == null)
            {
                return(factor);
            }

            //Check if the line goes via the "circle" if the sign changes
            //Also need to check close points that fit in a 45 deg tilted "square" where sign may not change

            //Optimise for all conditions tested - property access takes some time
            float tplat = trailp.latitudeDegrees;
            float tplon = trailp.longitudeDegrees;
            float r1lat = r1.LatitudeDegrees;
            float r1lon = r1.LongitudeDegrees;
            float r2lat = r2.LatitudeDegrees;
            float r2lon = r2.LongitudeDegrees;
            if (r1lat > tplat && r2lat < tplat ||
                r1lat < tplat && r2lat > tplat ||
                r1lon > tplon && r2lon < tplon ||
                r1lon < tplon && r2lon > tplon ||
                dt1 < radius * sqrt2 && dt2 < radius * sqrt2)
            {
                //Law of cosines - get a1, angle at r1, the first point
                float d12 = TrailGPSLocation.DistanceMetersToPointGpsSimple(r1, r2);
#if SQUARE_DISTANCE
                float a1_0 = (float)((dt1 + d12 - dt2) / (2 * Math.Sqrt(dt1 * d12)));
#else
                float a1_0 = (dt1 * dt1 + d12 * d12 - dt2 * dt2) / (2 * dt1 * d12);
#endif

                //Point is in circle if closest point is between r1&r2 and it is in circle (neither r1 nor r2 is)
                //This means the angle a1 must be +/- 90 degrees : cos(a1)>=0
                if (a1_0 > -0.001)
                {
                    //Rounding errors w GPS measurements
                    a1_0 = Math.Min(a1_0, 1);
                    a1_0 = Math.Max(a1_0, -1);
                    float a1 = (float)Math.Acos(a1_0);
                    //x is closest point to t on r1-r2
                    //Dist from r1 to x
                    float d1x = (float)Math.Abs(dt1 * a1_0); //a1_0 = (float)Math.Cos(a1);
                    //Dist from t1 to x
                    float dtx = dt1 * (float)Math.Sin(a1);
                    if (d1x < d12 && dtx < radius)
                    {
                        d      = dtx;
                        factor = (float)(d1x / d12);
                        //Return factor, to return best aproximation from r1
                    }
                }
            }
            return(factor);
        }