mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 08:38:45 +00:00
378 lines
12 KiB
C++
378 lines
12 KiB
C++
/*
|
|
* 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 "RealtimePlotWindow.h"
|
|
#include "Athlete.h"
|
|
|
|
RealtimePlotWindow::RealtimePlotWindow(Context *context) :
|
|
GcWindow(context), context(context), active(false)
|
|
{
|
|
setContentsMargins(0,0,0,0);
|
|
setProperty("color", GColor(CTRAINPLOTBACKGROUND));
|
|
|
|
QWidget *c = new QWidget;
|
|
QVBoxLayout *cl = new QVBoxLayout(c);
|
|
setControls(c);
|
|
|
|
// setup the controls
|
|
QLabel *showLabel = new QLabel(tr("Show"), c);
|
|
cl->addWidget(showLabel);
|
|
|
|
showHr = new QCheckBox(tr("Heart Rate"), this);
|
|
showHr->setCheckState(Qt::Checked);
|
|
cl->addWidget(showHr);
|
|
|
|
showSpeed = new QCheckBox(tr("Speed"), this);
|
|
showSpeed->setCheckState(Qt::Checked);
|
|
cl->addWidget(showSpeed);
|
|
|
|
showCad = new QCheckBox(tr("Cadence"), this);
|
|
showCad->setCheckState(Qt::Checked);
|
|
cl->addWidget(showCad);
|
|
|
|
showPower = new QCheckBox(tr("Power"), this);
|
|
showPower->setCheckState(Qt::Checked);
|
|
cl->addWidget(showPower);
|
|
|
|
showAlt = new QCheckBox(tr("Alternate Power"), this);
|
|
showAlt->setCheckState(Qt::Checked);
|
|
cl->addWidget(showAlt);
|
|
|
|
showPow30s = new QCheckBox(tr("30s Power"), this);
|
|
showPow30s->setCheckState(Qt::Checked);
|
|
cl->addWidget(showPow30s);
|
|
|
|
showSmO2 = new QCheckBox(tr("SmO2"), this);
|
|
showSmO2->setCheckState(Qt::Checked);
|
|
cl->addWidget(showSmO2);
|
|
|
|
showtHb = new QCheckBox(tr("tHb"), this);
|
|
showtHb->setCheckState(Qt::Checked);
|
|
cl->addWidget(showtHb);
|
|
|
|
showO2Hb = new QCheckBox(tr("O2Hb"), this);
|
|
showO2Hb->setCheckState(Qt::Checked);
|
|
cl->addWidget(showO2Hb);
|
|
|
|
showHHb = new QCheckBox(tr("HHb"), this);
|
|
showHHb->setCheckState(Qt::Checked);
|
|
cl->addWidget(showHHb);
|
|
|
|
QLabel *smoothLabel = new QLabel(tr("Smoothing (5Hz Samples)"), this);
|
|
smoothLineEdit = new QLineEdit(this);
|
|
smoothLineEdit->setFixedWidth(40);
|
|
|
|
cl->addWidget(smoothLabel);
|
|
cl->addWidget(smoothLineEdit);
|
|
smoothSlider = new QSlider(Qt::Horizontal);
|
|
smoothSlider->setTickPosition(QSlider::TicksBelow);
|
|
smoothSlider->setTickInterval(10);
|
|
smoothSlider->setMinimum(1);
|
|
smoothSlider->setMaximum(150);
|
|
smoothLineEdit->setValidator(new QIntValidator(smoothSlider->minimum(),
|
|
smoothSlider->maximum(),
|
|
smoothLineEdit));
|
|
cl->addWidget(smoothSlider);
|
|
cl->addStretch();
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
rtPlot = new RealtimePlot(context);
|
|
layout->addWidget(rtPlot);
|
|
|
|
// common controls
|
|
connect(showPower, SIGNAL(stateChanged(int)), this, SLOT(setShowPower(int)));
|
|
connect(showPow30s, SIGNAL(stateChanged(int)), this, SLOT(setShowPow30s(int)));
|
|
connect(showHr, SIGNAL(stateChanged(int)), this, SLOT(setShowHr(int)));
|
|
connect(showSpeed, SIGNAL(stateChanged(int)), this, SLOT(setShowSpeed(int)));
|
|
connect(showCad, SIGNAL(stateChanged(int)), this, SLOT(setShowCad(int)));
|
|
connect(showAlt, SIGNAL(stateChanged(int)), this, SLOT(setShowAlt(int)));
|
|
connect(showSmO2, SIGNAL(stateChanged(int)), this, SLOT(setShowSmO2(int)));
|
|
connect(showtHb, SIGNAL(stateChanged(int)), this, SLOT(setShowtHb(int)));
|
|
connect(showO2Hb, SIGNAL(stateChanged(int)), this, SLOT(setShowO2Hb(int)));
|
|
connect(showHHb, SIGNAL(stateChanged(int)), this, SLOT(setShowHHb(int)));
|
|
connect(smoothSlider, SIGNAL(valueChanged(int)), this, SLOT(setSmoothingFromSlider()));
|
|
connect(smoothLineEdit, SIGNAL(editingFinished()), this, SLOT(setSmoothingFromLineEdit()));
|
|
|
|
// get updates..
|
|
connect(context, SIGNAL(telemetryUpdate(RealtimeData)), this, SLOT(telemetryUpdate(RealtimeData)));
|
|
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
|
|
|
|
// lets initialise all the smoothing variables
|
|
hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0;
|
|
smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0;
|
|
for(int i=0; i<150; i++) {
|
|
powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0;
|
|
smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0;
|
|
}
|
|
|
|
// set to zero
|
|
telemetryUpdate(RealtimeData());
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::configChanged(qint32)
|
|
{
|
|
setProperty("color", GColor(CTRAINPLOTBACKGROUND));
|
|
repaint();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::start()
|
|
{
|
|
// lets initialise all the smoothing variables
|
|
hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0;
|
|
smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0;
|
|
for(int i=0; i<150; i++) {
|
|
powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0;
|
|
smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::stop()
|
|
{
|
|
// lets initialise all the smoothing variables
|
|
hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0;
|
|
smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0;
|
|
for(int i=0; i<150; i++) {
|
|
powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0;
|
|
smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::pause()
|
|
{
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::telemetryUpdate(RealtimeData rtData)
|
|
{
|
|
|
|
// lets apply smoothing if we have to
|
|
if (rtPlot->smooth > 0) {
|
|
|
|
// Heartrate
|
|
double hr = rtData.value(RealtimeData::HeartRate);
|
|
hrtot += hr;
|
|
hrtot -= hrHist[hrindex];
|
|
hrHist[hrindex] = hr;
|
|
hrindex++;
|
|
if (hrindex >= rtPlot->smooth) hrindex = 0;
|
|
hr = hrtot / rtPlot->smooth;
|
|
rtPlot->hrData->addData(hr);
|
|
|
|
// Speed
|
|
double spd= rtData.value(RealtimeData::Speed);
|
|
spdtot += spd; spdtot -= spdHist[spdindex]; spdHist[spdindex] = spd;
|
|
spdindex++; if (spdindex >= rtPlot->smooth) spdindex = 0;
|
|
spd = spdtot / rtPlot->smooth;
|
|
if (!context->athlete->useMetricUnits) spd *= MILES_PER_KM;
|
|
rtPlot->spdData->addData(spd);
|
|
|
|
// Power
|
|
double pow = rtData.value(RealtimeData::Watts);
|
|
powtot += pow; powtot -= powHist[powindex]; powHist[powindex] = pow;
|
|
powindex++; if (powindex >= rtPlot->smooth) powindex = 0;
|
|
pow = powtot / rtPlot->smooth;
|
|
rtPlot->pwrData->addData(pow);
|
|
|
|
// Alternate Power
|
|
double alt = rtData.value(RealtimeData::AltWatts);
|
|
alttot += alt; alttot -= altHist[altindex]; altHist[altindex] = alt;
|
|
altindex++; if (altindex >= rtPlot->smooth) altindex = 0;
|
|
alt = alttot / rtPlot->smooth;
|
|
rtPlot->altPwrData->addData(alt);
|
|
|
|
// Cadence
|
|
double cad = rtData.value(RealtimeData::Cadence);
|
|
cadtot += cad; cadtot -= cadHist[cadindex]; cadHist[cadindex] = cad;
|
|
cadindex++; if (cadindex >= rtPlot->smooth) cadindex = 0;
|
|
cad = cadtot / rtPlot->smooth;
|
|
rtPlot->cadData->addData(cad);
|
|
|
|
// SmO2
|
|
double smo2 = rtData.value(RealtimeData::SmO2);
|
|
smo2tot += smo2; smo2tot -= smo2Hist[smo2index]; smo2Hist[smo2index] = smo2;
|
|
smo2index++; if (smo2index >= rtPlot->smooth) smo2index = 0;
|
|
smo2 = smo2tot / rtPlot->smooth;
|
|
rtPlot->smo2Data->addData(smo2);
|
|
|
|
// tHb
|
|
double thb = rtData.value(RealtimeData::tHb);
|
|
thbtot += thb; thbtot -= thbHist[thbindex]; thbHist[thbindex] = thb;
|
|
thbindex++; if (thbindex >= rtPlot->smooth) thbindex = 0;
|
|
thb = thbtot / rtPlot->smooth;
|
|
rtPlot->thbData->addData(thb);
|
|
|
|
// O2Hb
|
|
double o2hb = rtData.value(RealtimeData::O2Hb);
|
|
o2hbtot += o2hb; o2hbtot -= o2hbHist[o2hbindex]; o2hbHist[o2hbindex] = o2hb;
|
|
o2hbindex++; if (o2hbindex >= rtPlot->smooth) o2hbindex = 0;
|
|
o2hb = o2hbtot / rtPlot->smooth;
|
|
rtPlot->o2hbData->addData(o2hb);
|
|
|
|
// HHb
|
|
double hhb = rtData.value(RealtimeData::HHb);
|
|
hhbtot += hhb; hhbtot -= hhbHist[hhbindex]; hhbHist[hhbindex] = hhb;
|
|
hhbindex++; if (hhbindex >= rtPlot->smooth) hhbindex = 0;
|
|
hhb = hhbtot / rtPlot->smooth;
|
|
rtPlot->hhbData->addData(hhb);
|
|
|
|
// its smoothed to 30s anyway
|
|
rtPlot->pwr30Data->addData(rtData.value(RealtimeData::Watts));
|
|
|
|
} else {
|
|
|
|
rtPlot->pwrData->addData(rtData.value(RealtimeData::Watts));
|
|
rtPlot->altPwrData->addData(rtData.value(RealtimeData::AltWatts));
|
|
rtPlot->pwr30Data->addData(rtData.value(RealtimeData::Watts));
|
|
rtPlot->cadData->addData(rtData.value(RealtimeData::Cadence));
|
|
rtPlot->spdData->addData(rtData.value(RealtimeData::Speed));
|
|
rtPlot->hrData->addData(rtData.value(RealtimeData::HeartRate));
|
|
|
|
rtPlot->smo2Data->addData(rtData.value(RealtimeData::SmO2));
|
|
rtPlot->thbData->addData(rtData.value(RealtimeData::tHb));
|
|
rtPlot->o2hbData->addData(rtData.value(RealtimeData::O2Hb));
|
|
rtPlot->hhbData->addData(rtData.value(RealtimeData::HHb));
|
|
}
|
|
rtPlot->replot(); // redraw
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setSmoothingFromSlider()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromLineEdit which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
if (rtPlot->smooth != smoothSlider->value()) {
|
|
setSmoothing(smoothSlider->value());
|
|
smoothLineEdit->setText(QString("%1").arg(rtPlot->smooth));
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setSmoothingFromLineEdit()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromSlider which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
int value = smoothLineEdit->text().toInt();
|
|
if (value != rtPlot->smooth) {
|
|
smoothSlider->setValue(value);
|
|
setSmoothing(value);
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowPow30s(int value)
|
|
{
|
|
showPow30s->setChecked(value);
|
|
rtPlot->showPow30s(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowPower(int value)
|
|
{
|
|
showPower->setChecked(value);
|
|
rtPlot->showPower(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowSmO2(int value)
|
|
{
|
|
showSmO2->setChecked(value);
|
|
rtPlot->showSmO2(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowtHb(int value)
|
|
{
|
|
showtHb->setChecked(value);
|
|
rtPlot->showtHb(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowO2Hb(int value)
|
|
{
|
|
showO2Hb->setChecked(value);
|
|
rtPlot->showO2Hb(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowHHb(int value)
|
|
{
|
|
showHHb->setChecked(value);
|
|
rtPlot->showHHb(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowHr(int value)
|
|
{
|
|
showHr->setChecked(value);
|
|
rtPlot->showHr(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowSpeed(int value)
|
|
{
|
|
showSpeed->setChecked(value);
|
|
rtPlot->showSpeed(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowCad(int value)
|
|
{
|
|
showCad->setChecked(value);
|
|
rtPlot->showCad(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setShowAlt(int value)
|
|
{
|
|
showAlt->setChecked(value);
|
|
rtPlot->showAlt(value);
|
|
rtPlot->replot();
|
|
}
|
|
|
|
void
|
|
RealtimePlotWindow::setSmoothing(int value)
|
|
{
|
|
hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0;
|
|
smoothSlider->setValue(value);
|
|
rtPlot->setSmoothing(value);
|
|
}
|