Compare commits

...

7 Commits

Author SHA1 Message Date
Alejandro Martinez
b204e85fe5 Enable WCPZoneTime when Power Data is present
For consistency sake
2015-11-03 12:37:41 -03:00
Mark Liversedge
5f073f781d Merge pull request #1620 from Joern-R/ini-old
Fix SEGV when using "Library/GoldenCheetah" athlete directory (in 3.3… only
2015-11-03 15:36:18 +00:00
Mark Liversedge
4436ca5a18 CI Deprecate QT4 and remove KML from QT5
.. should get a working build based on QT5
2015-11-03 15:19:18 +00:00
Joern
98858da51c Fix SEGV when using "Library/GoldenCheetah" athlete directory (in 3.3 only)
... problem relates to introduction of new .INI files
... old /gc ini file approach is still in place - now again working
2015-11-03 16:13:54 +01:00
Mark Liversedge
ea2a66e399 Add W'bal Zones - Time above CP
.. to see how much time is spent above CP
   whilst in different fatigued states.
2015-11-03 14:42:36 +00:00
Mark Liversedge
22e3ee1ca6 Merge pull request #1619 from amtriathlon/Stryd
Basic Stryd (Power Meter for Running) support
2015-11-03 14:41:18 +00:00
Alejandro Martinez
1a57e45fb6 Basic Stryd (Power Meter for Running) support
Enables power metrics for non cycling activities when power data is present.
2015-11-03 11:29:53 -03:00
11 changed files with 254 additions and 63 deletions

View File

@@ -7,7 +7,8 @@ compiler:
- gcc
env:
matrix:
- BRANCH=master QT=qt4 QT_PATH=qt
## Deprecate QT4 Support
## - BRANCH=master QT=qt4 QT_PATH=qt
- BRANCH=master QT=qt5 QT_PATH=qt5
global:
- secure: iqYW7f3//ZkMVzeCEarYn0S0DqKjFU9juBh0KF6WTlUsKX902Jtsk7dFoJlNDYBf63HLgV+wW2Hc6MxI9sGiUkom0gY9/To/aeGIJFGEX2sLm/e0Ok3qN521FA0Q/OiCFsD0RC6J+yrHxzI+rf8Z1rujceUsz2KgsrfAjYYv+BY=
@@ -24,7 +25,8 @@ before_install:
- brew install libusb libusb-compat
- brew install srmio
- brew install libsamplerate
- brew install --HEAD travis/libkml.rb
## Disable KML for now
##- brew install --HEAD travis/libkml.rb
- sudo chmod -R +w /usr/local
- curl -O http://www.ftdichip.com/Drivers/D2XX/MacOSX/D2XX1.2.2.dmg
- git clone --depth 1 https://github.com/sintegrial/qwtplot3d.git qwtplot3d
@@ -63,8 +65,9 @@ before_script:
- sed -i "" "s|#\(KQOAUTH_LIBS =.*\)|\1 -F\$\$[QT_INSTALL_LIBS] -framework kqoauth|"
src/gcconfig.pri
- sed -i "" "s|#\(QWT3D_INSTALL =.*\)|\1 ../qwtplot3d|" src/gcconfig.pri
- sed -i "" "s|#\(KML_INSTALL =\).*|\1 /usr/local|" src/gcconfig.pri
- sed -i "" "s|#\(KML_LIBS =.*\)|\1 -L/usr/local/lib -lkmlxsd -lkmlregionator -lkmldom
## Disable KML for now
##- sed -i "" "s|#\(KML_INSTALL =\).*|\1 /usr/local|" src/gcconfig.pri
##- sed -i "" "s|#\(KML_LIBS =.*\)|\1 -L/usr/local/lib -lkmlxsd -lkmlregionator -lkmldom
-lkmlconvenience -lkmlengine -lkmlbase|" src/gcconfig.pri
- sed -i "" "s|#\(ICAL_INSTALL =.*\)|\1 /usr/local|" src/gcconfig.pri
- sed -i "" "s|#\(ICAL_LIBS =.*\)|\1 -L/usr/local/lib -lical|" src/gcconfig.pri

View File

@@ -719,7 +719,7 @@ class TotalWork : public RideMetric {
}
setValue(joules/1000);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new TotalWork(*this); }
};
@@ -952,7 +952,7 @@ struct AvgPower : public RideMetric {
setValue(count > 0 ? total / count : 0);
setCount(count);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new AvgPower(*this); }
};
@@ -1078,7 +1078,7 @@ struct AAvgPower : public RideMetric {
setValue(count > 0 ? total / count : 0);
setCount(count);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new AAvgPower(*this); }
};
@@ -1119,7 +1119,7 @@ struct NonZeroPower : public RideMetric {
setValue(count > 0 ? total / count : 0);
setCount(count);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new NonZeroPower(*this); }
};
@@ -1282,7 +1282,7 @@ class HrPw : public RideMetric {
setValue(0);
}
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new HrPw(*this); }
};
@@ -1325,7 +1325,7 @@ class Workbeat : public RideMetric {
setValue((work->value() * hb->value()) / 100000.00f);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new Workbeat(*this); }
};
@@ -1372,7 +1372,7 @@ class WattsRPE : public RideMetric {
}
setValue(ratio);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WattsRPE(*this); }
};
@@ -1419,7 +1419,7 @@ class APPercent : public RideMetric {
}
setValue(percent);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new APPercent(*this); }
};
@@ -1466,7 +1466,7 @@ class HrNp : public RideMetric {
setValue(0);
}
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new HrNp(*this); }
};
@@ -1610,7 +1610,7 @@ class MaxPower : public RideMetric {
}
setValue(max);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MaxPower(*this); }
};
@@ -2117,7 +2117,7 @@ class EOA : public RideMetric {
AvgPower *ap = dynamic_cast<AvgPower*>(deps.value("average_power"));
setValue(((aap->value(true)-ap->value(true))/aap->value(true)) * 100.00f);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new EOA(*this); }
};
@@ -2220,7 +2220,7 @@ class MeanPowerVariance : public RideMetric {
topRank = outliers.getYForRank(0);
}
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MeanPowerVariance(*this); }
};
@@ -2261,7 +2261,7 @@ class MaxPowerVariance : public RideMetric {
else
setValue(mean->topRank);
}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MaxPowerVariance(*this); }
};

View File

@@ -97,7 +97,7 @@ class XPower : public RideMetric {
setValue(xpower);
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new XPower(*this); }
};
@@ -136,7 +136,7 @@ class VariabilityIndex : public RideMetric {
setValue(vi);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new VariabilityIndex(*this); }
};
@@ -187,7 +187,7 @@ class RelativeIntensity : public RideMetric {
}
// end added djconnel
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new RelativeIntensity(*this); }
};
@@ -230,7 +230,7 @@ class CriticalPower : public RideMetric {
setValue(other.value(true) > value(true) ? other.value(true) : value(true));
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new CriticalPower(*this); }
};
@@ -277,7 +277,7 @@ class aTISS : public RideMetric {
setValue(aTISS);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aTISS(*this); }
};
@@ -325,7 +325,7 @@ class anTISS : public RideMetric {
setValue(anTISS);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new anTISS(*this); }
};
@@ -365,7 +365,7 @@ class dTISS : public RideMetric {
else setValue((atscore/(atscore+antscore)) * 100.00f);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new dTISS(*this); }
};
class BikeScore : public RideMetric {
@@ -408,7 +408,7 @@ class BikeScore : public RideMetric {
setValue(score);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new BikeScore(*this); }
};
@@ -445,7 +445,7 @@ class ResponseIndex : public RideMetric {
setValue(ri);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new ResponseIndex(*this); }
};

View File

@@ -92,7 +92,7 @@ class NP : public RideMetric {
setValue(np);
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new NP(*this); }
};
@@ -130,7 +130,7 @@ class VI : public RideMetric {
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new VI(*this); }
};
@@ -180,7 +180,7 @@ class IntensityFactor : public RideMetric {
}
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new IntensityFactor(*this); }
};
@@ -231,7 +231,7 @@ class TSS : public RideMetric {
setValue(score);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new TSS(*this); }
};
@@ -276,7 +276,7 @@ class TSSPerHour : public RideMetric {
setCount(hours);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new TSSPerHour(*this); }
};

View File

@@ -123,8 +123,9 @@
// 117 29 Aug 2015 Mark Liversedge Min non-zero HR
// 118 16 Sep 2015 Damien Grauser Use FTP for TSS and IF
// 119 20 Oct 2015 Ale Martinez Added VDOT and TPace for Running
// 120 3 Nov 2015 Mark Liversedge Added Above CP time in W'bal zones
int DBSchemaVersion = 119;
int DBSchemaVersion = 120;
RideMetricFactory *RideMetricFactory::_instance;
QVector<QString> RideMetricFactory::noDeps;

View File

@@ -537,6 +537,12 @@ RideSummaryWindow::htmlSummary()
<< "wtime_in_zone_L3"
<< "wtime_in_zone_L4";
static const QStringList timeInZonesCPWBAL = QStringList()
<< "wcptime_in_zone_L1"
<< "wcptime_in_zone_L2"
<< "wcptime_in_zone_L3"
<< "wcptime_in_zone_L4";
// Use pre-computed and saved metric values if the ride has not
// been edited. Otherwise we need to re-compute every time.
// this is only for ride summary, when showing for a date range
@@ -921,14 +927,21 @@ RideSummaryWindow::htmlSummary()
// W'bal Zones
int WPRIME = context->athlete->zones()->getWprime(range);
QVector<double> wtime_in_zone(4);
QVector<double> wcptime_in_zone(4);
for (int i = 0; i < timeInZonesWBAL.count(); ++i) {
// if using metrics or data
if (ridesummary) wtime_in_zone[i] = rideItem->getForSymbol(timeInZonesWBAL[i]);
else wtime_in_zone[i] = context->athlete->rideCache->getAggregate(timeInZonesWBAL[i], specification, useMetricUnits, true).toDouble();
if (ridesummary) {
wtime_in_zone[i] = rideItem->getForSymbol(timeInZonesWBAL[i]);
wcptime_in_zone[i] = rideItem->getForSymbol(timeInZonesCPWBAL[i]);
} else {
wtime_in_zone[i] = context->athlete->rideCache->getAggregate(timeInZonesWBAL[i], specification, useMetricUnits, true).toDouble();
wcptime_in_zone[i] = context->athlete->rideCache->getAggregate(timeInZonesCPWBAL[i], specification, useMetricUnits, true).toDouble();
}
}
summary += tr("<h3>W'bal Zones</h3>");
summary += WPrime::summarize(WPRIME, wtime_in_zone, altColor);
summary += WPrime::summarize(WPRIME, wtime_in_zone, wcptime_in_zone, altColor);
}
}
@@ -1590,6 +1603,12 @@ RideSummaryWindow::htmlCompareSummary() const
<< "wtime_in_zone_L3"
<< "wtime_in_zone_L4";
static const QStringList timeInZonesCPWBAL = QStringList()
<< "wcptime_in_zone_L1"
<< "wcptime_in_zone_L2"
<< "wcptime_in_zone_L3"
<< "wcptime_in_zone_L4";
if (ridesummary) {
//
@@ -2115,6 +2134,15 @@ RideSummaryWindow::htmlCompareSummary() const
int idx=0;
for (int i=0; i<WPrime::zoneCount(); i++) {
// above cp W'bal time in zone
int cptimeZone = dr.context->athlete->rideCache->getAggregate(timeInZonesCPWBAL[idx], dr.specification,
context->athlete->useMetricUnits, true).toDouble();
int cpdt = cptimeZone - context->compareDateRanges[0].context->athlete->rideCache->getAggregate(timeInZonesCPWBAL[idx],
context->compareDateRanges[0].specification,
context->athlete->useMetricUnits, true).toDouble();
// all W'bal time in zone
int timeZone = dr.context->athlete->rideCache->getAggregate(timeInZonesWBAL[idx], dr.specification,
context->athlete->useMetricUnits, true).toDouble();

View File

@@ -310,6 +310,8 @@ GSettings::contains(const QString & key) const {
void
GSettings::migrateQSettingsSystem() {
if (!newFormat) return;
// do the migration for the System Settings - if not yet done
// - System is only migrated once per PC (since it only exists once
// on MAC GC_CHROME is already set previously - so migrate anyway

View File

@@ -188,14 +188,14 @@ WPrime::setRide(RideFile *input)
// and will also contain non-zero values
double totalBelowCP=0;
double countBelowCP=0;
QVector<int> inputArray(last+1);
powerValues.resize(last+1);
EXP = 0;
for (int i=0; i<last; i++) {
int value = smoothed.value(i);
if (value < 0) value = 0; // don't go negative now
inputArray[i] = value > CP ? value-CP : 0;
powerValues[i] = value > CP ? value-CP : 0;
if (value < CP) {
totalBelowCP += value;
@@ -224,7 +224,7 @@ WPrime::setRide(RideFile *input)
QVector<double> myvalues(last+1);
WPrimeIntegrator a(inputArray, 0, last, TAU);
WPrimeIntegrator a(powerValues, 0, last, TAU);
a.start();
a.wait();
@@ -400,7 +400,7 @@ WPrime::setErg(ErgFile *input)
// and will also contain non-zero values
double totalBelowCP=0;
double countBelowCP=0;
QVector<int> inputArray(last+1);
QVector<int> powerValues(last+1);
EXP = 0;
for (int i=0; i<last; i++) {
@@ -408,7 +408,7 @@ WPrime::setErg(ErgFile *input)
int lap;
int value = input->wattsAt(i*1000, lap);
inputArray[i] = value > CP ? value-CP : 0;
powerValues[i] = value > CP ? value-CP : 0;
if (value < CP) {
totalBelowCP += value;
@@ -424,7 +424,7 @@ WPrime::setErg(ErgFile *input)
QVector<double> myvalues(last+1);
WPrimeIntegrator a(inputArray, 0, last, TAU);
WPrimeIntegrator a(powerValues, 0, last, TAU);
a.start();
a.wait();
@@ -553,7 +553,7 @@ WPrimeIntegrator::run()
// HTML zone summary
//
QString
WPrime::summarize(int WPRIME, QVector<double> wtiz, QColor color)
WPrime::summarize(int WPRIME, QVector<double> wtiz, QVector<double> wcptiz, QColor color)
{
// if wtiz is not 4 big return empty
if (wtiz.count() != 4) return "";
@@ -577,6 +577,8 @@ WPrime::summarize(int WPRIME, QVector<double> wtiz, QColor color)
summary += tr("<td align=\"center\">Low (J)</td>");
summary += tr("<td align=\"center\">Time</td>");
summary += tr("<td align=\"center\">%</td>");
summary += tr("<td align=\"center\">Above CP Time</td>");
summary += tr("<td align=\"center\">%</td>");
summary += "</tr>";
// calc totals to use for percentages
@@ -602,6 +604,8 @@ WPrime::summarize(int WPRIME, QVector<double> wtiz, QColor color)
summary += QString("<td align=\"center\">%1</td>").arg(WPRIME - (WPRIME / 100.0f * wbal_zones[zone].hi), 0, 'f', 0);
summary += QString("<td align=\"center\">%1</td>").arg(time_to_string((unsigned) round(wtiz[zone])));
summary += QString("<td align=\"center\">%1</td>").arg((double)wtiz[zone]/duration * 100, 0, 'f', 0);
summary += QString("<td align=\"center\">%1</td>").arg(time_to_string((unsigned) round(wcptiz[zone])));
summary += QString("<td align=\"center\">%1</td>").arg((double)wcptiz[zone]/wtiz[zone] * 100, 0, 'f', 0);
summary += "</tr>";
}
summary += "</table>";
@@ -638,7 +642,7 @@ class MinWPrime : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MinWPrime(*this); }
};
@@ -668,7 +672,7 @@ class MaxWPrime : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MaxWPrime(*this); }
};
@@ -698,7 +702,7 @@ class MaxMatch : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new MaxMatch(*this); }
};
@@ -730,7 +734,7 @@ class Matches : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new Matches(*this); }
};
@@ -760,7 +764,7 @@ class WPrimeTau : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WPrimeTau(*this); }
};
@@ -802,7 +806,7 @@ class WPrimeExp : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WPrimeExp(*this); }
};
@@ -844,7 +848,7 @@ class WPrimeWatts : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WPrimeWatts(*this); }
};
@@ -889,7 +893,7 @@ class CPExp : public RideMetric {
}
bool canAggregate() { return false; }
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new CPExp(*this); }
};
@@ -946,7 +950,7 @@ class WZoneTime : public RideMetric {
bool canAggregate() { return false; }
void aggregateWith(const RideMetric &) {}
bool isRelevantForRide(const RideItem *ride) const { return !ride->isSwim && !ride->isRun; }
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WZoneTime(*this); }
};
@@ -1023,6 +1027,152 @@ class WZoneTime4 : public WZoneTime {
RideMetric *clone() const { return new WZoneTime4(*this); }
};
// time in zone
class WCPZoneTime : public RideMetric {
Q_DECLARE_TR_FUNCTIONS(WCPZoneTime)
int level;
public:
WCPZoneTime() : level(0)
{
setType(RideMetric::Total);
setMetricUnits(tr("seconds"));
setImperialUnits(tr("seconds"));
setPrecision(0);
setConversion(1.0);
}
bool isTime() const { return true; }
void setLevel(int level) { this->level=level-1; } // zones start from zero not 1
void compute(const RideFile *ride, const Zones *zones, int zoneRange,
const HrZones *, int,
const QHash<QString,RideMetric*> &,
const Context *)
{
double CP = 250; // default
double WPRIME = 20000;
if (zones && zoneRange > 0) {
CP = zones->getCP(zoneRange);
WPRIME = zones->getWprime(zoneRange);
}
// did we override CP in metadata / metrics ?
int oCP = ride->getTag("CP","0").toInt();
if (oCP) CP=oCP;
int oW = ride->getTag("W'","0").toInt();
if (oW) WPRIME=oW;
// 4 zones
QVector<double> tiz(4);
tiz.fill(0.0f);
RideFile *cride = const_cast<RideFile*>(ride);
int i=0;
if (cride->wprimeData() && cride->wprimeData()->ydata().count()) {
// get the power values
foreach(int value, cride->wprimeData()->ydata()) {
// skip if below CP
if (cride->wprimeData()->powerValues[i++] <= 0) continue;
// percent is PERCENT OF W' USED
double percent = 100.0f - ((double (value) / WPRIME) * 100.0f);
if (percent < 0.0f) percent = 0.0f;
if (percent > 100.0f) percent = 100.0f;
// and zones in 1s increments
if (percent <= 25.0f) tiz[0]++;
else if (percent <= 50.0f) tiz[1]++;
else if (percent <= 75.0f) tiz[2]++;
else tiz[3]++;
}
}
setValue(tiz[level]);
}
bool canAggregate() { return false; }
void aggregateWith(const RideMetric &) {}
bool isRelevantForRide(const RideItem *ride) const { return ride->present.contains("P") || (!ride->isSwim && !ride->isRun); }
RideMetric *clone() const { return new WCPZoneTime(*this); }
};
class WCPZoneTime1 : public WCPZoneTime {
Q_DECLARE_TR_FUNCTIONS(WCPZoneTime1)
public:
WCPZoneTime1()
{
setLevel(1);
setSymbol("wcptime_in_zone_L1");
setInternalName("W1 Above CP W'bal Low Fatigue");
}
void initialize ()
{
setName(tr("W1 Above CP W'bal Low Fatigue"));
setMetricUnits(tr("seconds"));
setImperialUnits(tr("seconds"));
}
RideMetric *clone() const { return new WCPZoneTime1(*this); }
};
class WCPZoneTime2 : public WCPZoneTime {
Q_DECLARE_TR_FUNCTIONS(WCPZoneTime2)
public:
WCPZoneTime2()
{
setLevel(2);
setSymbol("wcptime_in_zone_L2");
setInternalName("W2 Above CP W'bal Moderate Fatigue");
}
void initialize ()
{
setName(tr("W2 Above CP W'bal Moderate Fatigue"));
setMetricUnits(tr("seconds"));
setImperialUnits(tr("seconds"));
}
RideMetric *clone() const { return new WCPZoneTime2(*this); }
};
class WCPZoneTime3 : public WCPZoneTime {
Q_DECLARE_TR_FUNCTIONS(WCPZoneTime3)
public:
WCPZoneTime3()
{
setLevel(3);
setSymbol("wcptime_in_zone_L3");
setInternalName("W3 Above CP W'bal Heavy Fatigue");
}
void initialize ()
{
setName(tr("W3 Above CP W'bal Heavy Fatigue"));
setMetricUnits(tr("seconds"));
setImperialUnits(tr("seconds"));
}
RideMetric *clone() const { return new WCPZoneTime3(*this); }
};
class WCPZoneTime4 : public WCPZoneTime {
Q_DECLARE_TR_FUNCTIONS(WCPZoneTime4)
public:
WCPZoneTime4()
{
setLevel(4);
setSymbol("wcptime_in_zone_L4");
setInternalName("W4 Above CP W'bal Severe Fatigue");
}
void initialize ()
{
setName(tr("W4 W'bal Severe Fatigue"));
setMetricUnits(tr("seconds"));
setImperialUnits(tr("seconds"));
}
RideMetric *clone() const { return new WCPZoneTime4(*this); }
};
// add to catalogue
static bool addMetrics() {
RideMetricFactory::instance().addMetric(MinWPrime());
@@ -1032,6 +1182,10 @@ static bool addMetrics() {
RideMetricFactory::instance().addMetric(WPrimeTau());
RideMetricFactory::instance().addMetric(WPrimeExp());
RideMetricFactory::instance().addMetric(WPrimeWatts());
RideMetricFactory::instance().addMetric(WCPZoneTime1());
RideMetricFactory::instance().addMetric(WCPZoneTime2());
RideMetricFactory::instance().addMetric(WCPZoneTime3());
RideMetricFactory::instance().addMetric(WCPZoneTime4());
RideMetricFactory::instance().addMetric(WZoneTime1());
RideMetricFactory::instance().addMetric(WZoneTime2());
RideMetricFactory::instance().addMetric(WZoneTime3());

View File

@@ -55,6 +55,9 @@ class WPrime {
QVector<double> &ydata() { check(); return values; }
QVector<double> &xdata(bool bydist) { check(); return bydist ? xdvalues : xvalues; }
// array of power >CP
QVector<int> powerValues;
QVector<double> &mydata() { check(); return mvalues; }
QVector<double> &mxdata(bool bydist) { check(); return bydist ? mxdvalues : mxvalues; }
@@ -72,7 +75,7 @@ class WPrime {
int minForCP(int CP);
// zoning with supplied values to avoid using a new Zones type config
static QString summarize(int WPRIME, QVector<double> wtiz, QColor color);
static QString summarize(int WPRIME, QVector<double> wtiz, QVector<double> wcptiz, QColor color);
static int zoneCount() { return 4; }
static QString zoneName(int i);
static QString zoneDesc(int i);

View File

@@ -92,7 +92,7 @@ class aXPower : public RideMetric {
setValue(xpower);
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aXPower(*this); }
};
@@ -131,7 +131,7 @@ class aVariabilityIndex : public RideMetric {
setValue(vi);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aVariabilityIndex(*this); }
};
@@ -182,7 +182,7 @@ class aRelativeIntensity : public RideMetric {
}
// end added djconnel
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aRelativeIntensity(*this); }
};
@@ -224,7 +224,7 @@ class aBikeScore : public RideMetric {
setValue(score);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aBikeScore(*this); }
};
@@ -261,7 +261,7 @@ class aResponseIndex : public RideMetric {
setValue(ri);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aResponseIndex(*this); }
};

View File

@@ -88,7 +88,7 @@ class aNP : public RideMetric {
setValue(np);
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aNP(*this); }
};
@@ -126,7 +126,7 @@ class aVI : public RideMetric {
setCount(secs);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aVI(*this); }
};
@@ -164,7 +164,7 @@ class aIntensityFactor : public RideMetric {
}
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aIntensityFactor(*this); }
};
@@ -203,7 +203,7 @@ class aTSS : public RideMetric {
setValue(score);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aTSS(*this); }
};
@@ -248,7 +248,7 @@ class aTSSPerHour : public RideMetric {
setCount(hours);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aTSSPerHour(*this); }
};
@@ -285,7 +285,7 @@ class aEfficiencyFactor : public RideMetric {
setValue(ef);
}
bool isRelevantForRide(const RideItem*ride) const { return (!ride->isRun && !ride->isSwim); }
bool isRelevantForRide(const RideItem*ride) const { return ride->present.contains("P") || (!ride->isRun && !ride->isSwim); }
RideMetric *clone() const { return new aEfficiencyFactor(*this); }
};