Add speed and cadence to the plot and automatically adjust y-axis based on

which lines are displayed.
This commit is contained in:
Sean C. Rhea
2006-09-07 18:50:19 +00:00
parent 3ec3f823b6
commit 4eff6b6eb9
3 changed files with 111 additions and 14 deletions

View File

@@ -31,13 +31,14 @@ static const inline double
max(double a, double b) { if (a > b) return a; else return b; }
AllPlot::AllPlot() :
hrArray(NULL), wattsArray(NULL), timeArray(NULL), smooth(30)
hrArray(NULL), wattsArray(NULL),
speedArray(NULL), cadArray(NULL),
timeArray(NULL), smooth(30)
{
insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
setCanvasBackground(Qt::white);
setAxisTitle(xBottom, "Time (minutes)");
setAxisTitle(yLeft, "Power / HR");
wattsCurve = new QwtPlotCurve("Power");
wattsCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
@@ -49,6 +50,16 @@ AllPlot::AllPlot() :
hrCurve->setPen(QPen(Qt::blue));
hrCurve->attach(this);
speedCurve = new QwtPlotCurve("Speed");
speedCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
speedCurve->setPen(QPen(Qt::green));
speedCurve->attach(this);
cadCurve = new QwtPlotCurve("Cadence");
cadCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
cadCurve->setPen(QPen(Qt::cyan));
cadCurve->attach(this);
grid = new QwtPlotGrid();
grid->enableX(false);
QPen gridPen;
@@ -58,33 +69,42 @@ AllPlot::AllPlot() :
}
struct DataPoint {
double time, hr, watts;
DataPoint(double t, double h, double w) : time(t), hr(h), watts(w) {}
double time, hr, watts, speed, cad;
DataPoint(double t, double h, double w, double s, double c) :
time(t), hr(h), watts(w), speed(s), cad(c) {}
};
void
AllPlot::recalc()
{
int rideTimeSecs = (int) ceil(timeArray[arrayLength - 1]);
double ymax = 0.0;
double totalWatts = 0.0;
double totalHr = 0.0;
double totalSpeed = 0.0;
double totalCad = 0.0;
QList<DataPoint*> list;
int i = 0;
double *smoothWatts = new double[rideTimeSecs + 1];
double *smoothHr = new double[rideTimeSecs + 1];
double *smoothSpeed = new double[rideTimeSecs + 1];
double *smoothCad = new double[rideTimeSecs + 1];
double *smoothTime = new double[rideTimeSecs + 1];
for (int secs = 0; secs < smooth; ++secs) {
smoothWatts[secs] = 0.0;
smoothHr[secs] = 0.0;
smoothSpeed[secs] = 0.0;
smoothCad[secs] = 0.0;
smoothTime[secs] = secs / 60.0;
}
for (int secs = smooth; secs <= rideTimeSecs; ++secs) {
while ((i < arrayLength) && (timeArray[i] <= secs)) {
DataPoint *dp =
new DataPoint(timeArray[i], hrArray[i], wattsArray[i]);
new DataPoint(timeArray[i], hrArray[i], wattsArray[i],
speedArray[i], cadArray[i]);
totalWatts += wattsArray[i];
totalHr += hrArray[i];
totalSpeed += speedArray[i];
totalCad += cadArray[i];
list.append(dp);
++i;
}
@@ -93,6 +113,8 @@ AllPlot::recalc()
list.removeFirst();
totalWatts -= dp->watts;
totalHr -= dp->hr;
totalSpeed -= dp->speed;
totalCad -= dp->cad;
delete dp;
}
// TODO: this is wrong. We should do a weighted average over the
@@ -100,44 +122,80 @@ AllPlot::recalc()
if (list.empty()) {
smoothWatts[secs] = 0.0;
smoothHr[secs] = 0.0;
smoothSpeed[secs] = 0.0;
smoothCad[secs] = 0.0;
}
else {
smoothWatts[secs] = totalWatts / list.size();
if (smoothWatts[secs] > ymax)
ymax = smoothWatts[secs];
smoothHr[secs] = totalHr / list.size();
if (smoothHr[secs] > ymax)
ymax = smoothHr[secs];
smoothSpeed[secs] = totalSpeed / list.size();
smoothCad[secs] = totalCad / list.size();
}
smoothTime[secs] = secs / 60.0;
}
wattsCurve->setData(smoothTime, smoothWatts, rideTimeSecs + 1);
hrCurve->setData(smoothTime, smoothHr, rideTimeSecs + 1);
speedCurve->setData(smoothTime, smoothSpeed, rideTimeSecs + 1);
cadCurve->setData(smoothTime, smoothCad, rideTimeSecs + 1);
setAxisScale(xBottom, 0.0, smoothTime[rideTimeSecs]);
setAxisScale(yLeft, 0.0, ymax + 30);
setYMax();
replot();
delete [] smoothWatts;
delete [] smoothHr;
delete [] smoothSpeed;
delete [] smoothCad;
delete [] smoothTime;
}
void
AllPlot::setYMax()
{
double ymax = 0;
QString ylabel = "";
if (wattsCurve->isVisible()) {
ymax = max(ymax, wattsCurve->maxYValue());
ylabel += QString((ylabel == "") ? "" : " / ") + "Watts";
}
if (hrCurve->isVisible()) {
ymax = max(ymax, hrCurve->maxYValue());
ylabel += QString((ylabel == "") ? "" : " / ") + "BPM";
}
if (speedCurve->isVisible()) {
ymax = max(ymax, speedCurve->maxYValue());
ylabel += QString((ylabel == "") ? "" : " / ") + "MPH";
}
if (cadCurve->isVisible()) {
ymax = max(ymax, cadCurve->maxYValue());
ylabel += QString((ylabel == "") ? "" : " / ") + "RPM";
}
setAxisScale(yLeft, 0.0, ymax * 1.1);
setAxisTitle(yLeft, ylabel);
}
void
AllPlot::setData(RawFile *raw)
{
delete [] hrArray;
delete [] wattsArray;
delete [] hrArray;
delete [] speedArray;
delete [] cadArray;
delete [] timeArray;
setTitle(raw->startTime.toString(GC_DATETIME_FORMAT));
hrArray = new double[raw->points.size()];
wattsArray = new double[raw->points.size()];
hrArray = new double[raw->points.size()];
speedArray = new double[raw->points.size()];
cadArray = new double[raw->points.size()];
timeArray = new double[raw->points.size()];
arrayLength = 0;
QListIterator<RawFilePoint*> i(raw->points);
while (i.hasNext()) {
RawFilePoint *point = i.next();
timeArray[arrayLength] = point->secs;
hrArray[arrayLength] = max(0, point->hr);
wattsArray[arrayLength] = max(0, point->watts);
hrArray[arrayLength] = max(0, point->hr);
speedArray[arrayLength] = max(0, point->mph);
cadArray[arrayLength] = max(0, point->cad);
++arrayLength;
}
recalc();
@@ -148,6 +206,7 @@ AllPlot::showPower(int state)
{
assert(state != Qt::PartiallyChecked);
wattsCurve->setVisible(state == Qt::Checked);
setYMax();
replot();
}
@@ -156,6 +215,25 @@ AllPlot::showHr(int state)
{
assert(state != Qt::PartiallyChecked);
hrCurve->setVisible(state == Qt::Checked);
setYMax();
replot();
}
void
AllPlot::showSpeed(int state)
{
assert(state != Qt::PartiallyChecked);
speedCurve->setVisible(state == Qt::Checked);
setYMax();
replot();
}
void
AllPlot::showCad(int state)
{
assert(state != Qt::PartiallyChecked);
cadCurve->setVisible(state == Qt::Checked);
setYMax();
replot();
}

View File

@@ -35,6 +35,8 @@ class AllPlot : public QwtPlot
QwtPlotCurve *wattsCurve;
QwtPlotCurve *hrCurve;
QwtPlotCurve *speedCurve;
QwtPlotCurve *cadCurve;
AllPlot();
@@ -46,6 +48,8 @@ class AllPlot : public QwtPlot
void showPower(int state);
void showHr(int state);
void showSpeed(int state);
void showCad(int state);
void showGrid(int state);
void setSmoothing(int value);
@@ -55,12 +59,15 @@ class AllPlot : public QwtPlot
double *hrArray;
double *wattsArray;
double *speedArray;
double *cadArray;
double *timeArray;
int arrayLength;
int smooth;
void recalc();
void setYMax();
};
#endif // _GC_AllPlot_h

View File

@@ -102,6 +102,14 @@ MainWindow::MainWindow(const QDir &home) :
showHr->setCheckState(Qt::Checked);
showLayout->addWidget(showHr);
QCheckBox *showSpeed = new QCheckBox("Speed", window);
showSpeed->setCheckState(Qt::Checked);
showLayout->addWidget(showSpeed);
QCheckBox *showCad = new QCheckBox("Cadence", window);
showCad->setCheckState(Qt::Checked);
showLayout->addWidget(showCad);
QHBoxLayout *smoothLayout = new QHBoxLayout;
QLabel *smoothLabel = new QLabel(tr("Smoothing (secs)"), window);
smoothLineEdit = new QLineEdit(window);
@@ -148,6 +156,10 @@ MainWindow::MainWindow(const QDir &home) :
allPlot, SLOT(showPower(int)));
connect(showHr, SIGNAL(stateChanged(int)),
allPlot, SLOT(showHr(int)));
connect(showSpeed, SIGNAL(stateChanged(int)),
allPlot, SLOT(showSpeed(int)));
connect(showCad, SIGNAL(stateChanged(int)),
allPlot, SLOT(showCad(int)));
connect(showGrid, SIGNAL(stateChanged(int)),
allPlot, SLOT(showGrid(int)));
connect(smoothSlider, SIGNAL(valueChanged(int)),