private void interpolCurrent(double time) { TrackParser.Sample result = mCurrInterpol; TrackParser.Sample curr = mCurrSample; TrackParser.Sample next = mCurrSample; double progress = 0; if (!Double.IsNaN(curr.mAbsEndTime)) { progress = (time - curr.mAbsStartTime) / (curr.mAbsEndTime - curr.mAbsStartTime); } if (progress > 0 && mCurrIndex < mTrackData.Samples.Count - 1) { next = mTrackData.Samples[mCurrIndex + 1]; } result.mLap = curr.mLap; result.mAbsStartTime = time; result.mAbsEndTime = curr.mAbsEndTime; result.mElapsedTime = interpolate(curr.mElapsedTime, next.mElapsedTime, progress); result.mSpeed = interpolate(curr.mSpeed, next.mSpeed, progress); result.mAccel = interpolate(curr.mAccel, next.mAccel, progress); result.mLateralAccel = interpolate(curr.mLateralAccel, next.mLateralAccel, progress); result.mLatitude = interpolate(curr.mLatitude, next.mLatitude, progress); result.mLongtiude = interpolate(curr.mLongtiude, next.mLongtiude, progress); result.mAltitude = interpolate(curr.mAltitude, next.mAltitude, progress); result.mBearing = interpolate(curr.mBearing, next.mBearing, progress); }
private Bitmap prepareTrackBmp(Rectangle trackRect, Gps2PixelProjection trackProj, TrackParser td) { // We need at least a lap to draw something if (!td.HasSamples || trackProj == null) { return(null); } // We'll draw one of the laps. Just get the first lap. TrackParser.Lap currLap = td.Laps[0]; int w = trackRect.Width; int h = trackRect.Height; Bitmap bmp = new Bitmap(w, h); using (Graphics g = Graphics.FromImage(bmp)) { using (Brush bgColor = new SolidBrush(Color.Gray), trackColor = new SolidBrush(Color.Yellow)) { using (Pen trackPen = new Pen(trackColor, kTrackWidth)) { g.FillRectangle(bgColor, 0, 0, w, h); List <TrackParser.Sample> samples = td.Samples; TrackParser.Sample s = samples[0]; CPointF last = new CPointF(); CPointF next = new CPointF(); transformGpsCoord(s.mLongtiude, s.mLatitude, trackProj, last); float px = (float)trackProj.mPixelOffsetX; float py = (float)trackProj.mPixelOffsetY; last.mX -= px; last.mY -= py; for (int i = 1, n = samples.Count; i < n; i++) { s = samples[i]; if (s.mLap != currLap) { continue; } transformGpsCoord(s.mLongtiude, s.mLatitude, trackProj, next); next.mX -= px; next.mY -= py; g.DrawLine(trackPen, last.mX, last.mY, next.mX, next.mY); last.mX = next.mX; last.mY = next.mY; } } } } return(bmp); }
private void findCurrSample(double time) { List <TrackParser.Sample> samples = mTrackData.Samples; int n = samples.Count; int n1 = n - 1; if (time < 0) { // can't go before the first sample mCurrSample = samples[0]; mCurrIndex = 0; return; } else if (time > samples[n1].mAbsStartTime) { // can't go past the last sample mCurrSample = samples[n1]; mCurrIndex = n - 1; return; } // The most common case is that we need to advance to the next sample if (mCurrSample != null && mCurrIndex < n1) { TrackParser.Sample s = samples[mCurrIndex + 1]; if (time >= s.mAbsStartTime && (Double.IsNaN(s.mAbsEndTime) || (!Double.IsNaN(s.mAbsEndTime) && time < s.mAbsEndTime))) { mCurrIndex++; mCurrSample = s; return; } } // Going forward from current sample if (mCurrSample != null && mCurrIndex < n1 && time > mCurrSample.mAbsEndTime) { while (mCurrIndex < n1 && time > mCurrSample.mAbsEndTime) { mCurrIndex++; mCurrSample = samples[mCurrIndex]; } return; } // Going backwards from current sample if (mCurrSample != null && mCurrIndex > 0 && time < mCurrSample.mAbsStartTime) { while (mCurrIndex > 0 && time < mCurrSample.mAbsStartTime) { mCurrIndex--; mCurrSample = samples[mCurrIndex]; } return; } // The most unlikely case is that we're just from scratch going to // a random position. We could do a dichotomic search. We'll just start with the // obvious linear search and optimize later if really needed (very unlikely), // in which case we could combine the 2 last cases to do a dichotomic search // with a preset direction and a preset starting point. Yawn. for (int i = 0; i < n; i++) { TrackParser.Sample s = samples[mCurrIndex + 1]; if (time >= s.mAbsStartTime && (Double.IsNaN(s.mAbsEndTime) || (!Double.IsNaN(s.mAbsEndTime) && time < s.mAbsEndTime))) { mCurrIndex++; mCurrSample = s; return; } } System.Diagnostics.Debug.Fail("Time not found in samples"); }
public Interpolator(TrackParser trackData) { mTrackData = trackData; mCurrInterpol = new TrackParser.Sample(); }
private void threadEntryPoint() { int fps = mFps; int msx = mMovieSx; int msy = mMovieSy; int tsx = mTrackSx; int tsy = mTrackSy; TrackParser td = mTrackData; using (Graphics g = Graphics.FromImage(mAviBmp)) { using (Brush chromaColor = new SolidBrush(Color.Blue), bgColor = new SolidBrush(Color.Gray), posColor = new SolidBrush(Color.Red), textColor = new SolidBrush(Color.Orange)) { Rectangle bgRect = new Rectangle(msx - tsx, msy - tsy, tsx, tsy); int nbFrames = (int)(mTrackData.TotalTime * fps); // prepare track drawing (map GPS coord => screen coord: offset + scale) Rectangle trackRect; Gps2PixelProjection trackProj = prepareTrackProj(bgRect, td, out trackRect); Bitmap trackBmp = prepareTrackBmp(trackRect, trackProj, td); // prepare g-meter pos // prepare text positions PointF[] textPos; using (Font labelFont = prepareText(bgRect, out textPos), numFont = new Font(FontFamily.GenericMonospace, labelFont.Size, FontStyle.Bold)) { Interpolator interp = new Interpolator(td); double invFps = 1 / (double)fps; bool userStopRequested = false; for (int frame = 0, updateFps = 0; frame < nbFrames && !userStopRequested; frame++, updateFps++) { double currTime = (double)frame * invFps; TrackParser.Sample currSample = interp.GoTo(currTime); double currLapTime = interp.CurrLapTime; // keep track of current dot & interpolate between dots // draw background g.FillRectangle(chromaColor, 0, 0, msx, msy); g.FillRectangle(bgColor, bgRect); // draw track + current pos drawTrackPos(g, posColor, trackRect, trackBmp, trackProj, currSample.mLongtiude, currSample.mLatitude); // draw bearing // TODO // draw text drawText(g, textColor, labelFont, numFont, textPos, currSample.mSpeed, currSample.mAccel, currSample.mLateralAccel, currTime, currLapTime, interp.CurrLapIndex, interp.LastLapDuration); // finally dump frame and update preview/progress MainModule.MainForm.Invoke(mAddFrameFunc); if (updateFps == fps) { updateFps = 0; } if (updateFps == 0) { // Update status, progress, etc. userStopRequested = syncUpdate(frame, nbFrames, new Bitmap(mAviBmp)); } if (mThreadMustStop) { break; } } } // using Font // Make sure to tell owner that the generator is done // This one must be async -- this thread will quit and the owner will // try to join to wait for the thread to finish. asyncUpdate(nbFrames, nbFrames, new Bitmap(mAviBmp)); } // using Brush } // using Graphics }