From 3a07cc52d7cbecd5901acfccfc11be204683192a Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Wed, 26 May 2021 12:42:17 -0300 Subject: [PATCH] Generalize Power Zones for any sport All sports defined as values for Sport metadata field can have specifics Power Zones and default to Bike zones otherwise. Similar to current power zones for Run. Part 3 of #3280 --- src/Charts/AllPlot.cpp | 22 +++++----- src/Charts/CPPlot.cpp | 26 ++++++------ src/Charts/CPPlot.h | 4 +- src/Charts/CriticalPowerWindow.cpp | 20 ++++----- src/Charts/HistogramWindow.cpp | 2 +- src/Charts/HrPwPlot.cpp | 8 ++-- src/Charts/OverviewItems.cpp | 18 ++++---- src/Charts/PfPvPlot.cpp | 8 ++-- src/Charts/PowerHist.cpp | 24 +++++------ src/Charts/PowerHist.h | 4 +- src/Charts/RideMapWindow.cpp | 8 ++-- src/Charts/RideSummaryWindow.cpp | 40 +++++++++--------- src/Core/Athlete.cpp | 14 +++--- src/Core/Athlete.h | 6 +-- src/Core/DataFilter.cpp | 16 +++---- src/Core/RideItem.cpp | 30 ++++++------- src/Core/Settings.h | 1 - src/FileIO/RideFile.cpp | 8 ++-- src/FileIO/RideFileCache.cpp | 10 ++--- src/Gui/AthletePages.cpp | 27 ++++++------ src/Gui/AthletePages.h | 12 +++--- src/Gui/SolveCPDialog.cpp | 8 ++-- src/Metrics/BasicRideMetrics.cpp | 4 +- src/Metrics/BikeScore.cpp | 22 +++++----- src/Metrics/CPSolver.cpp | 8 ++-- src/Metrics/Coggan.cpp | 16 +++---- src/Metrics/DanielsPoints.cpp | 8 ++-- src/Metrics/PeakPower.cpp | 4 +- src/Metrics/TimeInZone.cpp | 18 ++++---- src/Metrics/WPrime.cpp | 36 ++++++++-------- src/Metrics/Zones.cpp | 8 ++-- src/Metrics/Zones.h | 6 +-- src/Metrics/aBikeScore.cpp | 8 ++-- src/Metrics/aCoggan.cpp | 8 ++-- src/Python/SIP/Bindings.cpp | 68 +++++++++++++++--------------- src/R/RTool.cpp | 68 +++++++++++++++--------------- 36 files changed, 298 insertions(+), 300 deletions(-) diff --git a/src/Charts/AllPlot.cpp b/src/Charts/AllPlot.cpp index 1863b317c..292e09112 100644 --- a/src/Charts/AllPlot.cpp +++ b/src/Charts/AllPlot.cpp @@ -109,7 +109,7 @@ class AllPlotBackground: public QwtPlotItem if (parent->context->isCompareIntervals) { - zones = parent->context->athlete->zones(rideItem ? rideItem->isRun : false); + zones = parent->context->athlete->zones(rideItem ? rideItem->sport : "Bike"); if (!zones) return; // use first compare interval date @@ -120,10 +120,10 @@ class AllPlotBackground: public QwtPlotItem if (zone_range == -1) zone_range = zones->whichRange(QDate::currentDate()); - } else if (rideItem && parent->context->athlete->zones(rideItem->isRun)) { + } else if (rideItem && parent->context->athlete->zones(rideItem->sport)) { - zones = parent->context->athlete->zones(rideItem->isRun); - zone_range = parent->context->athlete->zones(rideItem->isRun)->whichRange(rideItem->dateTime.date()); + zones = parent->context->athlete->zones(rideItem->sport); + zone_range = parent->context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date()); } else { @@ -180,7 +180,7 @@ class AllPlotZoneLabel: public QwtPlotItem if (parent->context->isCompareIntervals) { - zones = parent->context->athlete->zones(rideItem ? rideItem->isRun : false); + zones = parent->context->athlete->zones(rideItem ? rideItem->sport : "Bike"); if (!zones) return; // use first compare interval date @@ -191,10 +191,10 @@ class AllPlotZoneLabel: public QwtPlotItem if (zone_range == -1) zone_range = zones->whichRange(QDate::currentDate()); - } else if (rideItem && parent->context->athlete->zones(rideItem->isRun)) { + } else if (rideItem && parent->context->athlete->zones(rideItem->sport)) { - zones = parent->context->athlete->zones(rideItem->isRun); - zone_range = parent->context->athlete->zones(rideItem->isRun)->whichRange(rideItem->dateTime.date()); + zones = parent->context->athlete->zones(rideItem->sport); + zone_range = parent->context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date()); } else { @@ -1688,13 +1688,13 @@ void AllPlot::refreshZoneLabels() } zoneLabels.clear(); - if (rideItem && context->athlete->zones(rideItem->isRun)) { + if (rideItem && context->athlete->zones(rideItem->sport)) { - int zone_range = context->athlete->zones(rideItem->isRun)->whichRange(rideItem->dateTime.date()); + int zone_range = context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date()); // generate labels for existing zones if (zone_range >= 0) { - int num_zones = context->athlete->zones(rideItem->isRun)->numZones(zone_range); + int num_zones = context->athlete->zones(rideItem->sport)->numZones(zone_range); for (int z = 0; z < num_zones; z ++) { AllPlotZoneLabel *label = new AllPlotZoneLabel(this, z); label->attach(this); diff --git a/src/Charts/CPPlot.cpp b/src/Charts/CPPlot.cpp index 6676b4ff7..3adefd77a 100644 --- a/src/Charts/CPPlot.cpp +++ b/src/Charts/CPPlot.cpp @@ -63,7 +63,7 @@ CPPlot::CPPlot(CriticalPowerWindow *parent, Context *context, bool rangemode) : model(0), modelVariant(0), fit(0), fitdata(0), modelDecay(false), // state - context(context), bestsCache(NULL), dateCV(0.0), isRun(false), isSwim(false), + context(context), bestsCache(NULL), dateCV(0.0), sport(""), rideSeries(RideFile::watts), isFiltered(false), shadeMode(2), shadeIntervals(true), rangemode(rangemode), @@ -810,7 +810,7 @@ CPPlot::updateModelHelper() } else if (rideSeries == RideFile::kph) { - const PaceZones *zones = (isRun || isSwim) ? context->athlete->paceZones(isSwim) : NULL; + const PaceZones *zones = (sport == "Run" || sport == "Swim") ? context->athlete->paceZones(sport=="Swim") : NULL; // Rank field is reused for pace according to sport bool metricPace = zones ? appsettings->value(this, zones->paceSetting(), GlobalContext::context()->useMetricUnits).toBool() : GlobalContext::context()->useMetricUnits; cpw->titleRank->setText(zones ? zones->paceUnits(metricPace) : "n/a"); @@ -1078,7 +1078,7 @@ CPPlot::plotTests(RideItem *rideitem) foreach(RideItem *r, context->athlete->rideCache->rides()) { // does it match ? - if ((r->isSwim == isSwim) && (r->isRun == isRun) && spec.pass(r)) + if ((r->sport == sport) && spec.pass(r)) rides << r; } @@ -1475,7 +1475,7 @@ CPPlot::plotBests(RideItem *rideItem) // set zones from shading CP QList power_zone; - int n_zones = context->athlete->zones(isRun)->lowsFromCP(&power_zone, (int) int(shadingCP)); + int n_zones = context->athlete->zones(sport)->lowsFromCP(&power_zone, (int) int(shadingCP)); // now run through each zone and create a curve int high = maxNonZero - 1; @@ -1530,7 +1530,7 @@ CPPlot::plotBests(RideItem *rideItem) // now the labels if (shadeMode && (criticalSeries != CriticalPowerWindow::work || work[high] > 100.0)) { - QwtText text(context->athlete->zones(isRun)->getDefaultZoneName(zone)); + QwtText text(context->athlete->zones(sport)->getDefaultZoneName(zone)); text.setFont(QFont("Helvetica", 20, QFont::Bold)); color.setAlpha(255); text.setColor(color); @@ -1569,7 +1569,7 @@ CPPlot::plotBests(RideItem *rideItem) // set zones from shading CV QList pace_zone; - int n_zones = context->athlete->paceZones(isSwim)->lowsFromCV(&pace_zone, shadingCV); + int n_zones = context->athlete->paceZones(sport=="Swim")->lowsFromCV(&pace_zone, shadingCV); // now run through each zone and create a curve int high = maxNonZero - 1; @@ -1618,7 +1618,7 @@ CPPlot::plotBests(RideItem *rideItem) // now the labels if (shadeMode) { - QwtText text(context->athlete->paceZones(isSwim)->getDefaultZoneName(zone)); + QwtText text(context->athlete->paceZones(sport=="Swim")->getDefaultZoneName(zone)); text.setFont(QFont("Helvetica", 20, QFont::Bold)); color.setAlpha(255); text.setColor(color); @@ -2013,7 +2013,7 @@ CPPlot::setRide(RideItem *rideItem) // if plotting in percentage mode, so get data and plot it now // delete if sport changed if (!rangemode) { - setSport(rideItem->isRun, rideItem->isSwim); + setSport(rideItem->sport); delete bestsCache; bestsCache = NULL; clearCurves(); @@ -2114,8 +2114,8 @@ CPPlot::pointHover(QwtPlotCurve *curve, int index) // use the right pace config bool metricPace = true; - if (isSwim) metricPace = appsettings->value(this, GC_SWIMPACE, GlobalContext::context()->useMetricUnits).toBool(); - else if (isRun) metricPace = appsettings->value(this, GC_PACE, GlobalContext::context()->useMetricUnits).toBool(); + if (sport == "Swim") metricPace = appsettings->value(this, GC_SWIMPACE, GlobalContext::context()->useMetricUnits).toBool(); + else if (sport == "Run") metricPace = appsettings->value(this, GC_PACE, GlobalContext::context()->useMetricUnits).toBool(); else metricPace = GlobalContext::context()->useMetricUnits; @@ -2180,16 +2180,16 @@ CPPlot::pointHover(QwtPlotCurve *curve, int index) // for speed series add pace with units according to settings if (criticalSeries == CriticalPowerWindow::kph) { - if (isRun || isSwim) { + if (sport == "Run" || sport == "Swim") { - const PaceZones *zones = context->athlete->paceZones(isSwim); + const PaceZones *zones = context->athlete->paceZones(sport=="Swim"); if (zones) paceStr = QString("\n%1 %2").arg(zones->kphToPaceString(yvalue, metricPace)) .arg(zones->paceUnits(metricPace)); } const double km = yvalue*xvalue/60.0; // distance in km - if (isSwim) { + if (sport == "Swim") { if (metricPace) paceStr += tr("\n%1 m").arg(1000*km, 0, 'f', 0); else paceStr += tr("\n%1 yd").arg(1000*km/METERS_PER_YARD, 0, 'f', 0); diff --git a/src/Charts/CPPlot.h b/src/Charts/CPPlot.h index 64850013e..4476a405a 100644 --- a/src/Charts/CPPlot.h +++ b/src/Charts/CPPlot.h @@ -80,7 +80,7 @@ class CPPlot : public QwtPlot void setVeloCP(int x) { veloCP = x; } void setDateCP(int x) { dateCP = x; } void setDateCV(double x) { dateCV = x; } - void setSport(bool run, bool swim) { isRun = run; isSwim = swim; } + void setSport(QString s) { sport = s; } void setSeries(CriticalPowerWindow::CriticalSeriesType); void setPlotType(int index); void showXAxisLinear(bool x); @@ -162,7 +162,7 @@ class CPPlot : public QwtPlot int veloCP; int dateCP; double dateCV; - bool isRun, isSwim; + QString sport; QTime lastupdate; // settings diff --git a/src/Charts/CriticalPowerWindow.cpp b/src/Charts/CriticalPowerWindow.cpp index 574a6bb1f..266c2a762 100644 --- a/src/Charts/CriticalPowerWindow.cpp +++ b/src/Charts/CriticalPowerWindow.cpp @@ -1312,9 +1312,9 @@ CriticalPowerWindow::rideSelected() if (currentRide) { - if (context->athlete->zones(currentRide->isRun)) { - int zoneRange = context->athlete->zones(currentRide->isRun)->whichRange(currentRide->dateTime.date()); - int CP = zoneRange >= 0 ? context->athlete->zones(currentRide->isRun)->getCP(zoneRange) : 0; + if (context->athlete->zones(currentRide->sport)) { + int zoneRange = context->athlete->zones(currentRide->sport)->whichRange(currentRide->dateTime.date()); + int CP = zoneRange >= 0 ? context->athlete->zones(currentRide->sport)->getCP(zoneRange) : 0; CPEdit->setText(QString("%1").arg(CP)); cpPlot->setDateCP(CP); } else { @@ -1757,12 +1757,12 @@ CriticalPowerWindow::dateRangeChanged(DateRange dateRange) nActivities, nRides, nRuns, nSwims, sport); // lets work out the average CP configure value - if (series() != veloclinicplot && context->athlete->zones(nActivities == nRuns)) { - int fromZoneRange = context->athlete->zones(nActivities == nRuns)->whichRange(cfrom); - int toZoneRange = context->athlete->zones(nActivities == nRuns)->whichRange(cto); + if (series() != veloclinicplot && context->athlete->zones(sport)) { + int fromZoneRange = context->athlete->zones(sport)->whichRange(cfrom); + int toZoneRange = context->athlete->zones(sport)->whichRange(cto); - int CPfrom = fromZoneRange >= 0 ? context->athlete->zones(nActivities == nRuns)->getCP(fromZoneRange) : 0; - int CPto = toZoneRange >= 0 ? context->athlete->zones(nActivities == nRuns)->getCP(toZoneRange) : CPfrom; + int CPfrom = fromZoneRange >= 0 ? context->athlete->zones(sport)->getCP(fromZoneRange) : 0; + int CPto = toZoneRange >= 0 ? context->athlete->zones(sport)->getCP(toZoneRange) : CPfrom; if (CPfrom == 0) CPfrom = CPto; int dateCP = (CPfrom + CPto) / 2; @@ -1783,10 +1783,10 @@ CriticalPowerWindow::dateRangeChanged(DateRange dateRange) double dateCV = (CVfrom + CVto) / 2.0; cpPlot->setDateCV(dateCV); - cpPlot->setSport(nActivities == nRuns, nActivities == nSwims); + cpPlot->setSport(sport); } else { cpPlot->setDateCV(0.0); - cpPlot->setSport(false, false); + cpPlot->setSport(""); } cpPlot->setDateRange(dateRange.from, dateRange.to, stale); diff --git a/src/Charts/HistogramWindow.cpp b/src/Charts/HistogramWindow.cpp index d6c8e57b4..43af3fcf2 100644 --- a/src/Charts/HistogramWindow.cpp +++ b/src/Charts/HistogramWindow.cpp @@ -770,7 +770,7 @@ HistogramWindow::rideSelected() if (rangemode) { // get range that applies to this ride - powerRange = context->athlete->zones(ride->isRun)->whichRange(ride->dateTime.date()); + powerRange = context->athlete->zones(ride->sport)->whichRange(ride->dateTime.date()); hrRange = context->athlete->hrZones(ride->sport)->whichRange(ride->dateTime.date()); } diff --git a/src/Charts/HrPwPlot.cpp b/src/Charts/HrPwPlot.cpp index f265c4acd..a0dcbfcfa 100644 --- a/src/Charts/HrPwPlot.cpp +++ b/src/Charts/HrPwPlot.cpp @@ -593,7 +593,7 @@ class HrPwPlotBackground: public QwtPlotItem return; int zone_range = -1; - const Zones *zones = parent->context->athlete->zones(rideItem->isRun); + const Zones *zones = parent->context->athlete->zones(rideItem->sport); if (zones) zone_range = zones->whichRange(rideItem->dateTime.date()); if (parent->isShadeZones() && zones && (zone_range >= 0)) { @@ -642,7 +642,7 @@ class HrPwPlotZoneLabel: public QwtPlotItem return; int zone_range = -1; - const Zones *zones = parent->context->athlete->zones(rideItem->isRun); + const Zones *zones = parent->context->athlete->zones(rideItem->sport); if (zones) zone_range = zones->whichRange(rideItem->dateTime.date()); // create new zone labels if we're shading @@ -718,10 +718,10 @@ HrPwPlot::refreshZoneLabels() { bg = NULL; } - if (rideItem && context->athlete->zones(rideItem->isRun)) { + if (rideItem && context->athlete->zones(rideItem->sport)) { int zone_range = -1; - const Zones *zones = context->athlete->zones(rideItem->isRun); + const Zones *zones = context->athlete->zones(rideItem->sport); if (zones) zone_range = zones->whichRange(rideItem->dateTime.date()); // generate labels for existing zones diff --git a/src/Charts/OverviewItems.cpp b/src/Charts/OverviewItems.cpp index bdb7cf634..bba062412 100644 --- a/src/Charts/OverviewItems.cpp +++ b/src/Charts/OverviewItems.cpp @@ -243,11 +243,11 @@ ZoneOverviewItem::ZoneOverviewItem(ChartSpace *parent, QString name, RideFile::s // // POWER // - if (!polarized && series == RideFile::watts && parent->context->athlete->zones(false)) { + if (!polarized && series == RideFile::watts && parent->context->athlete->zones("Bike")) { // set the zero values - for(int i=0; icontext->athlete->zones(false)->getScheme().nzones_default; i++) { + for(int i=0; icontext->athlete->zones("Bike")->getScheme().nzones_default; i++) { *barset << 0; - categories << parent->context->athlete->zones(false)->getScheme().zone_default_name[i]; + categories << parent->context->athlete->zones("Bike")->getScheme().zone_default_name[i]; } } @@ -1232,14 +1232,14 @@ ZoneOverviewItem::setDateRange(DateRange dr) for(int i=0; i<3; i++) { vals[i] += item->getForSymbol(timeInZonesPolarized[i]); } - } else if (parent->context->athlete->zones(item->isRun)) { + } else if (parent->context->athlete->zones(item->sport)) { int numzones; - int range = parent->context->athlete->zones(item->isRun)->whichRange(item->dateTime.date()); + int range = parent->context->athlete->zones(item->sport)->whichRange(item->dateTime.date()); if (range > -1) { - numzones = parent->context->athlete->zones(item->isRun)->numZones(range); + numzones = parent->context->athlete->zones(item->sport)->numZones(range); for(int i=0; igetForSymbol(timeInZones[i]); } @@ -1372,15 +1372,15 @@ ZoneOverviewItem::setData(RideItem *item) if (time > 0 && sum > 0) barset->replace(i, round((time/sum) * 100)); else barset->replace(i, 0); } - } else if (parent->context->athlete->zones(item->isRun)) { + } else if (parent->context->athlete->zones(item->sport)) { int numzones; - int range = parent->context->athlete->zones(item->isRun)->whichRange(item->dateTime.date()); + int range = parent->context->athlete->zones(item->sport)->whichRange(item->dateTime.date()); if (range > -1) { double sum=0; - numzones = parent->context->athlete->zones(item->isRun)->numZones(range); + numzones = parent->context->athlete->zones(item->sport)->numZones(range); for(int i=0; igetForSymbol(timeInZones[i]); } diff --git a/src/Charts/PfPvPlot.cpp b/src/Charts/PfPvPlot.cpp index 467e1cffa..36fc3f29d 100644 --- a/src/Charts/PfPvPlot.cpp +++ b/src/Charts/PfPvPlot.cpp @@ -67,7 +67,7 @@ public: if (parent->context->isCompareIntervals) { - zones = parent->context->athlete->zones(rideItem ? rideItem->isRun : false); + zones = parent->context->athlete->zones(rideItem ? rideItem->sport : "Bike"); if (!zones) return; // use first compare interval date @@ -78,9 +78,9 @@ public: if (zone_range == -1) zone_range = zones->whichRange(QDate::currentDate()); - } else if (rideItem && parent->context->athlete->zones(rideItem->isRun)) { + } else if (rideItem && parent->context->athlete->zones(rideItem->sport)) { - zones = parent->context->athlete->zones(rideItem->isRun); + zones = parent->context->athlete->zones(rideItem->sport); zone_range = zones->whichRange(rideItem->dateTime.date()); } else { @@ -297,7 +297,7 @@ PfPvPlot::refreshZoneItems() // set zones from ride or athlete and date of // first item in the compare set - const Zones *zones = context->athlete->zones(rideItem ? rideItem->isRun : false); + const Zones *zones = context->athlete->zones(rideItem ? rideItem->sport : "Bike"); int zone_range = -1; // comparing does zones for items selected not current ride diff --git a/src/Charts/PowerHist.cpp b/src/Charts/PowerHist.cpp index cf5817d87..388c5c9e9 100644 --- a/src/Charts/PowerHist.cpp +++ b/src/Charts/PowerHist.cpp @@ -298,7 +298,7 @@ PowerHist::refreshZoneLabels() if (series == RideFile::watts || series == RideFile::wattsKg) { - const Zones *zones = context->athlete->zones(rideItem->isRun); + const Zones *zones = context->athlete->zones(rideItem->sport); int zone_range = zones->whichRange(rideItem->dateTime.date()); // generate labels for existing zones @@ -684,7 +684,7 @@ PowerHist::recalcCompare() } else { - const Zones *zones = context->athlete->zones(false); + const Zones *zones = context->athlete->zones("Bike"); int zone_range = -1; if (zones) { @@ -911,16 +911,16 @@ PowerHist::recalc(bool force) curveSelected->setSamples(sx, sy); // zone scale draw - if ((series == RideFile::watts || series == RideFile::wattsKg) && zoned && rideItem && context->athlete->zones(rideItem->isRun)) { + if ((series == RideFile::watts || series == RideFile::wattsKg) && zoned && rideItem && context->athlete->zones(rideItem->sport)) { if (cpzoned) { setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw()); setAxisScale(QwtPlot::xBottom, -0.99, 3, 1); } else { - int zone_range = context->athlete->zones(rideItem->isRun)->whichRange(rideItem->dateTime.date()); - setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(rideItem->isRun), zone_range)); + int zone_range = context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date()); + setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(rideItem->sport), zone_range)); if (zone_range >= 0) - setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones(rideItem->isRun)->numZones(zone_range), 1); + setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones(rideItem->sport)->numZones(zone_range), 1); else setAxisScale(QwtPlot::xBottom, -0.99, 0, 1); } @@ -963,14 +963,14 @@ PowerHist::recalc(bool force) } // watts zoned for a time range - if (source == Cache && zoned && (series == RideFile::watts || series == RideFile::wattsKg) && context->athlete->zones(false)) { + if (source == Cache && zoned && (series == RideFile::watts || series == RideFile::wattsKg) && context->athlete->zones("Bike")) { if (cpzoned) { setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw()); setAxisScale(QwtPlot::xBottom, -0.99, 3, 1); } else { - setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(false), 0)); - if (context->athlete->zones(false)->getRangeSize()) - setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones(false)->numZones(0), 1); // use zones from first defined range + setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones("Bike"), 0)); + if (context->athlete->zones("Bike")->getRangeSize()) + setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones("Bike")->numZones(0), 1); // use zones from first defined range } } @@ -1420,7 +1420,7 @@ PowerHist::intervalHover(IntervalItem *x) // set data HistData hoverData; - setArraysFromRide(rideItem->ride(), hoverData, context->athlete->zones(rideItem->isRun), x); + setArraysFromRide(rideItem->ride(), hoverData, context->athlete->zones(rideItem->sport), x); // set curve QVectorx,y,sx,sy; @@ -1864,7 +1864,7 @@ PowerHist::setData(RideItem *_rideItem, bool force) if (ride && hasData) { //setTitle(ride->startTime().toString(GC_DATETIME_FORMAT)); - setArraysFromRide(ride, standard, context->athlete->zones(rideItem->isRun), NULL); + setArraysFromRide(ride, standard, context->athlete->zones(rideItem->sport), NULL); } else { diff --git a/src/Charts/PowerHist.h b/src/Charts/PowerHist.h index 7a0b94b0c..a34eb26ab 100644 --- a/src/Charts/PowerHist.h +++ b/src/Charts/PowerHist.h @@ -319,7 +319,7 @@ public: if (! rideItem) return; - const Zones *zones = parent->context->athlete->zones(rideItem->isRun); + const Zones *zones = parent->context->athlete->zones(rideItem->sport); int zone_range = -1; if (zones) zone_range = zones->whichRange(rideItem->dateTime.date()); @@ -382,7 +382,7 @@ public: if (! rideItem) return; - const Zones *zones = parent->context->athlete->zones(rideItem->isRun); + const Zones *zones = parent->context->athlete->zones(rideItem->sport); int zone_range = -1; if (zones) zone_range = zones->whichRange(rideItem->dateTime.date()); diff --git a/src/Charts/RideMapWindow.cpp b/src/Charts/RideMapWindow.cpp index 21835d2c4..64e792017 100644 --- a/src/Charts/RideMapWindow.cpp +++ b/src/Charts/RideMapWindow.cpp @@ -355,9 +355,9 @@ RideMapWindow::rideSelected() rideCP = 300; stale = false; - if (context->athlete->zones(ride->isRun)) { - range = context->athlete->zones(ride->isRun)->whichRange(ride->dateTime.date()); - if (range >= 0) rideCP = context->athlete->zones(ride->isRun)->getCP(range); + if (context->athlete->zones(ride->sport)) { + range = context->athlete->zones(ride->sport)->whichRange(ride->dateTime.date()); + if (range >= 0) rideCP = context->athlete->zones(ride->sport)->getCP(range); } loadRide(); @@ -750,7 +750,7 @@ void RideMapWindow::createHtml() QColor RideMapWindow::GetColor(int watts) { if (range < 0 || hideShadedZones()) return Qt::red; - else return zoneColor(context->athlete->zones(myRideItem ? myRideItem->isRun : false)->whichZone(range, watts), 7); + else return zoneColor(context->athlete->zones(myRideItem ? myRideItem->sport : "Bike")->whichZone(range, watts), 7); } // create the ride line diff --git a/src/Charts/RideSummaryWindow.cpp b/src/Charts/RideSummaryWindow.cpp index 05d866f3a..831574321 100644 --- a/src/Charts/RideSummaryWindow.cpp +++ b/src/Charts/RideSummaryWindow.cpp @@ -942,30 +942,30 @@ RideSummaryWindow::htmlSummary() // or summarising date range with homogeneous activities // if ((ridesummary && rideItem && rideItem->present.contains("P")) || - (!ridesummary && ((nActivities==nRides) || (nActivities==nRuns)))) { + (!ridesummary && !sport.isEmpty())) { // set to unknown just in case range = -1; int WPRIME=22000; // reasonable default - if (ridesummary && rideItem && context->athlete->zones(rideItem->isRun)) { + if (ridesummary && rideItem && context->athlete->zones(rideItem->sport)) { // get zones to use via ride for ridesummary - range = context->athlete->zones(rideItem->isRun)->whichRange(rideItem->dateTime.date()); + range = context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date()); if (range > -1) { - numzones = context->athlete->zones(rideItem->isRun)->numZones(range); - WPRIME = context->athlete->zones(rideItem ? rideItem->isRun : false)->getWprime(range); + numzones = context->athlete->zones(rideItem->sport)->numZones(range); + WPRIME = context->athlete->zones(rideItem ? rideItem->sport : "Bike")->getWprime(range); } // or for end of daterange plotted for daterange summary with // homogeneous activites, use the corresponding Power Zones - } else if (!ridesummary && context->athlete->zones(nActivities==nRuns)) { + } else if (!ridesummary && context->athlete->zones(sport)) { // get from end if period - range = context->athlete->zones(nActivities==nRuns)->whichRange(myDateRange.to); + range = context->athlete->zones(sport)->whichRange(myDateRange.to); if (range > -1) { - numzones = context->athlete->zones(nActivities==nRuns)->numZones(range); - WPRIME = context->athlete->zones(nActivities==nRuns)->getWprime(range); + numzones = context->athlete->zones(sport)->numZones(range); + WPRIME = context->athlete->zones(sport)->getWprime(range); } } @@ -982,8 +982,8 @@ RideSummaryWindow::htmlSummary() } summary += tr("

Power Zones

"); - if (ridesummary) summary += context->athlete->zones(rideItem->isRun)->summarize(range, time_in_zone, altColor); - else summary += context->athlete->zones(nActivities==nRuns)->summarize(range, time_in_zone, altColor); //aggregating for date range + if (ridesummary) summary += context->athlete->zones(rideItem->sport)->summarize(range, time_in_zone, altColor); + else summary += context->athlete->zones(sport)->summarize(range, time_in_zone, altColor); //aggregating for date range // W'bal Zones QVector wtime_in_zone(4); @@ -1978,15 +1978,14 @@ RideSummaryWindow::htmlCompareSummary() const // // TIME IN POWER ZONES (we can't do w'bal compare at present) // when all rides or all runs, use zones accordingly - if (((nActivities==nRides) || (nActivities==nRuns)) && - context->athlete->zones(nActivities==nRuns)) { + if (!sport.isEmpty() && context->athlete->zones(sport)) { // get from end if period - int rangeidx = context->athlete->zones(nActivities==nRuns)->whichRange(QDate::currentDate()); // use current zone names et al + int rangeidx = context->athlete->zones(sport)->whichRange(QDate::currentDate()); // use current zone names et al if (rangeidx > -1) { // get the list of zones - ZoneRange range = const_cast(context->athlete->zones(nActivities==nRuns))->getZoneRange(rangeidx); + ZoneRange range = const_cast(context->athlete->zones(sport))->getZoneRange(rangeidx); QList zones = range.zones; // we've got a range and a count of zones so all is well @@ -2125,7 +2124,7 @@ RideSummaryWindow::htmlCompareSummary() const // TIME IN PACE ZONES // when all runs or all swims, use zones accordingly if (((nActivities==nRuns) || (nActivities==nSwims)) && - context->athlete->zones(nActivities==nSwims)) { + context->athlete->paceZones(nActivities==nSwims)) { // get from end if period int rangeidx = context->athlete->paceZones(nActivities==nSwims)->whichRange(QDate::currentDate()); // use current zone names et al @@ -2345,15 +2344,14 @@ RideSummaryWindow::htmlCompareSummary() const // // TIME IN POWER ZONES AND W'BAL ZONES // when all rides or all runs, use zones accordingly - if (((nActivities==nRides) || (nActivities==nRuns)) && - context->athlete->zones(nActivities==nRuns)) { + if (!sport.isEmpty() && context->athlete->zones(sport)) { // get from end if period - int rangeidx = context->athlete->zones(nActivities==nRuns)->whichRange(QDate::currentDate()); // use current zone names et al + int rangeidx = context->athlete->zones(sport)->whichRange(QDate::currentDate()); // use current zone names et al if (rangeidx > -1) { // get the list of zones - ZoneRange range = const_cast(context->athlete->zones(nActivities==nRuns))->getZoneRange(rangeidx); + ZoneRange range = const_cast(context->athlete->zones(sport))->getZoneRange(rangeidx); QList zones = range.zones; // we've got a range and a count of zones so all is well @@ -2559,7 +2557,7 @@ RideSummaryWindow::htmlCompareSummary() const // TIME IN PACE ZONES // when all runs or all swims, use zones accordingly if (((nActivities==nRuns) || (nActivities==nSwims)) && - context->athlete->zones(nActivities==nSwims)) { + context->athlete->paceZones(nActivities==nSwims)) { // get from end if period int rangeidx = context->athlete->paceZones(nActivities==nSwims)->whichRange(QDate::currentDate()); // use current zone names et al diff --git a/src/Core/Athlete.cpp b/src/Core/Athlete.cpp index 68352744b..c4520ec13 100644 --- a/src/Core/Athlete.cpp +++ b/src/Core/Athlete.cpp @@ -92,8 +92,9 @@ Athlete::Athlete(Context *context, const QDir &homeDir) // Power Zones for Bike & Run - for (int i=0; i < 2; i++) { - zones_[i] = new Zones(i>0); + foreach (QString sport, GlobalContext::context()->rideMetadata->sports()) { + QString i = RideFile::sportTag(sport); + zones_[i] = new Zones(i); QFile zonesFile(home->config().canonicalPath() + "/" + zones_[i]->fileName()); if (zonesFile.exists()) { if (!zones_[i]->read(zonesFile)) { @@ -102,16 +103,15 @@ Athlete::Athlete(Context *context, const QDir &homeDir) QMessageBox::warning(context->mainWindow, tr("Reading Zones File %1").arg(zones_[i]->fileName()), zones_[i]->warningString()); } } - if (i == 1 && zones_[i]->getRangeSize() == 0) { // No running Power zones + if (i != "Bike" && zones_[i]->getRangeSize() == 0) { // No Power zones // Start with Cycling Power zones for backward compatibilty - QFile zonesFile(home->config().canonicalPath() + "/" + zones_[0]->fileName()); + QFile zonesFile(home->config().canonicalPath() + "/" + Zones().fileName()); // Load without error/warning report to avoid repetition if (zonesFile.exists()) zones_[i]->read(zonesFile); } } - // Heartrate Zones for Bike & Run - QString defaultHrZoneFN = HrZones().fileName(); + // Heartrate Zones foreach (QString sport, GlobalContext::context()->rideMetadata->sports()) { QString i = RideFile::sportTag(sport); hrzones_[i] = new HrZones(i); @@ -253,7 +253,7 @@ Athlete::~Athlete() delete seasons; delete measures; - for (int i=0; i<2; i++) delete zones_[i]; + foreach (Zones* zones, zones_) delete zones; foreach (HrZones* hrzones, hrzones_) delete hrzones; for (int i=0; i<2; i++) delete pacezones_[i]; delete autoImportConfig; diff --git a/src/Core/Athlete.h b/src/Core/Athlete.h index b7904661e..1f6044af6 100644 --- a/src/Core/Athlete.h +++ b/src/Core/Athlete.h @@ -81,10 +81,10 @@ class Athlete : public QObject const AthleteDirectoryStructure *directoryStructure() const {return home; } // zones - const Zones *zones(bool isRun) const { return zones_[isRun]; } - const HrZones *hrZones(QString sport) const { return hrzones_.value(sport); } + const Zones *zones(QString sport) const { return zones_.value(sport, zones_.value("Bike")); } + const HrZones *hrZones(QString sport) const { return hrzones_.value(sport, hrzones_.value("Bike")); } const PaceZones *paceZones(bool isSwim) const { return pacezones_[isSwim]; } - Zones *zones_[2]; + QHash zones_; QHash hrzones_; PaceZones *pacezones_[2]; void setCriticalPower(int cp); diff --git a/src/Core/DataFilter.cpp b/src/Core/DataFilter.cpp index 6fea44220..7723b7c70 100644 --- a/src/Core/DataFilter.cpp +++ b/src/Core/DataFilter.cpp @@ -3262,20 +3262,20 @@ Result Leaf::eval(DataFilterRuntime *df, Leaf *leaf, Result x, long it, RideItem double PMAX = 0; int zoneRange; - if (m->context->athlete->zones(m->isRun)) { + if (m->context->athlete->zones(m->sport)) { // if range is -1 we need to fall back to a default value - zoneRange = m->context->athlete->zones(m->isRun)->whichRange(m->dateTime.date()); - FTP = CP = zoneRange >= 0 ? m->context->athlete->zones(m->isRun)->getCP(zoneRange) : 0; - AeTP = zoneRange >= 0 ? m->context->athlete->zones(m->isRun)->getAeT(zoneRange) : 0; - WPRIME = zoneRange >= 0 ? m->context->athlete->zones(m->isRun)->getWprime(zoneRange) : 0; - PMAX = zoneRange >= 0 ? m->context->athlete->zones(m->isRun)->getPmax(zoneRange) : 0; + zoneRange = m->context->athlete->zones(m->sport)->whichRange(m->dateTime.date()); + FTP = CP = zoneRange >= 0 ? m->context->athlete->zones(m->sport)->getCP(zoneRange) : 0; + AeTP = zoneRange >= 0 ? m->context->athlete->zones(m->sport)->getAeT(zoneRange) : 0; + WPRIME = zoneRange >= 0 ? m->context->athlete->zones(m->sport)->getWprime(zoneRange) : 0; + PMAX = zoneRange >= 0 ? m->context->athlete->zones(m->sport)->getPmax(zoneRange) : 0; // use CP for FTP, or is it configured separately bool useCPForFTP = (appsettings->cvalue(m->context->athlete->cyclist, - m->context->athlete->zones(m->isRun)->useCPforFTPSetting(), 0).toInt() == 0); + m->context->athlete->zones(m->sport)->useCPforFTPSetting(), 0).toInt() == 0); if (zoneRange >= 0 && !useCPForFTP) { - FTP = m->context->athlete->zones(m->isRun)->getFTP(zoneRange); + FTP = m->context->athlete->zones(m->sport)->getFTP(zoneRange); } // did we override CP in metadata ? diff --git a/src/Core/RideItem.cpp b/src/Core/RideItem.cpp index 31200dd3e..d0b8f4a36 100644 --- a/src/Core/RideItem.cpp +++ b/src/Core/RideItem.cpp @@ -498,8 +498,8 @@ RideItem::checkStale() // HRV fingerprint added to detect changes on HRV Measures // get the new zone configuration fingerprint that applies for the ride date - unsigned long rfingerprint = static_cast(context->athlete->zones(isRun)->getFingerprint(dateTime.date())) - + (appsettings->cvalue(context->athlete->cyclist, context->athlete->zones(isRun)->useCPforFTPSetting(), 0).toInt() ? 1 : 0) + unsigned long rfingerprint = static_cast(context->athlete->zones(sport)->getFingerprint(dateTime.date())) + + (appsettings->cvalue(context->athlete->cyclist, context->athlete->zones(sport)->useCPforFTPSetting(), 0).toInt() ? 1 : 0) + static_cast(context->athlete->paceZones(isSwim)->getFingerprint(dateTime.date())) + static_cast(context->athlete->hrZones(sport)->getFingerprint(dateTime.date())) + static_cast(context->athlete->routes->getFingerprint()) @@ -601,7 +601,7 @@ RideItem::refresh() samples = f->dataPoints().count() > 0; // zone ranges - if (context->athlete->zones(isRun)) zoneRange = context->athlete->zones(isRun)->whichRange(dateTime.date()); + if (context->athlete->zones(sport)) zoneRange = context->athlete->zones(sport)->whichRange(dateTime.date()); else zoneRange = -1; if (context->athlete->hrZones(sport)) hrZoneRange = context->athlete->hrZones(sport)->whichRange(dateTime.date()); @@ -650,8 +650,8 @@ RideItem::refresh() updateIntervals(); // update fingerprints etc, crc done above - fingerprint = static_cast(context->athlete->zones(isRun)->getFingerprint(dateTime.date())) - + (appsettings->cvalue(context->athlete->cyclist, context->athlete->zones(isRun)->useCPforFTPSetting(), 0).toInt() ? 1 : 0) + fingerprint = static_cast(context->athlete->zones(sport)->getFingerprint(dateTime.date())) + + (appsettings->cvalue(context->athlete->cyclist, context->athlete->zones(sport)->useCPforFTPSetting(), 0).toInt() ? 1 : 0) + static_cast(context->athlete->paceZones(isSwim)->getFingerprint(dateTime.date())) + static_cast(context->athlete->hrZones(sport)->getFingerprint(dateTime.date())) + static_cast(context->athlete->routes->getFingerprint()) + @@ -861,12 +861,12 @@ RideItem::updateIntervals() double PMAX = 0; bool zoneok = false; - if (context->athlete->zones(isRun)) { + if (context->athlete->zones(sport)) { // if range is -1 we need to fall back to a default value - CP = zoneRange >= 0 ? context->athlete->zones(isRun)->getCP(zoneRange) : 0; - WPRIME = zoneRange >= 0 ? context->athlete->zones(isRun)->getWprime(zoneRange) : 0; - PMAX = zoneRange >= 0 ? context->athlete->zones(isRun)->getPmax(zoneRange) : 0; + CP = zoneRange >= 0 ? context->athlete->zones(sport)->getCP(zoneRange) : 0; + WPRIME = zoneRange >= 0 ? context->athlete->zones(sport)->getWprime(zoneRange) : 0; + PMAX = zoneRange >= 0 ? context->athlete->zones(sport)->getPmax(zoneRange) : 0; // did we override CP in metadata ? int oCP = getText("CP","0").toInt(); @@ -876,7 +876,7 @@ RideItem::updateIntervals() if (oW) WPRIME=oW; if (oPMAX) PMAX=oPMAX; - if (zoneRange >= 0 && context->athlete->zones(isRun)) zoneok=true; + if (zoneRange >= 0 && context->athlete->zones(sport)) zoneok=true; } // USER / DEVICE INTERVALS @@ -1154,7 +1154,7 @@ RideItem::updateIntervals() tte.duration = t; tte.joules = integrated_series[i+t]-integrated_series[i]; tte.quality = tc / double(t); - tte.zone = zoneok ? context->athlete->zones(isRun)->whichZone(zoneRange, tte.joules/tte.duration) : 1; + tte.zone = zoneok ? context->athlete->zones(sport)->whichZone(zoneRange, tte.joules/tte.duration) : 1; } else { @@ -1165,7 +1165,7 @@ RideItem::updateIntervals() tte.duration = t; tte.joules = integrated_series[i+t]-integrated_series[i]; tte.quality = thisquality; - tte.zone = zoneok ? context->athlete->zones(isRun)->whichZone(zoneRange, tte.joules/tte.duration) : 1; + tte.zone = zoneok ? context->athlete->zones(sport)->whichZone(zoneRange, tte.joules/tte.duration) : 1; } } @@ -1286,7 +1286,7 @@ RideItem::updateIntervals() foreach(effort x, candidates[i]) { IntervalItem *intervalItem=NULL; - int zone = zoneok ? 1 + context->athlete->zones(isRun)->whichZone(zoneRange, x.joules/x.duration) : 1; + int zone = zoneok ? 1 + context->athlete->zones(sport)->whichZone(zoneRange, x.joules/x.duration) : 1; if (x.quality >= 1.0f) { intervalItem = new IntervalItem(this, @@ -1315,7 +1315,7 @@ RideItem::updateIntervals() IntervalItem *intervalItem=NULL; - int zone = zoneok ? 1 + context->athlete->zones(isRun)->whichZone(zoneRange, x.joules/x.duration) : 1; + int zone = zoneok ? 1 + context->athlete->zones(sport)->whichZone(zoneRange, x.joules/x.duration) : 1; intervalItem = new IntervalItem(this, QString(tr("L%3 SPRINT of %1 secs (%2 watts)")).arg(x.duration).arg(x.joules/x.duration).arg(zone), x.start, x.start+x.duration, @@ -1491,7 +1491,7 @@ RideItem::updateIntervals() // which zone was this match ? double ap = intervalItem->getForSymbol("average_power"); double duration = intervalItem->getForSymbol("workout_time"); - int zone = zoneok ? 1 + context->athlete->zones(isRun)->whichZone(zoneRange, ap) : 1; + int zone = zoneok ? 1 + context->athlete->zones(sport)->whichZone(zoneRange, ap) : 1; intervalItem->name = QString(tr("L%1 %5 %2 (%3w %4 kJ)")) .arg(zone) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index 73b6bbc0a..f6c00a048 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -287,7 +287,6 @@ #define GC_CRANKLENGTH "crankLength" #define GC_WHEELSIZE "wheelsize" #define GC_USE_CP_FOR_FTP "cp/useforftp" // use CP for FTP -#define GC_USE_CP_FOR_FTP_RUN "cp/useforftprun" // use CP for FTP #define GC_NETWORKFILESTORE_FOLDER "networkfilestore/folder" // folder to sync with #define GC_AUTOBACKUP_FOLDER "autobackup/folder" #define GC_AUTOBACKUP_PERIOD "autobackup/period" // how often is the Athlete Folder backuped up / 0 == never diff --git a/src/FileIO/RideFile.cpp b/src/FileIO/RideFile.cpp index 9a76f87e4..4457b06ee 100644 --- a/src/FileIO/RideFile.cpp +++ b/src/FileIO/RideFile.cpp @@ -2358,10 +2358,10 @@ RideFile::recalculateDerivedSeries(bool force) double anTISS = 0.0f; // set WPrime and CP - if (context->athlete->zones(isRun())) { - int zoneRange = context->athlete->zones(isRun())->whichRange(startTime().date()); - CP = zoneRange >= 0 ? context->athlete->zones(isRun())->getCP(zoneRange) : 0; - //WPRIME = zoneRange >= 0 ? context->athlete->zones(isRun())->getWprime(zoneRange) : 0; + if (context->athlete->zones(sport())) { + int zoneRange = context->athlete->zones(sport())->whichRange(startTime().date()); + CP = zoneRange >= 0 ? context->athlete->zones(sport())->getCP(zoneRange) : 0; + //WPRIME = zoneRange >= 0 ? context->athlete->zones(sport())->getWprime(zoneRange) : 0; // did we override CP in metadata / metrics ? int oCP = getTag("CP","0").toInt(); diff --git a/src/FileIO/RideFileCache.cpp b/src/FileIO/RideFileCache.cpp index 62ef85204..c2fb4755b 100644 --- a/src/FileIO/RideFileCache.cpp +++ b/src/FileIO/RideFileCache.cpp @@ -1563,18 +1563,18 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s if (ride->isDataPresent(needSeries) == false) return; // get zones that apply, if any - int zoneRange = context->athlete->zones(ride->isRun()) ? context->athlete->zones(ride->isRun())->whichRange(ride->startTime().date()) : -1; + int zoneRange = context->athlete->zones(ride->sport()) ? context->athlete->zones(ride->sport())->whichRange(ride->startTime().date()) : -1; int hrZoneRange = context->athlete->hrZones(ride->sport()) ? context->athlete->hrZones(ride->sport())->whichRange(ride->startTime().date()) : -1; int paceZoneRange = context->athlete->paceZones(ride->isSwim()) ? context->athlete->paceZones(ride->isSwim())->whichRange(ride->startTime().date()) : -1; CP=0; int AeTP=0; if (zoneRange != -1) { - CP=context->athlete->zones(ride->isRun())->getCP(zoneRange); - AeTP=context->athlete->zones(ride->isRun())->getAeT(zoneRange); + CP=context->athlete->zones(ride->sport())->getCP(zoneRange); + AeTP=context->athlete->zones(ride->sport())->getAeT(zoneRange); } - if (zoneRange != -1) WPRIME=context->athlete->zones(ride->isRun())->getWprime(zoneRange); + if (zoneRange != -1) WPRIME=context->athlete->zones(ride->sport())->getWprime(zoneRange); else WPRIME=0; LTHR=0; @@ -1641,7 +1641,7 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s // watts time in zone if (series == RideFile::watts && zoneRange != -1) { - int index = context->athlete->zones(ride->isRun())->whichZone(zoneRange, dp->value(series)); + int index = context->athlete->zones(ride->sport())->whichZone(zoneRange, dp->value(series)); if (index >=0) wattsTimeInZone[index] += ride->recIntSecs(); } diff --git a/src/Gui/AthletePages.cpp b/src/Gui/AthletePages.cpp index 68482e75f..bfd7523fb 100644 --- a/src/Gui/AthletePages.cpp +++ b/src/Gui/AthletePages.cpp @@ -881,22 +881,23 @@ ZonePage::ZonePage(Context *context) : context(context) sportLabel = new QLabel(tr("Sport")); sportCombo = new QComboBox(); - sportCombo->addItem(tr("Bike")); - sportCombo->addItem(tr("Run")); - sportCombo->setCurrentIndex(0); hlayout->addStretch(); hlayout->addWidget(sportLabel); hlayout->addWidget(sportCombo); hlayout->addStretch(); layout->addLayout(hlayout); - connect(sportCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSport(int))); + connect(sportCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSport())); tabs = new QTabWidget(this); layout->addWidget(tabs); - for (int i=0; i < nSports; i++) { - zones[i] = new Zones(i > 0); + foreach (QString sport, GlobalContext::context()->rideMetadata->sports()) { + QString i = RideFile::sportTag(sport); + + // Add sport to combo + sportCombo->addItem(sport, i); // get current config by reading it in (leave mainwindow zones alone) + zones[i] = new Zones(i); QFile zonesFile(context->athlete->home->config().canonicalPath() + "/" + zones[i]->fileName()); if (zonesFile.exists()) { zones[i]->read(zonesFile); @@ -908,20 +909,22 @@ ZonePage::ZonePage(Context *context) : context(context) schemePage[i] = new SchemePage(zones[i]); cpPage[i] = new CPPage(context, zones[i], schemePage[i]); } + sportCombo->setCurrentIndex(0); // finish setup for the default sport - changeSport(sportCombo->currentIndex()); + changeSport(); } ZonePage::~ZonePage() { - for (int i=0; icurrentData().toString(); tabs->clear(); tabs->addTab(cpPage[i], tr("Critical Power")); tabs->addTab(schemePage[i], tr("Default")); @@ -934,16 +937,16 @@ ZonePage::saveClicked() qint32 changed = 0; qint32 cppageChanged = 0; // write - for (int i=0; i < nSports; i++) { + foreach (QString i, zones.keys()) { zones[i]->setScheme(schemePage[i]->getScheme()); zones[i]->write(context->athlete->home->config()); // re-read Zones in case it changed QFile zonesFile(context->athlete->home->config().canonicalPath() + "/" + context->athlete->zones_[i]->fileName()); context->athlete->zones_[i]->read(zonesFile); - if (i == 1 && context->athlete->zones_[i]->getRangeSize() == 0) { // No running Power zones + if (i != "Bike" && context->athlete->zones_[i]->getRangeSize() == 0) { // No Power zones // Start with Cycling Power zones for backward compatibilty - QFile zonesFile(context->athlete->home->config().canonicalPath() + "/" + context->athlete->zones_[0]->fileName()); + QFile zonesFile(context->athlete->home->config().canonicalPath() + "/" + Zones().fileName()); if (zonesFile.exists()) context->athlete->zones_[i]->read(zonesFile); } diff --git a/src/Gui/AthletePages.h b/src/Gui/AthletePages.h index dd55e1916..c0a17b5cc 100644 --- a/src/Gui/AthletePages.h +++ b/src/Gui/AthletePages.h @@ -311,19 +311,17 @@ class ZonePage : public QWidget private: - static const int nSports = 2; - QLabel *sportLabel; QComboBox *sportCombo; //ZoneScheme scheme; - Zones *zones[nSports]; - quint16 b4Fingerprint[nSports]; // how did it start ? - SchemePage *schemePage[nSports]; - CPPage *cpPage[nSports]; + QHash zones; + QHash b4Fingerprint; // how did it start ? + QHash schemePage; + QHash cpPage; private slots: - void changeSport(int i); + void changeSport(); }; diff --git a/src/Gui/SolveCPDialog.cpp b/src/Gui/SolveCPDialog.cpp index 8dd4e564c..34de2f842 100644 --- a/src/Gui/SolveCPDialog.cpp +++ b/src/Gui/SolveCPDialog.cpp @@ -450,12 +450,12 @@ SolveCPDialog::solveClicked() if (static_cast(dataTable->itemWidget(it, 0))->isChecked()) item = static_cast(it->data(0, Qt::UserRole).value()); - if (item && item->context->athlete->zones(item->isRun)) { + if (item && item->context->athlete->zones(item->sport)) { // get CP etc - int zoneRange = item->context->athlete->zones(item->isRun)->whichRange(item->dateTime.date()); - int CP = zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getCP(zoneRange) : 0; - int WPRIME = zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getWprime(zoneRange) : 0; + int zoneRange = item->context->athlete->zones(item->sport)->whichRange(item->dateTime.date()); + int CP = zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getCP(zoneRange) : 0; + int WPRIME = zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getWprime(zoneRange) : 0; if (!mincp || CP < mincp) mincp = CP; if (!maxcp || CP > maxcp) maxcp = CP; diff --git a/src/Metrics/BasicRideMetrics.cpp b/src/Metrics/BasicRideMetrics.cpp index e0b81a357..e14f349e0 100644 --- a/src/Metrics/BasicRideMetrics.cpp +++ b/src/Metrics/BasicRideMetrics.cpp @@ -1684,10 +1684,10 @@ class APPercent : public RideMetric { double percent = 0.0f; AvgPower *pw = dynamic_cast(deps.value("average_power")); - if (pw->value(true) > 0.0f && item->context->athlete->zones(item->isRun) && item->zoneRange >= 0) { + if (pw->value(true) > 0.0f && item->context->athlete->zones(item->sport) && item->zoneRange >= 0) { // get Pmax - double pmax = item->context->athlete->zones(item->isRun)->getPmax(item->zoneRange); + double pmax = item->context->athlete->zones(item->sport)->getPmax(item->zoneRange); percent = pw->value(true)/pmax * 100; } setValue(percent); diff --git a/src/Metrics/BikeScore.cpp b/src/Metrics/BikeScore.cpp index 49a3365b8..47a86ee09 100644 --- a/src/Metrics/BikeScore.cpp +++ b/src/Metrics/BikeScore.cpp @@ -174,12 +174,12 @@ class RelativeIntensity : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { - if (item->context->athlete->zones(item->isRun) && item->zoneRange >= 0) { + if (item->context->athlete->zones(item->sport) && item->zoneRange >= 0) { assert(deps.contains("skiba_xpower")); XPower *xp = dynamic_cast(deps.value("skiba_xpower")); assert(xp); int cp = item->getText("CP","0").toInt(); - reli = xp->value(true) / (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)); + reli = xp->value(true) / (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)); secs = xp->count(); } setValue(reli); @@ -219,8 +219,8 @@ class CriticalPower : public RideMetric { // not overriden so use the set value // if it has been set at all - if (!cp && item->context->athlete->zones(item->isRun) && item->zoneRange >= 0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp && item->context->athlete->zones(item->sport) && item->zoneRange >= 0) + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); setValue(cp); } @@ -251,7 +251,7 @@ class aTISS : public RideMetric { void compute(RideItem *item, Specification spec, const QHash &) { - if (!item->context->athlete->zones(item->isRun) || item->zoneRange < 0) return; + if (!item->context->athlete->zones(item->sport) || item->zoneRange < 0) return; // no ride or no samples if (spec.isEmpty(item->ride())) { @@ -267,7 +267,7 @@ class aTISS : public RideMetric { double aTISS = 0.0f; int cp = item->getText("CP","0").toInt(); - if (!cp) cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp) cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); if (cp && item->ride()->areDataPresent()->watts) { @@ -315,7 +315,7 @@ class anTISS : public RideMetric { return; } - if (!item->context->athlete->zones(item->isRun) || item->zoneRange < 0) return; + if (!item->context->athlete->zones(item->sport) || item->zoneRange < 0) return; // anTISS - Aerobic Training Impact Scoring System static const double a = 0.238923886004611f; @@ -325,7 +325,7 @@ class anTISS : public RideMetric { double anTISS = 0.0f; int cp = item->getText("CP","0").toInt(); - if (!cp) cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp) cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); if (cp && item->ride()->areDataPresent()->watts) { RideFileIterator it(item->ride(), spec); @@ -367,7 +367,7 @@ class dTISS : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { - if (!item->context->athlete->zones(item->isRun) || item->zoneRange < 0) return; + if (!item->context->athlete->zones(item->sport) || item->zoneRange < 0) return; assert(deps.contains("atiss_score")); assert(deps.contains("antiss_score")); @@ -408,7 +408,7 @@ class BikeScore : public RideMetric { // run, swim or no zones if (item->isSwim || item->isRun || - !item->context->athlete->zones(item->isRun) || item->zoneRange < 0) { + !item->context->athlete->zones(item->sport) || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; @@ -422,7 +422,7 @@ class BikeScore : public RideMetric { double normWork = xp->value(true) * xp->count(); double rawBikeScore = normWork * ri->value(true); int cp = item->getText("CP","0").toInt(); - double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)) * 3600; + double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)) * 3600; score = rawBikeScore / workInAnHourAtCP * 100.0; setValue(score); diff --git a/src/Metrics/CPSolver.cpp b/src/Metrics/CPSolver.cpp index 4fb9f0b84..991fa3621 100644 --- a/src/Metrics/CPSolver.cpp +++ b/src/Metrics/CPSolver.cpp @@ -301,10 +301,10 @@ class BestR : public RideMetric { double W = 20000; // set from the ride - if (item->context->athlete->zones(item->isRun)) { - int zoneRange = item->context->athlete->zones(item->isRun)->whichRange(item->dateTime.date()); - CP = zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getCP(zoneRange) : 0; - W = zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getWprime(zoneRange) : 0; + if (item->context->athlete->zones(item->sport)) { + int zoneRange = item->context->athlete->zones(item->sport)->whichRange(item->dateTime.date()); + CP = zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getCP(zoneRange) : 0; + W = zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getWprime(zoneRange) : 0; // did we override CP in metadata / metrics ? int oCP = item->getText("CP","0").toInt(); diff --git a/src/Metrics/Coggan.cpp b/src/Metrics/Coggan.cpp index 2ce003630..4c3aa7686 100644 --- a/src/Metrics/Coggan.cpp +++ b/src/Metrics/Coggan.cpp @@ -172,7 +172,7 @@ class IntensityFactor : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { // no zones - if (!item->context->athlete->zones(item->isRun) || item->zoneRange < 0) { + if (!item->context->athlete->zones(item->sport) || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; @@ -184,17 +184,17 @@ class IntensityFactor : public RideMetric { int ftp = item->getText("FTP","0").toInt(); - bool useCPForFTP = (appsettings->cvalue(item->context->athlete->cyclist, item->context->athlete->zones(item->isRun)->useCPforFTPSetting(), 0).toInt() == 0); + bool useCPForFTP = (appsettings->cvalue(item->context->athlete->cyclist, item->context->athlete->zones(item->sport)->useCPforFTPSetting(), 0).toInt() == 0); if (useCPForFTP) { int cp = item->getText("CP","0").toInt(); if (cp == 0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); ftp = cp; } - rif = np->value(true) / (ftp ? ftp : item->context->athlete->zones(item->isRun)->getFTP(item->zoneRange)); + rif = np->value(true) / (ftp ? ftp : item->context->athlete->zones(item->sport)->getFTP(item->zoneRange)); secs = np->count(); setValue(rif); @@ -229,7 +229,7 @@ class BikeStress : public RideMetric { // run, swim or no zones if (item->isSwim || item->isRun || - !item->context->athlete->zones(item->isRun) || item->zoneRange < 0) { + !item->context->athlete->zones(item->sport) || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; @@ -245,17 +245,17 @@ class BikeStress : public RideMetric { int ftp = item->getText("FTP","0").toInt(); - bool useCPForFTP = (appsettings->cvalue(item->context->athlete->cyclist, item->context->athlete->zones(item->isRun)->useCPforFTPSetting(), 0).toInt() == 0); + bool useCPForFTP = (appsettings->cvalue(item->context->athlete->cyclist, item->context->athlete->zones(item->sport)->useCPforFTPSetting(), 0).toInt() == 0); if (useCPForFTP) { int cp = item->getText("CP","0").toInt(); if (cp == 0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); ftp = cp; } - double workInAnHourAtCP = (ftp ? ftp : item->context->athlete->zones(item->isRun)->getFTP(item->zoneRange)) * 3600; + double workInAnHourAtCP = (ftp ? ftp : item->context->athlete->zones(item->sport)->getFTP(item->zoneRange)) * 3600; score = rawTSS / workInAnHourAtCP * 100.0; setValue(score); diff --git a/src/Metrics/DanielsPoints.cpp b/src/Metrics/DanielsPoints.cpp index 98427be2a..27415b3a6 100644 --- a/src/Metrics/DanielsPoints.cpp +++ b/src/Metrics/DanielsPoints.cpp @@ -175,12 +175,12 @@ private: double lastSecs = 0.0; double weighted = 0.0; - if (item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0) { + if (item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; } - double cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + double cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); score = 0.0; @@ -281,13 +281,13 @@ class DanielsEquivalentPower : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { // no zones - if (item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0) { + if (item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; } - double cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + double cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); assert(deps.contains("daniels_points")); assert(deps.contains("time_riding")); diff --git a/src/Metrics/PeakPower.cpp b/src/Metrics/PeakPower.cpp index 93835060f..d79cb5858 100644 --- a/src/Metrics/PeakPower.cpp +++ b/src/Metrics/PeakPower.cpp @@ -69,7 +69,7 @@ class PeakPercent : public RideMetric { double CP = 250; double WPRIME = 22000; - const Zones* zones = item->context->athlete->zones(item->isRun); + const Zones* zones = item->context->athlete->zones(item->sport); if (zones) { // if range is -1 we need to fall back to a default value @@ -127,7 +127,7 @@ class PowerZone : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { // no zones - const Zones* zones = item->context->athlete->zones(item->isRun); + const Zones* zones = item->context->athlete->zones(item->sport); if (!zones || !item->ride()->areDataPresent()->watts) { setValue(RideFile::NIL); setCount(0); diff --git a/src/Metrics/TimeInZone.cpp b/src/Metrics/TimeInZone.cpp index 8ecc398ab..e1989537d 100644 --- a/src/Metrics/TimeInZone.cpp +++ b/src/Metrics/TimeInZone.cpp @@ -50,7 +50,7 @@ class ZoneTime : public RideMetric { // no ride or no samples if (spec.isEmpty(item->ride()) || - item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0 || + item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0 || !item->ride()->areDataPresent()->watts) { setValue(RideFile::NIL); setCount(0); @@ -65,7 +65,7 @@ class ZoneTime : public RideMetric { while (it.hasNext()) { struct RideFilePoint *point = it.next(); totalSecs += item->ride()->recIntSecs(); - if (item->context->athlete->zones(item->isRun)->whichZone(item->zoneRange, point->watts) == level) + if (item->context->athlete->zones(item->sport)->whichZone(item->zoneRange, point->watts) == level) seconds += item->ride()->recIntSecs(); } setValue(seconds); @@ -752,14 +752,14 @@ class ZoneTimeI : public RideMetric { // no ride or no samples if (spec.isEmpty(item->ride()) || - item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0 || + item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0 || !item->ride()->areDataPresent()->watts) { setValue(RideFile::NIL); setCount(0); return; } - int AeT = item->context->athlete->zones(item->isRun)->getAeT(item->zoneRange); + int AeT = item->context->athlete->zones(item->sport)->getAeT(item->zoneRange); double totalSecs = 0.0; seconds = 0; @@ -811,15 +811,15 @@ class ZoneTimeII : public RideMetric { // no ride or no samples if (spec.isEmpty(item->ride()) || - item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0 || + item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0 || !item->ride()->areDataPresent()->watts) { setValue(RideFile::NIL); setCount(0); return; } - int AeT = item->context->athlete->zones(item->isRun)->getAeT(item->zoneRange); - int CP = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + int AeT = item->context->athlete->zones(item->sport)->getAeT(item->zoneRange); + int CP = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); double totalSecs = 0.0; seconds = 0; @@ -871,14 +871,14 @@ class ZoneTimeIII : public RideMetric { // no ride or no samples if (spec.isEmpty(item->ride()) || - item->context->athlete->zones(item->isRun) == NULL || item->zoneRange < 0 || + item->context->athlete->zones(item->sport) == NULL || item->zoneRange < 0 || !item->ride()->areDataPresent()->watts) { setValue(RideFile::NIL); setCount(0); return; } - int CP = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + int CP = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); double totalSecs = 0.0; seconds = 0; diff --git a/src/Metrics/WPrime.cpp b/src/Metrics/WPrime.cpp index c6b7b84a5..f5740e677 100644 --- a/src/Metrics/WPrime.cpp +++ b/src/Metrics/WPrime.cpp @@ -173,10 +173,10 @@ WPrime::setRide(RideFile *input) // Get CP CP = 250; // default WPRIME = 20000; - if (input->context->athlete->zones(input->isRun())) { - int zoneRange = input->context->athlete->zones(input->isRun())->whichRange(input->startTime().date()); - CP = zoneRange >= 0 ? input->context->athlete->zones(input->isRun())->getCP(zoneRange) : 0; - WPRIME = zoneRange >= 0 ? input->context->athlete->zones(input->isRun())->getWprime(zoneRange) : 0; + if (input->context->athlete->zones(input->sport())) { + int zoneRange = input->context->athlete->zones(input->sport())->whichRange(input->startTime().date()); + CP = zoneRange >= 0 ? input->context->athlete->zones(input->sport())->getCP(zoneRange) : 0; + WPRIME = zoneRange >= 0 ? input->context->athlete->zones(input->sport())->getWprime(zoneRange) : 0; // did we override CP in metadata / metrics ? int oCP = input->getTag("CP","0").toInt(); @@ -484,10 +484,10 @@ WPrime::setErg(ErgFile *input) CP = 250; // defaults WPRIME = 20000; - if (input->context->athlete->zones(false)) { - int zoneRange = input->context->athlete->zones(false)->whichRange(QDate::currentDate()); - CP = zoneRange >= 0 ? input->context->athlete->zones(false)->getCP(zoneRange) : 250; - WPRIME = zoneRange >= 0 ? input->context->athlete->zones(false)->getWprime(zoneRange) : 20000; + if (input->context->athlete->zones("Bike")) { + int zoneRange = input->context->athlete->zones("Bike")->whichRange(QDate::currentDate()); + CP = zoneRange >= 0 ? input->context->athlete->zones("Bike")->getCP(zoneRange) : 250; + WPRIME = zoneRange >= 0 ? input->context->athlete->zones("Bike")->getWprime(zoneRange) : 20000; } // no data or no power data then forget it. @@ -923,8 +923,8 @@ class WPrimeExp : public RideMetric { void compute(RideItem *item, Specification spec, const QHash &) { int cp = item->getText("CP","0").toInt(); - if (!cp && item->context->athlete->zones(item->isRun) && item->zoneRange >=0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp && item->context->athlete->zones(item->sport) && item->zoneRange >=0) + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); double total = 0; double secs = 0; @@ -969,8 +969,8 @@ class WPrimeWatts : public RideMetric { void compute(RideItem *item, Specification spec, const QHash &) { int cp = item->getText("CP","0").toInt(); - if (!cp && item->context->athlete->zones(item->isRun) && item->zoneRange >=0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp && item->context->athlete->zones(item->sport) && item->zoneRange >=0) + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); double total = 0; double secs = 0; @@ -1022,8 +1022,8 @@ class CPExp : public RideMetric { } int cp = item->getText("CP","0").toInt(); - if (!cp && item->context->athlete->zones(item->isRun) && item->zoneRange >=0) - cp = item->context->athlete->zones(item->isRun)->getCP(item->zoneRange); + if (!cp && item->context->athlete->zones(item->sport) && item->zoneRange >=0) + cp = item->context->athlete->zones(item->sport)->getCP(item->zoneRange); double total = 0; double secs = 0; @@ -1069,7 +1069,7 @@ class WZoneTime : public RideMetric { void compute(RideItem *item, Specification, const QHash &) { - double WPRIME = item->zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getWprime(item->zoneRange) : 20000; + double WPRIME = item->zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getWprime(item->zoneRange) : 20000; // 4 zones QVector tiz(4); @@ -1208,8 +1208,8 @@ class WCPZoneTime : public RideMetric { void compute(RideItem *item, Specification, const QHash &) { double WPRIME = 20000; - if (item->context->athlete->zones(item->isRun) && item->zoneRange > 0) { - WPRIME = item->context->athlete->zones(item->isRun)->getWprime(item->zoneRange); + if (item->context->athlete->zones(item->sport) && item->zoneRange > 0) { + WPRIME = item->context->athlete->zones(item->sport)->getWprime(item->zoneRange); } // did we override CP in metadata / metrics ? @@ -1357,7 +1357,7 @@ class WZoneWork : public RideMetric { void compute(RideItem *item, Specification, const QHash &) { - double WPRIME = item->zoneRange >= 0 ? item->context->athlete->zones(item->isRun)->getWprime(item->zoneRange) : 20000; + double WPRIME = item->zoneRange >= 0 ? item->context->athlete->zones(item->sport)->getWprime(item->zoneRange) : 20000; // 4 zones QVector tiz(4); diff --git a/src/Metrics/Zones.cpp b/src/Metrics/Zones.cpp index 4cb4fac0c..610611611 100644 --- a/src/Metrics/Zones.cpp +++ b/src/Metrics/Zones.cpp @@ -51,10 +51,10 @@ void Zones::initializeZoneParameters() sizeof(initial_zone_default) / sizeof(initial_zone_default[0]); - if (run) { - fileName_ = "run-power.zones"; - } else { + if (sport_.isEmpty() || sport_ == "Bike") { fileName_ = "power.zones"; + } else { + fileName_ = sport_.toLower() + "-power.zones"; } scheme.zone_default.clear(); @@ -1094,5 +1094,5 @@ Zones::getFingerprint(QDate forDate) const QString Zones::useCPforFTPSetting() const { - return run ? GC_USE_CP_FOR_FTP_RUN : GC_USE_CP_FOR_FTP; + return GC_USE_CP_FOR_FTP + ((sport_.isEmpty() || sport_ == "Bike") ? "" : sport_.toLower()); } diff --git a/src/Metrics/Zones.h b/src/Metrics/Zones.h index a3ce010a8..7b51106fe 100644 --- a/src/Metrics/Zones.h +++ b/src/Metrics/Zones.h @@ -89,7 +89,7 @@ class Zones : public QObject private: // Sport - bool run; + QString sport_; // Scheme bool defaults_from_user; @@ -104,7 +104,7 @@ class Zones : public QObject public: - Zones(bool run=false) : run(run), defaults_from_user(false) { + Zones(QString sport="Bike") : sport_(sport), defaults_from_user(false) { initializeZoneParameters(); } @@ -123,7 +123,7 @@ class Zones : public QObject void initializeZoneParameters(); // Sport - bool isRun() { return run; } + QString sport() { return sport_; } // // Zone history - Ranges diff --git a/src/Metrics/aBikeScore.cpp b/src/Metrics/aBikeScore.cpp index d513b5a31..d16b4c822 100644 --- a/src/Metrics/aBikeScore.cpp +++ b/src/Metrics/aBikeScore.cpp @@ -172,12 +172,12 @@ class aRelativeIntensity : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { - if (item->context->athlete->zones(item->isRun) && item->zoneRange >= 0) { + if (item->context->athlete->zones(item->sport) && item->zoneRange >= 0) { assert(deps.contains("a_skiba_xpower")); aXPower *xp = dynamic_cast(deps.value("a_skiba_xpower")); assert(xp); int cp = item->getText("CP","0").toInt(); - reli = xp->value(true) / (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)); + reli = xp->value(true) / (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)); secs = xp->count(); } setValue(reli); @@ -210,7 +210,7 @@ class aBikeScore : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { - if (!item->context->athlete->zones(item->isRun) || item->zoneRange < 0) { + if (!item->context->athlete->zones(item->sport) || item->zoneRange < 0) { setValue(RideFile::NIL); setCount(0); return; @@ -224,7 +224,7 @@ class aBikeScore : public RideMetric { double normWork = xp->value(true) * xp->count(); double rawBikeScore = normWork * ri->value(true); int cp = item->getText("CP","0").toInt(); - double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)) * 3600; + double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)) * 3600; score = rawBikeScore / workInAnHourAtCP * 100.0; setValue(score); diff --git a/src/Metrics/aCoggan.cpp b/src/Metrics/aCoggan.cpp index ecdd10953..b320c6501 100644 --- a/src/Metrics/aCoggan.cpp +++ b/src/Metrics/aCoggan.cpp @@ -172,7 +172,7 @@ class aIntensityFactor : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { // no ride or no samples - if (item->zoneRange < 0 || item->context->athlete->zones(item->isRun) == NULL) { + if (item->zoneRange < 0 || item->context->athlete->zones(item->sport) == NULL) { setValue(RideFile::NIL); setCount(0); return; @@ -182,7 +182,7 @@ class aIntensityFactor : public RideMetric { aIsoPower *np = dynamic_cast(deps.value("a_coggan_np")); assert(np); int cp = item->getText("CP","0").toInt(); - rif = np->value(true) / (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)); + rif = np->value(true) / (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)); secs = np->count(); setValue(rif); @@ -218,7 +218,7 @@ class aBikeStress : public RideMetric { void compute(RideItem *item, Specification, const QHash &deps) { // no ride or no samples - if (item->zoneRange < 0 || item->context->athlete->zones(item->isRun) == NULL) { + if (item->zoneRange < 0 || item->context->athlete->zones(item->sport) == NULL) { setValue(RideFile::NIL); setCount(0); return; @@ -232,7 +232,7 @@ class aBikeStress : public RideMetric { double normWork = np->value(true) * np->count(); double rawTSS = normWork * rif->value(true); int cp = item->getText("CP","0").toInt(); - double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->isRun)->getCP(item->zoneRange)) * 3600; + double workInAnHourAtCP = (cp ? cp : item->context->athlete->zones(item->sport)->getCP(item->zoneRange)) * 3600; score = rawTSS / workInAnHourAtCP * 100.0; setValue(score); diff --git a/src/Python/SIP/Bindings.cpp b/src/Python/SIP/Bindings.cpp index a6c326841..09fe7fc2c 100644 --- a/src/Python/SIP/Bindings.cpp +++ b/src/Python/SIP/Bindings.cpp @@ -208,35 +208,35 @@ Bindings::athleteZones(PyObject* date, QString sport) const gcZoneConfig swim("bike"); // BIKE POWER - if (context->athlete->zones(false)) { + if (context->athlete->zones("Bike")) { // run through the bike zones - int range=context->athlete->zones(false)->whichRange(forDate); + int range=context->athlete->zones("Bike")->whichRange(forDate); if (range >= 0) { bike.date = forDate; - bike.cp = context->athlete->zones(false)->getCP(range); - bike.wprime = context->athlete->zones(false)->getWprime(range); - bike.pmax = context->athlete->zones(false)->getPmax(range); - bike.aetp = context->athlete->zones(false)->getAeT(range); - bike.ftp = context->athlete->zones(false)->getFTP(range); - bike.zoneslow = context->athlete->zones(false)->getZoneLows(range); + bike.cp = context->athlete->zones("Bike")->getCP(range); + bike.wprime = context->athlete->zones("Bike")->getWprime(range); + bike.pmax = context->athlete->zones("Bike")->getPmax(range); + bike.aetp = context->athlete->zones("Bike")->getAeT(range); + bike.ftp = context->athlete->zones("Bike")->getFTP(range); + bike.zoneslow = context->athlete->zones("Bike")->getZoneLows(range); } } // RUN POWER - if (context->athlete->zones(false)) { + if (context->athlete->zones("Run")) { // run through the bike zones - int range=context->athlete->zones(true)->whichRange(forDate); + int range=context->athlete->zones("Run")->whichRange(forDate); if (range >= 0) { run.date = forDate; - run.cp = context->athlete->zones(true)->getCP(range); - run.wprime = context->athlete->zones(true)->getWprime(range); - run.pmax = context->athlete->zones(true)->getPmax(range); - run.aetp = context->athlete->zones(true)->getAeT(range); - run.ftp = context->athlete->zones(true)->getFTP(range); - run.zoneslow = context->athlete->zones(true)->getZoneLows(range); + run.cp = context->athlete->zones("Run")->getCP(range); + run.wprime = context->athlete->zones("Run")->getWprime(range); + run.pmax = context->athlete->zones("Run")->getPmax(range); + run.aetp = context->athlete->zones("Run")->getAeT(range); + run.ftp = context->athlete->zones("Run")->getFTP(range); + run.zoneslow = context->athlete->zones("Run")->getZoneLows(range); } } @@ -299,41 +299,41 @@ Bindings::athleteZones(PyObject* date, QString sport) const } else { // BIKE POWER - if (context->athlete->zones(false)) { + if (context->athlete->zones("Bike")) { - for (int range=0; range < context->athlete->zones(false)->getRangeSize(); range++) { + for (int range=0; range < context->athlete->zones("Bike")->getRangeSize(); range++) { // run through the bike zones gcZoneConfig c("bike"); - c.date = context->athlete->zones(false)->getStartDate(range); - c.cp = context->athlete->zones(false)->getCP(range); - c.wprime = context->athlete->zones(false)->getWprime(range); - c.pmax = context->athlete->zones(false)->getPmax(range); - c.aetp = context->athlete->zones(false)->getAeT(range); - c.ftp = context->athlete->zones(false)->getFTP(range); - c.zoneslow = context->athlete->zones(false)->getZoneLows(range); + c.date = context->athlete->zones("Bike")->getStartDate(range); + c.cp = context->athlete->zones("Bike")->getCP(range); + c.wprime = context->athlete->zones("Bike")->getWprime(range); + c.pmax = context->athlete->zones("Bike")->getPmax(range); + c.aetp = context->athlete->zones("Bike")->getAeT(range); + c.ftp = context->athlete->zones("Bike")->getFTP(range); + c.zoneslow = context->athlete->zones("Bike")->getZoneLows(range); config << c; } } // RUN POWER - if (context->athlete->zones(false)) { + if (context->athlete->zones("Run")) { // run through the bike zones - for (int range=0; range < context->athlete->zones(true)->getRangeSize(); range++) { + for (int range=0; range < context->athlete->zones("Run")->getRangeSize(); range++) { // run through the bike zones gcZoneConfig c("run"); - c.date = context->athlete->zones(true)->getStartDate(range); - c.cp = context->athlete->zones(true)->getCP(range); - c.wprime = context->athlete->zones(true)->getWprime(range); - c.pmax = context->athlete->zones(true)->getPmax(range); - c.aetp = context->athlete->zones(true)->getAeT(range); - c.ftp = context->athlete->zones(true)->getFTP(range); - c.zoneslow = context->athlete->zones(true)->getZoneLows(range); + c.date = context->athlete->zones("Run")->getStartDate(range); + c.cp = context->athlete->zones("Run")->getCP(range); + c.wprime = context->athlete->zones("Run")->getWprime(range); + c.pmax = context->athlete->zones("Run")->getPmax(range); + c.aetp = context->athlete->zones("Run")->getAeT(range); + c.ftp = context->athlete->zones("Run")->getFTP(range); + c.zoneslow = context->athlete->zones("Run")->getZoneLows(range); config << c; } diff --git a/src/R/RTool.cpp b/src/R/RTool.cpp index e03eec3e6..a4bee1dcd 100644 --- a/src/R/RTool.cpp +++ b/src/R/RTool.cpp @@ -521,35 +521,35 @@ RTool::zones(SEXP pDate, SEXP pSport) gcZoneConfig swim("bike"); // BIKE POWER - if (rtool->context->athlete->zones(false)) { + if (rtool->context->athlete->zones("Bike")) { // run through the bike zones - int range=rtool->context->athlete->zones(false)->whichRange(forDate); + int range=rtool->context->athlete->zones("Bike")->whichRange(forDate); if (range >= 0) { bike.date = forDate; - bike.cp = rtool->context->athlete->zones(false)->getCP(range); - bike.wprime = rtool->context->athlete->zones(false)->getWprime(range); - bike.pmax = rtool->context->athlete->zones(false)->getPmax(range); - bike.aetp = rtool->context->athlete->zones(false)->getAeT(range); - bike.ftp = rtool->context->athlete->zones(false)->getFTP(range); - bike.zoneslow = rtool->context->athlete->zones(false)->getZoneLows(range); + bike.cp = rtool->context->athlete->zones("Bike")->getCP(range); + bike.wprime = rtool->context->athlete->zones("Bike")->getWprime(range); + bike.pmax = rtool->context->athlete->zones("Bike")->getPmax(range); + bike.aetp = rtool->context->athlete->zones("Bike")->getAeT(range); + bike.ftp = rtool->context->athlete->zones("Bike")->getFTP(range); + bike.zoneslow = rtool->context->athlete->zones("Bike")->getZoneLows(range); } } // RUN POWER - if (rtool->context->athlete->zones(false)) { + if (rtool->context->athlete->zones("Run")) { // run through the bike zones - int range=rtool->context->athlete->zones(true)->whichRange(forDate); + int range=rtool->context->athlete->zones("Run")->whichRange(forDate); if (range >= 0) { run.date = forDate; - run.cp = rtool->context->athlete->zones(true)->getCP(range); - run.wprime = rtool->context->athlete->zones(true)->getWprime(range); - run.pmax = rtool->context->athlete->zones(true)->getPmax(range); - run.aetp = rtool->context->athlete->zones(true)->getAeT(range); - run.ftp = rtool->context->athlete->zones(true)->getFTP(range); - run.zoneslow = rtool->context->athlete->zones(true)->getZoneLows(range); + run.cp = rtool->context->athlete->zones("Run")->getCP(range); + run.wprime = rtool->context->athlete->zones("Run")->getWprime(range); + run.pmax = rtool->context->athlete->zones("Run")->getPmax(range); + run.aetp = rtool->context->athlete->zones("Run")->getAeT(range); + run.ftp = rtool->context->athlete->zones("Run")->getFTP(range); + run.zoneslow = rtool->context->athlete->zones("Run")->getZoneLows(range); } } @@ -612,41 +612,41 @@ RTool::zones(SEXP pDate, SEXP pSport) } else { // BIKE POWER - if (rtool->context->athlete->zones(false)) { + if (rtool->context->athlete->zones("Bike")) { - for (int range=0; range < rtool->context->athlete->zones(false)->getRangeSize(); range++) { + for (int range=0; range < rtool->context->athlete->zones("Bike")->getRangeSize(); range++) { // run through the bike zones gcZoneConfig c("bike"); - c.date = rtool->context->athlete->zones(false)->getStartDate(range); - c.cp = rtool->context->athlete->zones(false)->getCP(range); - c.wprime = rtool->context->athlete->zones(false)->getWprime(range); - c.pmax = rtool->context->athlete->zones(false)->getPmax(range); - c.aetp = rtool->context->athlete->zones(false)->getAeT(range); - c.ftp = rtool->context->athlete->zones(false)->getFTP(range); - c.zoneslow = rtool->context->athlete->zones(false)->getZoneLows(range); + c.date = rtool->context->athlete->zones("Bike")->getStartDate(range); + c.cp = rtool->context->athlete->zones("Bike")->getCP(range); + c.wprime = rtool->context->athlete->zones("Bike")->getWprime(range); + c.pmax = rtool->context->athlete->zones("Bike")->getPmax(range); + c.aetp = rtool->context->athlete->zones("Bike")->getAeT(range); + c.ftp = rtool->context->athlete->zones("Bike")->getFTP(range); + c.zoneslow = rtool->context->athlete->zones("Bike")->getZoneLows(range); config << c; } } // RUN POWER - if (rtool->context->athlete->zones(false)) { + if (rtool->context->athlete->zones("Run")) { // run through the bike zones - for (int range=0; range < rtool->context->athlete->zones(true)->getRangeSize(); range++) { + for (int range=0; range < rtool->context->athlete->zones("Run")->getRangeSize(); range++) { // run through the bike zones gcZoneConfig c("run"); - c.date = rtool->context->athlete->zones(true)->getStartDate(range); - c.cp = rtool->context->athlete->zones(true)->getCP(range); - c.wprime = rtool->context->athlete->zones(true)->getWprime(range); - c.pmax = rtool->context->athlete->zones(true)->getPmax(range); - c.aetp = rtool->context->athlete->zones(true)->getAeT(range); - c.ftp = rtool->context->athlete->zones(true)->getFTP(range); - c.zoneslow = rtool->context->athlete->zones(true)->getZoneLows(range); + c.date = rtool->context->athlete->zones("Run")->getStartDate(range); + c.cp = rtool->context->athlete->zones("Run")->getCP(range); + c.wprime = rtool->context->athlete->zones("Run")->getWprime(range); + c.pmax = rtool->context->athlete->zones("Run")->getPmax(range); + c.aetp = rtool->context->athlete->zones("Run")->getAeT(range); + c.ftp = rtool->context->athlete->zones("Run")->getFTP(range); + c.zoneslow = rtool->context->athlete->zones("Run")->getZoneLows(range); config << c; }