void THISCLASS::StartRecording() { // Set the end time of the current timeline if (mCurrentTimeline) { if (mCurrentTimeline->mEvents.size() >= Timeline::mNumberOfEvents) { mCurrentTimeline->mEvents.back().mType = sType_TimelineOverflow; mCurrentTimeline->mEvents.back().mComponent = 0; } LapTime(&(mCurrentTimeline->mEnd), sType_None, 0); } // Swap current and old timeline Timeline *temp = mLastTimeline; mLastTimeline = mCurrentTimeline; mCurrentTimeline = temp; // Initialize the current timeline if (! mCurrentTimeline) { mCurrentTimeline = new Timeline(); } mCurrentTimeline->mEvents.clear(); mCurrentTimeline->mEvents.reserve(Timeline::mNumberOfEvents); // Set the start state mCurrentTimeline->mBeginState.mStartedInProductionMode = mSwisTrackCore->IsStartedInProductionMode(); mCurrentTimeline->mBeginState.mStarted = mSwisTrackCore->IsStarted(); mCurrentTimeline->mBeginState.mTriggerActive = mSwisTrackCore->IsTriggerActive(); // Set the start time of the new timeline LapTime(&(mCurrentTimeline->mBegin), sType_None, 0); }
int DriverData::lapDiff(LapTime *lap) { int msec; if (!lap[0].isValid()) msec = LapTime("59:59.999").toMsecs(); else msec = lap[0].toMsecs(); int idx = 0; for (int i = 1; i < 4; ++i) { if (lap[i].isValid() && lap[i].toMsecs() < msec) { idx = i; msec = lap[i].toMsecs(); } } for (int i = 0; i < 4; ++i) { if (i != idx && lap[i].isValid()) lap[i] = lap[i] - lap[idx]; } return idx; }
void THISCLASS::Add(eType type, Component *component) { if (! mCurrentTimeline) { return; } if (mCurrentTimeline->mEvents.size() >= Timeline::mNumberOfEvents) { return; } Event it; LapTime(&it, type, component); Add(&it); }
void DriverData::updateSectorRecords() { for (int i = 0; i < 3; ++i) { if ( sessionRecords.bestSectors[i].second == 0 || (((lapData.last().getSectorTime(i + 1) < sessionRecords.bestSectors[i].first) || ((lapData.last().getSectorTime(i + 1) == sessionRecords.bestSectors[i].first) && (colorData.sectorColor(i + 1) == LTPackets::VIOLET || colorData.sectorColor(i + 1) == LTPackets::GREEN))) && sessionRecords.bestSectors[i].second != 0)) { sessionRecords.bestSectors[i] = QPair<LapTime, int>(LapTime(lapData.last().getSectorTime(i + 1)), lapData.last().lapNum); } } }
void DriverData::addInLap(const EventData &ed) { if (lastLap.lapNum <= 0) return; lapData.append(lastLap); if (outLap == true) lapData.last().lapTime = LapTime("INST. LAP"); else lapData.last().lapTime = LapTime("IN LAP"); lapData.last().qualiLapExtraData.sessionTime = ed.getRemainingTime(); lapData.last().practiceLapExtraData.sessionTime = ed.getRemainingTime(); if (ed.getEventType() == LTPackets::QUALI_EVENT) { int qPeriod = ed.getQualiPeriod() > 0 ? ed.getQualiPeriod() : 1; lastLap.qualiLapExtraData.qualiPeriod = qPeriod; lapData.last().qualiLapExtraData.qualiPeriod = qPeriod; } updateSectorRecords(); }
void THISCLASS::AddStepStart() { // Take a measurement Event it; LapTime(&it, sType_StepStart, 0); Add(&it); // Update the frames per second if (mPreviousStep.mType == sType_StepStart) { double currentstepdistance = CalculateDuration(&mPreviousStep, &it); double w = 0.5; mStepDistance = mStepDistance * w + currentstepdistance * (1 - w); } // Set the previous step mPreviousStep = it; }
bool TrackRecords::loadTrackRecords(QString fileName) { QFile f(fileName); if (f.open(QIODevice::ReadOnly)) { QDataStream stream(&f); char *tab; stream >> tab; QString sbuf(tab); delete [] tab; if (QString(sbuf) != "F1LT2_TR") { f.close(); return false; } trackRecords.clear(); int size; stream >> size; for (int i = 0; i < size; ++i) { Track track; stream >> track.name; int verSize; stream >> verSize; for (int j = 0; j < verSize; ++j) { TrackVersion tv; stream >> tv.year; stream >> tv.map; QString time; for (int k = 0; k < 2; ++k) { stream >> time; tv.trackRecords[k].time = LapTime(time); stream >> tv.trackRecords[k].driver; stream >> tv.trackRecords[k].team; stream >> tv.trackRecords[k].year; } int tsSize; stream >> tsSize; for (int k = 0; k < tsSize; ++k) { TrackWeekendRecords ts; stream >> ts.year; for (int w = 0; w < 4; ++w) { stream >> time; ts.sessionRecords[w].time = LapTime(time); stream >> ts.sessionRecords[w].driver; stream >> ts.sessionRecords[w].team; stream >> ts.sessionRecords[w].session; } int dsSize; stream >> dsSize; for (int w = 0; w < dsSize; ++w) { DriverWeekendRecords ds; stream >> ds.driver; stream >> ds.team; for (int x = 0; x < 5; ++x) { for (int y = 0; y < 4; ++y) { stream >> time; ds.sessionRecords[x][y].time = LapTime(time); stream >> ds.sessionRecords[x][y].session; } } ts.driverRecords.append(ds); } tv.trackWeekendRecords.append(ts); } track.trackVersions.append(tv); } qSort(track.trackVersions); trackRecords.append(track); } }
void DriverData::addFPQLap(const EventData &ed) { //during practice and quali we only save timed laps if ((lastLap.lapTime.toString() != "") && (lapData.empty() || (/*(lastLap.numLap > lapData.last().numLap) &&*/ lastLap.getSectorTime(1).toString() != "" && lastLap.getSectorTime(2).toString() != "" && lastLap.getSectorTime(3).toString() != ""))) { bool correction = false; //sometimes servers messes up with lap numbers, we catch this if the numlap is <= than the last one if (!lapData.isEmpty() && lastLap.lapNum+1 <= lapData.last().lapNum) { correction = true; bool approx = lapData.last().qualiLapExtraData.approxLap || lapData.last().practiceLapExtraData.approxLap; int numlap = lapData.last().lapNum-1; lapData.last() = LapData(lastLap); lapData.last().qualiLapExtraData.approxLap = approx; lapData.last().practiceLapExtraData.approxLap = approx; if (lapData.size() > 1) lapData.last().lapNum = numlap; if (sessionRecords.bestLap.lapNum == numlap) sessionRecords.bestLap.lapNum = lapData.last().lapNum; } else { //if decryption fails, replace the garbage we obtained with the best lap time if (lastLap.lapTime.toString() != "" && !lastLap.lapTime.isValid()) lastLap.lapTime = sessionRecords.bestLap.lapTime; lastLap.qualiLapExtraData.sessionTime = ed.getRemainingTime(); lastLap.practiceLapExtraData.sessionTime = ed.getRemainingTime(); lapData.append(lastLap); lapData.last().lapNum--; if (ed.getEventType() == LTPackets::QUALI_EVENT) { int qPeriod = ed.getQualiPeriod() > 0 ? ed.getQualiPeriod() : 1; lastLap.qualiLapExtraData.qualiPeriod = qPeriod; lapData.last().qualiLapExtraData.qualiPeriod = qPeriod; } updateSectorRecords(); } if (!correction) { if (ed.getEventType() == LTPackets::PRACTICE_EVENT) { if (lastLap < sessionRecords.bestLap) sessionRecords.bestLap = lapData.last(); else if (lastLap.lapTime == sessionRecords.bestLap.lapTime) { lapData.last().lapTime = LapData::sumSectors(lapData.last().getSectorTime(1).toString(), lapData.last().getSectorTime(2).toString(), lapData.last().getSectorTime(3).toString()); lapData.last().practiceLapExtraData.approxLap = true; } else lapData.last().practiceLapExtraData.approxLap = false; } else if (ed.getEventType() == LTPackets::QUALI_EVENT) { if (lastLap < sessionRecords.bestLap) sessionRecords.bestLap = lapData.last(); if (lastLap < sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1] || !sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1].getTime().isValid()) { sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1] = lapData.last(); if (sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1] < sessionRecords.bestLap) sessionRecords.bestLap = sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1]; } //if the current lap time is the same as the best lap, probably the driver hasn't improved so we have to calculate the real lap time from the sectors time else if (lastLap.lapTime == sessionRecords.bestQLaps[lastLap.qualiLapExtraData.qualiPeriod-1].lapTime) { lapData.last().lapTime = LapData::sumSectors(lapData.last().getSectorTime(1).toString(), lapData.last().getSectorTime(2).toString(), lapData.last().getSectorTime(3).toString()); lapData.last().qualiLapExtraData.approxLap = true; } else lapData.last().qualiLapExtraData.approxLap = false; correctPosition(ed); } } lapData.last().gap = QString::number((lapData.last().lapTime - ed.getSessionRecords().getFastestLap().getTime()).toDouble()); posHistory.append(lastLap.pos); outLap = false; } //saving in and out laps else if (lastLap.lapNum > 1) { if (lapData.isEmpty() || (!lapData.isEmpty() && lapData.last().lapNum < lastLap.lapNum-1)) { if (outLap == true || inPits == false) { lapData.append(lastLap); lapData.last().lapTime = LapTime("OUT LAP"); if (inPits == true) lapData.last().lapTime = LapTime("INST. LAP"); lapData.last().lapNum--; outLap = false; } else { lapData.append(lastLap); lapData.last().lapTime = LapTime("IN LAP"); lapData.last().lapNum--; } lapData.last().qualiLapExtraData.sessionTime = ed.getRemainingTime(); lapData.last().practiceLapExtraData.sessionTime = ed.getRemainingTime(); if (ed.getEventType() == LTPackets::QUALI_EVENT) { int qPeriod = ed.getQualiPeriod() > 0 ? ed.getQualiPeriod() : 1; lastLap.qualiLapExtraData.qualiPeriod = qPeriod; lapData.last().qualiLapExtraData.qualiPeriod = qPeriod; } updateSectorRecords(); } } }
void DriverData::addRaceLap(const EventData &ed) { //ok, this looks a bit complicated, but since the LT server doesn't give us the actuall lap number for every driver during the race we have to find another way to gather laps: //- first of all - don't append laps if driver has retired (it's rather obvious) //- don't add empty lap time, except for the first lap of the race - it's always empty //- if this lap is in-lap - add it, if no - add it only if we have the sector 3 time //- if the lapData array is empty - check if lapNum is greater than 0 //- don't add the out lap - "OUT", //- finally - check if we don't try to add the same lap again, we use the gap, interval and lap time info for this if (!retired && ed.getCompletedLaps() > 0 && (lastLap.lapTime.toString() != "" || lastLap.lapNum == 1) && // ((lastLap.lapTime.toString() != "IN PIT" && lastLap.sector3.toString() != "") || lastLap.lapTime.toString() == "IN PIT") && ((lastLap.lapNum > 0 && lapData.isEmpty()) || (!lapData.isEmpty() && // (lastLap.numLap > lapData.last().numLap) && (lastLap.lapTime.toString() != "OUT" /*&& !(lastLap.sector3.toString() == "STOP" && lapData.last().sector3.toString() == "STOP")*/) && !(lapData.last().gap == lastLap.gap && lapData.last().interval == lastLap.interval && lapData.last().lapTime == lastLap.lapTime) ))) { //this is tricky - if driver goes to the pits, we get this info before he crosses the finish line, but not always... //therefore, we don't correct the lap number, assuming that everything is ok, and the lap number is last lap + 1 if ((lastLap.lapTime.toString() != "IN PIT" && !lapData.isEmpty()) || (lapData.isEmpty() && lastLap.lapTime.toString() == "OUT")) correctNumLap(ed.getCompletedLaps()); //1st lap is always empty (excluding situations when driver goes to pit or retires), so if we got a valid time on the first lap //it means that LT server has sent us some junk (probably time from quali) if (lastLap.lapNum == 1 && lastLap.lapTime.isValid()) lastLap.lapTime = LapTime(); //if this is RETIRED lap, update only the lap time if (lastLap.lapTime.toString() == "RETIRED" && !lapData.isEmpty()) { lapData.last().lapTime = lastLap.lapTime; return; } if (lastLap.lapTime.toString() == "IN PIT") lastLap.raceLapExtraData.pitLap = true; else lastLap.raceLapExtraData.pitLap = false; //if we get "IN PIT" before driver crossed the line, we get it again after he croses, in that case update only gap and interval if (!lapData.empty() && lastLap.lapTime.toString() == "IN PIT" && lapData.last().lapTime.toString() == "IN PIT" && !releasedFromPits) { lapData.last().gap = lastLap.gap; lapData.last().interval = lastLap.interval; return; } //when connected to LT during the race and driver was going out of the pits we save this lap as PIT lap if (lastLap.lapTime.toString() == "OUT") lastLap.lapTime = LapTime("IN PIT"); lastLap.carID = carID; if (!lapData.empty() && lapData.last().lapNum >= lastLap.lapNum) lapData.last() = lastLap; else { lapData.append(lastLap); posHistory.append(lastLap.pos); } releasedFromPits = false; if (lastLap < sessionRecords.bestLap) sessionRecords.bestLap = lastLap; //best sectors // if (colorData[LTPackets::RACE_SECTOR_1] == LTPackets::GREEN || colorData[LTPackets::RACE_SECTOR_1] == LTPackets::VIOLET) // { // bestSectors[0].first = lapData.last().sector1; // bestSectors[0].second = lapData.last().numLap; // } // if (colorData[LTPackets::RACE_SECTOR_2] == LTPackets::GREEN || colorData[LTPackets::RACE_SECTOR_2] == LTPackets::VIOLET) // { // bestSectors[1].first = lapData.last().sector2; // bestSectors[1].second = lapData.last().numLap; // } updateSectorRecords(); if (ed.getFlagStatus() == LTPackets::SAFETY_CAR_DEPLOYED || ed.getFlagStatus() == LTPackets::RED_FLAG) lapData.last().raceLapExtraData.scLap = true; else lapData.last().raceLapExtraData.scLap = false; } //driver was set out from the pits, if he pits again on the next lap we will add it if (lastLap.lapTime.toString() == "OUT") releasedFromPits = true; }
void SessionLapTimesChart::drawChart(QPainter *p) { int firstLap = first, lastLap = last; double x = paintRect.left(); double y; double yFactor = (((double)paintRect.height()) / (double)(tMax-tMin)); double secs; int size; findFirstAndLastLap(firstLap, lastLap, size); firstLap = first; lastLap = last; if (/*lastLap - firstLap == 0 ||*/ lapDataArray.isEmpty()) return; drawAxes(p, firstLap, lastLap); double xFactor = ((double)paintRect.width()) / (double)(lastLap - firstLap); p->setRenderHint(QPainter::Antialiasing); int lastPaintedSC = -1; // lapDataXYArray.clear(); int lapsInWindow = 0; for (int i = 0; i < lapDataArray.size(); ++i) { if (lapDataArray[i].getLapNumber() >= firstLap && lapDataArray[i].getLapNumber() <= lastLap)// && lapDataArray[i].getTime().isValid()) { secs = lapDataArray[i].getTime().toDouble(); if (!lapDataArray[i].getTime().isValid() && lapDataArray[i].getLapNumber()-1 >= firstLap && i > 0)// && i < lapDataArray.size()-1) { secs = lapDataArray[i-1].getTime().toDouble(); if (!lapDataArray[i-1].getTime().isValid() && lapDataArray[i].getLapNumber()+1 <= lastLap && i < lapDataArray.size()-1) { QString pl = EventData::getInstance().getDriversData()[lapDataArray[i].getCarID()-1].getPitTime(lapDataArray[i].getLapNumber()); secs = LapTime(lapDataArray[i+1].getTime() + LapTime(pl) + LapTime(5000)).toDouble(); } } if (lapDataArray[i].getRaceLapExtraData().isSCLap() && !lapDataArray[i].getGap().contains("L") && lapDataArray[i].getLapNumber() > lastPaintedSC) { drawSCLap(p, lapDataArray[i], xFactor); lastPaintedSC = lapDataArray[i].getLapNumber(); } // if (lapDataArray[i].getRaceLapExtraData().isSCLap() && lapDataArray[i].getLapNumber() > lastPaintedSC) // { // double sc_x1 = (double)(lapDataArray[i].getLapNumber() - firstLap) * xFactor + (double)paintRect.left(); // double sc_x2 = (double)(lapDataArray[i].getLapNumber()+1 - firstLap) * xFactor + (double)paintRect.left(); // if (sc_x1 < paintRect.left()) // sc_x1 = paintRect.left(); // if (lastPaintedSCPixel == -1) // lastPaintedSCPixel = round(sc_x2); // else if (abs(round(sc_x1) - lastPaintedSCPixel) <= 5) // { // sc_x1 = (double)lastPaintedSCPixel; // lastPaintedSCPixel = round(sc_x2); // } // p->setPen(QColor(255, 255, 0, 0)); // p->setBrush(QBrush(QColor(255, 255, 0, 35))); // p->drawRect(round(sc_x1), paintRect.top(), round(sc_x2-sc_x1), paintRect.height()); // lastPaintedSC = lapDataArray[i].getLapNumber(); // } if (secs > tMax && tMax == max) secs = tMax; // if (secs < tMin) // secs = tMin; y = (double)(paintRect.bottom() - (double)(secs-tMin) * yFactor); x = (double)(lapDataArray[i].getLapNumber() - firstLap) * xFactor + (double)paintRect.left(); //int no = EventData::getInstance()lapDataArray[i].getCarID() QColor color = getCarColor(lapDataArray[i]); QPen pen; pen.setWidth(3); pen.setColor(color); p->setPen(pen); QPainterPath path; if (!scaling) { if (lapsInWindow >= lapDataCoordinates.size()) lapDataCoordinates.append(LapDataCoordinates(i, (int)x, (int)y)); else lapDataCoordinates[lapsInWindow] = LapDataCoordinates(i, (int)x, (int)y); } // p->setBrush(QBrush(ColorsManager::getInstance().getDefaultColor(LTPackets::BACKGROUND])); p->setBrush(QBrush(color)); if (y < paintRect.bottom()) { if (lapDataArray[i].getTime().toString() == "IN PIT") { // p->setBrush(QBrush(QColor())); path.addEllipse(QPoint(x, y), 7, 7); } else { path.addEllipse(QPoint(x, y), 2, 2); } p->drawPath(path); } if (lapDataArray[i].getLapNumber()-1 >= firstLap && i > 0) { double x1 = (double)(lapDataArray[i].getLapNumber() - 1 - firstLap) * xFactor + (double)paintRect.left(); secs = lapDataArray[i-1].getTime().toDouble(); if (!lapDataArray[i-1].getTime().isValid() && i-2 >= firstLap) { secs = lapDataArray[i-2].getTime().toDouble(); if (!lapDataArray[i-2].getTime().isValid())// && i < lapDataArray.size()-1) { QString pl = EventData::getInstance().getDriversData()[lapDataArray[i-1].getCarID()-1].getPitTime(lapDataArray[i-1].getLapNumber()); secs = LapTime(lapDataArray[i].getTime() + LapTime(pl) + LapTime(5000)).toDouble(); } } if (secs > tMax && tMax == max) secs = tMax; // if (secs < tMin) // secs = tMin; double y1 = (double)(paintRect.bottom() - (double)(secs-tMin) * yFactor); if ((y > paintRect.bottom() && y1 > paintRect.bottom()) || (y < paintRect.top() && y1 < paintRect.top())) continue; ChartWidget::checkX1(x1, y1, x, y); ChartWidget::checkX2(x1, y1, x, y); p->drawLine(x1, y1, x, y); drawRetire(p, x, y, 7, lapDataArray[i]); } ++lapsInWindow; } } if (!scaling) clearLapDataCoordinates(lapsInWindow); }