diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,6 +62,7 @@ add_executable(${PROGRAM_NAME} WIN32
plot.cpp
zoomer.cpp
hidabletabwidget.cpp
+ framebuffer.cpp
${UI_FILES}
misc/windows_icon.rc
)
diff --git a/framebuffer.cpp b/framebuffer.cpp
new file mode 100644
--- /dev/null
+++ b/framebuffer.cpp
@@ -0,0 +1,98 @@
+/*
+ Copyright © 2015 Hasan Yavuz Özderya
+
+ This file is part of serialplot.
+
+ serialplot 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 3 of the License, or
+ (at your option) any later version.
+
+ serialplot 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 serialplot. If not, see .
+*/
+
+#include "framebuffer.h"
+
+FrameBuffer::FrameBuffer(size_t size) :
+ data(size, 0.)
+{
+
+}
+
+void FrameBuffer::resize(size_t size)
+{
+ size_t old_size = this->size();
+ size_t new_size = size;
+
+ if (new_size < old_size)
+ {
+ data.remove(0, old_size - new_size);
+ }
+ else if (new_size > old_size)
+ {
+ // This is seriously inefficient!
+ for (size_t i = old_size; i < new_size; i++)
+ {
+ data.prepend(0);
+ }
+ }
+}
+
+void FrameBuffer::addSamples(QVector samples)
+{
+ int offset = size() - samples.size();
+
+ if (offset < 0)
+ {
+ // new samples exceed the size of frame buffer
+ // excess part (from beginning) of the input will be ignored
+ for (unsigned int i = 0; i < size(); i++)
+ {
+ data[i] = samples[i - offset];
+ }
+ }
+ else if (offset == 0) // input is the same size as the framebuffer
+ {
+ data = samples;
+ }
+ else // regular case; input is smaller than framebuffer
+ {
+ // shift old samples
+ int shift = samples.size();
+ for (int i = 0; i < offset; i++)
+ {
+ data[i] = data[i + shift];
+ }
+ // place new samples
+ for (int i = 0; i < samples.size(); i++)
+ {
+ data[offset + i] = samples[i];
+ }
+ }
+}
+
+void FrameBuffer::clear()
+{
+ data.fill(0);
+}
+
+size_t FrameBuffer::size() const
+{
+ return (size_t) data.size();
+}
+
+QPointF FrameBuffer::sample(size_t i) const
+{
+ return QPointF(i, data[i]);
+}
+
+QRectF FrameBuffer::boundingRect() const
+{
+ return qwtBoundingRect(*this);
+}
diff --git a/framebuffer.h b/framebuffer.h
new file mode 100644
--- /dev/null
+++ b/framebuffer.h
@@ -0,0 +1,45 @@
+/*
+ Copyright © 2015 Hasan Yavuz Özderya
+
+ This file is part of serialplot.
+
+ serialplot 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 3 of the License, or
+ (at your option) any later version.
+
+ serialplot 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 serialplot. If not, see .
+*/
+
+#ifndef FRAMEBUFFER_H
+#define FRAMEBUFFER_H
+
+#include
+#include
+#include
+
+class FrameBuffer : public QwtSeriesData
+{
+public:
+ FrameBuffer(size_t size);
+
+ void resize(size_t size);
+ void addSamples(QVector samples);
+ void clear(); // fill 0
+
+ // QwtSeriesData implementations
+ size_t size() const;
+ QPointF sample(size_t i) const;
+ QRectF boundingRect() const;
+
+private:
+ QVector data;
+};
+
+#endif // FRAMEBUFFER_H
diff --git a/main.cpp b/main.cpp
--- a/main.cpp
+++ b/main.cpp
@@ -23,6 +23,12 @@
#include "version.h"
+// TEST CODE
+#include "framebuffer.h"
+// #include
+#include
+#include
+
MainWindow* pMainWindow;
void messageHandler(QtMsgType type, const QMessageLogContext &context,
@@ -45,5 +51,33 @@ int main(int argc, char *argv[])
qDebug() << "Revision" << VERSION_REVISION;
w.show();
+
+ // test framebuffer
+ FrameBuffer buffer(10);
+ QVector s(3,15.);
+ s.append(1.0);
+ s.append(2.0);
+ s.append(3.0);
+ buffer.addSamples(s);
+ // buffer.addSamples(s);
+ // buffer.resize(5);
+ QwtPlot plot;
+ QwtPlotCurve curve;
+ curve.setSamples(&buffer);
+ curve.attach(&plot);
+ plot.show();
+ qDebug() << buffer.sample(0);
+ qDebug() << buffer.sample(1);
+ qDebug() << "size:" << buffer.size();
+ buffer.addSamples(s);
+ // curve.setSamples(&buffer);
+ plot.replot();
+ // qDebug() << buffer.sample(5);
+ // qDebug() << buffer.sample(7);
+ // qDebug() << buffer.sample(8);
+ // qDebug() << buffer.sample(9);
+ // qDebug() << buffer.sample(15);
+ // qDebug() << buffer.sample(19);
+
return a.exec();
}
diff --git a/mainwindow.cpp b/mainwindow.cpp
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -137,18 +137,12 @@ MainWindow::MainWindow(QWidget *parent)
numOfSamples = ui->spNumOfSamples->value();
numOfChannels = 1;
- dataX.resize(numOfSamples);
- for (int i = 0; i < dataX.size(); i++)
- {
- dataX[i] = i;
- }
-
// init channel data and curve list
for (unsigned int i = 0; i < numOfChannels; i++)
{
- channelsData.append(DataArray(numOfSamples, 0.0));
+ channelBuffers.append(new FrameBuffer(numOfSamples));
curves.append(new QwtPlotCurve());
- curves[i]->setSamples(dataX, channelsData[i]);
+ curves[i]->setSamples(channelBuffers[i]);
curves[i]->setPen(makeColor(i));
curves[i]->attach(ui->plot);
}
@@ -205,6 +199,7 @@ MainWindow::~MainWindow()
{
for (auto curve : curves)
{
+ // also deletes respective FrameBuffer
delete curve;
}
@@ -396,39 +391,8 @@ void MainWindow::skipByte()
void MainWindow::addChannelData(unsigned int channel, DataArray data)
{
- DataArray* channelDataArray = &(channelsData[channel]);
- int offset = numOfSamples - data.size();
-
- if (offset < 0)
- {
- for (unsigned int i = 0; i < numOfSamples; i++)
- {
- (*channelDataArray)[i] = data[i - offset];
- }
- }
- else if (offset == 0)
- {
- (*channelDataArray) = data;
- }
- else
- {
- // shift old samples
- int shift = data.size();
- for (int i = 0; i < offset; i++)
- {
- (*channelDataArray)[i] = (*channelDataArray)[i + shift];
- }
- // place new samples
- for (int i = 0; i < data.size(); i++)
- {
- (*channelDataArray)[offset + i] = data[i];
- }
- }
-
- // update plot
- curves[channel]->setSamples(dataX, (*channelDataArray));
+ channelBuffers[channel]->addSamples(data);
ui->plot->replot(); // TODO: replot after all channel data updated
-
sampleCount += data.size();
}
@@ -436,51 +400,21 @@ void MainWindow::clearPlot()
{
for (unsigned int ci = 0; ci < numOfChannels; ci++)
{
- channelsData[ci].fill(0.0);
- curves[ci]->setSamples(dataX, channelsData[ci]);
+ channelBuffers[ci]->clear();
}
-
- // update plot
ui->plot->replot();
}
void MainWindow::onNumOfSamplesChanged(int value)
{
- unsigned int oldNum = this->numOfSamples;
numOfSamples = value;
- // resize data arrays
- if (numOfSamples < oldNum)
- {
- dataX.resize(numOfSamples);
- for (unsigned int ci = 0; ci < numOfChannels; ci++)
- {
- channelsData[ci].remove(0, oldNum - numOfSamples);
- curves[ci]->setSamples(dataX, channelsData[ci]);
- }
- ui->plot->replot();
- }
- else if(numOfSamples > oldNum)
+ for (unsigned int ci = 0; ci < numOfChannels; ci++)
{
- // update data arrays
- dataX.resize(numOfSamples);
- for (unsigned int i = oldNum; i < numOfSamples; i++)
- {
- dataX[i] = i;
- for (unsigned int ci = 0; ci < numOfChannels; ci++)
- {
- // TODO: opportunity of major optimization here
- // let's hope nobody sees this
- channelsData[ci].prepend(0);
- }
- }
- // update curves
- for (unsigned int ci = 0; ci < numOfChannels; ci++)
- {
- curves[ci]->setSamples(dataX, channelsData[ci]);
- }
- ui->plot->replot();
+ channelBuffers[ci]->resize(numOfSamples);
}
+
+ ui->plot->replot();
}
void MainWindow::onNumOfChannelsChanged(int value)
@@ -493,9 +427,9 @@ void MainWindow::onNumOfChannelsChanged(
// add new channels
for (unsigned int i = 0; i < numOfChannels - oldNum; i++)
{
- channelsData.append(DataArray(numOfSamples, 0.0));
+ channelBuffers.append(new FrameBuffer(numOfSamples));
curves.append(new QwtPlotCurve());
- curves.last()->setSamples(dataX, channelsData.last());
+ curves.last()->setSamples(channelBuffers.last());
curves.last()->setPen(makeColor(curves.length()-1));
curves.last()->attach(ui->plot);
}
@@ -505,10 +439,9 @@ void MainWindow::onNumOfChannelsChanged(
// remove channels
for (unsigned int i = 0; i < oldNum - numOfChannels; i++)
{
- channelsData.removeLast();
- auto curve = curves.takeLast();
- curve->detach();
- delete curve;
+ // also deletes owned FrameBuffer
+ delete curves.takeLast();
+ channelBuffers.removeLast();
}
}
}
@@ -732,7 +665,7 @@ void MainWindow::onExportCsv()
{
for (unsigned int ci = 0; ci < numOfChannels; ci++)
{
- fileStream << channelsData[ci][i];
+ fileStream << channelBuffers[ci]->sample(i).y();
if (ci != numOfChannels-1) fileStream << ",";
}
fileStream << '\n';
diff --git a/mainwindow.h b/mainwindow.h
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -36,6 +36,7 @@
#include "portcontrol.h"
#include "ui_about_dialog.h"
+#include "framebuffer.h"
namespace Ui {
class MainWindow;
@@ -79,8 +80,8 @@ private:
QList curves;
typedef QVector DataArray;
- DataArray dataX; // array that simply contains numbers 0..numberOfSamples
- QList channelsData;
+ // Note: FrameBuffer s are owned by their respective QwtPlotCurve s.
+ QList channelBuffers;
// `data` contains i th channels data
void addChannelData(unsigned int channel, DataArray data);
diff --git a/serialplot.pro b/serialplot.pro
--- a/serialplot.pro
+++ b/serialplot.pro
@@ -39,7 +39,8 @@ SOURCES += main.cpp\
portcontrol.cpp \
plot.cpp \
zoomer.cpp \
- hidabletabwidget.cpp
+ hidabletabwidget.cpp \
+ framebuffer.cpp
HEADERS += mainwindow.h \
utils.h \
@@ -48,7 +49,8 @@ HEADERS += mainwindow.h \
floatswap.h \
plot.h \
zoomer.h \
- hidabletabwidget.h
+ hidabletabwidget.h \
+ framebuffer.h
FORMS += mainwindow.ui \
about_dialog.ui \