diff --git a/src/AllPlot.cpp b/src/AllPlot.cpp index 8a0204bd5..de3c46473 100644 --- a/src/AllPlot.cpp +++ b/src/AllPlot.cpp @@ -308,6 +308,8 @@ AllPlotObject::AllPlotObject(AllPlot *plot) : plot(plot) gearCurve = new QwtPlotCurve(tr("Gear Ratio")); gearCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); gearCurve->setYAxis(QwtAxisId(QwtAxis::yLeft, 0)); + gearCurve->setStyle(QwtPlotCurve::Steps); + gearCurve->setCurveAttribute(QwtPlotCurve::Inverted); smo2Curve = new QwtPlotCurve(tr("SmO2")); smo2Curve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); @@ -1291,18 +1293,18 @@ AllPlot::setHighlightIntervals(bool state) struct DataPoint { - double time, hr, watts, atiss, antiss, np, rv, rcad, rgct, gear, + double time, hr, watts, atiss, antiss, np, rv, rcad, rgct, smo2, thb, ap, xp, speed, cad, alt, temp, wind, torque, lrbalance, lte, rte, lps, rps, kphd, wattsd, cadd, nmd, hrd, slope; DataPoint(double t, double h, double w, double at, double an, double n, double rv, double rcad, double rgct, - double gear, double smo2, double thb, double l, double x, double s, double c, + double smo2, double thb, double l, double x, double s, double c, double a, double te, double wi, double tq, double lrb, double lte, double rte, double lps, double rps, double kphd, double wattsd, double cadd, double nmd, double hrd, double sl) : time(t), hr(h), watts(w), atiss(at), antiss(an), np(n), rv(rv), rcad(rcad), rgct(rgct), - gear(gear), smo2(smo2), thb(thb), ap(l), xp(x), speed(s), cad(c), + smo2(smo2), thb(thb), ap(l), xp(x), speed(s), cad(c), alt(a), temp(te), wind(wi), torque(tq), lrbalance(lrb), lte(lte), rte(rte), lps(lps), rps(rps), kphd(kphd), wattsd(wattsd), cadd(cadd), nmd(nmd), hrd(hrd), slope(sl) {} }; @@ -1476,7 +1478,6 @@ AllPlot::recalc(AllPlotObject *objects) double totalRCad = 0.0; double totalRV = 0.0; double totalRGCT = 0.0; - double totalGear = 0.0; double totalSmO2 = 0.0; double totaltHb = 0.0; double totalATISS = 0.0; @@ -1510,7 +1511,6 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothRV.resize(rideTimeSecs + 1); objects->smoothRCad.resize(rideTimeSecs + 1); objects->smoothRGCT.resize(rideTimeSecs + 1); - objects->smoothGear.resize(rideTimeSecs + 1); objects->smoothSmO2.resize(rideTimeSecs + 1); objects->smoothtHb.resize(rideTimeSecs + 1); objects->smoothAT.resize(rideTimeSecs + 1); @@ -1554,7 +1554,6 @@ AllPlot::recalc(AllPlotObject *objects) (!objects->rvArray.empty() ? objects->rvArray[i] : 0), (!objects->rcadArray.empty() ? objects->rcadArray[i] : 0), (!objects->rgctArray.empty() ? objects->rgctArray[i] : 0), - (!objects->gearArray.empty() ? objects->gearArray[i] : 0), (!objects->smo2Array.empty() ? objects->smo2Array[i] : 0), (!objects->thbArray.empty() ? objects->thbArray[i] : 0), (!objects->apArray.empty() ? objects->apArray[i] : 0), @@ -1583,7 +1582,6 @@ AllPlot::recalc(AllPlotObject *objects) if (!objects->rvArray.empty()) totalRV += objects->rvArray[i]; if (!objects->rcadArray.empty()) totalRCad += objects->rcadArray[i]; if (!objects->rgctArray.empty()) totalRGCT += objects->rgctArray[i]; - if (!objects->gearArray.empty()) totalGear += objects->gearArray[i]; if (!objects->smo2Array.empty()) totalSmO2 += objects->smo2Array[i]; if (!objects->thbArray.empty()) totaltHb += objects->thbArray[i]; if (!objects->atissArray.empty()) totalATISS += objects->atissArray[i]; @@ -1647,7 +1645,6 @@ AllPlot::recalc(AllPlotObject *objects) totalRV -= dp.rv; totalRCad -= dp.rcad; totalRGCT -= dp.rgct; - totalGear -= dp.gear; totalSmO2 -= dp.smo2; totaltHb -= dp.thb; totalATISS -= dp.atiss; @@ -1682,7 +1679,6 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothRV[secs] = 0.0; objects->smoothRCad[secs] = 0.0; objects->smoothRGCT[secs] = 0.0; - objects->smoothGear[secs] = 0.0; objects->smoothSmO2[secs] = 0.0; objects->smoothtHb[secs] = 0.0; objects->smoothAT[secs] = 0.0; @@ -1716,7 +1712,6 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothRV[secs] = totalRV / list.size(); objects->smoothRCad[secs] = totalRCad / list.size(); objects->smoothRGCT[secs] = totalRGCT / list.size(); - objects->smoothGear[secs] = totalGear / list.size(); objects->smoothSmO2[secs] = totalSmO2 / list.size(); objects->smoothtHb[secs] = totaltHb / list.size(); objects->smoothAT[secs] = totalATISS / list.size(); @@ -1769,7 +1764,6 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothRV.resize(0); objects->smoothRCad.resize(0); objects->smoothRGCT.resize(0); - objects->smoothGear.resize(0); objects->smoothSmO2.resize(0); objects->smoothtHb.resize(0); objects->smoothAT.resize(0); @@ -1854,6 +1848,13 @@ AllPlot::recalc(AllPlotObject *objects) } } + // and now set data series which MUST not be smoothed AT ALL (e.g. gear ratio) + objects->smoothGear.resize(0); + foreach (RideFilePoint *dp, rideItem->ride()->dataPoints()) { + objects->smoothGear.append(dp->gear); + } + + QVector &xaxis = bydist ? objects->smoothDistance : objects->smoothTime; int startingIndex = qMin(smooth, xaxis.count()); int totalPoints = xaxis.count() - startingIndex; diff --git a/src/HistogramWindow.cpp b/src/HistogramWindow.cpp index 2b6dc7a81..125b43c7b 100644 --- a/src/HistogramWindow.cpp +++ b/src/HistogramWindow.cpp @@ -26,6 +26,7 @@ static const double nmDelta = 0.1; static const double hrDelta = 1.0; static const double kphDelta = 0.1; static const double cadDelta = 1.0; +static const double gearDelta = 0.01; //RideFileCache creates POW(10) * decimals sections // digits for text entry validator static const int wattsDigits = 0; @@ -34,6 +35,7 @@ static const int nmDigits = 1; static const int hrDigits = 0; static const int kphDigits = 1; static const int cadDigits = 0; +static const int gearDigits = 2; // @@ -832,7 +834,8 @@ void HistogramWindow::addSeries() << RideFile::kph << RideFile::cad << RideFile::nm - << RideFile::aPower; + << RideFile::aPower + << RideFile::gear; foreach (RideFile::SeriesType x, seriesList) seriesCombo->addItem(RideFile::seriesName(x), static_cast(x)); @@ -1087,6 +1090,7 @@ HistogramWindow::getDelta() case 4: return cadDelta; case 5: return nmDelta; case 6: return wattsDelta; //aPower + case 7: return gearDelta; default: return 1; } } @@ -1115,6 +1119,7 @@ HistogramWindow::getDigits() case 4: return cadDigits; case 5: return nmDigits; case 6: return wattsDigits; // aPower + case 7: return gearDigits; default: return 1; } } diff --git a/src/PowerHist.cpp b/src/PowerHist.cpp index 81a1c635e..772aa2596 100644 --- a/src/PowerHist.cpp +++ b/src/PowerHist.cpp @@ -156,6 +156,10 @@ PowerHist::configChanged() pen.setColor(GColor(CCADENCE).darker(200)); brush_color = GColor(CCADENCE); break; + case RideFile::gear: + pen.setColor(GColor(CGEAR).darker(200)); + brush_color = GColor(CGEAR); + break; default: case RideFile::hr: pen.setColor(GColor(CHEARTRATE).darker(200)); @@ -412,6 +416,12 @@ PowerHist::recalcCompare() array = &cid.kphArray; arrayLength = cid.kphArray.size(); + } else if (series == RideFile::gear) { + + array = &cid.gearArray; + arrayLength = cid.gearArray.size(); + + } else if (series == RideFile::cad) { array = &cid.cadArray; arrayLength = cid.cadArray.size(); @@ -891,6 +901,11 @@ PowerHist::binData(HistData &standard, QVector&x, // x-axis for data arrayLength = standard.kphArray.size(); selectedArray = &standard.kphSelectedArray; + } else if (series == RideFile::gear) { + array = &standard.gearArray; + arrayLength = standard.gearArray.size(); + selectedArray = &standard.gearSelectedArray; + } else if (series == RideFile::cad) { array = &standard.cadArray; arrayLength = standard.cadArray.size(); @@ -1085,6 +1100,7 @@ PowerHist::setData(RideFileCache *cache) standard.nmArray.resize(0); standard.hrArray.resize(0); standard.kphArray.resize(0); + standard.gearArray.resize(0); standard.cadArray.resize(0); // we do not use the selected array since it is @@ -1098,6 +1114,7 @@ PowerHist::setData(RideFileCache *cache) standard.hrSelectedArray.resize(0); standard.hrZoneSelectedArray.resize(0); standard.kphSelectedArray.resize(0); + standard.gearSelectedArray.resize(0); standard.cadSelectedArray.resize(0); longFromDouble(standard.wattsArray, cache->distributionArray(RideFile::watts)); @@ -1106,6 +1123,7 @@ PowerHist::setData(RideFileCache *cache) longFromDouble(standard.hrArray, cache->distributionArray(RideFile::hr)); longFromDouble(standard.nmArray, cache->distributionArray(RideFile::nm)); longFromDouble(standard.cadArray, cache->distributionArray(RideFile::cad)); + longFromDouble(standard.gearArray, cache->distributionArray(RideFile::gear)); longFromDouble(standard.kphArray, cache->distributionArray(RideFile::kph)); if (!context->athlete->useMetricUnits) { @@ -1212,6 +1230,7 @@ PowerHist::setDataFromCompare() add.hrArray.resize(0); add.hrZoneArray.resize(10); add.kphArray.resize(0); + add.gearArray.resize(0); add.cadArray.resize(0); longFromDouble(add.wattsArray, s->distributionArray(RideFile::watts)); @@ -1219,6 +1238,7 @@ PowerHist::setDataFromCompare() longFromDouble(add.aPowerArray, s->distributionArray(RideFile::aPower)); longFromDouble(add.hrArray, s->distributionArray(RideFile::hr)); longFromDouble(add.nmArray, s->distributionArray(RideFile::nm)); + longFromDouble(add.gearArray, s->distributionArray(RideFile::gear)); longFromDouble(add.cadArray, s->distributionArray(RideFile::cad)); longFromDouble(add.kphArray, s->distributionArray(RideFile::kph)); @@ -1551,6 +1571,7 @@ PowerHist::setData(RideItem *_rideItem, bool force) bool hasData = ((series == RideFile::watts || series == RideFile::wattsKg) && ride->areDataPresent()->watts) || (series == RideFile::nm && ride->areDataPresent()->nm) || (series == RideFile::kph && ride->areDataPresent()->kph) || + (series == RideFile::gear && ride->areDataPresent()->gear) || (series == RideFile::cad && ride->areDataPresent()->cad) || (series == RideFile::aPower && ride->areDataPresent()->apower) || (series == RideFile::hr && ride->areDataPresent()->hr); @@ -1585,6 +1606,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo static const double hrDelta = 1.0; static const double kphDelta = 0.1; static const double cadDelta = 1.0; + static const double gearDelta = 0.01; //RideFileCache creates POW(10) * decimals section static const int maxSize = 4096; // recording interval in minutes @@ -1599,6 +1621,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo standard.hrArray.resize(0); standard.hrZoneArray.resize(0); standard.kphArray.resize(0); + standard.gearArray.resize(0); standard.cadArray.resize(0); standard.wattsSelectedArray.resize(0); @@ -1609,6 +1632,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo standard.hrSelectedArray.resize(0); standard.hrZoneSelectedArray.resize(0); standard.kphSelectedArray.resize(0); + standard.gearSelectedArray.resize(0); standard.cadSelectedArray.resize(0); // unit conversion factor for imperial units for selected parameters @@ -1768,6 +1792,19 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo } } + int gearIndex = int(floor(p1->gear / gearDelta)); + if (gearIndex >= 0 && gearIndex < maxSize) { + if (gearIndex >= standard.gearArray.size()) + standard.gearArray.resize(gearIndex + 1); + standard.gearArray[gearIndex]++; + + if (selected) { + if (gearIndex >= standard.gearSelectedArray.size()) + standard.gearSelectedArray.resize(gearIndex + 1); + standard.gearSelectedArray[gearIndex]++; + } + } + int cadIndex = int(floor(p1->cad / cadDelta)); if (cadIndex >= 0 && cadIndex < maxSize) { if (cadIndex >= standard.cadArray.size()) @@ -1881,6 +1918,10 @@ PowerHist::setParameterAxisTitle() axislabel = QString(tr("Torque (%1)")).arg(context->athlete->useMetricUnits ? tr("N-m") : tr("ft-lbf")); break; + case RideFile::gear: + axislabel = tr("Gear Ratio"); + break; + default: axislabel = QString(tr("Unknown data series")); break; diff --git a/src/PowerHist.h b/src/PowerHist.h index cf1e8aa36..491966948 100644 --- a/src/PowerHist.h +++ b/src/PowerHist.h @@ -94,7 +94,7 @@ class HistData // each curve needs a lot of data (!? this may need refactoring, // storage for data counts QVector aPowerArray, wattsArray, wattsZoneArray, wattsCPZoneArray, wattsKgArray, nmArray, hrArray, - hrZoneArray, kphArray, cadArray, metricArray; + hrZoneArray, kphArray, cadArray, gearArray, metricArray; // storage for data counts in interval selected QVector aPowerSelectedArray, @@ -104,7 +104,7 @@ class HistData // each curve needs a lot of data (!? this may need refactoring, wattsKgSelectedArray, nmSelectedArray, hrSelectedArray, hrZoneSelectedArray, kphSelectedArray, - cadSelectedArray; + cadSelectedArray, gearSelectedArray; }; class PowerHist : public QwtPlot diff --git a/src/RideFile.cpp b/src/RideFile.cpp index ea0353352..f87b281dd 100644 --- a/src/RideFile.cpp +++ b/src/RideFile.cpp @@ -31,6 +31,7 @@ #include #include // for std::lower_bound #include +#include #define mark() \ { \ @@ -1489,14 +1490,39 @@ RideFile::recalculateDerivedSeries() // need to say we got it setDataPresent(RideFile::gear, true); - // calculate gear ratio, without rounding (but will need - // to do something to it in order to identify gear) + // calculate gear ratio, with simple 3 level rounding (considering that the ratio steps are not linear): + // -> below ratio 1, round to next 0,05 border (ratio step of 2 tooth change is around 0,03 for 20/36 (MTB) + // -> above ratio 1 and 3, round to next 0,1 border (MTB + Racebike - bigger differences per shifting step) + // -> above ration 3, round to next 0,5 border (mainly Racebike - even wider differences) // speed and wheelsize in meters - p->gear = (1000.00f * p->kph) / (p->cad * 60.00f * wheelsize); + // but only if ride point has power, cadence and speed > 0 otherwise calculation will give a random result + if (p->watts > 0.0f && p->cad > 0.0f && p->kph > 0.0f) { + p->gear = (1000.00f * p->kph) / (p->cad * 60.00f * wheelsize); + // do the rounding + double rounding = 0.0f; + if (p->gear < 1.0f) { + rounding = 0.05f; + } + else if (p->gear >= 1.0f && p->gear < 3.0f) { + rounding = 0.1f; + } else { + rounding = 0.5f; + } + double mod = fmod(p->gear, rounding); + double factor = trunc(p->gear / rounding); + if (mod < rounding) p->gear = factor * rounding; + else p->gear = (factor+1) * rounding; + + // final rounding to 2 decimals + p->gear = round(p->gear * 100.00f) / 100.00f; + } + else { + p->gear = 0.0f; // to be filled up with previous gear later + } // truncate big values if (p->gear > maximumFor(RideFile::gear)) p->gear = 0; - + } else { p->gear = 0.0f; } @@ -1505,6 +1531,34 @@ RideFile::recalculateDerivedSeries() lastP = p; } + // remove gear outlier (for single outlier values = 1 second) and + // fill 0 gaps in Gear series with previous or next gear ration value (whichever of those is above 0) + if (dataPresent.gear) { + double last = 0.0f; + double current = 0.0f; + double next = 0.0f; + double lastGear = 0.0; + for (int i = 0; igear > 0) + lastGear = dataPoints_[i]->gear; + else + dataPoints_[i]->gear = lastGear; + // set the single outliers (there might be better ways, but this is easy + if (i>0) last = dataPoints_[i-1]->gear; else last = 0.0f; + current = dataPoints_[i]->gear; + if (igear; else next = 0.0f; + // if there is a big jump to current in relation to last-next consider this a outlier + double diff1 = abs(last-next); + double diff2 = abs(last-current); + if ((diff1 < 0.01f) || (diff2 >= (diff1+0.5f))){ + // single outlier (no shift up/down in 2 seconds + dataPoints_[i]->gear = (last>next) ? last : next; + } + + } + } + // Smooth the slope if it has been derived if (!dataPresent.slope && dataPresent.alt && dataPresent.km) { int smoothPoints = 10; diff --git a/src/RideFileCache.cpp b/src/RideFileCache.cpp index 569650f14..65cd0e13f 100644 --- a/src/RideFileCache.cpp +++ b/src/RideFileCache.cpp @@ -58,6 +58,7 @@ RideFileCache::RideFileCache(Context *context, QString fileName, RideFile *passe wattsDistribution.resize(0); hrDistribution.resize(0); cadDistribution.resize(0); + gearDistribution.resize(0); nmDistribution.resize(0); kphDistribution.resize(0); xPowerDistribution.resize(0); @@ -193,6 +194,7 @@ static long offsetForTiz(RideFileCacheHeader head, RideFile::SeriesType series) offset += head.wattsDistCount * sizeof(float); offset += head.hrDistCount * sizeof(float); offset += head.cadDistCount * sizeof(float); + offset += head.gearDistCount * sizeof(float); offset += head.nmDistrCount * sizeof(float); offset += head.kphDistCount * sizeof(float); offset += head.xPowerDistCount * sizeof(float); @@ -362,6 +364,7 @@ RideFileCache::RideFileCache(RideFile *ride) : wattsDistribution.resize(0); hrDistribution.resize(0); cadDistribution.resize(0); + gearDistribution.resize(0); nmDistribution.resize(0); kphDistribution.resize(0); xPowerDistribution.resize(0); @@ -397,15 +400,16 @@ RideFileCache::RideFileCache(RideFile *ride) : doubleArray(wattsKgMeanMaxDouble, wattsKgMeanMax, RideFile::wattsKg); doubleArray(aPowerMeanMaxDouble, aPowerMeanMax, RideFile::aPower); - doubleArray(wattsDistributionDouble, wattsDistribution, RideFile::watts); - doubleArray(hrDistributionDouble, hrDistribution, RideFile::hr); - doubleArray(cadDistributionDouble, cadDistribution, RideFile::cad); - doubleArray(nmDistributionDouble, nmDistribution, RideFile::nm); - doubleArray(kphDistributionDouble, kphDistribution, RideFile::kph); - doubleArray(xPowerDistributionDouble, xPowerDistribution, RideFile::xPower); - doubleArray(npDistributionDouble, npDistribution, RideFile::NP); - doubleArray(wattsKgDistributionDouble, wattsKgDistribution, RideFile::wattsKg); - doubleArray(aPowerDistributionDouble, aPowerDistribution, RideFile::aPower); + doubleArrayForDistribution(wattsDistributionDouble, wattsDistribution); + doubleArrayForDistribution(hrDistributionDouble, hrDistribution); + doubleArrayForDistribution(cadDistributionDouble, cadDistribution); + doubleArrayForDistribution(gearDistributionDouble, gearDistribution); + doubleArrayForDistribution(nmDistributionDouble, nmDistribution); + doubleArrayForDistribution(kphDistributionDouble, kphDistribution); + doubleArrayForDistribution(xPowerDistributionDouble, xPowerDistribution); + doubleArrayForDistribution(npDistributionDouble, npDistribution); + doubleArrayForDistribution(wattsKgDistributionDouble, wattsKgDistribution); + doubleArrayForDistribution(aPowerDistributionDouble, aPowerDistribution); } int @@ -414,6 +418,7 @@ RideFileCache::decimalsFor(RideFile::SeriesType series) switch (series) { case RideFile::secs : return 0; break; case RideFile::cad : return 0; break; + case RideFile::gear : return 2; break; case RideFile::hr : return 0; break; case RideFile::km : return 3; break; case RideFile::kph : return 1; break; @@ -604,6 +609,10 @@ RideFileCache::distributionArray(RideFile::SeriesType series) return cadDistributionDouble; break; + case RideFile::gear: + return gearDistributionDouble; + break; + case RideFile::hr: return hrDistributionDouble; break; @@ -726,6 +735,7 @@ void RideFileCache::RideFileCache::compute() computeDistribution(wattsDistribution, RideFile::watts); computeDistribution(hrDistribution, RideFile::hr); computeDistribution(cadDistribution, RideFile::cad); + computeDistribution(gearDistribution, RideFile::gear); computeDistribution(nmDistribution, RideFile::nm); computeDistribution(kphDistribution, RideFile::kph); computeDistribution(wattsKgDistribution, RideFile::wattsKg); @@ -1393,6 +1403,7 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt distAggregate(wattsDistributionDouble, rideCache.wattsDistributionDouble); distAggregate(hrDistributionDouble, rideCache.hrDistributionDouble); distAggregate(cadDistributionDouble, rideCache.cadDistributionDouble); + distAggregate(gearDistributionDouble, rideCache.gearDistributionDouble); distAggregate(nmDistributionDouble, rideCache.nmDistributionDouble); distAggregate(kphDistributionDouble, rideCache.kphDistributionDouble); distAggregate(xPowerDistributionDouble, rideCache.xPowerDistributionDouble); @@ -1496,6 +1507,7 @@ RideFileCache::serialize(QDataStream *out) head.npDistCount = xPowerDistribution.size(); head.hrDistCount = hrDistribution.size(); head.cadDistCount = cadDistribution.size(); + head.gearDistCount = gearDistribution.size(); head.nmDistrCount = nmDistribution.size(); head.kphDistCount = kphDistribution.size(); head.wattsKgDistCount = wattsKgDistribution.size(); @@ -1524,6 +1536,7 @@ RideFileCache::serialize(QDataStream *out) out->writeRawData((const char *) wattsDistribution.data(), sizeof(float) * wattsDistribution.size()); out->writeRawData((const char *) hrDistribution.data(), sizeof(float) * hrDistribution.size()); out->writeRawData((const char *) cadDistribution.data(), sizeof(float) * cadDistribution.size()); + out->writeRawData((const char *) gearDistribution.data(), sizeof(float) * gearDistribution.size()); out->writeRawData((const char *) nmDistribution.data(), sizeof(float) * nmDistribution.size()); out->writeRawData((const char *) kphDistribution.data(), sizeof(float) * kphDistribution.size()); out->writeRawData((const char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size()); @@ -1568,6 +1581,7 @@ RideFileCache::readCache() wattsDistribution.resize(head.wattsDistCount); hrDistribution.resize(head.hrDistCount); cadDistribution.resize(head.cadDistCount); + gearDistribution.resize(head.gearDistCount); nmDistribution.resize(head.nmDistrCount); kphDistribution.resize(head.kphDistCount); xPowerDistribution.resize(head.xPowerDistCount); @@ -1597,6 +1611,7 @@ RideFileCache::readCache() inFile.readRawData((char *) wattsDistribution.data(), sizeof(float) * wattsDistribution.size()); inFile.readRawData((char *) hrDistribution.data(), sizeof(float) * hrDistribution.size()); inFile.readRawData((char *) cadDistribution.data(), sizeof(float) * cadDistribution.size()); + inFile.readRawData((char *) gearDistribution.data(), sizeof(float) * gearDistribution.size()); inFile.readRawData((char *) nmDistribution.data(), sizeof(float) * nmDistribution.size()); inFile.readRawData((char *) kphDistribution.data(), sizeof(float) * kphDistribution.size()); inFile.readRawData((char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size()); @@ -1626,15 +1641,16 @@ RideFileCache::readCache() doubleArray(wattsKgMeanMaxDouble, wattsKgMeanMax, RideFile::wattsKg); doubleArray(aPowerMeanMaxDouble, aPowerMeanMax, RideFile::aPower); - doubleArray(wattsDistributionDouble, wattsDistribution, RideFile::watts); - doubleArray(hrDistributionDouble, hrDistribution, RideFile::hr); - doubleArray(cadDistributionDouble, cadDistribution, RideFile::cad); - doubleArray(nmDistributionDouble, nmDistribution, RideFile::nm); - doubleArray(kphDistributionDouble, kphDistribution, RideFile::kph); - doubleArray(xPowerDistributionDouble, xPowerDistribution, RideFile::xPower); - doubleArray(npDistributionDouble, npDistribution, RideFile::NP); - doubleArray(wattsKgDistributionDouble, wattsKgDistribution, RideFile::wattsKg); - doubleArray(aPowerDistributionDouble, aPowerDistribution, RideFile::aPower); + doubleArrayForDistribution(wattsDistributionDouble, wattsDistribution); + doubleArrayForDistribution(hrDistributionDouble, hrDistribution); + doubleArrayForDistribution(cadDistributionDouble, cadDistribution); + doubleArrayForDistribution(gearDistributionDouble, gearDistribution); + doubleArrayForDistribution(nmDistributionDouble, nmDistribution); + doubleArrayForDistribution(kphDistributionDouble, kphDistribution); + doubleArrayForDistribution(xPowerDistributionDouble, xPowerDistribution); + doubleArrayForDistribution(npDistributionDouble, npDistribution); + doubleArrayForDistribution(wattsKgDistributionDouble, wattsKgDistribution); + doubleArrayForDistribution(aPowerDistributionDouble, aPowerDistribution); cacheFile.close(); } @@ -1650,6 +1666,15 @@ void RideFileCache::doubleArray(QVector &into, QVector &from, Rid return; } +// for Distribution Series the values in Long/Float are ALWAYS Seconds (therefor no decimals adjustment calcuation required) +void RideFileCache::doubleArrayForDistribution(QVector &into, QVector &from) +{ + into.resize(from.size()); + for(int i=0; i &into, QVector &from, RideFile::SeriesType series); + static void doubleArrayForDistribution(QVector &into, QVector &from); protected: @@ -279,6 +282,7 @@ class RideFileCache // RideFile::decimalsFor() then it will be distributed in 0.1 of a unit QVector wattsDistribution; // RideFile::watts QVector hrDistribution; // RideFile::hr + QVector gearDistribution; // RideFile::gear QVector cadDistribution; // RideFile::cad QVector nmDistribution; // RideFile::nm QVector kphDistribution; // RideFile::kph @@ -290,6 +294,7 @@ class RideFileCache QVector wattsDistributionDouble; // RideFile::watts QVector hrDistributionDouble; // RideFile::hr + QVector gearDistributionDouble; // RideFile::gear QVector cadDistributionDouble; // RideFile::cad QVector nmDistributionDouble; // RideFile::nm QVector kphDistributionDouble; // RideFile::kph diff --git a/src/ScatterPlot.cpp b/src/ScatterPlot.cpp index 2f9d29ad1..385b62a44 100644 --- a/src/ScatterPlot.cpp +++ b/src/ScatterPlot.cpp @@ -310,8 +310,13 @@ void ScatterPlot::setData (ScatterSettings *settings) double xv = pointType(point, settings->x, side, context->athlete->useMetricUnits, cranklength); double yv = pointType(point, settings->y, side, context->athlete->useMetricUnits, cranklength); - // skip zeroes? - if (settings->ignore && (int(xv) == 0 || int(yv) == 0)) continue; + // skip zeroes? - special logic for Model Gear, since there value between 0.01 and 1 happen and are relevant + if ((settings->x != MODEL_GEAR && settings->y != MODEL_GEAR) + && settings->ignore && (int(xv) == 0 || int(yv) == 0)) continue; + if ((settings->x == MODEL_GEAR) + && settings->ignore && (xv == 0.0f || int(yv) == 0)) continue; + if ((settings->y == MODEL_GEAR) + && settings->ignore && (int(xv) == 0 || yv == 0.0f)) continue; // add it x <x == MODEL_CPV) setAxisScale(xBottom, 0, 3); else setAxisScale(xBottom, minX, maxX); + // gear + if (settings->x == MODEL_GEAR) setAxisScale(xBottom, 0, 7); + if (settings->y == MODEL_GEAR) setAxisScale(yLeft, 0, 7); + // and those interval markers refreshIntervalMarkers(settings);