diff --git a/src/ScatterPlot.cpp b/src/ScatterPlot.cpp index e6f39d0fd..6d05657b7 100644 --- a/src/ScatterPlot.cpp +++ b/src/ScatterPlot.cpp @@ -411,6 +411,7 @@ void ScatterPlot::setData (ScatterSettings *settings) // setup the framing curve if (intervals.count() == 0 || settings->frame) { + smooth(x, y, points, settings->smoothing); if (side) { @@ -465,7 +466,7 @@ void ScatterPlot::setData (ScatterSettings *settings) int i=0; if (settings->compareMode > 0) i++; - for (i; i< context->compareIntervals.count(); i++) { + for (; i< context->compareIntervals.count(); i++) { CompareInterval interval = context->compareIntervals.at(i); if (interval.checked == false) @@ -508,6 +509,8 @@ void ScatterPlot::setData (ScatterSettings *settings) } } + smooth(xval, yval, nbPoints, settings->smoothing); + QColor intervalColor = interval.color; // left / right are darker lighter if (side) intervalColor = intervalColor.lighter(50); @@ -850,8 +853,63 @@ ScatterPlot::addTrendLine(QVector xval, QVector yval, int nbPoin } void -ScatterPlot::smooth(QVector *xval, QVector *yval, int *count, double recInterval, int applySmooth) +ScatterPlot::smooth(QVector &xval, QVector &yval, int count, int applySmooth) { + if (applySmooth<2) + return; + + QVector smoothX(count); + QVector smoothY(count); + + for (int i=0; i0 && count-i >=0; i--) { + rXtot += smoothX[count-i]; + rYtot += smoothY[count-i]; + } + + // now run backwards setting the rolling average + for (int i=count-1; i>=applySmooth; i--) { + int hereX = smoothX[i]; + smoothX[i] = rXtot / applySmooth; + rXtot -= hereX; + rXtot += smoothX[i-applySmooth]; + + int hereY = smoothY[i]; + smoothY[i] = rYtot / applySmooth; + rYtot -= hereY; + rYtot += smoothY[i-applySmooth]; + } + + // Finish with smaller rolling average + for (int i=applySmooth-1; i>0; i--) { + int hereX = smoothX[i]; + smoothX[i] = rXtot / (i+2); + rXtot -= hereX; + + int hereY = smoothY[i]; + smoothY[i] = rYtot / (i+2); + rYtot -= hereY; + } + + xval = smoothX; + yval = smoothY; +} + +void +ScatterPlot::resample(QVector &xval, QVector &yval, int &count, double recInterval, int applySmooth) +{ + if (recInterval >= applySmooth) + return; + + int newcount=0; QVector newxval; QVector newyval; @@ -862,17 +920,17 @@ ScatterPlot::smooth(QVector *xval, QVector *yval, int *count, do int j=0; - for (int i = 0; i < *count; i++) { + for (int i = 0; i < count; i++) { j++; if (jat(i)*recInterval; - totalY += yval->at(i)*recInterval; + totalX += xval.at(i)*recInterval; + totalY += yval.at(i)*recInterval; } else { double part = recInterval-j+applySmooth; - totalX += xval->at(i)*part; - totalY += yval->at(i)*part; + totalX += xval.at(i)*part; + totalY += yval.at(i)*part; double smoothX = totalX/applySmooth; double smoothY = totalY/applySmooth; @@ -882,13 +940,14 @@ ScatterPlot::smooth(QVector *xval, QVector *yval, int *count, do newcount++; j=0; - totalX = xval->at(i)*(recInterval-part); - totalY = yval->at(i)*(recInterval-part); + totalX = xval.at(i)*(recInterval-part); + totalY = yval.at(i)*(recInterval-part); } } } - count = &newcount; - xval = &newxval; - yval = &newyval; + count = newcount; + xval = newxval; + yval = newyval; } + diff --git a/src/ScatterPlot.h b/src/ScatterPlot.h index a3b1ac247..36f4daaee 100644 --- a/src/ScatterPlot.h +++ b/src/ScatterPlot.h @@ -109,7 +109,8 @@ class ScatterPlot : public QwtPlot void addTrendLine(QVector xval, QVector yval, int nbPoints, QColor intervalColor); - void smooth(QVector *xval, QVector *yval, int *count, double recInterval, int applySmooth); + void smooth(QVector &xval, QVector &yval, int count, int applySmooth); + void resample(QVector &xval, QVector &yval, int &count, double recInterval, int applySmooth); // save the settings RideItem *ride; // what we plotting? diff --git a/src/ScatterWindow.cpp b/src/ScatterWindow.cpp index c6e819818..66e7be3db 100644 --- a/src/ScatterWindow.cpp +++ b/src/ScatterWindow.cpp @@ -104,7 +104,7 @@ ScatterWindow::ScatterWindow(Context *context) : rIgnore->setChecked(true); rIgnore->hide(); rFrameInterval = new QCheckBox(tr("Frame intervals")); - rFrameInterval->setChecked(true); + rFrameInterval->setChecked(true); // layout reveal controls QHBoxLayout *r = new QHBoxLayout; @@ -146,6 +146,25 @@ ScatterWindow::ScatterWindow(Context *context) : rySelector->setValue(2); cl->addRow(yLabel, ySelector); + QLabel *smoothLabel = new QLabel(tr("Smooth"), this); + smoothLineEdit = new QLineEdit(this); + smoothLineEdit->setFixedWidth(40); + + smoothSlider = new QSlider(Qt::Horizontal, this); + smoothSlider->setTickPosition(QSlider::TicksBelow); + smoothSlider->setTickInterval(10); + smoothSlider->setMinimum(1); + smoothSlider->setMaximum(60); + smoothLineEdit->setValidator(new QIntValidator(smoothSlider->minimum(), + smoothSlider->maximum(), + smoothLineEdit)); + smoothSlider->setValue(0); + + QHBoxLayout *smoothLayout = new QHBoxLayout; + smoothLayout->addWidget(smoothLineEdit); + smoothLayout->addWidget(smoothSlider); + cl->addRow(smoothLabel, smoothLayout); + // selectors ignore = new QCheckBox(tr("Ignore Zero")); ignore->setChecked(true); @@ -189,6 +208,8 @@ ScatterWindow::ScatterWindow(Context *context) : connect(rFrameInterval, SIGNAL(stateChanged(int)), this, SLOT(setrFrame())); connect(rIgnore, SIGNAL(stateChanged(int)), this, SLOT(setrIgnore())); connect(compareMode, SIGNAL(currentIndexChanged(int)), this, SLOT(setCompareMode(int))); + connect(smoothSlider, SIGNAL(valueChanged(int)), this, SLOT(setSmoothingFromSlider())); + connect(smoothLineEdit, SIGNAL(editingFinished()), this, SLOT(setSmoothingFromLineEdit())); connect(context, SIGNAL(configChanged()), this, SLOT(configChanged())); // comparing things @@ -287,6 +308,25 @@ ScatterWindow::setTrendLine(int value) setData(); } +void +ScatterWindow::setSmoothingFromSlider() +{ + smoothLineEdit->setText(QString("%1").arg(smoothSlider->value())); + + settings.smoothing = smoothSlider->value(); + setData(); +} + +void +ScatterWindow::setSmoothingFromLineEdit() +{ + int value = smoothLineEdit->text().toInt(); + + smoothSlider->setValue(value); + settings.smoothing = value; + setData(); +} + void ScatterWindow::intervalSelected() { @@ -334,6 +374,7 @@ ScatterWindow::setData() settings.frame = frame->isChecked(); settings.compareMode = compareMode->currentIndex(); settings.trendLine = trendLine->currentIndex(); + settings.smoothing = smoothSlider->value(); /* Not a blank state ? Just no data and we can change series ? if ((setting.x == MODEL_POWER || setting.y == MODEL_POWER ) && !ride->ride()->isDataPresent(RideFile::watts)) diff --git a/src/ScatterWindow.h b/src/ScatterWindow.h index 17c4ab243..d0d66ff07 100644 --- a/src/ScatterWindow.h +++ b/src/ScatterWindow.h @@ -40,7 +40,7 @@ class ScatterSettings { public: ScatterSettings() : ride(NULL), x(0), y(0), crop(false), ignore(false), frame(false), - gridlines(false), secStart(0), secEnd(0) {} + gridlines(false), compareMode(0), trendLine(0), secStart(0), secEnd(0), smoothing(0) {} RideItem *ride; // ride to use int x,y; // which channels to use @@ -52,6 +52,7 @@ class ScatterSettings trendLine; int secStart, secEnd; // what time slice to show? + int smoothing; QList intervals; // intervals to apply }; @@ -68,6 +69,7 @@ class ScatterWindow : public GcChartWindow Q_PROPERTY(bool frame READ isFrame WRITE set_Frame USER true) Q_PROPERTY(int compareMode READ get_compareMode WRITE set_compareMode USER true) Q_PROPERTY(int trendLine READ get_trendLine WRITE set_trendLine USER true) + Q_PROPERTY(int smoothing READ get_smoothing WRITE set_smoothing USER true) public: @@ -94,6 +96,8 @@ class ScatterWindow : public GcChartWindow void set_compareMode(int x) { compareMode->setCurrentIndex(x); } int get_trendLine() const { return trendLine->currentIndex(); } void set_trendLine(int x) { trendLine->setCurrentIndex(x); } + int get_smoothing() const { return smoothSlider->value(); } + void set_smoothing(int x) { smoothSlider->setValue(x); } public slots: void rideSelected(); @@ -114,6 +118,8 @@ class ScatterWindow : public GcChartWindow void setrIgnore(); void setCompareMode(int); void setTrendLine(int); + void setSmoothingFromSlider(); + void setSmoothingFromLineEdit(); // compare mode started or items to compare changed void compareChanged(); @@ -147,6 +153,9 @@ class ScatterWindow : public GcChartWindow QComboBox *compareMode, *trendLine; + QSlider *smoothSlider; + QLineEdit *smoothLineEdit; + RideItem *current; private: