From 9c14f78c5479718ba84242e30a27c4293f98617a Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Mon, 15 Jun 2015 16:05:14 -0300 Subject: [PATCH 1/2] Fixed wrong caching when CPPlot is filtered by activity type --- src/CPPlot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CPPlot.cpp b/src/CPPlot.cpp index 42574b2b6..26a319f18 100644 --- a/src/CPPlot.cpp +++ b/src/CPPlot.cpp @@ -1533,7 +1533,7 @@ CPPlot::setRide(RideItem *rideItem) // first make sure the bests cache is up to date as we may need it // if plotting in percentage mode, so get data and plot it now // delete if sport changed - if (!rangemode && (rideItem->isRun != isRun || rideItem->isSwim != isSwim)) { + if (!rangemode) { setSport(rideItem->isRun, rideItem->isSwim); delete bestsCache; bestsCache = NULL; From a6d7e565b3e89f23175dc2e78a3df00b1a8b7c07 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Wed, 17 Jun 2015 11:28:58 -0300 Subject: [PATCH 2/2] Enable Efficiency Factor and Aerobic Decoupling metrics for Running Fixes #1407 --- src/AerobicDecoupling.cpp | 14 ++++++++++++-- src/Coggan.cpp | 21 ++++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/AerobicDecoupling.cpp b/src/AerobicDecoupling.cpp index 5833d4e60..fbed0e121 100644 --- a/src/AerobicDecoupling.cpp +++ b/src/AerobicDecoupling.cpp @@ -62,6 +62,7 @@ class AerobicDecoupling : public RideMetric { const QHash &, const Context *) { double firstHalfPower = 0.0, secondHalfPower = 0.0; + double firstHalfSpeed = 0.0, secondHalfSpeed = 0.0; double firstHalfHR = 0.0, secondHalfHR = 0.0; int halfway = ride->dataPoints().size() / 2; int count = 0; @@ -72,6 +73,7 @@ class AerobicDecoupling : public RideMetric { if (count++ < halfway) { if (point->hr > 0) { firstHalfPower += point->watts; + firstHalfSpeed += point->kph; firstHalfHR += point->hr; ++firstHalfCount; } @@ -79,14 +81,18 @@ class AerobicDecoupling : public RideMetric { else { if (point->hr > 0) { secondHalfPower += point->watts; + secondHalfSpeed += point->kph; secondHalfHR += point->hr; ++secondHalfCount; } } } - if ((firstHalfPower > 0) && (secondHalfPower > 0)) { + if (((firstHalfPower > 0) && (secondHalfPower > 0)) || + (ride->isRun() && (firstHalfSpeed > 0) && (secondHalfSpeed > 0))) { firstHalfPower /= firstHalfCount; + firstHalfSpeed /= firstHalfCount; secondHalfPower /= secondHalfCount; + secondHalfSpeed /= secondHalfCount; firstHalfHR /= firstHalfCount; secondHalfHR /= secondHalfCount; @@ -97,12 +103,16 @@ class AerobicDecoupling : public RideMetric { // should be : double firstHalfRatio = firstHalfPower / firstHalfHR; double secondHalfRatio = secondHalfPower / secondHalfHR; + if (ride->isRun()) { + firstHalfRatio = firstHalfSpeed / firstHalfHR; + secondHalfRatio = secondHalfSpeed / secondHalfHR; + } percent = 100.0 * (firstHalfRatio - secondHalfRatio) / firstHalfRatio; } setValue(percent); } - bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("H") && ride->present.contains("P"); } + bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("H") && (ride->present.contains("P") || (ride->isRun && ride->present.contains("S"))); } RideMetric *clone() const { return new AerobicDecoupling(*this); } }; diff --git a/src/Coggan.cpp b/src/Coggan.cpp index ab5747691..b83d82a9b 100644 --- a/src/Coggan.cpp +++ b/src/Coggan.cpp @@ -19,6 +19,7 @@ #include "RideMetric.h" #include "RideItem.h" #include "Zones.h" +#include "Units.h" #include #include @@ -252,6 +253,7 @@ class TSSPerHour : public RideMetric { RideMetric *clone() const { return new TSSPerHour(*this); } }; +/* Running update based on: http://www.joefrielsblog.com/2014/11/the-efficiency-factor-in-running.html */ class EfficiencyFactor : public RideMetric { Q_DECLARE_TR_FUNCTIONS(EfficiencyFactor) double ef; @@ -271,21 +273,29 @@ class EfficiencyFactor : public RideMetric { setPrecision(3); } - void compute(const RideFile *, const Zones *, int, + void compute(const RideFile *ride, const Zones *, int, const HrZones *, int, const QHash &deps, const Context *) { assert(deps.contains("coggan_np")); + assert(deps.contains("xPace")); assert(deps.contains("average_hr")); - NP *np = dynamic_cast(deps.value("coggan_np")); - assert(np); + if (ride->isRun()) { + RideMetric *xPace = dynamic_cast(deps.value("xPace")); + assert(xPace); + ef = xPace->value(true) > 0 ? ((1000.0/METERS_PER_YARD) / xPace->value(true)) : 0.0; + } else { + NP *np = dynamic_cast(deps.value("coggan_np")); + assert(np); + ef = np->value(true); + } RideMetric *ah = dynamic_cast(deps.value("average_hr")); assert(ah); - ef = np->value(true) / ah->value(true); + ef = ah->value(true) > 0 ? ef / ah->value(true) : 0.0; setValue(ef); } - bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); } + bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("H") && (ride->present.contains("P") || (ride->isRun && ride->present.contains("S"))); } RideMetric *clone() const { return new EfficiencyFactor(*this); } }; @@ -302,6 +312,7 @@ static bool addAllCoggan() { RideMetricFactory::instance().addMetric(VI(), &deps); deps.clear(); deps.append("coggan_np"); + deps.append("xPace"); deps.append("average_hr"); RideMetricFactory::instance().addMetric(EfficiencyFactor(), &deps); deps.clear();