From 06b3c53bb91dab8660fa685cdc30b66d679c69b2 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Tue, 25 Feb 2014 18:44:53 +0000 Subject: [PATCH] Delta Watts, Torque, Cadence and HR .. Following on from the recent update to add acceleration this update adds other derived data series based upon the rate of change. .. Added to the ride plot and the CP plot. Not sure of the overall utility of these updates but bear in mind that they are targetting sprinting and track users and analysis. As well as the positive side of this (development of power cadence etc) we also want to think about and collect data on fatigue rate (possibly only power and torque) - fatigue over time - fatigue over pedal stroke --- src/AllPlot.cpp | 452 ++++++++++++++++++++++++++++++++++-- src/AllPlot.h | 22 +- src/AllPlotWindow.cpp | 135 ++++++++++- src/AllPlotWindow.h | 42 ++-- src/CpintPlot.cpp | 25 ++ src/CriticalPowerWindow.cpp | 20 ++ src/RideFile.cpp | 30 ++- src/RideFile.h | 8 +- src/RideFileCache.cpp | 173 +++++++++++++- src/RideFileCache.h | 35 ++- 10 files changed, 895 insertions(+), 47 deletions(-) diff --git a/src/AllPlot.cpp b/src/AllPlot.cpp index af9f7a305..c256b8689 100644 --- a/src/AllPlot.cpp +++ b/src/AllPlot.cpp @@ -300,6 +300,22 @@ AllPlotObject::AllPlotObject(AllPlot *plot) : plot(plot) accelCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); accelCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); + wattsDCurve = new QwtPlotCurve(tr("Power Delta")); + wattsDCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + wattsDCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); + + cadDCurve = new QwtPlotCurve(tr("Cadence Delta")); + cadDCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + cadDCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); + + nmDCurve = new QwtPlotCurve(tr("Torque Delta")); + nmDCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + nmDCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); + + hrDCurve = new QwtPlotCurve(tr("Heartrate Delta")); + hrDCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + hrDCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); + speedCurve = new QwtPlotCurve(tr("Speed")); speedCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); speedCurve->setYAxis(QwtAxisId(QwtAxis::yRight, 0)); @@ -373,6 +389,7 @@ AllPlotObject::setColor(QColor color) { QList worklist; worklist << mCurve << wCurve << wattsCurve << npCurve << xpCurve << speedCurve << accelCurve + << wattsDCurve << cadDCurve << nmDCurve << hrDCurve << apCurve << cadCurve << tempCurve << hrCurve << torqueCurve << balanceLCurve << balanceRCurve << altCurve; @@ -415,6 +432,10 @@ AllPlotObject::~AllPlotObject() hrCurve->detach(); delete hrCurve; speedCurve->detach(); delete speedCurve; accelCurve->detach(); delete accelCurve; + wattsDCurve->detach(); delete wattsDCurve; + cadDCurve->detach(); delete cadDCurve; + nmDCurve->detach(); delete nmDCurve; + hrDCurve->detach(); delete hrDCurve; cadCurve->detach(); delete cadCurve; altCurve->detach(); delete altCurve; tempCurve->detach(); delete tempCurve; @@ -439,6 +460,10 @@ AllPlotObject::setVisible(bool show) hrCurve->detach(); speedCurve->detach(); accelCurve->detach(); + wattsDCurve->detach(); + cadDCurve->detach(); + nmDCurve->detach(); + hrDCurve->detach(); cadCurve->detach(); altCurve->detach(); tempCurve->detach(); @@ -471,6 +496,10 @@ AllPlotObject::setVisible(bool show) hrCurve->attach(plot); speedCurve->attach(plot); accelCurve->attach(plot); + wattsDCurve->attach(plot); + cadDCurve->attach(plot); + nmDCurve->attach(plot); + hrDCurve->attach(plot); cadCurve->attach(plot); tempCurve->attach(plot); windCurve->attach(plot); @@ -504,6 +533,10 @@ AllPlotObject::hideUnwanted() if (!plot->showHr) hrCurve->detach(); if (!plot->showSpeed) speedCurve->detach(); if (!plot->showAccel) accelCurve->detach(); + if (!plot->showPowerD) wattsDCurve->detach(); + if (!plot->showCadD) cadDCurve->detach(); + if (!plot->showTorqueD) nmDCurve->detach(); + if (!plot->showHrD) hrDCurve->detach(); if (!plot->showCad) cadCurve->detach(); if (!plot->showAlt) altCurve->detach(); if (!plot->showTemp) tempCurve->detach(); @@ -524,6 +557,10 @@ AllPlot::AllPlot(AllPlotWindow *parent, Context *context, RideFile::SeriesType s showHr(true), showSpeed(true), showAccel(false), + showPowerD(false), + showCadD(false), + showTorqueD(false), + showHrD(false), showCad(true), showAlt(true), showTemp(true), @@ -631,6 +668,10 @@ AllPlot::configChanged() standard->hrCurve->setRenderHint(QwtPlotItem::RenderAntialiased); standard->speedCurve->setRenderHint(QwtPlotItem::RenderAntialiased); standard->accelCurve->setRenderHint(QwtPlotItem::RenderAntialiased); + standard->wattsDCurve->setRenderHint(QwtPlotItem::RenderAntialiased); + standard->cadDCurve->setRenderHint(QwtPlotItem::RenderAntialiased); + standard->nmDCurve->setRenderHint(QwtPlotItem::RenderAntialiased); + standard->hrDCurve->setRenderHint(QwtPlotItem::RenderAntialiased); standard->cadCurve->setRenderHint(QwtPlotItem::RenderAntialiased); standard->altCurve->setRenderHint(QwtPlotItem::RenderAntialiased); standard->tempCurve->setRenderHint(QwtPlotItem::RenderAntialiased); @@ -646,6 +687,7 @@ AllPlot::configChanged() QPen wattsPen = QPen(GColor(CPOWER)); wattsPen.setWidth(width); standard->wattsCurve->setPen(wattsPen); + standard->wattsDCurve->setPen(wattsPen); QPen npPen = QPen(GColor(CNPOWER)); npPen.setWidth(width); standard->npCurve->setPen(npPen); @@ -658,6 +700,7 @@ AllPlot::configChanged() QPen hrPen = QPen(GColor(CHEARTRATE)); hrPen.setWidth(width); standard->hrCurve->setPen(hrPen); + standard->hrDCurve->setPen(hrPen); QPen speedPen = QPen(GColor(CSPEED)); speedPen.setWidth(width); standard->speedCurve->setPen(speedPen); @@ -667,6 +710,7 @@ AllPlot::configChanged() QPen cadPen = QPen(GColor(CCADENCE)); cadPen.setWidth(width); standard->cadCurve->setPen(cadPen); + standard->cadDCurve->setPen(cadPen); QPen altPen(GColor(CALTITUDE)); altPen.setWidth(width); standard->altCurve->setPen(altPen); @@ -685,6 +729,7 @@ AllPlot::configChanged() QPen torquePen = QPen(GColor(CTORQUE)); torquePen.setWidth(width); standard->torqueCurve->setPen(torquePen); + standard->nmDCurve->setPen(torquePen); QPen balanceLPen = QPen(GColor(CBALANCERIGHT)); balanceLPen.setWidth(width); standard->balanceLCurve->setPen(balanceLPen); @@ -751,6 +796,22 @@ AllPlot::configChanged() p.setAlpha(64); standard->accelCurve->setBrush(QBrush(p)); + p = standard->wattsDCurve->pen().color(); + p.setAlpha(64); + standard->wattsDCurve->setBrush(QBrush(p)); + + p = standard->cadDCurve->pen().color(); + p.setAlpha(64); + standard->cadDCurve->setBrush(QBrush(p)); + + p = standard->nmDCurve->pen().color(); + p.setAlpha(64); + standard->nmDCurve->setBrush(QBrush(p)); + + p = standard->hrDCurve->pen().color(); + p.setAlpha(64); + standard->hrDCurve->setBrush(QBrush(p)); + p = standard->speedCurve->pen().color(); p.setAlpha(64); standard->speedCurve->setBrush(QBrush(p)); @@ -783,6 +844,10 @@ AllPlot::configChanged() standard->hrCurve->setBrush(Qt::NoBrush); standard->speedCurve->setBrush(Qt::NoBrush); standard->accelCurve->setBrush(Qt::NoBrush); + standard->wattsDCurve->setBrush(Qt::NoBrush); + standard->cadDCurve->setBrush(Qt::NoBrush); + standard->nmDCurve->setBrush(Qt::NoBrush); + standard->hrDCurve->setBrush(Qt::NoBrush); standard->cadCurve->setBrush(Qt::NoBrush); standard->torqueCurve->setBrush(Qt::NoBrush); standard->tempCurve->setBrush(Qt::NoBrush); @@ -862,9 +927,9 @@ AllPlot::setHighlightIntervals(bool state) } struct DataPoint { - double time, hr, watts, np, ap, xp, speed, cad, alt, temp, wind, torque, lrbalance, kphd; - DataPoint(double t, double h, double w, double n, double l, double x, double s, double c, double a, double te, double wi, double tq, double lrb, double kphd) : - time(t), hr(h), watts(w), np(n), ap(l), xp(x), speed(s), cad(c), alt(a), temp(te), wind(wi), torque(tq), lrbalance(lrb), kphd(kphd) {} + double time, hr, watts, np, ap, xp, speed, cad, alt, temp, wind, torque, lrbalance, kphd, wattsd, cadd, nmd, hrd; + DataPoint(double t, double h, double w, double n, double l, double x, double s, double c, double a, double te, double wi, double tq, double lrb, double kphd, double wattsd, double cadd, double nmd, double hrd) : + time(t), hr(h), watts(w), np(n), ap(l), xp(x), speed(s), cad(c), alt(a), temp(te), wind(wi), torque(tq), lrbalance(lrb), kphd(kphd), wattsd(wattsd), cadd(cadd), nmd(nmd), hrd(hrd) {} }; bool AllPlot::shadeZones() const @@ -940,8 +1005,14 @@ AllPlot::recalc(AllPlotObject *objects) objects->hrCurve->setSamples(data, data); if (!objects->speedArray.empty()) objects->speedCurve->setSamples(data, data); - if (!objects->accelArray.empty()) - objects->accelCurve->setSamples(data, data); + + // deltas + if (!objects->accelArray.empty()) objects->accelCurve->setSamples(data, data); + if (!objects->wattsDArray.empty()) objects->wattsDCurve->setSamples(data, data); + if (!objects->cadDArray.empty()) objects->cadDCurve->setSamples(data, data); + if (!objects->nmDArray.empty()) objects->nmDCurve->setSamples(data, data); + if (!objects->hrDArray.empty()) objects->hrDCurve->setSamples(data, data); + if (!objects->cadArray.empty()) objects->cadCurve->setSamples(data, data); if (!objects->altArray.empty()) @@ -970,6 +1041,10 @@ AllPlot::recalc(AllPlotObject *objects) double totalHr = 0.0; double totalSpeed = 0.0; double totalAccel = 0.0; + double totalWattsD = 0.0; + double totalCadD = 0.0; + double totalNmD = 0.0; + double totalHrD = 0.0; double totalCad = 0.0; double totalDist = 0.0; double totalAlt = 0.0; @@ -987,6 +1062,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr.resize(rideTimeSecs + 1); objects->smoothSpeed.resize(rideTimeSecs + 1); objects->smoothAccel.resize(rideTimeSecs + 1); + objects->smoothWattsD.resize(rideTimeSecs + 1); + objects->smoothCadD.resize(rideTimeSecs + 1); + objects->smoothNmD.resize(rideTimeSecs + 1); + objects->smoothHrD.resize(rideTimeSecs + 1); objects->smoothCad.resize(rideTimeSecs + 1); objects->smoothTime.resize(rideTimeSecs + 1); objects->smoothDistance.resize(rideTimeSecs + 1); @@ -1007,6 +1086,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr[secs] = 0.0; objects->smoothSpeed[secs] = 0.0; objects->smoothAccel[secs] = 0.0; + objects->smoothWattsD[secs] = 0.0; + objects->smoothCadD[secs] = 0.0; + objects->smoothNmD[secs] = 0.0; + objects->smoothHrD[secs] = 0.0; objects->smoothCad[secs] = 0.0; objects->smoothTime[secs] = secs / 60.0; objects->smoothDistance[secs] = 0.0; @@ -1035,7 +1118,11 @@ AllPlot::recalc(AllPlotObject *objects) (!objects->windArray.empty() ? objects->windArray[i] : 0), (!objects->torqueArray.empty() ? objects->torqueArray[i] : 0), (!objects->balanceArray.empty() ? objects->balanceArray[i] : 0), - (!objects->accelArray.empty() ? objects->accelArray[i] : 0)); + (!objects->accelArray.empty() ? objects->accelArray[i] : 0), + (!objects->wattsDArray.empty() ? objects->wattsDArray[i] : 0), + (!objects->cadDArray.empty() ? objects->cadDArray[i] : 0), + (!objects->nmDArray.empty() ? objects->nmDArray[i] : 0), + (!objects->hrDArray.empty() ? objects->hrDArray[i] : 0)); if (!objects->wattsArray.empty()) totalWatts += objects->wattsArray[i]; if (!objects->npArray.empty()) @@ -1046,8 +1133,13 @@ AllPlot::recalc(AllPlotObject *objects) totalAP += objects->apArray[i]; if (!objects->hrArray.empty()) totalHr += objects->hrArray[i]; - if (!objects->accelArray.empty()) - totalAccel += objects->accelArray[i]; + + if (!objects->accelArray.empty()) totalAccel += objects->accelArray[i]; + if (!objects->wattsDArray.empty()) totalWattsD += objects->wattsDArray[i]; + if (!objects->cadDArray.empty()) totalCadD += objects->cadDArray[i]; + if (!objects->nmDArray.empty()) totalNmD += objects->nmDArray[i]; + if (!objects->hrDArray.empty()) totalHrD += objects->hrDArray[i]; + if (!objects->speedArray.empty()) totalSpeed += objects->speedArray[i]; if (!objects->cadArray.empty()) @@ -1083,6 +1175,10 @@ AllPlot::recalc(AllPlotObject *objects) totalHr -= dp.hr; totalSpeed -= dp.speed; totalAccel -= dp.kphd; + totalWattsD -= dp.wattsd; + totalCadD -= dp.cadd; + totalNmD -= dp.nmd; + totalHrD -= dp.hrd; totalCad -= dp.cad; totalAlt -= dp.alt; totalTemp -= dp.temp; @@ -1101,6 +1197,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr[secs] = 0.0; objects->smoothSpeed[secs] = 0.0; objects->smoothAccel[secs] = 0.0; + objects->smoothWattsD[secs] = 0.0; + objects->smoothCadD[secs] = 0.0; + objects->smoothNmD[secs] = 0.0; + objects->smoothHrD[secs] = 0.0; objects->smoothCad[secs] = 0.0; objects->smoothAltitude[secs] = objects->smoothAltitude[secs - 1]; objects->smoothTemp[secs] = 0.0; @@ -1118,6 +1218,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr[secs] = totalHr / list.size(); objects->smoothSpeed[secs] = totalSpeed / list.size(); objects->smoothAccel[secs] = totalAccel / double(list.size()); + objects->smoothWattsD[secs] = totalWattsD / double(list.size()); + objects->smoothCadD[secs] = totalCadD / double(list.size()); + objects->smoothNmD[secs] = totalNmD / double(list.size()); + objects->smoothHrD[secs] = totalHrD / double(list.size()); objects->smoothCad[secs] = totalCad / list.size(); objects->smoothAltitude[secs] = totalAlt / list.size(); objects->smoothTemp[secs] = totalTemp / list.size(); @@ -1152,6 +1256,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr.resize(0); objects->smoothSpeed.resize(0); objects->smoothAccel.resize(0); + objects->smoothWattsD.resize(0); + objects->smoothCadD.resize(0); + objects->smoothNmD.resize(0); + objects->smoothHrD.resize(0); objects->smoothCad.resize(0); objects->smoothTime.resize(0); objects->smoothDistance.resize(0); @@ -1171,6 +1279,10 @@ AllPlot::recalc(AllPlotObject *objects) objects->smoothHr.append(dp->hr); objects->smoothSpeed.append(context->athlete->useMetricUnits ? dp->kph : dp->kph * MILES_PER_KM); objects->smoothAccel.append(dp->kphd); + objects->smoothWattsD.append(dp->wattsd); + objects->smoothCadD.append(dp->cadd); + objects->smoothNmD.append(dp->nmd); + objects->smoothHrD.append(dp->hrd); objects->smoothCad.append(dp->cad); objects->smoothTime.append(dp->secs/60); objects->smoothDistance.append(context->athlete->useMetricUnits ? dp->km : dp->km * MILES_PER_KM); @@ -1241,6 +1353,22 @@ AllPlot::recalc(AllPlotObject *objects) objects->accelCurve->setSamples(xaxis.data() + startingIndex, objects->smoothAccel.data() + startingIndex, totalPoints); } + if (!objects->wattsDArray.empty()) { + objects->wattsDCurve->setSamples(xaxis.data() + startingIndex, objects->smoothWattsD.data() + startingIndex, totalPoints); + } + + if (!objects->cadDArray.empty()) { + objects->cadDCurve->setSamples(xaxis.data() + startingIndex, objects->smoothCadD.data() + startingIndex, totalPoints); + } + + if (!objects->nmDArray.empty()) { + objects->nmDCurve->setSamples(xaxis.data() + startingIndex, objects->smoothNmD.data() + startingIndex, totalPoints); + } + + if (!objects->hrDArray.empty()) { + objects->hrDCurve->setSamples(xaxis.data() + startingIndex, objects->smoothHrD.data() + startingIndex, totalPoints); + } + if (!objects->cadArray.empty()) { objects->cadCurve->setSamples(xaxis.data() + startingIndex, objects->smoothCad.data() + startingIndex, totalPoints); } @@ -1689,7 +1817,6 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) double *smoothT = &plot->standard->smoothTime[startidx]; double *smoothHR = &plot->standard->smoothHr[startidx]; double *smoothS = &plot->standard->smoothSpeed[startidx]; - double *smoothAC = &plot->standard->smoothAccel[startidx]; double *smoothC = &plot->standard->smoothCad[startidx]; double *smoothA = &plot->standard->smoothAltitude[startidx]; double *smoothD = &plot->standard->smoothDistance[startidx]; @@ -1699,6 +1826,13 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) double *smoothBALL = &plot->standard->smoothBalanceL[startidx]; double *smoothBALR = &plot->standard->smoothBalanceR[startidx]; + // deltas + double *smoothAC = &plot->standard->smoothAccel[startidx]; + double *smoothWD = &plot->standard->smoothWattsD[startidx]; + double *smoothCD = &plot->standard->smoothCadD[startidx]; + double *smoothND = &plot->standard->smoothNmD[startidx]; + double *smoothHD = &plot->standard->smoothHrD[startidx]; + QwtIntervalSample *smoothRS = &plot->standard->smoothRelSpeed[startidx]; double *xaxis = bydist ? smoothD : smoothT; @@ -1747,7 +1881,11 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) standard->apCurve->detach(); standard->hrCurve->detach(); standard->speedCurve->detach(); - standard->accelCurve->detach(); + standard->accelCurve->detach(); + standard->wattsDCurve->detach(); + standard->cadDCurve->detach(); + standard->nmDCurve->detach(); + standard->hrDCurve->detach(); standard->cadCurve->detach(); standard->altCurve->detach(); standard->tempCurve->detach(); @@ -1765,6 +1903,10 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) standard->hrCurve->setVisible(rideItem->ride()->areDataPresent()->hr && showHr); standard->speedCurve->setVisible(rideItem->ride()->areDataPresent()->kph && showSpeed); standard->accelCurve->setVisible(rideItem->ride()->areDataPresent()->kph && showAccel); + standard->wattsDCurve->setVisible(rideItem->ride()->areDataPresent()->watts && showPowerD); + standard->cadDCurve->setVisible(rideItem->ride()->areDataPresent()->cad && showCadD); + standard->nmDCurve->setVisible(rideItem->ride()->areDataPresent()->nm && showTorqueD); + standard->hrDCurve->setVisible(rideItem->ride()->areDataPresent()->hr && showHrD); standard->cadCurve->setVisible(rideItem->ride()->areDataPresent()->cad && showCad); standard->altCurve->setVisible(rideItem->ride()->areDataPresent()->alt && showAlt); standard->tempCurve->setVisible(rideItem->ride()->areDataPresent()->temp && showTemp); @@ -1784,6 +1926,10 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) standard->hrCurve->setSamples(xaxis, smoothHR,stopidx-startidx); standard->speedCurve->setSamples(xaxis, smoothS, stopidx-startidx); standard->accelCurve->setSamples(xaxis, smoothAC, stopidx-startidx); + standard->wattsDCurve->setSamples(xaxis, smoothWD, stopidx-startidx); + standard->cadDCurve->setSamples(xaxis, smoothCD, stopidx-startidx); + standard->nmDCurve->setSamples(xaxis, smoothND, stopidx-startidx); + standard->hrDCurve->setSamples(xaxis, smoothHD, stopidx-startidx); standard->cadCurve->setSamples(xaxis, smoothC, stopidx-startidx); standard->altCurve->setSamples(xaxis, smoothA, stopidx-startidx); standard->tempCurve->setSamples(xaxis, smoothTE, stopidx-startidx); @@ -1892,6 +2038,50 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) } standard->accelCurve->setSymbol(sym); + sym = new QwtSymbol; + sym->setPen(QPen(GColor(CPLOTMARKER))); + if (stopidx-startidx < 150) { + sym->setStyle(QwtSymbol::Ellipse); + sym->setSize(3); + } else { + sym->setStyle(QwtSymbol::NoSymbol); + sym->setSize(0); + } + standard->wattsDCurve->setSymbol(sym); + + sym = new QwtSymbol; + sym->setPen(QPen(GColor(CPLOTMARKER))); + if (stopidx-startidx < 150) { + sym->setStyle(QwtSymbol::Ellipse); + sym->setSize(3); + } else { + sym->setStyle(QwtSymbol::NoSymbol); + sym->setSize(0); + } + standard->cadDCurve->setSymbol(sym); + + sym = new QwtSymbol; + sym->setPen(QPen(GColor(CPLOTMARKER))); + if (stopidx-startidx < 150) { + sym->setStyle(QwtSymbol::Ellipse); + sym->setSize(3); + } else { + sym->setStyle(QwtSymbol::NoSymbol); + sym->setSize(0); + } + standard->nmDCurve->setSymbol(sym); + + sym = new QwtSymbol; + sym->setPen(QPen(GColor(CPLOTMARKER))); + if (stopidx-startidx < 150) { + sym->setStyle(QwtSymbol::Ellipse); + sym->setSize(3); + } else { + sym->setStyle(QwtSymbol::NoSymbol); + sym->setSize(0); + } + standard->hrDCurve->setSymbol(sym); + sym = new QwtSymbol; sym->setPen(QPen(GColor(CPLOTMARKER))); if (stopidx-startidx < 150) { @@ -1989,6 +2179,18 @@ AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx) if (!plot->standard->smoothAccel.empty()) { standard->accelCurve->attach(this); } + if (!plot->standard->smoothWattsD.empty()) { + standard->wattsDCurve->attach(this); + } + if (!plot->standard->smoothCadD.empty()) { + standard->cadDCurve->attach(this); + } + if (!plot->standard->smoothNmD.empty()) { + standard->nmDCurve->attach(this); + } + if (!plot->standard->smoothHrD.empty()) { + standard->hrDCurve->attach(this); + } if (!plot->standard->smoothSpeed.empty()) { standard->speedCurve->attach(this); } @@ -2047,6 +2249,10 @@ AllPlot::setDataFromPlot(AllPlot *plot) standard->hrCurve->detach(); standard->speedCurve->detach(); standard->accelCurve->detach(); + standard->wattsDCurve->detach(); + standard->cadDCurve->detach(); + standard->nmDCurve->detach(); + standard->hrDCurve->detach(); standard->cadCurve->detach(); standard->altCurve->detach(); standard->tempCurve->detach(); @@ -2064,6 +2270,10 @@ AllPlot::setDataFromPlot(AllPlot *plot) standard->hrCurve->setVisible(false); standard->speedCurve->setVisible(false); standard->accelCurve->setVisible(false); + standard->wattsDCurve->setVisible(false); + standard->cadDCurve->setVisible(false); + standard->nmDCurve->setVisible(false); + standard->hrDCurve->setVisible(false); standard->cadCurve->setVisible(false); standard->altCurve->setVisible(false); standard->tempCurve->setVisible(false); @@ -2104,6 +2314,38 @@ AllPlot::setDataFromPlot(AllPlot *plot) } break; + case RideFile::wattsd: + { + ourCurve = standard->wattsDCurve; + thereCurve = referencePlot->standard->wattsDCurve; + title = tr("Power Delta"); + } + break; + + case RideFile::cadd: + { + ourCurve = standard->cadDCurve; + thereCurve = referencePlot->standard->cadDCurve; + title = tr("Cadence Delta"); + } + break; + + case RideFile::nmd: + { + ourCurve = standard->nmDCurve; + thereCurve = referencePlot->standard->nmDCurve; + title = tr("Torque Delta"); + } + break; + + case RideFile::hrd: + { + ourCurve = standard->hrDCurve; + thereCurve = referencePlot->standard->hrDCurve; + title = tr("Heartrate Delta"); + } + break; + case RideFile::kph: { ourCurve = standard->speedCurve; @@ -2360,6 +2602,10 @@ AllPlot::setDataFromPlots(QList plots) standard->hrCurve->detach(); standard->speedCurve->detach(); standard->accelCurve->detach(); + standard->wattsDCurve->detach(); + standard->cadDCurve->detach(); + standard->nmDCurve->detach(); + standard->hrDCurve->detach(); standard->cadCurve->detach(); standard->altCurve->detach(); standard->tempCurve->detach(); @@ -2377,6 +2623,10 @@ AllPlot::setDataFromPlots(QList plots) standard->hrCurve->setVisible(false); standard->speedCurve->setVisible(false); standard->accelCurve->setVisible(false); + standard->wattsDCurve->setVisible(false); + standard->cadDCurve->setVisible(false); + standard->nmDCurve->setVisible(false); + standard->hrDCurve->setVisible(false); standard->cadCurve->setVisible(false); standard->altCurve->setVisible(false); standard->tempCurve->setVisible(false); @@ -2435,12 +2685,48 @@ AllPlot::setDataFromPlots(QList plots) case RideFile::kphd: { ourCurve = new QwtPlotCurve(tr("Acceleration")); - //ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); thereCurve = referencePlot->standard->accelCurve; title = tr("Acceleration"); } break; + case RideFile::wattsd: + { + ourCurve = new QwtPlotCurve(tr("Power Delta")); + ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + thereCurve = referencePlot->standard->wattsDCurve; + title = tr("Power Delta"); + } + break; + + case RideFile::cadd: + { + ourCurve = new QwtPlotCurve(tr("Cadence Delta")); + ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + thereCurve = referencePlot->standard->cadDCurve; + title = tr("Cadence Delta"); + } + break; + + case RideFile::nmd: + { + ourCurve = new QwtPlotCurve(tr("Torque Delta")); + ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + thereCurve = referencePlot->standard->nmDCurve; + title = tr("Torque Delta"); + } + break; + + case RideFile::hrd: + { + ourCurve = new QwtPlotCurve(tr("Heartrate Delta")); + ourCurve->setPaintAttribute(QwtPlotCurve::FilterPoints, true); + thereCurve = referencePlot->standard->hrDCurve; + title = tr("Heartrate Delta"); + } + break; + case RideFile::kph: { ourCurve = new QwtPlotCurve(tr("Speed")); @@ -2744,6 +3030,10 @@ AllPlot::setDataFromObject(AllPlotObject *object, AllPlot *reference) standard->hrCurve->detach(); standard->speedCurve->detach(); standard->accelCurve->detach(); + standard->wattsDCurve->detach(); + standard->cadDCurve->detach(); + standard->nmDCurve->detach(); + standard->hrDCurve->detach(); standard->cadCurve->detach(); standard->altCurve->detach(); standard->tempCurve->detach(); @@ -2763,6 +3053,10 @@ AllPlot::setDataFromObject(AllPlotObject *object, AllPlot *reference) standard->hrCurve->setVisible(false); standard->speedCurve->setVisible(false); standard->accelCurve->setVisible(false); + standard->wattsDCurve->setVisible(false); + standard->cadDCurve->setVisible(false); + standard->nmDCurve->setVisible(false); + standard->hrDCurve->setVisible(false); standard->cadCurve->setVisible(false); standard->altCurve->setVisible(false); standard->tempCurve->setVisible(false); @@ -2823,6 +3117,30 @@ AllPlot::setDataFromObject(AllPlotObject *object, AllPlot *reference) standard->accelCurve->setVisible(true); } + if (!object->wattsDArray.empty()) { + standard->wattsDCurve->setSamples(xaxis.data(), object->smoothWattsD.data(), totalPoints); + standard->wattsDCurve->attach(this); + standard->wattsDCurve->setVisible(true); + } + + if (!object->cadDArray.empty()) { + standard->cadDCurve->setSamples(xaxis.data(), object->smoothCadD.data(), totalPoints); + standard->cadDCurve->attach(this); + standard->cadDCurve->setVisible(true); + } + + if (!object->nmDArray.empty()) { + standard->nmDCurve->setSamples(xaxis.data(), object->smoothNmD.data(), totalPoints); + standard->nmDCurve->attach(this); + standard->nmDCurve->setVisible(true); + } + + if (!object->hrDArray.empty()) { + standard->hrDCurve->setSamples(xaxis.data(), object->smoothHrD.data(), totalPoints); + standard->hrDCurve->attach(this); + standard->hrDCurve->setVisible(true); + } + if (!object->cadArray.empty()) { standard->cadCurve->setSamples(xaxis.data(), object->smoothCad.data(), totalPoints); standard->cadCurve->attach(this); @@ -2876,6 +3194,10 @@ AllPlot::setDataFromObject(AllPlotObject *object, AllPlot *reference) standard->hrCurve->setVisible(referencePlot->showHr); standard->speedCurve->setVisible(referencePlot->showSpeed); standard->accelCurve->setVisible(referencePlot->showAccel); + standard->wattsDCurve->setVisible(referencePlot->showPowerD); + standard->cadDCurve->setVisible(referencePlot->showCadD); + standard->nmDCurve->setVisible(referencePlot->showTorqueD); + standard->hrDCurve->setVisible(referencePlot->showHrD); standard->cadCurve->setVisible(referencePlot->showCad); standard->altCurve->setVisible(referencePlot->showAlt); standard->tempCurve->setVisible(referencePlot->showTemp); @@ -2941,6 +3263,10 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) here->hrArray.resize(dataPresent->hr ? npoints : 0); here->speedArray.resize(dataPresent->kph ? npoints : 0); here->accelArray.resize(dataPresent->kph ? npoints : 0); + here->wattsDArray.resize(dataPresent->watts ? npoints : 0); + here->cadDArray.resize(dataPresent->cad ? npoints : 0); + here->nmDArray.resize(dataPresent->nm ? npoints : 0); + here->hrDArray.resize(dataPresent->hr ? npoints : 0); here->cadArray.resize(dataPresent->cad ? npoints : 0); here->altArray.resize(dataPresent->alt ? npoints : 0); here->tempArray.resize(dataPresent->temp ? npoints : 0); @@ -2960,6 +3286,10 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) here->hrCurve->detach(); here->speedCurve->detach(); here->accelCurve->detach(); + here->wattsDCurve->detach(); + here->cadDCurve->detach(); + here->nmDCurve->detach(); + here->hrDCurve->detach(); here->cadCurve->detach(); here->altCurve->detach(); here->tempCurve->detach(); @@ -2979,7 +3309,14 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) } if (!here->hrArray.empty()) here->hrCurve->attach(this); if (!here->speedArray.empty()) here->speedCurve->attach(this); + + // deltas if (!here->accelArray.empty()) here->accelCurve->attach(this); + if (!here->wattsDArray.empty()) here->wattsDCurve->attach(this); + if (!here->cadDArray.empty()) here->cadDCurve->attach(this); + if (!here->nmDArray.empty()) here->nmDCurve->attach(this); + if (!here->hrDArray.empty()) here->hrDCurve->attach(this); + if (!here->cadArray.empty()) here->cadCurve->attach(this); if (!here->tempArray.empty()) here->tempCurve->attach(this); if (!here->windArray.empty()) here->windCurve->attach(this); @@ -2997,7 +3334,6 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) here->apCurve->setVisible(dataPresent->apower && showAP); here->hrCurve->setVisible(dataPresent->hr && showHr); here->speedCurve->setVisible(dataPresent->kph && showSpeed); - here->accelCurve->setVisible(dataPresent->kph && showAccel); here->cadCurve->setVisible(dataPresent->cad && showCad); here->altCurve->setVisible(dataPresent->alt && showAlt); here->tempCurve->setVisible(dataPresent->temp && showTemp); @@ -3006,6 +3342,13 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) here->balanceLCurve->setVisible(dataPresent->lrbalance && showBalance); here->balanceRCurve->setVisible(dataPresent->lrbalance && showBalance); + // deltas + here->accelCurve->setVisible(dataPresent->kph && showAccel); + here->wattsDCurve->setVisible(dataPresent->watts && showPowerD); + here->cadDCurve->setVisible(dataPresent->cad && showCadD); + here->nmDCurve->setVisible(dataPresent->nm && showTorqueD); + here->hrDCurve->setVisible(dataPresent->hr && showHrD); + int arrayLength = 0; foreach (const RideFilePoint *point, ride->dataPoints()) { @@ -3030,8 +3373,13 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) if (!here->hrArray.empty()) here->hrArray[arrayLength] = max(0, point->hr); - if (!here->accelArray.empty()) - here->accelArray[arrayLength] = point->kphd; + + // delta series + if (!here->accelArray.empty()) here->accelArray[arrayLength] = point->kphd; + if (!here->wattsDArray.empty()) here->wattsDArray[arrayLength] = point->wattsd; + if (!here->cadDArray.empty()) here->cadDArray[arrayLength] = point->cadd; + if (!here->nmDArray.empty()) here->nmDArray[arrayLength] = point->nmd; + if (!here->hrDArray.empty()) here->hrDArray[arrayLength] = point->hrd; if (!here->speedArray.empty()) here->speedArray[arrayLength] = max(0, @@ -3082,6 +3430,10 @@ AllPlot::setDataFromRideFile(RideFile *ride, AllPlotObject *here) here->hrCurve->detach(); here->speedCurve->detach(); here->accelCurve->detach(); + here->wattsDCurve->detach(); + here->cadDCurve->detach(); + here->nmDCurve->detach(); + here->hrDCurve->detach(); here->cadCurve->detach(); here->altCurve->detach(); here->tempCurve->detach(); @@ -3217,6 +3569,58 @@ AllPlot::setShowAccel(bool show) replot(); } +void +AllPlot::setShowPowerD(bool show) +{ + showPowerD = show; + standard->wattsDCurve->setVisible(show); + setYMax(); + + // remember the curves and colors + isolation = false; + curveColors->saveState(); + replot(); +} + +void +AllPlot::setShowCadD(bool show) +{ + showCadD = show; + standard->cadDCurve->setVisible(show); + setYMax(); + + // remember the curves and colors + isolation = false; + curveColors->saveState(); + replot(); +} + +void +AllPlot::setShowTorqueD(bool show) +{ + showTorqueD = show; + standard->nmDCurve->setVisible(show); + setYMax(); + + // remember the curves and colors + isolation = false; + curveColors->saveState(); + replot(); +} + +void +AllPlot::setShowHrD(bool show) +{ + showHrD = show; + standard->hrDCurve->setVisible(show); + setYMax(); + + // remember the curves and colors + isolation = false; + curveColors->saveState(); + replot(); +} + void AllPlot::setShowCad(bool show) { @@ -3358,6 +3762,22 @@ AllPlot::setPaintBrush(int state) p.setAlpha(64); standard->accelCurve->setBrush(QBrush(p)); + p = standard->wattsDCurve->pen().color(); + p.setAlpha(64); + standard->wattsDCurve->setBrush(QBrush(p)); + + p = standard->cadDCurve->pen().color(); + p.setAlpha(64); + standard->cadDCurve->setBrush(QBrush(p)); + + p = standard->nmDCurve->pen().color(); + p.setAlpha(64); + standard->nmDCurve->setBrush(QBrush(p)); + + p = standard->hrDCurve->pen().color(); + p.setAlpha(64); + standard->hrDCurve->setBrush(QBrush(p)); + p = standard->speedCurve->pen().color(); p.setAlpha(64); standard->speedCurve->setBrush(QBrush(p)); @@ -3390,6 +3810,10 @@ AllPlot::setPaintBrush(int state) standard->hrCurve->setBrush(Qt::NoBrush); standard->speedCurve->setBrush(Qt::NoBrush); standard->accelCurve->setBrush(Qt::NoBrush); + standard->wattsDCurve->setBrush(Qt::NoBrush); + standard->cadDCurve->setBrush(Qt::NoBrush); + standard->hrDCurve->setBrush(Qt::NoBrush); + standard->nmDCurve->setBrush(Qt::NoBrush); standard->cadCurve->setBrush(Qt::NoBrush); standard->tempCurve->setBrush(Qt::NoBrush); standard->torqueCurve->setBrush(Qt::NoBrush); diff --git a/src/AllPlot.h b/src/AllPlot.h index 93e1dcfac..e4850c440 100644 --- a/src/AllPlot.h +++ b/src/AllPlot.h @@ -302,6 +302,10 @@ class AllPlotObject : public QObject QwtPlotCurve *hrCurve; QwtPlotCurve *speedCurve; QwtPlotCurve *accelCurve; + QwtPlotCurve *wattsDCurve; + QwtPlotCurve *cadDCurve; + QwtPlotCurve *nmDCurve; + QwtPlotCurve *hrDCurve; QwtPlotCurve *cadCurve; QwtPlotCurve *altCurve; QwtPlotCurve *tempCurve; @@ -320,6 +324,10 @@ class AllPlotObject : public QObject QVector apArray; QVector speedArray; QVector accelArray; + QVector wattsDArray; + QVector cadDArray; + QVector nmDArray; + QVector hrDArray; QVector cadArray; QVector timeArray; QVector distanceArray; @@ -337,6 +345,10 @@ class AllPlotObject : public QObject QVector smoothHr; QVector smoothSpeed; QVector smoothAccel; + QVector smoothWattsD; + QVector smoothCadD; + QVector smoothNmD; + QVector smoothHrD; QVector smoothCad; QVector smoothTime; QVector smoothDistance; @@ -412,13 +424,17 @@ class AllPlot : public QwtPlot public slots: + void setShowAccel(bool show); + void setShowPowerD(bool show); + void setShowCadD(bool show); + void setShowTorqueD(bool show); + void setShowHrD(bool show); void setShowPower(int id); void setShowNP(bool show); void setShowXP(bool show); void setShowAP(bool show); void setShowHr(bool show); void setShowSpeed(bool show); - void setShowAccel(bool show); void setShowCad(bool show); void setShowAlt(bool show); void setShowTemp(bool show); @@ -460,6 +476,10 @@ class AllPlot : public QwtPlot bool showHr; bool showSpeed; bool showAccel; + bool showPowerD; + bool showCadD; + bool showTorqueD; + bool showHrD; bool showCad; bool showAlt; bool showTemp; diff --git a/src/AllPlotWindow.cpp b/src/AllPlotWindow.cpp index ffece4a95..93f4a662f 100644 --- a/src/AllPlotWindow.cpp +++ b/src/AllPlotWindow.cpp @@ -147,6 +147,21 @@ AllPlotWindow::AllPlotWindow(Context *context) : showGrid = new QCheckBox(tr("Grid"), this); showGrid->setCheckState(Qt::Checked); cl1->addRow(new QLabel(""), showGrid); + cl1->addRow(new QLabel(""), new QLabel("")); + cl1->addRow(new QLabel("Delta Series"), new QLabel("")); + + showPowerD = new QCheckBox(tr("Power Δ"), this); + showPowerD->setCheckState(Qt::Unchecked); + cl1->addRow(new QLabel(""), showPowerD); + showCadD = new QCheckBox(tr("Cadence Δ"), this); + showCadD->setCheckState(Qt::Unchecked); + cl1->addRow(new QLabel(""), showCadD); + showTorqueD = new QCheckBox(tr("Torque Δ"), this); + showTorqueD->setCheckState(Qt::Unchecked); + cl1->addRow(new QLabel(""), showTorqueD); + showHrD = new QCheckBox(tr("Heartrate Δ"), this); + showHrD->setCheckState(Qt::Unchecked); + cl1->addRow(new QLabel(""), showHrD); showHr = new QCheckBox(tr("Heart Rate"), this); showHr->setCheckState(Qt::Checked); @@ -471,18 +486,22 @@ AllPlotWindow::AllPlotWindow(Context *context) : // common controls connect(showPower, SIGNAL(currentIndexChanged(int)), this, SLOT(setShowPower(int))); + connect(showCad, SIGNAL(stateChanged(int)), this, SLOT(setShowCad(int))); + connect(showTorque, SIGNAL(stateChanged(int)), this, SLOT(setShowTorque(int))); + connect(showHr, SIGNAL(stateChanged(int)), this, SLOT(setShowHr(int))); + connect(showPowerD, SIGNAL(stateChanged(int)), this, SLOT(setShowPowerD(int))); + connect(showCadD, SIGNAL(stateChanged(int)), this, SLOT(setShowCadD(int))); + connect(showTorqueD, SIGNAL(stateChanged(int)), this, SLOT(setShowTorqueD(int))); + connect(showHrD, SIGNAL(stateChanged(int)), this, SLOT(setShowHrD(int))); connect(showNP, SIGNAL(stateChanged(int)), this, SLOT(setShowNP(int))); connect(showXP, SIGNAL(stateChanged(int)), this, SLOT(setShowXP(int))); connect(showAP, SIGNAL(stateChanged(int)), this, SLOT(setShowAP(int))); - connect(showHr, SIGNAL(stateChanged(int)), this, SLOT(setShowHr(int))); connect(showSpeed, SIGNAL(stateChanged(int)), this, SLOT(setShowSpeed(int))); connect(showAccel, SIGNAL(stateChanged(int)), this, SLOT(setShowAccel(int))); - connect(showCad, SIGNAL(stateChanged(int)), this, SLOT(setShowCad(int))); connect(showAlt, SIGNAL(stateChanged(int)), this, SLOT(setShowAlt(int))); connect(showTemp, SIGNAL(stateChanged(int)), this, SLOT(setShowTemp(int))); connect(showWind, SIGNAL(stateChanged(int)), this, SLOT(setShowWind(int))); connect(showW, SIGNAL(stateChanged(int)), this, SLOT(setShowW(int))); - connect(showTorque, SIGNAL(stateChanged(int)), this, SLOT(setShowTorque(int))); connect(showBalance, SIGNAL(stateChanged(int)), this, SLOT(setShowBalance(int))); connect(showGrid, SIGNAL(stateChanged(int)), this, SLOT(setShowGrid(int))); connect(showFull, SIGNAL(stateChanged(int)), this, SLOT(setShowFull(int))); @@ -703,14 +722,18 @@ AllPlotWindow::compareChanged() // work out what we want to see QList wanted; if (showPower->currentIndex() < 2) wanted << RideFile::watts; + if (showPowerD->isChecked()) wanted << RideFile::wattsd; if (showHr->isChecked()) wanted << RideFile::hr; + if (showHrD->isChecked()) wanted << RideFile::hrd; if (showSpeed->isChecked()) wanted << RideFile::kph; if (showAccel->isChecked()) wanted << RideFile::kphd; if (showCad->isChecked()) wanted << RideFile::cad; + if (showCadD->isChecked()) wanted << RideFile::cadd; + if (showTorque->isChecked()) wanted << RideFile::nm; + if (showTorqueD->isChecked()) wanted << RideFile::nmd; if (showAlt->isChecked()) wanted << RideFile::alt; if (showTemp->isChecked()) wanted << RideFile::temp; if (showWind->isChecked()) wanted << RideFile::headwind; - if (showTorque->isChecked()) wanted << RideFile::nm; if (showNP->isChecked()) wanted << RideFile::NP; if (showXP->isChecked()) wanted << RideFile::xPower; if (showAP->isChecked()) wanted << RideFile::aPower; @@ -1252,21 +1275,29 @@ AllPlotWindow::setAllPlotWidgets(RideItem *ride) const RideFileDataPresent *dataPresent = ride->ride()->areDataPresent(); if (ride->ride() && ride->ride()->deviceType() != QString("Manual CSV")) { + showPowerD->setEnabled(dataPresent->watts); + showCadD->setEnabled(dataPresent->cad); + showTorqueD->setEnabled(dataPresent->nm); + showHrD->setEnabled(dataPresent->hr); showPower->setEnabled(dataPresent->watts); + showCad->setEnabled(dataPresent->cad); + showTorque->setEnabled(dataPresent->nm); showHr->setEnabled(dataPresent->hr); showSpeed->setEnabled(dataPresent->kph); showAccel->setEnabled(dataPresent->kph); - showCad->setEnabled(dataPresent->cad); showAlt->setEnabled(dataPresent->alt); showTemp->setEnabled(dataPresent->temp); showWind->setEnabled(dataPresent->headwind); - showTorque->setEnabled(dataPresent->nm); showBalance->setEnabled(dataPresent->lrbalance); } else { + showAccel->setEnabled(false); + showPowerD->setEnabled(false); + showCadD->setEnabled(false); + showTorqueD->setEnabled(false); + showHrD->setEnabled(false); showPower->setEnabled(false); showHr->setEnabled(false); showSpeed->setEnabled(false); - showAccel->setEnabled(false); showCad->setEnabled(false); showAlt->setEnabled(false); showTemp->setEnabled(false); @@ -1846,6 +1877,86 @@ AllPlotWindow::setShowAccel(int value) forceSetupSeriesStackPlots(); // scope changed so force redraw } +void +AllPlotWindow::setShowPowerD(int value) +{ + showPowerD->setChecked(value); + + // compare mode selfcontained update + if (isCompare()) { + compareChanged(); + return; + } + + bool checked = ( ( value == Qt::Checked ) && showPowerD->isEnabled()) ? true : false; + + allPlot->setShowPowerD(checked); + foreach (AllPlot *plot, allPlots) + plot->setShowPowerD(checked); + // and the series stacks too + forceSetupSeriesStackPlots(); // scope changed so force redraw +} + +void +AllPlotWindow::setShowCadD(int value) +{ + showCadD->setChecked(value); + + // compare mode selfcontained update + if (isCompare()) { + compareChanged(); + return; + } + + bool checked = ( ( value == Qt::Checked ) && showCadD->isEnabled()) ? true : false; + + allPlot->setShowCadD(checked); + foreach (AllPlot *plot, allPlots) + plot->setShowCadD(checked); + // and the series stacks too + forceSetupSeriesStackPlots(); // scope changed so force redraw +} + +void +AllPlotWindow::setShowTorqueD(int value) +{ + showTorqueD->setChecked(value); + + // compare mode selfcontained update + if (isCompare()) { + compareChanged(); + return; + } + + bool checked = ( ( value == Qt::Checked ) && showTorqueD->isEnabled()) ? true : false; + + allPlot->setShowTorqueD(checked); + foreach (AllPlot *plot, allPlots) + plot->setShowTorqueD(checked); + // and the series stacks too + forceSetupSeriesStackPlots(); // scope changed so force redraw +} + +void +AllPlotWindow::setShowHrD(int value) +{ + showHrD->setChecked(value); + + // compare mode selfcontained update + if (isCompare()) { + compareChanged(); + return; + } + + bool checked = ( ( value == Qt::Checked ) && showHrD->isEnabled()) ? true : false; + + allPlot->setShowHrD(checked); + foreach (AllPlot *plot, allPlots) + plot->setShowHrD(checked); + // and the series stacks too + forceSetupSeriesStackPlots(); // scope changed so force redraw +} + void AllPlotWindow::setShowCad(int value) { @@ -2361,14 +2472,18 @@ AllPlotWindow::setupSeriesStackPlots() // lets get a list of what we need to plot -- plot is same order as options in settings if (showPower->currentIndex() < 2 && rideItem->ride()->areDataPresent()->watts) serieslist << RideFile::watts; + if (showPowerD->isChecked() && rideItem->ride()->areDataPresent()->watts) serieslist << RideFile::wattsd; if (showHr->isChecked() && rideItem->ride()->areDataPresent()->hr) serieslist << RideFile::hr; + if (showHrD->isChecked() && rideItem->ride()->areDataPresent()->hr) serieslist << RideFile::hrd; if (showSpeed->isChecked() && rideItem->ride()->areDataPresent()->kph) serieslist << RideFile::kph; if (showAccel->isChecked() && rideItem->ride()->areDataPresent()->kph) serieslist << RideFile::kphd; if (showCad->isChecked() && rideItem->ride()->areDataPresent()->cad) serieslist << RideFile::cad; + if (showCadD->isChecked() && rideItem->ride()->areDataPresent()->cad) serieslist << RideFile::cadd; + if (showTorque->isChecked() && rideItem->ride()->areDataPresent()->nm) serieslist << RideFile::nm; + if (showTorqueD->isChecked() && rideItem->ride()->areDataPresent()->nm) serieslist << RideFile::nmd; if (showAlt->isChecked() && rideItem->ride()->areDataPresent()->alt) serieslist << RideFile::alt; if (showTemp->isChecked() && rideItem->ride()->areDataPresent()->temp) serieslist << RideFile::temp; if (showWind->isChecked() && rideItem->ride()->areDataPresent()->headwind) addHeadwind=true; //serieslist << RideFile::headwind; - if (showTorque->isChecked() && rideItem->ride()->areDataPresent()->nm) serieslist << RideFile::nm; if (showNP->isChecked() && rideItem->ride()->areDataPresent()->watts) serieslist << RideFile::NP; if (showXP->isChecked() && rideItem->ride()->areDataPresent()->watts) serieslist << RideFile::xPower; if (showAP->isChecked() && rideItem->ride()->areDataPresent()->watts) serieslist << RideFile::aPower; @@ -2539,6 +2654,10 @@ AllPlotWindow::setupStackPlots() _allPlot->setShowHr( (showHr->isEnabled()) ? ( showHr->checkState() == Qt::Checked ) : false ); _allPlot->setShowSpeed((showSpeed->isEnabled()) ? ( showSpeed->checkState() == Qt::Checked ) : false ); _allPlot->setShowAccel((showAccel->isEnabled()) ? ( showAccel->checkState() == Qt::Checked ) : false ); + _allPlot->setShowPowerD((showPowerD->isEnabled()) ? ( showPowerD->checkState() == Qt::Checked ) : false ); + _allPlot->setShowCadD((showCadD->isEnabled()) ? ( showCadD->checkState() == Qt::Checked ) : false ); + _allPlot->setShowTorqueD((showTorqueD->isEnabled()) ? ( showTorqueD->checkState() == Qt::Checked ) : false ); + _allPlot->setShowHrD((showHrD->isEnabled()) ? ( showHrD->checkState() == Qt::Checked ) : false ); _allPlot->setShowCad((showCad->isEnabled()) ? ( showCad->checkState() == Qt::Checked ) : false ); _allPlot->setShowAlt((showAlt->isEnabled()) ? ( showAlt->checkState() == Qt::Checked ) : false ); _allPlot->setShowTemp((showTemp->isEnabled()) ? ( showTemp->checkState() == Qt::Checked ) : false ); diff --git a/src/AllPlotWindow.h b/src/AllPlotWindow.h index d5571f245..bf349d3d3 100644 --- a/src/AllPlotWindow.h +++ b/src/AllPlotWindow.h @@ -58,16 +58,20 @@ class AllPlotWindow : public GcChartWindow Q_PROPERTY(int stackWidth READ _stackWidth WRITE setStackWidth USER true) Q_PROPERTY(int showGrid READ isShowGrid WRITE setShowGrid USER true) Q_PROPERTY(int showFull READ isShowFull WRITE setShowFull USER true) - Q_PROPERTY(int showHr READ isShowHr WRITE setShowHr USER true) Q_PROPERTY(int showNP READ isShowNP WRITE setShowNP USER true) Q_PROPERTY(int showXP READ isShowXP WRITE setShowXP USER true) Q_PROPERTY(int showAP READ isShowAP WRITE setShowAP USER true) Q_PROPERTY(int showSpeed READ isShowSpeed WRITE setShowSpeed USER true) Q_PROPERTY(int showAccel READ isShowAccel WRITE setShowAccel USER true) Q_PROPERTY(int showCad READ isShowCad WRITE setShowCad USER true) - Q_PROPERTY(int showAlt READ isShowAlt WRITE setShowAlt USER true) Q_PROPERTY(int showTorque READ isShowTorque WRITE setShowTorque USER true) Q_PROPERTY(int showPower READ isShowPower WRITE setShowPower USER true) + Q_PROPERTY(int showHr READ isShowHr WRITE setShowHr USER true) + Q_PROPERTY(int showCadD READ isShowCadD WRITE setShowCadD USER true) + Q_PROPERTY(int showTorqueD READ isShowTorqueD WRITE setShowTorqueD USER true) + Q_PROPERTY(int showPowerD READ isShowPowerD WRITE setShowPowerD USER true) + Q_PROPERTY(int showHrD READ isShowHrD WRITE setShowHrD USER true) + Q_PROPERTY(int showAlt READ isShowAlt WRITE setShowAlt USER true) Q_PROPERTY(int showBalance READ isShowBalance WRITE setShowBalance USER true) Q_PROPERTY(int showTemp READ isShowTemp WRITE setShowTemp USER true) Q_PROPERTY(int showW READ isShowW WRITE setShowW USER true) @@ -95,16 +99,20 @@ class AllPlotWindow : public GcChartWindow int _stackWidth() const { return stackWidth; } int isShowGrid() const { return showGrid->checkState(); } int isShowFull() const { return showFull->checkState(); } - int isShowHr() const { return showHr->checkState(); } int isShowNP() const { return showNP->checkState(); } int isShowXP() const { return showXP->checkState(); } int isShowAP() const { return showAP->checkState(); } + int isShowAlt() const { return showAlt->checkState(); } int isShowSpeed() const { return showSpeed->checkState(); } int isShowAccel() const { return showAccel->checkState(); } - int isShowCad() const { return showCad->checkState(); } - int isShowAlt() const { return showAlt->checkState(); } - int isShowTorque() const { return showTorque->checkState(); } int isShowPower() const { return showPower->currentIndex(); } + int isShowCad() const { return showCad->checkState(); } + int isShowTorque() const { return showTorque->checkState(); } + int isShowHr() const { return showHr->checkState(); } + int isShowPowerD() const { return showPowerD->checkState(); } + int isShowCadD() const { return showCadD->checkState(); } + int isShowTorqueD() const { return showTorqueD->checkState(); } + int isShowHrD() const { return showHrD->checkState(); } int isShowBalance() const { return showBalance->checkState(); } int isShowTemp() const { return showTemp->checkState(); } int isShowW() const { return showW->checkState(); } @@ -128,18 +136,22 @@ class AllPlotWindow : public GcChartWindow void setrSmoothingFromSlider(); void setrSmoothingFromLineEdit(); void setStackWidth(int x); - void setShowPower(int state); - void setShowHr(int state); void setShowNP(int state); void setShowXP(int state); void setShowAP(int state); void setShowSpeed(int state); void setShowAccel(int state); - void setShowCad(int state); void setShowAlt(int state); void setShowTemp(int state); void setShowWind(int state); + void setShowPower(int state); + void setShowCad(int state); void setShowTorque(int state); + void setShowHr(int state); + void setShowPowerD(int state); + void setShowCadD(int state); + void setShowTorqueD(int state); + void setShowHrD(int state); void setShowBalance(int state); void setShowW(int state); void setShowGrid(int state); @@ -221,20 +233,24 @@ class AllPlotWindow : public GcChartWindow QCheckBox *showGrid; QCheckBox *showFull; QCheckBox *paintBrush; - QCheckBox *showHr; + QCheckBox *showAlt; QCheckBox *showNP; QCheckBox *showXP; QCheckBox *showAP; QCheckBox *showSpeed; QCheckBox *showAccel; + QComboBox *showPower; QCheckBox *showCad; - QCheckBox *showAlt; + QCheckBox *showTorque; + QCheckBox *showHr; + QCheckBox *showPowerD; + QCheckBox *showCadD; + QCheckBox *showTorqueD; + QCheckBox *showHrD; QCheckBox *showTemp; QCheckBox *showWind; - QCheckBox *showTorque; QCheckBox *showBalance; QCheckBox *showW; - QComboBox *showPower; QComboBox *comboDistance; QSlider *smoothSlider; QLineEdit *smoothLineEdit; diff --git a/src/CpintPlot.cpp b/src/CpintPlot.cpp index b52b182ba..26baf08de 100644 --- a/src/CpintPlot.cpp +++ b/src/CpintPlot.cpp @@ -184,6 +184,22 @@ CpintPlot::setSeries(RideFile::SeriesType x) setAxisTitle(yLeft, tr("Average Heartrate (bpm)")); break; + case RideFile::wattsd: + setAxisTitle(yLeft, tr("Watts Delta (watts/s)")); + break; + + case RideFile::cadd: + setAxisTitle(yLeft, tr("Cadence Delta (rpm/s)")); + break; + + case RideFile::nmd: + setAxisTitle(yLeft, tr("Torque Delta (nm/s)")); + break; + + case RideFile::hrd: + setAxisTitle(yLeft, tr("Heartrate Delta (bpm/s)")); + break; + case RideFile::kphd: setAxisTitle(yLeft, tr("Acceleration (m/s/s)")); break; @@ -539,6 +555,11 @@ CpintPlot::clear_CP_Curves() delete label; allZoneLabels.clear(); } + + if (CPCurve) { + delete CPCurve; + CPCurve = NULL; + } } // plot the all curve, with shading according to the shade mode @@ -805,16 +826,19 @@ CpintPlot::calculate(RideItem *rideItem) break; case RideFile::cad: + case RideFile::cadd: line.setColor(GColor(CCADENCE).darker(200)); fill = (GColor(CCADENCE)); break; case RideFile::nm: + case RideFile::nmd: line.setColor(GColor(CTORQUE).darker(200)); fill = (GColor(CTORQUE)); break; case RideFile::hr: + case RideFile::hrd: line.setColor(GColor(CHEARTRATE).darker(200)); fill = (GColor(CHEARTRATE)); break; @@ -826,6 +850,7 @@ CpintPlot::calculate(RideItem *rideItem) default: case RideFile::watts: // won't ever get here + case RideFile::wattsd: case RideFile::NP: case RideFile::xPower: line.setColor(GColor(CPOWER).darker(200)); diff --git a/src/CriticalPowerWindow.cpp b/src/CriticalPowerWindow.cpp index ad245a410..066a3baf6 100644 --- a/src/CriticalPowerWindow.cpp +++ b/src/CriticalPowerWindow.cpp @@ -866,6 +866,22 @@ CriticalPowerWindow::updateCpint(double minutes) units = "metres/s/s"; break; + case RideFile::wattsd: + units = "watts/s"; + break; + + case RideFile::cadd: + units = "rpm/s"; + break; + + case RideFile::hrd: + units = "bpm/s"; + break; + + case RideFile::nmd: + units = "nm/s"; + break; + case RideFile::kph: units = "kph"; break; @@ -965,6 +981,10 @@ void CriticalPowerWindow::addSeries() << RideFile::vam << RideFile::aPower << RideFile::kphd + << RideFile::wattsd + << RideFile::nmd + << RideFile::cadd + << RideFile::hrd << RideFile::none; // this shows energy (hack) foreach (RideFile::SeriesType x, seriesList) { diff --git a/src/RideFile.cpp b/src/RideFile.cpp index 86f113bca..2380d6311 100644 --- a/src/RideFile.cpp +++ b/src/RideFile.cpp @@ -93,9 +93,12 @@ RideFile::seriesName(SeriesType series) case RideFile::km: return QString(tr("Distance")); case RideFile::kph: return QString(tr("Speed")); case RideFile::kphd: return QString(tr("Acceleration")); + case RideFile::wattsd: return QString(tr("Power Δ")); + case RideFile::cadd: return QString(tr("Cadence Δ")); + case RideFile::nmd: return QString(tr("Torque Δ")); + case RideFile::hrd: return QString(tr("Heartrate Δ")); case RideFile::nm: return QString(tr("Torque")); case RideFile::watts: return QString(tr("Power")); - case RideFile::wattsd: return QString(tr("Power acceleration")); case RideFile::xPower: return QString(tr("xPower")); case RideFile::aPower: return QString(tr("aPower")); case RideFile::NP: return QString(tr("Normalized Power")); @@ -119,10 +122,13 @@ RideFile::colorFor(SeriesType series) { switch (series) { case RideFile::cad: return GColor(CCADENCE); + case RideFile::cadd: return GColor(CCADENCE); case RideFile::hr: return GColor(CHEARTRATE); + case RideFile::hrd: return GColor(CHEARTRATE); case RideFile::kph: return GColor(CSPEED); case RideFile::kphd: return GColor(CSPEED); case RideFile::nm: return GColor(CTORQUE); + case RideFile::nmd: return GColor(CTORQUE); case RideFile::watts: return GColor(CPOWER); case RideFile::wattsd: return GColor(CPOWER); case RideFile::xPower: return GColor(CXPOWER); @@ -153,11 +159,14 @@ RideFile::unitName(SeriesType series, Context *context) switch (series) { case RideFile::secs: return QString(tr("seconds")); case RideFile::cad: return QString(tr("rpm")); + case RideFile::cadd: return QString(tr("rpm/s")); case RideFile::hr: return QString(tr("bpm")); + case RideFile::hrd: return QString(tr("bpm/s")); case RideFile::km: return QString(useMetricUnits ? tr("km") : tr("miles")); case RideFile::kph: return QString(useMetricUnits ? tr("kph") : tr("mph")); case RideFile::kphd: return QString(tr("m/s/s")); case RideFile::nm: return QString(tr("N")); + case RideFile::nmd: return QString(tr("N/s")); case RideFile::watts: return QString(tr("watts")); case RideFile::wattsd: return QString(tr("watts/s")); case RideFile::xPower: return QString(tr("watts")); @@ -699,6 +708,9 @@ RideFilePoint::value(RideFile::SeriesType series) const case RideFile::km : return km; break; case RideFile::kph : return kph; break; case RideFile::kphd : return kphd; break; + case RideFile::cadd : return cadd; break; + case RideFile::nmd : return nmd; break; + case RideFile::hrd : return hrd; break; case RideFile::nm : return nm; break; case RideFile::watts : return watts; break; case RideFile::wattsd : return wattsd; break; @@ -1019,8 +1031,7 @@ RideFile::recalculateDerivedSeries() foreach(RideFilePoint *p, dataPoints_) { - // - // Acceleration + // Delta if (lastP) { double deltaSpeed = p->kph - lastP->kph; @@ -1036,6 +1047,19 @@ RideFile::recalculateDerivedSeries() acc /= 3600; // meters per second p->kphd = acc; + + // Other delta values -- only interested in growth for power, cadence and torque + double pd = (p->watts - lastP->watts) / deltaTime; + p->wattsd = pd > 0 ? pd : 0; + + double cd = (p->cad - lastP->cad) / deltaTime; + p->cadd = cd > 0 ? cd : 0; + + double nd = (p->nm - lastP->nm) / deltaTime; + p->nmd = nd > 0 ? nd : 0; + + // we want recovery and increase times for hr + p->hrd = (p->hr - lastP->hr) / deltaTime; } } diff --git a/src/RideFile.h b/src/RideFile.h index fcd4e3f47..75734e4f0 100644 --- a/src/RideFile.h +++ b/src/RideFile.h @@ -53,6 +53,8 @@ class Context; // for context; cyclist, homedir // suffixes to the RideFileReader objects capable of converting those files // into RideFile objects. +#define DELTA_CHAR "Δ"; + struct RideFileDataPresent { // basic @@ -114,7 +116,7 @@ class RideFile : public QObject // QObject to emit signals virtual ~RideFile(); // Working with DATASERIES - enum seriestype { secs=0, cad, hr, km, kph, kphd, nm, watts, wattsd, alt, lon, lat, headwind, slope, temp, + enum seriestype { secs=0, cad, cadd, hr, hrd, km, kph, kphd, nm, nmd, watts, wattsd, alt, lon, lat, headwind, slope, temp, interval, NP, xPower, vam, wattsKg, lrbalance, aPower, wprime, none }; enum specialValues { noTemp = -255 }; @@ -278,7 +280,7 @@ struct RideFilePoint { // recorded data double secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind, slope, temp, lrbalance; - double wattsd, kphd; // acceleration in watts/s km/s + double hrd, cadd, kphd, nmd, wattsd; // acceleration in watts/s km/s int interval; // derived data (we calculate it) @@ -287,7 +289,7 @@ struct RideFilePoint // create blank point RideFilePoint() : secs(0.0), cad(0.0), hr(0.0), km(0.0), kph(0.0), - nm(0.0), watts(0.0), alt(0.0), lon(0.0), lat(0.0), headwind(0.0), slope(0.0), temp(-255.0), lrbalance(0), wattsd(0.0), kphd(0.0), interval(0), xp(0), np(0), apower(0) {} + nm(0.0), watts(0.0), alt(0.0), lon(0.0), lat(0.0), headwind(0.0), slope(0.0), temp(-255.0), lrbalance(0), hrd(0.0), cadd(0.0), kphd(0.0), nmd(0.0), wattsd(0.0), interval(0), xp(0), np(0), apower(0) {} // create point supplying all values RideFilePoint(double secs, double cad, double hr, double km, double kph, diff --git a/src/RideFileCache.cpp b/src/RideFileCache.cpp index cc195dd64..81fb50dd3 100644 --- a/src/RideFileCache.cpp +++ b/src/RideFileCache.cpp @@ -44,6 +44,10 @@ RideFileCache::RideFileCache(Context *context, QString fileName, RideFile *passe cadMeanMax.resize(0); nmMeanMax.resize(0); kphMeanMax.resize(0); + wattsdMeanMax.resize(0); + caddMeanMax.resize(0); + nmdMeanMax.resize(0); + hrdMeanMax.resize(0); kphdMeanMax.resize(0); xPowerMeanMax.resize(0); npMeanMax.resize(0); @@ -56,6 +60,10 @@ RideFileCache::RideFileCache(Context *context, QString fileName, RideFile *passe nmDistribution.resize(0); kphDistribution.resize(0); kphdDistribution.resize(0); + wattsdDistribution.resize(0); + caddDistribution.resize(0); + nmdDistribution.resize(0); + hrdDistribution.resize(0); xPowerDistribution.resize(0); npDistribution.resize(0); wattsKgDistribution.resize(0); @@ -130,6 +138,10 @@ RideFileCache::RideFileCache(RideFile *ride) : nmMeanMax.resize(0); kphMeanMax.resize(0); kphdMeanMax.resize(0); + wattsdMeanMax.resize(0); + caddMeanMax.resize(0); + nmdMeanMax.resize(0); + hrdMeanMax.resize(0); xPowerMeanMax.resize(0); npMeanMax.resize(0); vamMeanMax.resize(0); @@ -141,6 +153,10 @@ RideFileCache::RideFileCache(RideFile *ride) : nmDistribution.resize(0); kphDistribution.resize(0); kphdDistribution.resize(0); + wattsdDistribution.resize(0); + caddDistribution.resize(0); + nmdDistribution.resize(0); + hrdDistribution.resize(0); xPowerDistribution.resize(0); npDistribution.resize(0); wattsKgDistribution.resize(0); @@ -164,6 +180,10 @@ RideFileCache::RideFileCache(RideFile *ride) : doubleArray(nmMeanMaxDouble, nmMeanMax, RideFile::nm); doubleArray(kphMeanMaxDouble, kphMeanMax, RideFile::kph); doubleArray(kphdMeanMaxDouble, kphdMeanMax, RideFile::kphd); + doubleArray(wattsdMeanMaxDouble, wattsdMeanMax, RideFile::wattsd); + doubleArray(caddMeanMaxDouble, caddMeanMax, RideFile::cadd); + doubleArray(nmdMeanMaxDouble, nmdMeanMax, RideFile::nmd); + doubleArray(hrdMeanMaxDouble, hrdMeanMax, RideFile::hrd); doubleArray(npMeanMaxDouble, npMeanMax, RideFile::NP); doubleArray(vamMeanMaxDouble, vamMeanMax, RideFile::vam); doubleArray(xPowerMeanMaxDouble, xPowerMeanMax, RideFile::xPower); @@ -176,6 +196,10 @@ RideFileCache::RideFileCache(RideFile *ride) : doubleArray(nmDistributionDouble, nmDistribution, RideFile::nm); doubleArray(kphDistributionDouble, kphDistribution, RideFile::kph); doubleArray(kphdDistributionDouble, kphdDistribution, RideFile::kphd); + doubleArray(wattsdDistributionDouble, wattsdDistribution, RideFile::wattsd); + doubleArray(caddDistributionDouble, caddDistribution, RideFile::cadd); + doubleArray(nmdDistributionDouble, nmdDistribution, RideFile::nmd); + doubleArray(hrdDistributionDouble, hrdDistribution, RideFile::hrd); doubleArray(xPowerDistributionDouble, xPowerDistribution, RideFile::xPower); doubleArray(npDistributionDouble, npDistribution, RideFile::NP); doubleArray(wattsKgDistributionDouble, wattsKgDistribution, RideFile::wattsKg); @@ -192,6 +216,10 @@ RideFileCache::decimalsFor(RideFile::SeriesType series) case RideFile::km : return 3; break; case RideFile::kph : return 1; break; case RideFile::kphd : return 2; break; + case RideFile::wattsd : return 0; break; + case RideFile::cadd : return 0; break; + case RideFile::nmd : return 2; break; + case RideFile::hrd : return 0; break; case RideFile::nm : return 2; break; case RideFile::watts : return 0; break; case RideFile::xPower : return 0; break; @@ -245,6 +273,22 @@ RideFileCache::meanMaxDates(RideFile::SeriesType series) return kphdMeanMaxDate; break; + case RideFile::wattsd: + return wattsdMeanMaxDate; + break; + + case RideFile::cadd: + return caddMeanMaxDate; + break; + + case RideFile::nmd: + return nmdMeanMaxDate; + break; + + case RideFile::hrd: + return hrdMeanMaxDate; + break; + case RideFile::xPower: return xPowerMeanMaxDate; break; @@ -301,6 +345,22 @@ RideFileCache::meanMaxArray(RideFile::SeriesType series) return kphdMeanMaxDouble; break; + case RideFile::wattsd: + return wattsdMeanMaxDouble; + break; + + case RideFile::cadd: + return caddMeanMaxDouble; + break; + + case RideFile::nmd: + return nmdMeanMaxDouble; + break; + + case RideFile::hrd: + return hrdMeanMaxDouble; + break; + case RideFile::xPower: return xPowerMeanMaxDouble; break; @@ -357,6 +417,22 @@ RideFileCache::distributionArray(RideFile::SeriesType series) return kphdDistributionDouble; break; + case RideFile::wattsd: + return wattsdDistributionDouble; + break; + + case RideFile::cadd: + return caddDistributionDouble; + break; + + case RideFile::nmd: + return nmdDistributionDouble; + break; + + case RideFile::hrd: + return hrdDistributionDouble; + break; + case RideFile::aPower: return aPowerDistributionDouble; break; @@ -455,6 +531,10 @@ void RideFileCache::RideFileCache::compute() MeanMaxComputer thread9(ride, wattsKgMeanMax, RideFile::wattsKg); thread9.start(); MeanMaxComputer thread10(ride, aPowerMeanMax, RideFile::aPower); thread10.start(); MeanMaxComputer thread11(ride, kphdMeanMax, RideFile::kphd); thread11.start(); + MeanMaxComputer thread12(ride, wattsdMeanMax, RideFile::wattsd); thread12.start(); + MeanMaxComputer thread13(ride, caddMeanMax, RideFile::cadd); thread13.start(); + MeanMaxComputer thread14(ride, nmdMeanMax, RideFile::nmd); thread14.start(); + MeanMaxComputer thread15(ride, hrdMeanMax, RideFile::hrd); thread15.start(); // all the different distributions computeDistribution(wattsDistribution, RideFile::watts); @@ -463,6 +543,10 @@ void RideFileCache::RideFileCache::compute() computeDistribution(nmDistribution, RideFile::nm); computeDistribution(kphDistribution, RideFile::kph); computeDistribution(kphdDistribution, RideFile::kphd); + computeDistribution(wattsdDistribution, RideFile::wattsd); + computeDistribution(caddDistribution, RideFile::cadd); + computeDistribution(nmdDistribution, RideFile::nmd); + computeDistribution(hrdDistribution, RideFile::hrd); computeDistribution(wattsKgDistribution, RideFile::wattsKg); computeDistribution(aPowerDistribution, RideFile::aPower); @@ -478,6 +562,10 @@ void RideFileCache::RideFileCache::compute() thread9.wait(); thread10.wait(); thread11.wait(); + thread12.wait(); + thread13.wait(); + thread14.wait(); + thread15.wait(); } //---------------------------------------------------------------------- @@ -709,6 +797,10 @@ MeanMaxComputer::run() // there is a distinction between needing it present and using it in calcs RideFile::SeriesType needSeries = baseSeries; if (series == RideFile::kphd) needSeries = RideFile::kph; + if (series == RideFile::wattsd) needSeries = RideFile::watts; + if (series == RideFile::cadd) needSeries = RideFile::cad; + if (series == RideFile::nmd) needSeries = RideFile::nm; + if (series == RideFile::hrd) needSeries = RideFile::hr; // only bother if the data series is actually present if (ride->isDataPresent(needSeries) == false) return; @@ -909,8 +1001,9 @@ MeanMaxComputer::run() double last = 0; - // only care about first 3 minutes MAX for acceleration - if (series == RideFile::kphd && ride_bests.count() > 180) ride_bests.resize(180); + // only care about first 3 minutes MAX for delta series + if ((series == RideFile::kphd || series == RideFile::wattsd || series == RideFile::cadd || + series == RideFile::nmd || series == RideFile::hrd) && ride_bests.count() > 180) ride_bests.resize(180); array.resize(ride_bests.count()); @@ -933,6 +1026,10 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s // there is a distinction between needing it present and using it in calcs RideFile::SeriesType needSeries = baseSeries; if (series == RideFile::kphd) needSeries = RideFile::kph; + if (series == RideFile::wattsd) needSeries = RideFile::watts; + if (series == RideFile::cadd) needSeries = RideFile::cad; + if (series == RideFile::nmd) needSeries = RideFile::nm; + if (series == RideFile::hrd) needSeries = RideFile::hr; // only bother if the data series is actually present if (ride->isDataPresent(needSeries) == false) return; @@ -1052,6 +1149,10 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt nmMeanMax.resize(0); kphMeanMax.resize(0); kphdMeanMax.resize(0); + wattsdMeanMax.resize(0); + caddMeanMax.resize(0); + nmdMeanMax.resize(0); + hrdMeanMax.resize(0); xPowerMeanMax.resize(0); npMeanMax.resize(0); vamMeanMax.resize(0); @@ -1063,6 +1164,10 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt nmDistribution.resize(0); kphDistribution.resize(0); kphdDistribution.resize(0); + wattsdDistribution.resize(0); + caddDistribution.resize(0); + nmdDistribution.resize(0); + hrdDistribution.resize(0); xPowerDistribution.resize(0); npDistribution.resize(0); wattsKgDistribution.resize(0); @@ -1098,6 +1203,10 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt meanMaxAggregate(nmMeanMaxDouble, rideCache.nmMeanMaxDouble, nmMeanMaxDate, rideDate); meanMaxAggregate(kphMeanMaxDouble, rideCache.kphMeanMaxDouble, kphMeanMaxDate, rideDate); meanMaxAggregate(kphdMeanMaxDouble, rideCache.kphdMeanMaxDouble, kphdMeanMaxDate, rideDate); + meanMaxAggregate(wattsdMeanMaxDouble, rideCache.wattsdMeanMaxDouble, wattsdMeanMaxDate, rideDate); + meanMaxAggregate(caddMeanMaxDouble, rideCache.caddMeanMaxDouble, caddMeanMaxDate, rideDate); + meanMaxAggregate(nmdMeanMaxDouble, rideCache.nmdMeanMaxDouble, nmdMeanMaxDate, rideDate); + meanMaxAggregate(hrdMeanMaxDouble, rideCache.hrdMeanMaxDouble, hrdMeanMaxDate, rideDate); meanMaxAggregate(xPowerMeanMaxDouble, rideCache.xPowerMeanMaxDouble, xPowerMeanMaxDate, rideDate); meanMaxAggregate(npMeanMaxDouble, rideCache.npMeanMaxDouble, npMeanMaxDate, rideDate); meanMaxAggregate(vamMeanMaxDouble, rideCache.vamMeanMaxDouble, vamMeanMaxDate, rideDate); @@ -1110,6 +1219,10 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt distAggregate(nmDistributionDouble, rideCache.nmDistributionDouble); distAggregate(kphDistributionDouble, rideCache.kphDistributionDouble); distAggregate(kphdDistributionDouble, rideCache.kphdDistributionDouble); + distAggregate(wattsdDistributionDouble, rideCache.wattsdDistributionDouble); + distAggregate(caddDistributionDouble, rideCache.caddDistributionDouble); + distAggregate(nmdDistributionDouble, rideCache.nmdDistributionDouble); + distAggregate(hrdDistributionDouble, rideCache.hrdDistributionDouble); distAggregate(xPowerDistributionDouble, rideCache.xPowerDistributionDouble); distAggregate(npDistributionDouble, rideCache.npDistributionDouble); distAggregate(wattsKgDistributionDouble, rideCache.wattsKgDistributionDouble); @@ -1158,6 +1271,10 @@ RideFileCache::serialize(QDataStream *out) head.nmMeanMaxCount = nmMeanMax.size(); head.kphMeanMaxCount = kphMeanMax.size(); head.kphdMeanMaxCount = kphdMeanMax.size(); + head.wattsdMeanMaxCount = wattsdMeanMax.size(); + head.caddMeanMaxCount = caddMeanMax.size(); + head.nmdMeanMaxCount = nmdMeanMax.size(); + head.hrdMeanMaxCount = hrdMeanMax.size(); head.xPowerMeanMaxCount = xPowerMeanMax.size(); head.npMeanMaxCount = npMeanMax.size(); head.vamMeanMaxCount = vamMeanMax.size(); @@ -1171,6 +1288,10 @@ RideFileCache::serialize(QDataStream *out) head.nmDistrCount = nmDistribution.size(); head.kphDistCount = kphDistribution.size(); head.kphdDistCount = kphdDistribution.size(); + head.wattsdDistCount = wattsdDistribution.size(); + head.caddDistCount = caddDistribution.size(); + head.nmdDistCount = nmdDistribution.size(); + head.hrdDistCount = hrdDistribution.size(); head.wattsKgDistCount = wattsKgDistribution.size(); head.aPowerDistCount = aPowerDistribution.size(); @@ -1183,6 +1304,10 @@ RideFileCache::serialize(QDataStream *out) out->writeRawData((const char *) nmMeanMax.data(), sizeof(float) * nmMeanMax.size()); out->writeRawData((const char *) kphMeanMax.data(), sizeof(float) * kphMeanMax.size()); out->writeRawData((const char *) kphdMeanMax.data(), sizeof(float) * kphdMeanMax.size()); + out->writeRawData((const char *) wattsdMeanMax.data(), sizeof(float) * wattsdMeanMax.size()); + out->writeRawData((const char *) caddMeanMax.data(), sizeof(float) * caddMeanMax.size()); + out->writeRawData((const char *) nmdMeanMax.data(), sizeof(float) * nmdMeanMax.size()); + out->writeRawData((const char *) hrdMeanMax.data(), sizeof(float) * hrdMeanMax.size()); out->writeRawData((const char *) xPowerMeanMax.data(), sizeof(float) * xPowerMeanMax.size()); out->writeRawData((const char *) npMeanMax.data(), sizeof(float) * npMeanMax.size()); out->writeRawData((const char *) vamMeanMax.data(), sizeof(float) * vamMeanMax.size()); @@ -1196,6 +1321,10 @@ RideFileCache::serialize(QDataStream *out) out->writeRawData((const char *) nmDistribution.data(), sizeof(float) * nmDistribution.size()); out->writeRawData((const char *) kphDistribution.data(), sizeof(float) * kphDistribution.size()); out->writeRawData((const char *) kphdDistribution.data(), sizeof(float) * kphdDistribution.size()); + out->writeRawData((const char *) wattsdDistribution.data(), sizeof(float) * wattsdDistribution.size()); + out->writeRawData((const char *) caddDistribution.data(), sizeof(float) * caddDistribution.size()); + out->writeRawData((const char *) nmdDistribution.data(), sizeof(float) * nmdDistribution.size()); + out->writeRawData((const char *) hrdDistribution.data(), sizeof(float) * hrdDistribution.size()); out->writeRawData((const char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size()); out->writeRawData((const char *) npDistribution.data(), sizeof(float) * npDistribution.size()); out->writeRawData((const char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size()); @@ -1225,6 +1354,10 @@ RideFileCache::readCache() nmMeanMax.resize(head.nmMeanMaxCount); kphMeanMax.resize(head.kphMeanMaxCount); kphdMeanMax.resize(head.kphdMeanMaxCount); + wattsdMeanMax.resize(head.wattsdMeanMaxCount); + caddMeanMax.resize(head.caddMeanMaxCount); + nmdMeanMax.resize(head.nmdMeanMaxCount); + hrdMeanMax.resize(head.hrdMeanMaxCount); npMeanMax.resize(head.npMeanMaxCount); vamMeanMax.resize(head.vamMeanMaxCount); xPowerMeanMax.resize(head.xPowerMeanMaxCount); @@ -1237,6 +1370,10 @@ RideFileCache::readCache() nmDistribution.resize(head.nmDistrCount); kphDistribution.resize(head.kphDistCount); kphdDistribution.resize(head.kphdDistCount); + wattsdDistribution.resize(head.wattsdDistCount); + caddDistribution.resize(head.caddDistCount); + nmdDistribution.resize(head.nmdDistCount); + hrdDistribution.resize(head.hrdDistCount); xPowerDistribution.resize(head.xPowerDistCount); npDistribution.resize(head.npDistCount); wattsKgDistribution.resize(head.wattsKgDistCount); @@ -1249,6 +1386,10 @@ RideFileCache::readCache() inFile.readRawData((char *) nmMeanMax.data(), sizeof(float) * nmMeanMax.size()); inFile.readRawData((char *) kphMeanMax.data(), sizeof(float) * kphMeanMax.size()); inFile.readRawData((char *) kphdMeanMax.data(), sizeof(float) * kphdMeanMax.size()); + inFile.readRawData((char *) wattsdMeanMax.data(), sizeof(float) * wattsdMeanMax.size()); + inFile.readRawData((char *) caddMeanMax.data(), sizeof(float) * caddMeanMax.size()); + inFile.readRawData((char *) nmdMeanMax.data(), sizeof(float) * nmdMeanMax.size()); + inFile.readRawData((char *) hrdMeanMax.data(), sizeof(float) * hrdMeanMax.size()); inFile.readRawData((char *) xPowerMeanMax.data(), sizeof(float) * xPowerMeanMax.size()); inFile.readRawData((char *) npMeanMax.data(), sizeof(float) * npMeanMax.size()); inFile.readRawData((char *) vamMeanMax.data(), sizeof(float) * vamMeanMax.size()); @@ -1263,6 +1404,10 @@ RideFileCache::readCache() inFile.readRawData((char *) nmDistribution.data(), sizeof(float) * nmDistribution.size()); inFile.readRawData((char *) kphDistribution.data(), sizeof(float) * kphDistribution.size()); inFile.readRawData((char *) kphdDistribution.data(), sizeof(float) * kphdDistribution.size()); + inFile.readRawData((char *) wattsdDistribution.data(), sizeof(float) * wattsdDistribution.size()); + inFile.readRawData((char *) caddDistribution.data(), sizeof(float) * caddDistribution.size()); + inFile.readRawData((char *) nmdDistribution.data(), sizeof(float) * nmdDistribution.size()); + inFile.readRawData((char *) hrdDistribution.data(), sizeof(float) * hrdDistribution.size()); inFile.readRawData((char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size()); inFile.readRawData((char *) npDistribution.data(), sizeof(float) * npDistribution.size()); inFile.readRawData((char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size()); @@ -1280,6 +1425,10 @@ RideFileCache::readCache() doubleArray(nmMeanMaxDouble, nmMeanMax, RideFile::nm); doubleArray(kphMeanMaxDouble, kphMeanMax, RideFile::kph); doubleArray(kphdMeanMaxDouble, kphdMeanMax, RideFile::kphd); + doubleArray(wattsdMeanMaxDouble, wattsdMeanMax, RideFile::wattsd); + doubleArray(caddMeanMaxDouble, caddMeanMax, RideFile::cadd); + doubleArray(nmdMeanMaxDouble, nmdMeanMax, RideFile::nmd); + doubleArray(hrdMeanMaxDouble, hrdMeanMax, RideFile::hrd); doubleArray(npMeanMaxDouble, npMeanMax, RideFile::NP); doubleArray(vamMeanMaxDouble, vamMeanMax, RideFile::vam); doubleArray(xPowerMeanMaxDouble, xPowerMeanMax, RideFile::xPower); @@ -1292,6 +1441,10 @@ RideFileCache::readCache() doubleArray(nmDistributionDouble, nmDistribution, RideFile::nm); doubleArray(kphDistributionDouble, kphDistribution, RideFile::kph); doubleArray(kphdDistributionDouble, kphdDistribution, RideFile::kphd); + doubleArray(wattsdDistributionDouble, wattsdDistribution, RideFile::wattsd); + doubleArray(caddDistributionDouble, caddDistribution, RideFile::cadd); + doubleArray(nmdDistributionDouble, nmdDistribution, RideFile::nmd); + doubleArray(hrdDistributionDouble, hrdDistribution, RideFile::hrd); doubleArray(xPowerDistributionDouble, xPowerDistribution, RideFile::xPower); doubleArray(npDistributionDouble, npDistribution, RideFile::NP); doubleArray(wattsKgDistributionDouble, wattsKgDistribution, RideFile::wattsKg); @@ -1322,6 +1475,10 @@ static long offsetForMeanMax(RideFileCacheHeader head, RideFile::SeriesType seri case RideFile::vam : offset += head.npMeanMaxCount * sizeof(float); case RideFile::NP : offset += head.xPowerMeanMaxCount * sizeof(float); case RideFile::xPower : offset += head.kphMeanMaxCount * sizeof(float); + case RideFile::hrd : offset += head.hrdMeanMaxCount * sizeof(float); + case RideFile::nmd : offset += head.nmdMeanMaxCount * sizeof(float); + case RideFile::cadd : offset += head.caddMeanMaxCount * sizeof(float); + case RideFile::wattsd : offset += head.wattsdMeanMaxCount * sizeof(float); case RideFile::kphd : offset += head.kphdMeanMaxCount * sizeof(float); case RideFile::kph : offset += head.nmMeanMaxCount * sizeof(float); case RideFile::nm : offset += head.cadMeanMaxCount * sizeof(float); @@ -1346,6 +1503,10 @@ static long offsetForTiz(RideFileCacheHeader head, RideFile::SeriesType series) offset += head.vamMeanMaxCount * sizeof(float); offset += head.npMeanMaxCount * sizeof(float); offset += head.xPowerMeanMaxCount * sizeof(float); + offset += head.hrdMeanMaxCount * sizeof(float); + offset += head.nmdMeanMaxCount * sizeof(float); + offset += head.caddMeanMaxCount * sizeof(float); + offset += head.wattsdMeanMaxCount * sizeof(float); offset += head.kphdMeanMaxCount * sizeof(float); offset += head.kphMeanMaxCount * sizeof(float); offset += head.nmMeanMaxCount * sizeof(float); @@ -1360,6 +1521,10 @@ static long offsetForTiz(RideFileCacheHeader head, RideFile::SeriesType series) offset += head.nmDistrCount * sizeof(float); offset += head.kphDistCount * sizeof(float); offset += head.kphdDistCount * sizeof(float); + offset += head.wattsdDistCount * sizeof(float); + offset += head.caddDistCount * sizeof(float); + offset += head.nmdDistCount * sizeof(float); + offset += head.hrdDistCount * sizeof(float); offset += head.xPowerDistCount * sizeof(float); offset += head.npDistCount * sizeof(float); offset += head.wattsKgDistCount * sizeof(float); @@ -1383,6 +1548,10 @@ static long countForMeanMax(RideFileCacheHeader head, RideFile::SeriesType serie case RideFile::xPower : return head.xPowerMeanMaxCount; case RideFile::kph : return head.kphMeanMaxCount; case RideFile::kphd : return head.kphdMeanMaxCount; + case RideFile::wattsd : return head.wattsdMeanMaxCount; + case RideFile::cadd : return head.caddMeanMaxCount; + case RideFile::nmd : return head.nmdMeanMaxCount; + case RideFile::hrd : return head.hrdMeanMaxCount; case RideFile::nm : return head.nmMeanMaxCount; case RideFile::cad : return head.cadMeanMaxCount; case RideFile::hr : return head.hrMeanMaxCount; diff --git a/src/RideFileCache.h b/src/RideFileCache.h index f1708de3c..562c86889 100644 --- a/src/RideFileCache.h +++ b/src/RideFileCache.h @@ -40,7 +40,7 @@ typedef double data_t; // arrays when plotting CP curves and histograms. It is precoputed // to save time and cached in a file .cpx // -static const unsigned int RideFileCacheVersion = 13; +static const unsigned int RideFileCacheVersion = 14; // revision history: // version date description // 1 29-Apr-11 Initial - header, mean-max & distribution data blocks @@ -56,6 +56,7 @@ static const unsigned int RideFileCacheVersion = 13; // 11 17-Feb-14 Changed 3zone model to have 85% CP < middle < CP // 12 21-Feb-14 Added Acceleration (speed) // 12 22-Feb-14 Acceleration precision way too high! +// 13 24-Feb-14 Add hr, cad, watts, nm Δ data series // The cache file (.cpx) has a binary format: // 1 x Header data - describing the version and contents of the cache @@ -77,6 +78,10 @@ struct RideFileCacheHeader { nmMeanMaxCount, kphMeanMaxCount, kphdMeanMaxCount, + wattsdMeanMaxCount, + caddMeanMaxCount, + nmdMeanMaxCount, + hrdMeanMaxCount, xPowerMeanMaxCount, npMeanMaxCount, vamMeanMaxCount, @@ -88,6 +93,10 @@ struct RideFileCacheHeader { nmDistrCount, kphDistCount, kphdDistCount, + wattsdDistCount, + caddDistCount, + nmdDistCount, + hrdDistCount, xPowerDistCount, npDistCount, wattsKgDistCount, @@ -207,6 +216,10 @@ class RideFileCache QVector nmMeanMax; // RideFile::nm QVector kphMeanMax; // RideFile::kph QVector kphdMeanMax; // RideFile::kphd + QVector wattsdMeanMax; // RideFile::wattsd + QVector caddMeanMax; // RideFile::cadd + QVector nmdMeanMax; // RideFile::nmd + QVector hrdMeanMax; // RideFile::hrd QVector xPowerMeanMax; // RideFile::kph QVector npMeanMax; // RideFile::kph QVector vamMeanMax; // RideFile::vam @@ -219,6 +232,10 @@ class RideFileCache QVector nmMeanMaxDouble; // RideFile::nm QVector kphMeanMaxDouble; // RideFile::kph QVector kphdMeanMaxDouble; // RideFile::kphd + QVector wattsdMeanMaxDouble; // RideFile::wattsd + QVector caddMeanMaxDouble; // RideFile::cadd + QVector nmdMeanMaxDouble; // RideFile::nmd + QVector hrdMeanMaxDouble; // RideFile::hrd QVector xPowerMeanMaxDouble; // RideFile::kph QVector npMeanMaxDouble; // RideFile::kph QVector vamMeanMaxDouble; // RideFile::kph @@ -231,6 +248,10 @@ class RideFileCache QVector nmMeanMaxDate; // RideFile::nm QVector kphMeanMaxDate; // RideFile::kph QVector kphdMeanMaxDate; // RideFile::kph + QVector wattsdMeanMaxDate; // RideFile::wattsd + QVector caddMeanMaxDate; // RideFile::cadd + QVector nmdMeanMaxDate; // RideFile::nmd + QVector hrdMeanMaxDate; // RideFile::hrd QVector xPowerMeanMaxDate; // RideFile::kph QVector npMeanMaxDate; // RideFile::kph QVector vamMeanMaxDate; // RideFile::vam @@ -251,6 +272,10 @@ class RideFileCache QVector nmDistribution; // RideFile::nm QVector kphDistribution; // RideFile::kph QVector kphdDistribution; // RideFile::kphd + QVector wattsdDistribution; // RideFile::wattsd + QVector caddDistribution; // RideFile::cadd + QVector nmdDistribution; // RideFile::nmd + QVector hrdDistribution; // RideFile::hrd QVector xPowerDistribution; // RideFile::kph QVector npDistribution; // RideFile::kph QVector wattsKgDistribution; // RideFile::wattsKg @@ -262,8 +287,12 @@ class RideFileCache QVector nmDistributionDouble; // RideFile::nm QVector kphDistributionDouble; // RideFile::kph QVector kphdDistributionDouble; // RideFile::kph - QVector xPowerDistributionDouble; // RideFile::kph - QVector npDistributionDouble; // RideFile::kph + QVector wattsdDistributionDouble; // RideFile::wattsd + QVector caddDistributionDouble; // RideFile::cadd + QVector nmdDistributionDouble; // RideFile::nmd + QVector hrdDistributionDouble; // RideFile::hrd + QVector xPowerDistributionDouble; // RideFile::xpower + QVector npDistributionDouble; // RideFile::np QVector wattsKgDistributionDouble; // RideFile::wattsKg QVector aPowerDistributionDouble; // RideFile::aPower