public TelemetryStoryboard Create(LapTelemetryDto lapTelemetryDto)
        {
            TelemetryStoryboard   telemetryStoryboard = new TelemetryStoryboard(lapTelemetryDto.LapSummary);
            List <TelemetryFrame> telemetryFrames     = new List <TelemetryFrame>();
            TelemetryFrame        previousFrame       = null;

            foreach (TimedTelemetrySnapshot timedTelemetrySnapshot in lapTelemetryDto.DataPoints.OrderBy(x => x.LapTimeSeconds))
            {
                TelemetryFrame currentFrame = new TelemetryFrame(timedTelemetrySnapshot, telemetryStoryboard)
                {
                    PreviousFrame = previousFrame
                };
                if (previousFrame == null)
                {
                    telemetryStoryboard.FirstFrame = currentFrame;
                }
                else
                {
                    previousFrame.NextFrame = currentFrame;
                }
                telemetryFrames.Add(currentFrame);
                previousFrame = currentFrame;
            }

            telemetryStoryboard.TelemetryFrames = telemetryFrames.AsReadOnly();
            telemetryStoryboard.LastFrame       = previousFrame;
            return(telemetryStoryboard);
        }
        public double GetValueByTime(TimeSpan time, Func <TimedTelemetrySnapshot, double> valueFunc)
        {
            TelemetryFrame closestFrame  = FindFrameByTime(time);
            TelemetryFrame previousFrame = closestFrame.PreviousFrame;

            return(valueFunc(closestFrame.TelemetrySnapshot));
        }
        public TelemetryFrame Forward(TimeSpan timeSpan)
        {
            TimeSpan       toFind       = timeSpan + TelemetrySnapshot.LapTime;
            TelemetryFrame currentFrame = this;

            while (currentFrame != null && currentFrame.FrameTime < toFind)
            {
                currentFrame = currentFrame.NextFrame;
            }

            return(currentFrame ?? Storyboard.LastFrame);
        }
        public double GetValueByDistance(Distance distance, Func <TimedTelemetrySnapshot, double> valueFunc)
        {
            TelemetryFrame closestFrame  = FindFrameByDistance(distance);
            TelemetryFrame previousFrame = closestFrame.PreviousFrame;

            if (previousFrame == null)
            {
                return(valueFunc(closestFrame.TelemetrySnapshot));
            }

            double y0 = valueFunc(previousFrame.TelemetrySnapshot);
            double y1 = valueFunc(closestFrame.TelemetrySnapshot);

            double x0 = previousFrame.FrameDistance.InMeters;
            double x1 = closestFrame.FrameDistance.InMeters;

            double rate = (y1 - y0) / (x1 - x0);

            double distanceFromX = distance.InMeters - x0;

            return(y0 + (rate * distanceFromX));
        }
        public TelemetryFrame FindFrameByDistance(Distance distance)
        {
            TelemetryFrame frame = TelemetryFrames.FirstOrDefault(x => x.FrameDistance.InMeters >= distance.InMeters);

            return(frame ?? LastFrame);
        }
        public TelemetryFrame FindFrameByTime(TimeSpan time)
        {
            TelemetryFrame frame = TelemetryFrames.FirstOrDefault(x => x.FrameTime >= time);

            return(frame ?? LastFrame);
        }