From 202c04cbed068b908d3622c428992b4862a65428 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Fri, 13 Dec 2013 19:22:05 +0100 Subject: [PATCH] Move graph drawing functions to separate class --- Anyanka.pro | 6 +- graphdrawer.cpp | 76 ++++++++++++++++++ graphdrawer.h | 21 +++++ gui/graphview.cpp | 149 +++++------------------------------- gui/graphview.h | 4 +- singlerunsselectormodel.cpp | 6 -- 6 files changed, 123 insertions(+), 139 deletions(-) create mode 100644 graphdrawer.cpp create mode 100644 graphdrawer.h diff --git a/Anyanka.pro b/Anyanka.pro index 5d5babe..76443c8 100644 --- a/Anyanka.pro +++ b/Anyanka.pro @@ -49,7 +49,8 @@ SOURCES += main.cpp\ gui/exportrawdatadialog.cpp \ datafileexporter.cpp \ datawriterbackend.cpp \ - csvdatawriterbackend.cpp + csvdatawriterbackend.cpp \ + graphdrawer.cpp HEADERS += \ datafilesloader.h \ @@ -79,7 +80,8 @@ HEADERS += \ gui/exportrawdatadialog.h \ datafileexporter.h \ datawriterbackend.h \ - csvdatawriterbackend.h + csvdatawriterbackend.h \ + graphdrawer.h FORMS += \ gui/mainwindow.ui \ diff --git a/graphdrawer.cpp b/graphdrawer.cpp new file mode 100644 index 0000000..86142c5 --- /dev/null +++ b/graphdrawer.cpp @@ -0,0 +1,76 @@ +#include "graphdrawer.h" +#include + +#include + +GraphDrawer::GraphDrawer(QObject *parent) : + QObject(parent) +{ +} + +QPixmap* GraphDrawer::drawGraph(const double* const data, const size_t len, size_t w, size_t h, double min, double max) +{ + QPixmap* pixmap; + QPainter p; + int fromX = 0; + int fromY; + double xStep; + double yStep; + + if (w < 1 || h < 1 || data == nullptr || len < 1) + return nullptr; + + pixmap = new QPixmap(w, h); + p.begin(pixmap); + p.fillRect(0, 0, w, h, Qt::white); + p.setPen(QColor(Qt::blue)); + + xStep = static_cast(w) / len; + yStep = static_cast(h) / fabs(max - min); + fromY = h - yStep * data[0] - min; + for (uint i = 1; i < len; i++) { + int toX = xStep * i; + int toY = h - yStep * (data[i] - min); + p.drawLine(fromX, fromY, toX, toY); + + qDebug() << "fromX" << fromX << "fromY" << fromY << "toX" << toX << "toY" << toY; + fromX = toX; + fromY = toY; + } + + p.end(); + return pixmap; +} + +bool GraphDrawer::overlayIntegratedPeak(QPixmap* canvas, int startX, int startY, int stopX, int stopY, int peakStartX, int peakStartY, const QString& time, + const QString& area) +{ + QPainter p; + QFont font("arial", 10); + QFontMetrics fm(font); + int textWidth; + if (canvas == nullptr) + return false; + + p.begin(canvas); + p.setPen(Qt::red); + p.drawLine(startX, startY, stopX, stopY); + + /* Draw AREA and TIME caption */ + p.setFont(font); + p.setPen(Qt::black); + textWidth = fm.width(time); + if (peakStartY - textWidth < 2) + peakStartY += textWidth - peakStartY + 2; + p.save(); + p.translate(peakStartX, peakStartY); + p.rotate(-90); + p.drawText(0, 0, time); + p.rotate(+90); + p.restore(); + p.drawText(peakStartX + 5, peakStartY, area); + p.end(); + + //TODO: Report back what region of the canvas has been updated to allow drawing optimizations + return true; +} diff --git a/graphdrawer.h b/graphdrawer.h new file mode 100644 index 0000000..ad4987b --- /dev/null +++ b/graphdrawer.h @@ -0,0 +1,21 @@ +#ifndef GRAPHDRAWER_H +#define GRAPHDRAWER_H + +#include + +class GraphDrawer : public QObject +{ + Q_OBJECT +public: + explicit GraphDrawer(QObject* parent = nullptr); + QPixmap* drawGraph(const double* const data, const size_t len, size_t w, size_t h, double min, double max); + bool overlayIntegratedPeak(QPixmap* canvas, int startX, int startY, int stopX, int stopY, int peakStartX, int peakStartY, const QString& time, + const QString& area); + +signals: + +public slots: + +}; + +#endif // GRAPHDRAWER_H diff --git a/gui/graphview.cpp b/gui/graphview.cpp index 6aa98f5..1a0fcdf 100644 --- a/gui/graphview.cpp +++ b/gui/graphview.cpp @@ -35,6 +35,7 @@ GraphView::GraphView(QWidget* parent) : m_graphCrosshairX(-1), m_graphCrosshairY(-1) { + m_graphDrawer = std::unique_ptr(new GraphDrawer); setMouseTracking(true); setCursor(Qt::BlankCursor); } @@ -205,72 +206,6 @@ void GraphView::drawCrosshair(const int x, const int y) update(reg); } -void GraphView::drawIntegratedPeak(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, - const QString& time, const QString& area, const bool valley) -{ - QPainter p; - QPainter pBB; - QRegion reg; - int w, h; - int startX, startY, stopX, stopY, peakStartX, peakStartY; - double yStep, xStep; - double dStartY, dStopY; - QFont font("arial", 10); - QFontMetrics fm(font); - int textWidth; - if (m_backbuffer == nullptr) - return; - - w = this->width(); - h = this->height(); - xStep = static_cast(w) / m_drawDataLen; - yStep = static_cast(h) / (m_drawDataMax - m_drawDataMin); - startX = floor(fromX * xStep + 0.5); - stopX = floor(toX * xStep + 0.5); - startY = floor((h - yStep * (fromY - m_drawDataMin)) + 0.5); - stopY = floor((h - yStep * (toY - m_drawDataMin)) + 0.5); - peakStartX = floor(peakX * xStep + 0.5); - peakStartY = floor(h - yStep * (peakY - m_drawDataMin) + 0.5); - - dStartY = h - yStep * (fromY - m_drawDataMin); - dStopY = h - yStep * (toY - m_drawDataMin); - - /*qDebug("Drawing peak"); - qDebug() << "RSX" << fromX << "RSY" << fromY << "REX" << toX << "REY" << toY; - qDebug() << "X step" << xStep << "Y step" << yStep; - qDebug() << "SX" << startX << "SY" << startY << "EX" << stopX << "EY" << stopY << "w/h" << w << h; - qDebug() << "DSY" << dStartY << "DEY" << dStopY << "Slope I" << (toY-fromY)/(toX-fromX) << "Slope D" << (dStopY-dStartY)/(toX-fromX); - qDebug("---");*/ - - p.begin(m_plainGraph); - p.setPen(Qt::red); - p.drawLine(startX, startY, stopX, stopY); - - /* Draw AREA and TIME caption */ - p.setFont(font); - p.setPen(Qt::black); - textWidth = fm.width(time); - if (peakStartY - textWidth < 2) - peakStartY += textWidth - peakStartY + 2; - p.save(); - p.translate(peakStartX, peakStartY); - p.rotate(-90); - p.drawText(0, 0, time); - p.rotate(+90); - p.restore(); - p.drawText(peakStartX + 5, peakStartY, area); - p.end(); - - /* Copy updated plainGraph to backbuffer */ - pBB.begin(m_backbuffer); - pBB.drawPixmap(QRect(0, 0, w, h), *m_plainGraph); // Can be optimized! - //pBB.drawPixmap(startX, 0, *m_plainGraph, startX, 0, w - startX, h); - pBB.end(); - - //reg = QRect(startX, 0, w - startX, h); - update(); //Again - can be optimized! -} - void GraphView::drawIntegrationBaseline(const int x, const int y) { QPainter p; @@ -317,70 +252,10 @@ void GraphView::drawGraph() { int w = this->width(); int h = this->height(); - uint lastColumn = 0; - double yAvg = 0; - double yStep; - QPainter p; - QPixmap* fresh; - - if (m_drawData == nullptr) - return; - if (w < 1 || h < 1) + QPixmap* fresh = m_graphDrawer->drawGraph(m_drawData, m_drawDataLen, w, h, m_drawDataMin, m_drawDataMax); + if (fresh == nullptr) return; - fresh = new QPixmap(w, h); - qDebug() << "DGR" << w << h; - - p.begin(fresh); - p.fillRect(0, 0, w, h, Qt::white); - p.setPen(QColor(Qt::blue)); - - /* Scaling */ - yStep = static_cast(h) / fabs(m_drawDataMax - m_drawDataMin); - - /* Downscale to grid */ - if (w < m_drawDataLen) { - double columnsPerPixel = static_cast(m_drawDataLen) / w; - uint columnsPerLastPixel = 0; - int* block = new int[w]; - //qDebug() << "CPP" << columnsPerPixel << "yStep" << yStep << "Dims" << h << w << "Data" << w*columnsPerPixel << m_graphLen; - for (uint i = 0; i < m_drawDataLen; i++) { - uint column = i / columnsPerPixel; - if (column != lastColumn) { - yAvg /= columnsPerLastPixel; - block[lastColumn] = h - yStep * (yAvg -m_drawDataMin); - //qDebug() << "YAVG" << block[lastColumn] << "CPLP" << columnsPerLastPixel; - yAvg = 0; - columnsPerLastPixel= 0; - lastColumn = column; - } - yAvg += m_drawData[i]; - columnsPerLastPixel++; - } - /* Add the last column */ - yAvg /= columnsPerLastPixel; - block[w-1] = h - yStep * (yAvg - m_drawDataMin); - /* Draw the pixmap */ - for (int i = 1; i < w; i++) - p.drawLine(i-1, floor(block[i-1]+0.5), i, floor(block[i]+0.5)); - //qDebug() << "LAST YAVG" << block[m_graphLen-1] << "CPLP" << columnsPerLastPixel; - delete[] block; - } else { /* Upscale to grid */ - double pixelsPerValue = static_cast(w) / m_drawDataLen; - uint cPixX; - uint pPixX = 0; - uint cPixY; - uint pPixY = floor((h - yStep * (m_drawData[0] - m_drawDataMin)) + 0.5); - for (int i = 1; i < m_drawDataLen; i++) { - cPixX= floor(i * pixelsPerValue + 0.5); - cPixY = h - yStep * (m_drawData[i] - m_drawDataMin); - //qDebug() << "Upscale" << pPixX << pPixY << cPixX << cPixY; - p.drawLine(pPixX, pPixY, cPixX, cPixY); - pPixX = cPixX; - pPixY = cPixY; - } - } - if (m_backbuffer != nullptr) delete m_backbuffer; m_backbuffer = fresh; @@ -560,7 +435,23 @@ QRegion GraphView::eraseZoomRect(bool apply) void GraphView::onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, const QString& time, const QString& area, const bool valley) { - this->drawIntegratedPeak(fromX, fromY, toX, toY, peakX, peakY, time, area, valley); + int w = this->width(); + int h = this->height(); + double xStep = static_cast(w) / m_drawDataLen; + double yStep = static_cast(h) / (m_drawDataMax - m_drawDataMin); + int startX = floor(fromX * xStep + 0.5); + int stopX = floor(toX * xStep + 0.5); + int startY = floor((h - yStep * (fromY - m_drawDataMin)) + 0.5); + int stopY = floor((h - yStep * (toY - m_drawDataMin)) + 0.5); + int peakStartX = floor(peakX * xStep + 0.5); + int peakStartY = floor(h - yStep * (peakY - m_drawDataMin) + 0.5); + + if (m_graphDrawer->overlayIntegratedPeak(m_plainGraph, startX, startY, stopX, stopY, peakStartX, peakStartY, time, area)) { + //TODO: Optimize so that the whole graph is not redrawn on each integration + QPainter pBB(m_backbuffer); + pBB.drawPixmap(QRect(0, 0, w, h), *m_plainGraph); + update(); + } } void GraphView::onUpdateGraph(double* data, size_t len, double min, double max) diff --git a/gui/graphview.h b/gui/graphview.h index c26f034..9511d82 100644 --- a/gui/graphview.h +++ b/gui/graphview.h @@ -25,6 +25,7 @@ #include #include +#include "graphdrawer.h" #include "mathhelpers.h" #include "metatypes.h" @@ -49,8 +50,6 @@ public: private: void drawCrosshair(const int x, const int y); void drawGraph(); - void drawIntegratedPeak(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, - const QString& time, const QString& area, const bool valley); void drawIntegrationBaseline(const int x, const int y); void drawZoomRect(const int x, const int y); QRegion eraseCrosshair(bool apply = false); @@ -59,6 +58,7 @@ private: void resizeEvent(QResizeEvent* ev); + std::unique_ptr m_graphDrawer; bool m_ctxMenuOpen; QPixmap* m_backbuffer; QPixmap* m_plainGraph; diff --git a/singlerunsselectormodel.cpp b/singlerunsselectormodel.cpp index bf11ec2..8624726 100644 --- a/singlerunsselectormodel.cpp +++ b/singlerunsselectormodel.cpp @@ -37,12 +37,6 @@ QVariant SingleRunsSelectorModel::data(const QModelIndex& index, int role) const if (m_singleRunKeys.size() == 0) return QVariant(); - /*std::vector::const_iterator cit = m_singleRunKeys->cbegin(); - while (cit != m_singleRunKeys->cend()) { - if (runIdx == index.row()) - return cit->first; - runIdx++; cit++; - }*/ for (const std::string& s : m_singleRunKeys) { if (runIdx == index.row()) return QString::fromStdString(s); -- 2.43.5