Example #1
0
 /// <summary>
 /// Copy constructor.
 /// </summary>
 /// <param name="i"></param>
 public Interval(Interval i)
 {
     start = i.start;
       end = i.end;
 }
Example #2
0
 public bool Equals(Interval obj)
 {
     if (ReferenceEquals(null, obj)) return false;
       if (ReferenceEquals(this, obj)) return true;
       return obj.start == start && obj.end == end;
 }
Example #3
0
        public double CalculateSpeedPercentualStandardDeviation(ParameterizedLocation start, ParameterizedLocation end,
            Interval slidingAverageInterval)
        {
            // first collect all waypoints
              var nodes = new List<Pair<ParameterizedLocation, Waypoint>>();
              ParameterizedLocation adjustedStart = GetParameterizedLocationOfNextWaypoint(start, false);
              ParameterizedLocation adjustedEnd = GetParameterizedLocationOfPreviousWaypoint(end, false);
              var pl = new ParameterizedLocation(adjustedStart);

              if (!start.IsNode)
            nodes.Add(new Pair<ParameterizedLocation, Waypoint>(start, CreateWaypointFromParameterizedLocation(start)));
              while (pl != null && pl <= adjustedEnd)
              {
            if (pl.Value > segments[pl.SegmentIndex].Waypoints.Count - 1)
            {
              pl.SegmentIndex++;
              pl.Value = 0;
            }
            nodes.Add(new Pair<ParameterizedLocation, Waypoint>(pl, GetClosestWaypointFromParameterizedLocation(pl)));
            pl = GetNextPLNode(pl, ParameterizedLocation.Direction.Forward);
              }
              if (!end.IsNode)
            nodes.Add(new Pair<ParameterizedLocation, Waypoint>(end, CreateWaypointFromParameterizedLocation(end)));

              var speeds = new List<StatisticsUtil.WeightedItem>();
              if (slidingAverageInterval.Length == 0)
              {
            double elapsedTime = GetAttributeFromParameterizedLocation(WaypointAttribute.ElapsedTime, LastPL).Value;
            double meanSpeed = (GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, LastPL).Value - GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, FirstPL).Value) /
                           (elapsedTime == 0 ? 0 : elapsedTime);
            for (int i = 0; i < nodes.Count; i++)
            {
              ParameterizedLocation p = nodes[i].First;
              Waypoint w = nodes[i].Second;
              double beforeWeight = (i == 0 || IsFirstPLInSegment(p)
                                   ? 0
                                   : (double)(w.Time.Ticks - nodes[i - 1].Second.Time.Ticks) / TimeSpan.TicksPerSecond / 2);
              double afterWeight = (i == nodes.Count - 1 || IsLastPLInSegment(p)
                                  ? 0
                                  : (double)(nodes[i + 1].Second.Time.Ticks - w.Time.Ticks) / TimeSpan.TicksPerSecond / 2);
              speeds.Add(
            new StatisticsUtil.WeightedItem(
              beforeWeight + afterWeight,
              (meanSpeed == 0 ? 0 : segments[p.SegmentIndex].Waypoints[(int)p.Value].Attributes[WaypointAttribute.Speed].Value / meanSpeed)
              )
            );
            }
              }
              else
              {
            ParameterizedLocation siStartPL =
              GetParameterizedLocationFromTime(nodes[0].Second.Time.AddSeconds(slidingAverageInterval.Start));
            ParameterizedLocation siEndPL =
              GetParameterizedLocationFromTime(nodes[0].Second.Time.AddSeconds(slidingAverageInterval.End));
            for (int i = 0; i < nodes.Count; i++)
            {
              // start of sliding interval
              siStartPL =
            GetParameterizedLocationFromTime(nodes[i].Second.Time.AddSeconds(slidingAverageInterval.Start), siStartPL,
                                             ParameterizedLocation.Direction.Forward);
              // end of sliding interval
              siEndPL =
            GetParameterizedLocationFromTime(nodes[i].Second.Time.AddSeconds(slidingAverageInterval.End), siEndPL,
                                             ParameterizedLocation.Direction.Forward);
              if (siStartPL != null && siEndPL != null)
              {
            if (siStartPL.SegmentIndex < nodes[i].First.SegmentIndex)
              siStartPL = new ParameterizedLocation(nodes[i].First.SegmentIndex, 0);
            if (siEndPL.SegmentIndex > nodes[i].First.SegmentIndex)
              siEndPL = new ParameterizedLocation(nodes[i].First.SegmentIndex,
                                                  segments[nodes[i].First.SegmentIndex].Waypoints.Count - 1);
            ParameterizedLocation p = nodes[i].First;
            Waypoint w = nodes[i].Second;
            double siStartDistance = GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, siStartPL).Value;
            double siEndDistance = GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, siEndPL).Value;
            double siLength =
              GetTimeFromParameterizedLocation(siEndPL).Subtract(GetTimeFromParameterizedLocation(siStartPL)).
                TotalSeconds;
            double meanSpeed = (siLength == 0 ? 0 : (siEndDistance - siStartDistance) / siLength);

            double beforeWeight = (i == 0 || IsFirstPLInSegment(p)
                                     ? 0
                                     : (double)(w.Time.Ticks - nodes[i - 1].Second.Time.Ticks) / TimeSpan.TicksPerSecond /
                                       2);
            double afterWeight = (i == nodes.Count - 1 || IsLastPLInSegment(p)
                                    ? 0
                                    : (double)(nodes[i + 1].Second.Time.Ticks - w.Time.Ticks) / TimeSpan.TicksPerSecond / 2);
            speeds.Add(new StatisticsUtil.WeightedItem((beforeWeight + afterWeight),
                                                       (meanSpeed == 0 ? 0 : w.Attributes[WaypointAttribute.Speed].Value / meanSpeed)));
              }
            }
              }
              return StatisticsUtil.GetStandardDeviation(speeds);
        }
Example #4
0
 /// <summary>
 /// Calculates speeds and paces.
 /// </summary>
 private void CalculateSpeeds()
 {
     // using optimized but hard-to-understand algorithm
       var actualInterval = new Interval(SmoothingIntervals[WaypointAttribute.Speed]);
       if (actualInterval.Length == 0)
       {
     // need to have non-zero smothing interval when calculating speed, set it to a millisecond
     var center = actualInterval.Start;
     actualInterval = new Interval(center - 0.0005, center + 0.0005);
       }
       ParameterizedLocation siStartPL =
     GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(actualInterval.Start));
       ParameterizedLocation siEndPL = GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(actualInterval.End));
       for (int i = 0; i < segments.Count; i++)
       {
     for (int j = 0; j < segments[i].Waypoints.Count; j++)
     {
       Waypoint w = segments[i].Waypoints[j];
       // start of sliding interval
       siStartPL =
     GetParameterizedLocationFromTime(w.Time.AddSeconds(actualInterval.Start), siStartPL,
                                      ParameterizedLocation.Direction.Forward);
       // end of sliding interval
       siEndPL =
     GetParameterizedLocationFromTime(w.Time.AddSeconds(actualInterval.End), siEndPL,
                                      ParameterizedLocation.Direction.Forward);
       if (siStartPL != null && siEndPL != null)
       {
     if (siStartPL.SegmentIndex < i) siStartPL = new ParameterizedLocation(i, 0);
     if (siEndPL.SegmentIndex > i) siEndPL = new ParameterizedLocation(i, segments[i].Waypoints.Count - 1);
     double siStartDistance = GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, siStartPL).Value;
     double siEndDistance = GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, siEndPL).Value;
     double siLength = (GetTimeFromParameterizedLocation(siEndPL) - GetTimeFromParameterizedLocation(siStartPL)).TotalSeconds;
     w.Attributes[WaypointAttribute.Speed] = (siLength == 0 ? 0 : 3.6 * (siEndDistance - siStartDistance) / siLength);
       }
       else
       {
     w.Attributes[WaypointAttribute.Speed] = 0;
       }
       w.Attributes[WaypointAttribute.Pace] = ConvertUtil.ToPace(w.Attributes[WaypointAttribute.Speed].Value).TotalSeconds;
     }
       }
 }
Example #5
0
        private void CalculateSlidingAverageAttributes(WaypointAttribute attribute, Interval smoothingInterval)
        {
            // using optimized but hard-to-understand algorithm
              if (attribute != WaypointAttribute.HeartRate && attribute != WaypointAttribute.Altitude) throw new ArgumentException("The 'attribute' parameter must be either WaypointAttribute.HeartRate or WaypointAttribute.Altitude");

              bool zeroLengthInterval = smoothingInterval.Length == 0;
              bool containsAttribute = ContainsWaypointAttribute(attribute);

              ParameterizedLocation siStartPL = null;
              ParameterizedLocation siEndPL = null;
              if (!zeroLengthInterval)
              {
            siStartPL = GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(smoothingInterval.Start));
            siEndPL = GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(smoothingInterval.End));
              }
              for (int i = 0; i < segments.Count; i++)
              {
            double[] valueSums = null;
            bool[] valueIsSet = null;
            DateTime[] valueTimes = null;
            var nullValueFound = false;
            if (containsAttribute && !zeroLengthInterval)
            {
              valueSums = new double[segments[i].Waypoints.Count];
              valueIsSet = new bool[segments[i].Waypoints.Count];
              valueTimes = new DateTime[segments[i].Waypoints.Count];
              valueSums[0] = 0;
              if (segments[i].Waypoints.Count > 0)
              {
            valueIsSet[0] = segments[i].Waypoints[0].GetOriginalAttribute(attribute).HasValue;
            valueTimes[0] = segments[i].Waypoints[0].Time;
            nullValueFound = !valueIsSet[0];
              }
              for (int j = 1; j < segments[i].Waypoints.Count; j++)
              {
            var previousWaypoint = segments[i].Waypoints[j - 1];
            var thisWaypoint = segments[i].Waypoints[j];
            var previousOriginalAttribute = previousWaypoint.GetOriginalAttribute(attribute);
            var thisOriginalAttribute = thisWaypoint.GetOriginalAttribute(attribute);
            valueIsSet[j] = thisOriginalAttribute.HasValue;
            valueTimes[j] = thisWaypoint.Time;
            nullValueFound = nullValueFound || !valueIsSet[j];
            if (valueIsSet[j - 1] && valueIsSet[j])
            {
              valueSums[j] = valueSums[j - 1] +
                             (valueTimes[j] - valueTimes[j - 1]).TotalSeconds *
                             (previousOriginalAttribute.Value + thisOriginalAttribute.Value) / 2;
            }
            else
            {
              valueSums[j] = valueSums[j - 1];
            }
              }
            }

            for (int j = 0; j < segments[i].Waypoints.Count; j++)
            {
              Waypoint w = segments[i].Waypoints[j];
              if (!containsAttribute)
              {
            w.Attributes[attribute] = null;
              }
              else if (zeroLengthInterval)
              {
            w.Attributes[attribute] = w.GetOriginalAttribute(attribute);
              }
              else
              {
            // start of sliding interval
            siStartPL =
              GetParameterizedLocationFromTime(w.Time.AddSeconds(smoothingInterval.Start), siStartPL,
                                               ParameterizedLocation.Direction.Forward);
            // end of sliding interval
            siEndPL =
              GetParameterizedLocationFromTime(w.Time.AddSeconds(smoothingInterval.End), siEndPL,
                                               ParameterizedLocation.Direction.Forward);
            if (siStartPL != null && siEndPL != null)
            {
              if (siStartPL.SegmentIndex < i) siStartPL = new ParameterizedLocation(i, 0);
              if (siEndPL.SegmentIndex > i) siEndPL = new ParameterizedLocation(i, segments[i].Waypoints.Count - 1);

              double startSum;
              double endSum;
              var adjustedIntervalLength = (GetTimeFromParameterizedLocation(siEndPL) - GetTimeFromParameterizedLocation(siStartPL)).TotalSeconds;
              int startIndex;
              int endIndex;
              if (siStartPL.IsNode)
              {
                startSum = valueSums[(int)siStartPL.Value];
                startIndex = (int)siStartPL.Value;
              }
              else
              {
                var d = siStartPL.Value - Math.Floor(siStartPL.Value);
                startSum = (1 - d) * valueSums[(int)siStartPL.Value] + d * valueSums[(int)siStartPL.Value + 1];
                startIndex = (int)siStartPL.Value;
              }
              if (siEndPL.IsNode)
              {
                endSum = valueSums[(int)siEndPL.Value];
                endIndex = (int)siEndPL.Value;
              }
              else
              {
                var d = siEndPL.Value - Math.Floor(siEndPL.Value);
                endSum = (1 - d) * valueSums[(int)siEndPL.Value] + d * valueSums[(int)siEndPL.Value + 1];
                endIndex = (int)siEndPL.Value + 1;
              }

              if (adjustedIntervalLength == 0)
              {
                w.Attributes[attribute] = w.GetOriginalAttribute(attribute);
              }
              else
              {
                // check if there are any null values in this interval
                bool nullValueFoundInInterval;
                if (!nullValueFound)
                {
                  // no null value in whole route, don't need to check this interval
                  nullValueFoundInInterval = false;
                }
                else
                {
                  // there is at least one null value in the route, need to check if there exists any in this interval
                  nullValueFoundInInterval = false;
                  for (var k = startIndex; k <= endIndex; k++)
                  {
                    if (!valueIsSet[k])
                    {
                      nullValueFoundInInterval = true;
                      break;
                    }
                  }
                }
                if (!nullValueFoundInInterval)
                {
                  // no null values in this interval, perform normal calculation
                  w.Attributes[attribute] = (endSum - startSum) / adjustedIntervalLength;
                }
                else
                {
                  // null value found, calculate based on each non-null value waypoint pair
                  adjustedIntervalLength = 0;
                  double sum = 0;
                  for (var k = startIndex; k < endIndex; k++)
                  {
                    if (valueIsSet[k] && valueIsSet[k + 1])
                    {
                      double start = Math.Max(k, siStartPL.Value);
                      double end = Math.Min(k + 1, siEndPL.Value);
                      adjustedIntervalLength += (end - start) * (valueTimes[k + 1] - valueTimes[k]).TotalSeconds;
                      sum += (end - start) * (valueSums[k + 1] - valueSums[k]);
                    }
                  }
                  w.Attributes[attribute] = (adjustedIntervalLength == 0 ? (double?)null : sum / adjustedIntervalLength);
                }
              }
            }
            else
            {
              w.Attributes[attribute] = null;
            }
              }
            }
              }
        }
Example #6
0
        private void CalculateInclinations()
        {
            var containsAltitude = ContainsWaypointAttribute(WaypointAttribute.Altitude);
              var altitudeSmoothingInterval = new Interval(-0.005, 0.005);
              var distanceSmoothingInterval = SmoothingIntervals[WaypointAttribute.Altitude];
              if (distanceSmoothingInterval.Length == 0) distanceSmoothingInterval = altitudeSmoothingInterval;

              for (int i = 0; i < segments.Count; i++)
              {
            for (int j = 0; j < segments[i].Waypoints.Count; j++)
            {
              var waypoint = segments[i].Waypoints[j];
              if (containsAltitude)
              {
            var pl = new ParameterizedLocation(i, j);
            var startDirection = altitudeSmoothingInterval.Start < 0
                                   ? ParameterizedLocation.Direction.Backward
                                   : ParameterizedLocation.Direction.Forward;
            var endDirection = altitudeSmoothingInterval.End < 0
                                 ? ParameterizedLocation.Direction.Backward
                                 : ParameterizedLocation.Direction.Forward;

            // altitude calculations
            var altitudeStartTime = waypoint.Time.AddSeconds(altitudeSmoothingInterval.Start);
            var altitudeEndTime = waypoint.Time.AddSeconds(altitudeSmoothingInterval.End);
            var altitudeStartPL = GetParameterizedLocationFromTime(altitudeStartTime, pl, startDirection);
            var altitudeEndPL = GetParameterizedLocationFromTime(altitudeEndTime, pl, endDirection);
            if (altitudeStartPL.SegmentIndex < i)
            {
              altitudeStartPL = new ParameterizedLocation(i, 0);
              altitudeStartTime = segments[i].FirstWaypoint.Time;
            }
            if (altitudeEndPL.SegmentIndex > i)
            {
              altitudeEndPL = new ParameterizedLocation(i, segments[i].Waypoints.Count - 1);
              altitudeEndTime = segments[i].LastWaypoint.Time;
            }
            var altitudeDifference = GetAttributeFromParameterizedLocation(WaypointAttribute.Altitude, altitudeEndPL) -
                                     GetAttributeFromParameterizedLocation(WaypointAttribute.Altitude, altitudeStartPL);
            var altitudeDuration = (altitudeEndTime - altitudeStartTime).TotalSeconds;

            // distance calculations
            var distanceStartTime = waypoint.Time.AddSeconds(distanceSmoothingInterval.Start);
            var distanceEndTime = waypoint.Time.AddSeconds(distanceSmoothingInterval.End);
            var distanceStartPL = GetParameterizedLocationFromTime(distanceStartTime, pl, startDirection);
            var distanceEndPL = GetParameterizedLocationFromTime(distanceEndTime, pl, endDirection);
            if (distanceStartPL.SegmentIndex < i)
            {
              distanceStartPL = new ParameterizedLocation(i, 0);
              distanceStartTime = segments[i].FirstWaypoint.Time;
            }
            if (distanceEndPL.SegmentIndex > i)
            {
              distanceEndPL = new ParameterizedLocation(i, segments[i].Waypoints.Count - 1);
              distanceEndTime = segments[i].LastWaypoint.Time;
            }
            var distanceDifference = GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, distanceEndPL) -
                                     GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, distanceStartPL);
            var distanceDuration = (distanceEndTime - distanceStartTime).TotalSeconds;

            // calculate the inclination
            if (!distanceDifference.HasValue || !altitudeDifference.HasValue)
            {
              waypoint.Attributes[WaypointAttribute.Inclination] = null;
            }
            else if (altitudeDuration == 0 || distanceDuration == 0)
            {
              waypoint.Attributes[WaypointAttribute.Inclination] = 0;
            }
            else
            {
              waypoint.Attributes[WaypointAttribute.Inclination] = LinearAlgebraUtil.ToDegrees(Math.Atan2(altitudeDifference.Value / altitudeDuration, distanceDifference.Value / distanceDuration));
            }
              }
              else
              {
            waypoint.Attributes[WaypointAttribute.Inclination] = null;
              }
            }
              }
        }
Example #7
0
        private void CalculateDirectionDeviationsToNextLap()
        {
            if (lapTimes.Count >= 2)
              {
            int lapIndex = 0;
            var lapStartPL = GetParameterizedLocationFromTime(lapTimes[lapIndex]);
            var lapEndPL = GetParameterizedLocationFromTime(lapTimes[lapIndex + 1]);
            // using optimized but hard-to-understand algorithm
            var actualInterval = new Interval(SmoothingIntervals[WaypointAttribute.DirectionDeviationToNextLap]);
            if (actualInterval.Length == 0)
            {
              // need to have non-zero smothing interval when calculating direction vectors, set it to a millisecond
              var center = actualInterval.Start;
              actualInterval = new Interval(center - 0.0005, center + 0.0005);
            }
            ParameterizedLocation siStartPL =
              GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(actualInterval.Start));
            ParameterizedLocation siEndPL =
              GetParameterizedLocationFromTime(FirstWaypoint.Time.AddSeconds(actualInterval.End));
            for (int i = 0; i < segments.Count; i++)
            {
              // 1. calculate the direction angles in this segment, taking laps into account (never consider positions outside current lap)
              var directionAngles = new double[segments[i].Waypoints.Count];
              var startLapIndexInThisSegment = lapIndex;
              var lapStartPLInThisSegment = GetParameterizedLocationFromTime(lapTimes[lapIndex]);
              var lapEndPLInThisSegment = GetParameterizedLocationFromTime(lapTimes[lapIndex + 1]);
              for (int j = 0; j < segments[i].Waypoints.Count; j++)
              {
            Waypoint w = segments[i].Waypoints[j];
            while (w.Time.ToUniversalTime() > lapTimes[lapIndex].ToUniversalTime() && lapIndex < lapTimes.Count - 1)
            {
              lapIndex++;
              lapStartPL = GetParameterizedLocationFromTime(lapTimes[lapIndex - 1]);
              lapEndPL = GetParameterizedLocationFromTime(lapTimes[lapIndex]);
            }

            // start of sliding interval
            siStartPL =
              GetParameterizedLocationFromTime(w.Time.AddSeconds(actualInterval.Start), siStartPL,
                                               ParameterizedLocation.Direction.Forward);
            // end of sliding interval
            siEndPL =
              GetParameterizedLocationFromTime(w.Time.AddSeconds(actualInterval.End), siEndPL,
                                               ParameterizedLocation.Direction.Forward);
            if (siStartPL != null && siEndPL != null)
            {
              if (siStartPL.SegmentIndex < i) siStartPL = new ParameterizedLocation(i, 0);
              if (siEndPL.SegmentIndex > i) siEndPL = new ParameterizedLocation(i, segments[i].Waypoints.Count - 1);
              if (siStartPL < lapStartPL) siStartPL = new ParameterizedLocation(lapStartPL);
              if (siEndPL > lapEndPL) siEndPL = new ParameterizedLocation(lapEndPL);
              var siStartLocation = GetLocationFromParameterizedLocation(siStartPL);
              var siEndLocation = GetLocationFromParameterizedLocation(siEndPL);
              var middle = (siStartLocation / 2 + siEndLocation / 2);
              var p0 = siStartLocation.Project(middle);
              var p1 = siEndLocation.Project(middle);
              directionAngles[j] = LinearAlgebraUtil.GetAngleD(LinearAlgebraUtil.Normalize(p1 - p0));
            }
            else
            {
              directionAngles[j] = 0;
            }
              }

              // 2. calculate the directions and direction deviations based on values achieved in step 1
              lapIndex = startLapIndexInThisSegment;
              lapStartPL = lapStartPLInThisSegment;
              lapEndPL = lapEndPLInThisSegment;
              var lapLongLat = GetLocationFromParameterizedLocation(GetParameterizedLocationFromTime(lapTimes[lapIndex + 1]));
              for (int j = 0; j < segments[i].Waypoints.Count; j++)
              {
            Waypoint w = segments[i].Waypoints[j];

            // direction (clockwise from north: n = 0, e = 90, s = 180, w = 270)
            var direction = -directionAngles[j] + 90;
            if (direction < 0) direction += 360;
            w.Attributes[WaypointAttribute.Direction] = direction;

            // direction deviation to next lap
            while (w.Time.ToUniversalTime() > lapTimes[lapIndex].ToUniversalTime() && lapIndex < lapTimes.Count - 1)
            {
              lapIndex++;
              lapLongLat = GetLocationFromParameterizedLocation(GetParameterizedLocationFromTime(lapTimes[lapIndex]));
            }
            LongLat middle = (w.LongLat / 2 + lapLongLat / 2);
            PointD p0 = w.LongLat.Project(middle);
            PointD p1 = lapLongLat.Project(middle);
            PointD directionVectorToNextLap = LinearAlgebraUtil.Normalize(p1 - p0);
            w.Attributes[WaypointAttribute.DirectionDeviationToNextLap] = Math.Abs(LinearAlgebraUtil.GetAngleD(directionVectorToNextLap, LinearAlgebraUtil.CreateNormalizedVectorFromAngleD(directionAngles[j])));
              }
            }
              }
        }