/* * Copyright (c) 2010 Mark Liversedge (liversedge@gmail.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "RideMetric.h" #include "BestIntervalDialog.h" #include "RideItem.h" #include "Zones.h" #include "Settings.h" #include #include class AverageWPK : public RideMetric { Q_DECLARE_TR_FUNCTIONS(AverageWPK) public: AverageWPK() { setSymbol("average_wpk"); setInternalName("Watts Per Kilogram"); } void initialize () { setName(tr("Watts Per Kilogram")); setType(RideMetric::Average); setMetricUnits(tr("w/kg")); setImperialUnits(tr("w/kg")); setPrecision(2); } void compute(const RideFile *ride, const Zones *, int, const HrZones *, int, const QHash &deps, const Context *) { // unconst naughty boy RideFile *uride = const_cast(ride); // get thos dependencies double secs = deps.value("workout_time")->value(true); double weight = uride->getWeight(); double ap = deps.value("average_power")->value(true); // calculate watts per kilo setCount(secs); setValue((secs && ap && weight) ? ap/weight : 0); } RideMetric *clone() const { return new AverageWPK(*this); } }; class PeakWPK : public RideMetric { Q_DECLARE_TR_FUNCTIONS(PeakWPK) double wpk; double secs; double weight; public: PeakWPK() : wpk(0.0), secs(0.0), weight(0.0) { setType(RideMetric::Peak); setMetricUnits(tr("w/kg")); setImperialUnits(tr("w/kg")); setPrecision(2); } void setSecs(double secs) { this->secs=secs; } void compute(const RideFile *ride, const Zones *, int, const HrZones *, int, const QHash &, const Context *) { // unconst naughty boy RideFile *uride = const_cast(ride); if (!ride->dataPoints().isEmpty()) { weight = uride->getWeight(); //weight = ride->getTag("Weight", appsettings->cvalue(GC_WEIGHT, "75.0").toString()).toDouble(); // default to 75kg QList results; BestIntervalDialog::findBests(ride, secs, 1, results); if (results.count() > 0 && results.first().avg < 3000) wpk = results.first().avg / weight; else wpk = 0.0; } else { wpk = 0.0; } setValue(wpk); } RideMetric *clone() const { return new PeakWPK(*this); } }; class CPWPK : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(CPWPK) public: CPWPK() { setSecs(3600); setSymbol("60m_peak_wpk"); setInternalName("60 min Peak WPK"); } void initialize () { setName(tr("60 min Peak WPK")); } RideMetric *clone() const { return new CPWPK(*this); } }; class PeakWPK1s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK1s) public: PeakWPK1s() { setSecs(1); setSymbol("1s_peak_wpk"); setInternalName("1 sec Peak WPK"); } void initialize () { setName(tr("1 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK1s(*this); } }; class PeakWPK5s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK5s) public: PeakWPK5s() { setSecs(5); setSymbol("5s_peak_wpk"); setInternalName("5 sec Peak WPK"); } void initialize () { setName(tr("5 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK5s(*this); } }; class PeakWPK10s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK10s) public: PeakWPK10s() { setSecs(10); setSymbol("10s_peak_wpk"); setInternalName("10 sec Peak WPK"); } void initialize () { setName(tr("10 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK10s(*this); } }; class PeakWPK15s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK15s) public: PeakWPK15s() { setSecs(15); setSymbol("15s_peak_wpk"); setInternalName("15 sec Peak WPK"); } void initialize () { setName(tr("15 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK15s(*this); } }; class PeakWPK20s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK20s) public: PeakWPK20s() { setSecs(20); setSymbol("20s_peak_wpk"); setInternalName("20 sec Peak WPK"); } void initialize () { setName(tr("20 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK20s(*this); } }; class PeakWPK30s : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK30s) public: PeakWPK30s() { setSecs(30); setSymbol("30s_peak_wpk"); setInternalName("30 sec Peak WPK"); } void initialize () { setName(tr("30 sec Peak WPK")); } RideMetric *clone() const { return new PeakWPK30s(*this); } }; class PeakWPK1m : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK1m) public: PeakWPK1m() { setSecs(60); setSymbol("1m_peak_wpk"); setInternalName("1 min Peak WPK"); } void initialize () { setName(tr("1 min Peak WPK")); } RideMetric *clone() const { return new PeakWPK1m(*this); } }; class PeakWPK5m : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK5m) public: PeakWPK5m() { setSecs(300); setSymbol("5m_peak_wpk"); setInternalName("5 min Peak WPK"); } void initialize () { setName(tr("5 min Peak WPK")); } RideMetric *clone() const { return new PeakWPK5m(*this); } }; class PeakWPK10m : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK10m) public: PeakWPK10m() { setSecs(600); setSymbol("10m_peak_wpk"); setInternalName("10 min Peak WPK"); } void initialize () { setName(tr("10 min Peak WPK")); } RideMetric *clone() const { return new PeakWPK10m(*this); } }; class PeakWPK20m : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK20m) public: PeakWPK20m() { setSecs(1200); setSymbol("20m_peak_wpk"); setInternalName("20 min Peak WPK"); } void initialize () { setName(tr("20 min Peak WPK")); } RideMetric *clone() const { return new PeakWPK20m(*this); } }; class PeakWPK30m : public PeakWPK { Q_DECLARE_TR_FUNCTIONS(PeakWPK30m) public: PeakWPK30m() { setSecs(1800); setSymbol("30m_peak_wpk"); setInternalName("30 min Peak WPK"); } void initialize () { setName(tr("30 min Peak WPK")); } RideMetric *clone() const { return new PeakWPK30m(*this); } }; class Vo2max : public RideMetric { Q_DECLARE_TR_FUNCTIONS(Vo2max) public: Vo2max() { setSymbol("vo2max"); setInternalName("Estimated VO2MAX"); } void initialize () { setName(tr("Estimated VO2MAX")); setType(RideMetric::Peak); setMetricUnits(tr("ml/min/kg")); setImperialUnits(tr("ml/min/kg")); } void compute(const RideFile *, const Zones *, int, const HrZones *, int, const QHash &deps, const Context *) { PeakWPK5m *wpk5m = dynamic_cast(deps.value("5m_peak_wpk")); // Using New ACSM formula also outlined here: // http://blue.utb.edu/mbailey/pdf/MetCalnew.pdf // 10.8 * Watts / KG + 7 (3.5 per leg) setValue(0); setCount(0); if (wpk5m->value(false) > 0) { setValue(10.8 * wpk5m->value(false) + 7); setCount(1); } } bool isRelevantForRide(const RideItem *ride) const {return ride->present.contains("P"); } RideMetric *clone() const { return new Vo2max(*this); } }; class EtimatedAverageWPK_DrF : public RideMetric { Q_DECLARE_TR_FUNCTIONS(EtimatedAverageWPK_DrF) public: EtimatedAverageWPK_DrF() { setSymbol("estimated_average_wpk_drf"); setInternalName("estimated Watts Per Kilogram (DrF.)"); } void initialize () { setName(tr("estimated Watts Per Kilogram (DrF.)")); setType(RideMetric::Average); setMetricUnits(tr("w/kg")); setImperialUnits(tr("w/kg")); setPrecision(2); } void compute(const RideFile *ride, const Zones *, int, const HrZones *, int, const QHash &deps, const Context *) { // unconst naughty boy RideFile *uride = const_cast(ride); // get thos dependencies double vam = deps.value("vam")->value(true); double gradient = deps.value("gradient")->value(true); double secs = deps.value("workout_time")->value(true); // Calculated power output (W/kg) = [VAM (m/hour)] / [((2 + (% grade/10)) x 100)] setValue( gradient>=7 ? vam / 100.0 / (2 + gradient/10.0 ) : 0 ); setCount(secs); } bool isRelevantForRide(const RideItem *ride) const {return ride->present.contains("P"); } RideMetric *clone() const { return new EtimatedAverageWPK_DrF(*this); } }; static bool addAllWPK() { RideMetricFactory::instance().addMetric(PeakWPK1s()); RideMetricFactory::instance().addMetric(PeakWPK5s()); RideMetricFactory::instance().addMetric(PeakWPK10s()); RideMetricFactory::instance().addMetric(PeakWPK15s()); RideMetricFactory::instance().addMetric(PeakWPK20s()); RideMetricFactory::instance().addMetric(PeakWPK30s()); RideMetricFactory::instance().addMetric(PeakWPK1m()); RideMetricFactory::instance().addMetric(PeakWPK5m()); RideMetricFactory::instance().addMetric(PeakWPK10m()); RideMetricFactory::instance().addMetric(PeakWPK20m()); RideMetricFactory::instance().addMetric(PeakWPK30m()); RideMetricFactory::instance().addMetric(CPWPK()); QVector deps; deps.append("5m_peak_wpk"); RideMetricFactory::instance().addMetric(Vo2max(), &deps); deps.clear(); deps.append("average_power"); deps.append("workout_time"); RideMetricFactory::instance().addMetric(AverageWPK(), &deps); // Added for testing purpose // Work pretty well but // is it really a metric ? /*deps.clear(); deps.append("vam"); deps.append("gradient"); deps.append("workout_time"); RideMetricFactory::instance().addMetric(EtimatedAverageWPK_DrF(), &deps);*/ return true; } static bool allWPKAdded = addAllWPK();