From e9ebc20af48ab511c15f3f2f52a00a513c0972ad Mon Sep 17 00:00:00 2001 From: grauser Date: Thu, 5 May 2016 09:41:10 +0200 Subject: [PATCH] Interval : Add Search for Peak Speed, Peak Pace --- src/FileIO/RideFile.cpp | 11 +++ src/FileIO/RideFile.h | 5 ++ src/Gui/AddIntervalDialog.cpp | 145 +++++++++++++++++++++++++--------- src/Gui/AddIntervalDialog.h | 12 ++- 4 files changed, 131 insertions(+), 42 deletions(-) diff --git a/src/FileIO/RideFile.cpp b/src/FileIO/RideFile.cpp index e41f26811..ca2afd792 100644 --- a/src/FileIO/RideFile.cpp +++ b/src/FileIO/RideFile.cpp @@ -398,6 +398,17 @@ RideFile::unitName(SeriesType series, Context *context) } } +QString +RideFile::formatValueWithUnit(double value, SeriesType series, Conversion conversion, Context *context, bool isSwim) +{ + bool useMetricUnits = context->athlete->useMetricUnits; + + if (series == RideFile::kph && conversion == RideFile::pace) + return kphToPace(value, useMetricUnits, isSwim); + else + return QString("%1%2").arg(value).arg(unitName(series, context)); +} + void RideFile::clearIntervals() { diff --git a/src/FileIO/RideFile.h b/src/FileIO/RideFile.h index c510cbf92..267b37d27 100644 --- a/src/FileIO/RideFile.h +++ b/src/FileIO/RideFile.h @@ -202,11 +202,14 @@ class RideFile : public QObject // QObject to emit signals wbal, tcore, none }; // none must ALWAYS be last + enum conversion { original, pace }; + // NA = Not Applicable - i.e Temperature no recorded value // NIL = Not available, but still set to zero for compatibility // We should consider looking at code to handle NIL / NA enum specialValues { NA = -255, NIL = 0 }; typedef enum seriestype SeriesType; + typedef enum conversion Conversion; static SeriesType lastSeriesType() { return none; } static QStringList symbols(); // get a list of symbols for each series to use in a formula @@ -215,6 +218,8 @@ class RideFile : public QObject // QObject to emit signals static QString seriesName(SeriesType, bool compat=false); static QString unitName(SeriesType, Context *context); + static QString formatValueWithUnit(double value, SeriesType series, Conversion conversion, Context *context, bool isSwim); + static int decimalsFor(SeriesType series); static double maximumFor(SeriesType series); static double minimumFor(SeriesType series); diff --git a/src/Gui/AddIntervalDialog.cpp b/src/Gui/AddIntervalDialog.cpp index f6a980b16..8dfee6312 100644 --- a/src/Gui/AddIntervalDialog.cpp +++ b/src/Gui/AddIntervalDialog.cpp @@ -20,6 +20,7 @@ #include "Settings.h" #include "Athlete.h" #include "Context.h" +#include "Units.h" #include "IntervalItem.h" #include "RideFile.h" #include "RideItem.h" @@ -53,10 +54,10 @@ AddIntervalDialog::AddIntervalDialog(Context *context) : intervalMethodLayout->addLayout(methodRadios); intervalMethodLayout->addStretch(); - methodBestPower = new QRadioButton(tr("Peak Power")); - methodBestPower->setChecked(true); - methodButtonGroup->addButton(methodBestPower); - methodRadios->addWidget(methodBestPower); + methodPeakPower = new QRadioButton(tr("Peak Power")); + methodPeakPower->setChecked(true); + methodButtonGroup->addButton(methodPeakPower); + methodRadios->addWidget(methodPeakPower); methodClimb = new QRadioButton(tr("Ascent (elevation)")); methodClimb->setChecked(false); @@ -68,16 +69,26 @@ AddIntervalDialog::AddIntervalDialog(Context *context) : methodButtonGroup->addButton(methodWPrime); methodRadios->addWidget(methodWPrime); - methodFirst = new QRadioButton(tr("Time / Distance")); - methodFirst->setChecked(false); - methodButtonGroup->addButton(methodFirst); - methodRadios->addWidget(methodFirst); - methodHeartRate = new QRadioButton(tr("Heart rate")); methodHeartRate->setChecked(false); methodButtonGroup->addButton(methodHeartRate); methodRadios->addWidget(methodHeartRate); + methodPeakSpeed = new QRadioButton(tr("Peak Speed")); + methodPeakSpeed->setChecked(false); + methodButtonGroup->addButton(methodPeakSpeed); + methodRadios->addWidget(methodPeakSpeed); + + methodPeakPace = new QRadioButton(tr("Peak Pace")); + methodPeakPace->setChecked(false); + methodButtonGroup->addButton(methodPeakPace); + methodRadios->addWidget(methodPeakPace); + + methodFirst = new QRadioButton(tr("Time / Distance")); + methodFirst->setChecked(false); + methodButtonGroup->addButton(methodFirst); + methodRadios->addWidget(methodFirst); + intervalPeakPowerWidget = new QWidget(); intervalPeakPowerTypeLayout = new QHBoxLayout; intervalPeakPowerTypeLayout->addStretch(); @@ -252,10 +263,12 @@ AddIntervalDialog::AddIntervalDialog(Context *context) : mainLayout->addLayout(buttonLayout); connect(methodFirst, SIGNAL(clicked()), this, SLOT(methodFirstClicked())); - connect(methodBestPower, SIGNAL(clicked()), this, SLOT(methodBestPowerClicked())); + connect(methodPeakPower, SIGNAL(clicked()), this, SLOT(methodPeakPowerClicked())); connect(methodWPrime, SIGNAL(clicked()), this, SLOT(methodWPrimeClicked())); connect(methodClimb, SIGNAL(clicked()), this, SLOT(methodClimbClicked())); connect(methodHeartRate, SIGNAL(clicked()), this, SLOT(methodHeartRateClicked())); + connect(methodPeakPace, SIGNAL(clicked()), this, SLOT(methodPeakPaceClicked())); + connect(methodPeakSpeed, SIGNAL(clicked()), this, SLOT(methodPeakSpeedClicked())); connect(peakPowerStandard, SIGNAL(clicked()), this, SLOT(peakPowerStandardClicked())); connect(peakPowerCustom, SIGNAL(clicked()), this, SLOT(peakPowerCustomClicked())); connect(typeTime, SIGNAL(clicked()), this, SLOT(typeTimeClicked())); @@ -264,7 +277,7 @@ AddIntervalDialog::AddIntervalDialog(Context *context) : connect(addButton, SIGNAL(clicked()), this, SLOT(addClicked())); // get set to default to best powers (peaks) - methodBestPowerClicked(); + methodPeakPowerClicked(); } void @@ -285,7 +298,7 @@ AddIntervalDialog::methodFirstClicked() } void -AddIntervalDialog::methodBestPowerClicked() +AddIntervalDialog::methodPeakPowerClicked() { // clear the table clearResultsTable(resultsTable); @@ -293,6 +306,7 @@ AddIntervalDialog::methodBestPowerClicked() intervalWPrimeWidget->hide(); intervalPeakPowerWidget->show(); intervalClimbWidget->hide(); + if (peakPowerCustom->isChecked()) peakPowerCustomClicked(); else @@ -329,6 +343,42 @@ AddIntervalDialog::methodClimbClicked() intervalWPrimeWidget->hide(); } +void +AddIntervalDialog::methodPeakSpeedClicked() +{ + // clear the table + clearResultsTable(resultsTable); + + intervalClimbWidget->hide(); + intervalPeakPowerWidget->hide(); + intervalWPrimeWidget->hide(); + + intervalTypeWidget->show(); + if (typeDistance->isChecked()) + typeDistanceClicked(); + else + typeTimeClicked(); + intervalCountWidget->show(); +} + +void +AddIntervalDialog::methodPeakPaceClicked() +{ + // clear the table + clearResultsTable(resultsTable); + + intervalClimbWidget->hide(); + intervalPeakPowerWidget->hide(); + intervalWPrimeWidget->hide(); + + intervalTypeWidget->show(); + if (typeDistance->isChecked()) + typeDistanceClicked(); + else + typeTimeClicked(); + intervalCountWidget->show(); +} + void AddIntervalDialog::methodHeartRateClicked() { @@ -337,11 +387,13 @@ AddIntervalDialog::methodHeartRateClicked() intervalClimbWidget->hide(); intervalPeakPowerWidget->hide(); - intervalTypeWidget->hide(); - intervalDistanceWidget->hide(); intervalWPrimeWidget->hide(); - intervalTimeWidget->show(); + intervalTypeWidget->show(); + if (typeDistance->isChecked()) + typeDistanceClicked(); + else + typeTimeClicked(); intervalCountWidget->show(); } @@ -464,9 +516,10 @@ AddIntervalDialog::createClicked() QList results; // FIND PEAKS - if (methodBestPower->isChecked()) { + if (methodPeakPower->isChecked() || methodPeakSpeed->isChecked() || + methodPeakPace->isChecked() || methodHeartRate->isChecked()) { - if (peakPowerStandard->isChecked()) + if (methodPeakPower->isChecked() && peakPowerStandard->isChecked()) findPeakPowerStandard(context, ride, results); else { @@ -476,10 +529,20 @@ AddIntervalDialog::createClicked() return; } - findBests(context, byTime, ride, RideFile::watts, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, ""); + if (methodPeakPower->isChecked()) { + findPeaks(context, byTime, ride, RideFile::watts, RideFile::original, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, "Peak Power",""); + } + else if (methodPeakSpeed->isChecked()) { + findPeaks(context, byTime, ride, RideFile::kph, RideFile::original, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, "Peak Speed",""); + } + else if (methodPeakPace->isChecked()) { + findPeaks(context, byTime, ride, RideFile::kph, RideFile::pace, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, "Peak Pace", ""); + } + else if (methodHeartRate->isChecked()) { + findPeaks(context, byTime, ride, RideFile::hr, RideFile::original, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, "Peak HR", ""); + } } - } // FIND PEAKS @@ -491,11 +554,12 @@ AddIntervalDialog::createClicked() return; } - findBests(context, byTime, ride, RideFile::hr, (byTime?windowSizeSecs:windowSizeMeters), maxIntervals, results, ""); } + + // FIND BY TIME OR DISTANCE if (methodFirst->isChecked()) { @@ -761,22 +825,23 @@ AddIntervalDialog::findFirsts(bool typeTime, const RideFile *ride, double window void AddIntervalDialog::findPeakPowerStandard(Context *context, const RideFile *ride, QList &results) { - findBests(context, true, ride, RideFile::watts, 5, 1, results, tr("Peak 5s")); - findBests(context, true, ride, RideFile::watts, 10, 1, results, tr("Peak 10s")); - findBests(context, true, ride, RideFile::watts, 20, 1, results, tr("Peak 20s")); - findBests(context, true, ride, RideFile::watts, 30, 1, results, tr("Peak 30s")); - findBests(context, true, ride, RideFile::watts, 60, 1, results, tr("Peak 1min")); - findBests(context, true, ride, RideFile::watts, 120, 1, results, tr("Peak 2min")); - findBests(context, true, ride, RideFile::watts, 300, 1, results, tr("Peak 5min")); - findBests(context, true, ride, RideFile::watts, 600, 1, results, tr("Peak 10min")); - findBests(context, true, ride, RideFile::watts, 1200, 1, results, tr("Peak 20min")); - findBests(context, true, ride, RideFile::watts, 1800, 1, results, tr("Peak 30min")); - findBests(context, true, ride, RideFile::watts, 3600, 1, results, tr("Peak 60min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 5, 1, results, "", tr("Peak 5s")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 10, 1, results, "", tr("Peak 10s")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 20, 1, results, "", tr("Peak 20s")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 30, 1, results, "", tr("Peak 30s")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 60, 1, results, "", tr("Peak 1min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 120, 1, results, "", tr("Peak 2min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 300, 1, results, "", tr("Peak 5min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 600, 1, results, "", tr("Peak 10min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 1200, 1, results, "", tr("Peak 20min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 1800, 1, results, "", tr("Peak 30min")); + findPeaks(context, true, ride, RideFile::watts, RideFile::original, 3600, 1, results, "", tr("Peak 60min")); } void -AddIntervalDialog::findBests(Context *context, bool typeTime, const RideFile *ride, RideFile::SeriesType series, double windowSize, - int maxIntervals, QList &results, QString prefix) +AddIntervalDialog::findPeaks(Context *context, bool typeTime, const RideFile *ride, + RideFile::SeriesType series, RideFile::Conversion conversion, double windowSize, + int maxIntervals, QList &results, QString prefixe, QString overideName) { QList bests; QList _results; @@ -824,11 +889,14 @@ AddIntervalDialog::findBests(Context *context, bool typeTime, const RideFile *ri } } if (!overlaps) { - QString name = prefix; - if (prefix == "") { + QString name = overideName; + if (overideName == "") { name = tr("%1 %3%4 #%2"); - name = name.arg("Peak"); + if (prefixe == "") + name = name.arg(tr("Peak")); + else + name = name.arg(prefixe); name = name.arg(_results.count()+1); if (typeTime) { @@ -878,8 +946,9 @@ AddIntervalDialog::findBests(Context *context, bool typeTime, const RideFile *ri } } } - name += " (%4%5)"; - name = name.arg(round(candidate.avg)).arg(ride->unitName(series, context)); + name += " (%4)"; + name = name.arg(ride->formatValueWithUnit(round(candidate.avg), series, conversion, context, ride->isSwim())); + candidate.name = name; name = ""; _results.append(candidate); diff --git a/src/Gui/AddIntervalDialog.h b/src/Gui/AddIntervalDialog.h index 56cfdd78b..73fbbfccc 100644 --- a/src/Gui/AddIntervalDialog.h +++ b/src/Gui/AddIntervalDialog.h @@ -52,8 +52,9 @@ class AddIntervalDialog : public QDialog static void findPeakPowerStandard(Context *context, const RideFile *ride, QList &results); - static void findBests(Context *context, bool typeTime, const RideFile *ride, RideFile::SeriesType series, double windowSizeSecs, - int maxIntervals, QList &results, QString name); + static void findPeaks(Context *context, bool typeTime, const RideFile *ride, RideFile::SeriesType series, + RideFile::Conversion conversion, double windowSizeSecs, + int maxIntervals, QList &results, QString prefixe, QString overideName); static void findFirsts(bool typeTime, const RideFile *ride, double windowSizeSecs, int maxIntervals, QList &results); @@ -63,10 +64,12 @@ class AddIntervalDialog : public QDialog void addClicked(); // add to inverval selections void methodFirstClicked(); - void methodBestPowerClicked(); + void methodPeakPowerClicked(); void methodWPrimeClicked(); void methodClimbClicked(); void methodHeartRateClicked(); + void methodPeakPaceClicked(); + void methodPeakSpeedClicked(); void peakPowerStandardClicked(); void peakPowerCustomClicked(); void typeTimeClicked(); @@ -84,7 +87,8 @@ class AddIntervalDialog : public QDialog QPushButton *createButton, *addButton; QDoubleSpinBox *hrsSpinBox, *minsSpinBox, *secsSpinBox, *altSpinBox, *countSpinBox,*kmsSpinBox, *msSpinBox, *kjSpinBox; - QRadioButton *methodFirst, *methodBestPower, *methodWPrime, *methodClimb, *methodHeartRate; + QRadioButton *methodFirst, *methodPeakPower, *methodWPrime, *methodClimb, *methodHeartRate, + *methodPeakSpeed, *methodPeakPace; QRadioButton *typeDistance, *typeTime, *peakPowerStandard, *peakPowerCustom; QTableWidget *resultsTable; };