mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 16:39:57 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b204e85fe5 | ||
|
|
5f073f781d | ||
|
|
4436ca5a18 | ||
|
|
98858da51c | ||
|
|
ea2a66e399 | ||
|
|
22e3ee1ca6 | ||
|
|
1a57e45fb6 |
11
.travis.yml
11
.travis.yml
@@ -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
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
186
src/WPrime.cpp
186
src/WPrime.cpp
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user