Files
GoldenCheetah/src/ToolsDialog.cpp
Alejandro Martinez c1291ac3c0 Extended Critical Power Estimator for Running and Swimming
Also fixed some translation issues
2015-07-12 23:09:55 -03:00

215 lines
8.0 KiB
C++

/*
* Copyright (c) 2007 Justin F. Knotzke (jknotzke@shampoo.ca)
*
* 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 "ToolsDialog.h"
#include "HelpWhatsThis.h"
#include "Settings.h"
QHBoxLayout*
ToolsDialog::setupMinsSecs(QDoubleSpinBoxPtr &minsSpinBox,
QDoubleSpinBoxPtr &secsSpinBox,
QDoubleSpinBoxPtr &wattsSpinBox,
double maxMin, double defaultMin)
{
QHBoxLayout *result = new QHBoxLayout;
minsSpinBox = new QDoubleSpinBox(this);
minsSpinBox->setDecimals(0);
minsSpinBox->setRange(0.0, maxMin);
minsSpinBox->setSuffix(tr(" mins"));
minsSpinBox->setSingleStep(1.0);
minsSpinBox->setWrapping(false);
minsSpinBox->setAlignment(Qt::AlignRight);
minsSpinBox->setValue(defaultMin);
result->addWidget(minsSpinBox);
secsSpinBox = new QDoubleSpinBox(this);
secsSpinBox->setDecimals(0);
secsSpinBox->setRange(0.0, 59.0);
secsSpinBox->setSuffix(tr(" secs"));
secsSpinBox->setSingleStep(1.0);
secsSpinBox->setWrapping(true);
secsSpinBox->setAlignment(Qt::AlignRight);
result->addWidget(secsSpinBox);
wattsSpinBox = new QDoubleSpinBox(this);
wattsSpinBox->setDecimals(0);
wattsSpinBox->setRange(0.0, 3000.0);
wattsSpinBox->setSuffix(tr(" watts"));
wattsSpinBox->setSingleStep(1.0);
wattsSpinBox->setWrapping(false);
wattsSpinBox->setAlignment(Qt::AlignRight);
result->addWidget(wattsSpinBox);
return result;
}
ToolsDialog::ToolsDialog(QWidget *parent) : QDialog(parent)
{
setWindowTitle(tr("Critical Power Estimator"));
HelpWhatsThis *help = new HelpWhatsThis(this);
this->setWhatsThis(help->getWhatsThisText(HelpWhatsThis::MenuBar_Tools_CP_EST));
setAttribute(Qt::WA_DeleteOnClose);
setFixedSize(300, 300);
QVBoxLayout *mainVBox = new QVBoxLayout(this);
QHBoxLayout *hlayout = new QHBoxLayout;
QLabel *sportLabel = new QLabel(tr("Sport"));
sportCombo = new QComboBox();
sportCombo->addItem(tr("Bike"));
sportCombo->addItem(tr("Run"));
sportCombo->addItem(tr("Swim"));
sportCombo->setCurrentIndex(0);
hlayout->addStretch();
hlayout->addWidget(sportLabel);
hlayout->addWidget(sportCombo);
hlayout->addStretch();
mainVBox->addLayout(hlayout);
mainVBox->addWidget(new QLabel(tr("Your best short effort (3-5 min):")));
mainVBox->addLayout(setupMinsSecs(shortMinsSpinBox, shortSecsSpinBox,
shortWattsSpinBox, 5.0, 3.0));
mainVBox->addWidget(new QLabel(tr("Your best long effort (15-60 min):")));
mainVBox->addLayout(setupMinsSecs(longMinsSpinBox, longSecsSpinBox,
longWattsSpinBox, 60.0, 20.0));
mainVBox->addStretch();
QHBoxLayout *cpHBox = new QHBoxLayout;
cpHBox->addStretch();
labelCP = new QLabel(tr("Your critical power:"));
cpHBox->addWidget(labelCP);
txtCP = new QLineEdit(this);
txtCP->setAlignment(Qt::AlignRight);
txtCP->setReadOnly(true);
cpHBox->addWidget(txtCP, Qt::AlignLeft);
cpHBox->addStretch();
mainVBox->addLayout(cpHBox);
QHBoxLayout *wpHBox = new QHBoxLayout;
wpHBox->addStretch();
labelWP = new QLabel(tr("Your W':"));
wpHBox->addWidget(labelWP);
txtWP = new QLineEdit(this);
txtWP->setAlignment(Qt::AlignRight);
txtWP->setReadOnly(true);
wpHBox->addWidget(txtWP, Qt::AlignLeft);
wpHBox->addStretch();
mainVBox->addLayout(wpHBox);
mainVBox->addStretch();
QHBoxLayout *buttonHBox = new QHBoxLayout;
btnCalculate = new QPushButton(this);
btnCalculate->setText(tr("Estimate"));
buttonHBox->addStretch();
buttonHBox->addWidget(btnCalculate);
btnOK = new QPushButton(this);
btnOK->setText(tr("Done"));
buttonHBox->addWidget(btnOK);
mainVBox->addLayout(buttonHBox);
connect(sportCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSport()));
connect(btnOK, SIGNAL(clicked()), this, SLOT(on_btnOK_clicked()));
connect(btnCalculate, SIGNAL(clicked()), this, SLOT(on_btnCalculate_clicked()));
}
void
ToolsDialog::changeSport()
{
QString rnSuffix = appsettings->value(this, GC_PACE, true).toBool() ? tr(" km") : tr(" mi");
QString swSuffix = appsettings->value(this, GC_SWIMPACE, true).toBool() ? tr(" m") : tr(" yd");
switch (sportCombo->currentIndex()) {
case 0: // Bike
shortWattsSpinBox->setDecimals(0);
shortWattsSpinBox->setSuffix(tr(" watts"));
longWattsSpinBox->setDecimals(0);
longWattsSpinBox->setSuffix(tr(" watts"));
labelCP->setText(tr("Your critical power:"));
labelWP->setText(tr("Your W':"));
break;
case 1: // Run
shortWattsSpinBox->setDecimals(1);
shortWattsSpinBox->setSuffix(rnSuffix);
longWattsSpinBox->setDecimals(1);
longWattsSpinBox->setSuffix(rnSuffix);
labelCP->setText(tr("Your critical pace:"));
labelWP->setText(tr("Your D':"));
break;
case 2: // Swim
shortWattsSpinBox->setDecimals(0);
shortWattsSpinBox->setSuffix(swSuffix);
longWattsSpinBox->setDecimals(0);
longWattsSpinBox->setSuffix(swSuffix);
labelCP->setText(tr("Your critical pace:"));
labelWP->setText(tr("Your D':"));
break;
}
shortWattsSpinBox->clear();
longWattsSpinBox->clear();
txtCP->clear();
txtWP->clear();
}
void ToolsDialog::on_btnOK_clicked()
{
accept();
}
void ToolsDialog::on_btnCalculate_clicked()
{
bool metricRnPace = appsettings->value(this, GC_PACE, true).toBool();
bool metricSwPace = appsettings->value(this, GC_PACE, true).toBool();
double shortSecs =
shortMinsSpinBox->value() * 60.0 + shortSecsSpinBox->value();
double shortWatts = shortWattsSpinBox->value();
double longSecs =
longMinsSpinBox->value() * 60.0 + longSecsSpinBox->value();
double longWatts = longWattsSpinBox->value();
double CP;
double Wprime;
switch (sportCombo->currentIndex()) {
case 0: // Bike
CP = (longSecs * longWatts - shortSecs * shortWatts)
/ (longSecs - shortSecs);
txtCP->setText(tr("%1 watts").arg(static_cast<int>(round(CP))));
Wprime = ((shortSecs * (shortWatts-CP)) +
(longSecs * (longWatts-CP))) /2;
txtWP->setText(tr("%1 kJ").arg(static_cast<int>(round(Wprime/1000))));
break;
case 1: // Run
CP = (longSecs - shortSecs) / (longWatts - shortWatts);
txtCP->setText(QString("%1 %2").arg(QTime(0,0,0).addSecs(CP).toString("mm:ss")).arg(metricRnPace ? tr("min/km") : tr("min/mi")));
Wprime = ((shortWatts-shortSecs/CP) +
(longWatts-longSecs/CP)) /2;
txtWP->setText(QString("%1 %2").arg(round(Wprime*1000)/1000).arg(metricRnPace ? tr("km") : tr("mi")));
break;
case 2: // Swim
CP = 100 * (longSecs - shortSecs) / (longWatts - shortWatts);
txtCP->setText(QString("%1 %2").arg(QTime(0,0,0).addSecs(CP).toString("mm:ss")).arg(metricSwPace ? tr("min/100m") : tr("min/100yd")));
Wprime = ((shortWatts-100*shortSecs/CP) +
(longWatts-100*longSecs/CP)) /2;
txtWP->setText(QString("%1 %2").arg(round(Wprime)).arg(metricSwPace ? tr("m") : tr("yd")));
break;
}
}