datafileexporter.cpp \
datawriterbackend.cpp \
csvdatawriterbackend.cpp \
- graphdrawer.cpp \
- gui/exportgraphtoimagedialog.cpp
+ gui/exportgraphtoimagedialog.cpp \
+ graphtoimageexporter.cpp \
+ imagedrawer.cpp \
+ signaldrawer.cpp
HEADERS += \
datafilesloader.h \
datafileexporter.h \
datawriterbackend.h \
csvdatawriterbackend.h \
- graphdrawer.h \
- gui/exportgraphtoimagedialog.h
+ gui/exportgraphtoimagedialog.h \
+ graphtoimageexporter.h \
+ imagedrawer.h \
+ signaldrawer.h
FORMS += \
gui/mainwindow.ui \
*/
#include "datamanager.h"
+#include "imagedrawer.h"
#include "logger.h"
#include "gui/exportgraphtoimagedialog.h"
#include "gui/exportrawdatadialog.h"
void DataManager::showOneSignal(std::shared_ptr<SignalController> ctrl)
{
- SignalView* swp = new SignalView();
+ SignalView* swp = new SignalView(ctrl);
swp->setDataTableModel(ctrl->dataTableModel());
swp->setIntegrationTableModel(ctrl->integrationTableModel());
swp->setTypeText(QString::fromStdString(ctrl->signal()->resourceToString()));
swp->setXUnits(QString::fromStdString(ctrl->signal()->xunitToString()));
swp->setYUnits(QString::fromStdString(ctrl->signal()->yunitToString()));
- connect(swp->m_graphView, SIGNAL(crosshairErased()), ctrl.get(), SLOT(onViewCrosshairErased()));
+
+ /*connect(swp->m_graphView, SIGNAL(crosshairErased()), ctrl.get(), SLOT(onViewCrosshairErased()));
connect(swp->m_graphView, SIGNAL(crosshairMoved(int,int)), ctrl.get(), SLOT(onViewCrosshairMoved(int,int)));
connect(swp->m_graphView, SIGNAL(integrated(int,int,int,int)), ctrl.get(), SLOT(onViewIntegrated(int,int,int,int)));
connect(swp->m_graphView, SIGNAL(redrawNeeded()), ctrl.get(), SLOT(onViewRedrawNeeded()));
connect(swp->m_graphView, SIGNAL(resized(int,int)), ctrl.get(), SLOT(onViewResized(int,int)));
- connect(swp->m_graphView, SIGNAL(showContextMenuReq(int,int,QPoint)), ctrl.get(), SLOT(onViewShowContextMenu(int,int,QPoint)));
+ connect(swp->m_graphView, SIGNAL(showContextMelnuReq(int,int,QPoint)), ctrl.get(), SLOT(onViewShowContextMenu(int,int,QPoint)));
connect(swp->m_graphView, SIGNAL(zoomed(int,int,int,int)), ctrl.get(), SLOT(onViewZoomed(int,int,int,int)));
connect(ctrl.get(), SIGNAL(viewDrawGraph(double*,size_t,double,double)), swp->m_graphView, SLOT(onUpdateGraph(double*,size_t,double,double)));
connect(ctrl.get(), SIGNAL(viewCtxMenuClosed()), swp->m_graphView, SLOT(onCtxMenuClosed()));
- connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString,bool)), swp->m_graphView,
- SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString,bool)));
+ connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString)), swp->m_graphView,
+ SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString)));
connect(ctrl.get(), SIGNAL(viewUpdateCurrentValues(double,double)), swp, SLOT(onUpdateCurrentValues(double,double)));
- connect(ctrl.get(), SIGNAL(viewRemoveCurrentValues()), swp, SLOT(onRemoveCurrentValues()));
+ connect(ctrl.get(), SIGNAL(viewRemoveCurrentValues()), swp, SLOT(onRemoveCurrentValues()));*/
emit addToDashboard(swp);
- ctrl->draw();
+ swp->m_graphView->refresh();
}
/* Public slots */
if (sr == nullptr)
return;
- for (const std::pair<std::string, std::shared_ptr<SignalController>>& p : sr->allControllers())
- dlg.addSignal(p.second->currentStartX(), p.second->currentStartY(), p.second->currentStopX(), p.second->currentStopY(), p.first);
+ for (const std::pair<std::string, std::shared_ptr<SignalController>>& p : sr->allControllers()) {
+ dlg.addSignal(p.second->fromXAbs(), p.second->fromYAbs(), p.second->toXAbs(), p.second->toYAbs(), p.first);
+ }
if (dlg.exec() == QDialog::Accepted) {
- GraphDrawer drawer;
- double* data;
- size_t fromIdx, toIdx;
double fromX = 0, toX = 0;
double fromY = 0, toY = 0;
int iw, ih;
}
qDebug() << fromX << fromY << toX << toY;
- /* Get from an to indices */
- const std::vector<Signal::TimeValuePair>& tvpairs = sig->values();
- uint idx;
- for (idx = 0; idx < tvpairs.size(); idx++) {
- if (tvpairs.at(idx).first >= fromX) {
- fromIdx = idx;
- break;
- }
- }
- if (idx == tvpairs.size()) {
- QMessageBox::warning(nullptr, "Error while exporting to image", "Value \"From X\" is higher than the range of the dataset.");
- return;
- }
- for (;idx < tvpairs.size(); idx++) {
- if (tvpairs.at(idx).first >= toX) {
- toIdx = idx;
- break;
- }
- }
- if (idx == tvpairs.size())
- toIdx = idx - 1;
-
- qDebug() << "fromIdx" << fromIdx << "toIdx" << toIdx << "size" << tvpairs.size();
- data = ctrl->generateDrawData(fromIdx, toIdx);
- if (data == nullptr) {
+ /*if (data == nullptr) {
QMessageBox::warning(nullptr, "Error while exporting to image", "Cannot generate data to draw. Some values are probably invalid.");
return;
- }
+ }*/
+
+ ImageDrawer imgDrawer(iw, ih, this);
+ connect(ctrl.get(), SIGNAL(viewDrawGraph(double*,size_t,double,double)), &imgDrawer, SLOT(onUpdateGraph(double*,size_t,double,double)));
+ connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString)), &imgDrawer, SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString)));
+ //ctrl->onViewResized(iw, ih);
+ //ctrl->onViewZoomedByValues(fromX, fromY, toX, toY);
- QPixmap* pixmap = drawer.drawGraph(data, toIdx - fromIdx, iw, ih, fromY, toY);
- QImage result = pixmap->toImage();
+ QImage result = imgDrawer.pixmap()->toImage();
imageWriter.setFileName(dlg.path() + "." + dlg.imageFormat());
imageWriter.setFormat(dlg.imageFormat().toLatin1());
if (!imageWriter.write(result))
QMessageBox::critical(nullptr, "Error while exporting to image", "Image could not have been written.");
- delete pixmap;
- delete data;
}
}
+++ /dev/null
-#include "graphdrawer.h"
-#include <QtGui/QPainter>
-
-#include <QDebug>
-
-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<double>(w) / len;
- yStep = static_cast<double>(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);
-
- 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;
-}
+++ /dev/null
-#ifndef GRAPHDRAWER_H
-#define GRAPHDRAWER_H
-
-#include <QtCore/QObject>
-
-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
--- /dev/null
+#include "graphtoimageexporter.h"
+
+GraphToImageExporter::GraphToImageExporter(QObject* parent) :
+ QObject(parent)
+{
+}
+
+GraphToImageExporter::ReturnCode GraphToImageExporter::setParameters(const double fromX, const double fromY, const double toX, const double toY, const int width,
+ const int height, const QByteArray format, const QString& filename,
+ const std::shared_ptr<SignalController> ctrl)
+{
+ uint idx;
+
+ if (fromX >= toX)
+ return ReturnCode::E_INVALID_BOUNDS;
+ if (filename.length() == 0)
+ return ReturnCode::E_INVALID_FILENAME;
+ if (ctrl == nullptr)
+ return ReturnCode::E_NULL_CONTROLLER;
+ if (width < 1 || height < 1)
+ return ReturnCode::E_INVALID_SIZE;
+
+ /* Get from an to indices */
+ const std::vector<Signal::TimeValuePair>& tvpairs = ctrl->signal()->values();
+ for (idx = 0; idx < tvpairs.size(); idx++) {
+ if (tvpairs.at(idx).first >= fromX) {
+ m_fromIdx = idx;
+ break;
+ }
+ }
+ if (idx == tvpairs.size())
+ return ReturnCode::E_INVALID_BOUNDS;
+ for (;idx < tvpairs.size(); idx++) {
+ if (tvpairs.at(idx).first >= toX) {
+ m_toIdx = idx;
+ break;
+ }
+ }
+ if (idx == tvpairs.size())
+ m_toIdx = idx - 1;
+
+
+ //m_data = ctrl->generateDrawData(m_fromIdx, m_toIdx);
+ if (m_data == nullptr)
+ return ReturnCode::E_NULL_DATA;
+
+ return ReturnCode::SUCCESS;
+}
--- /dev/null
+#ifndef GRAPHTOIMAGEEXPORTER_H
+#define GRAPHTOIMAGEEXPORTER_H
+
+#include "signalcontroller.h"
+#include <QtCore/QObject>
+#include <QtGui/QImageWriter>
+
+class GraphToImageExporter : public QObject
+{
+ Q_OBJECT
+public:
+ enum class ReturnCode {
+ SUCCESS,
+ E_INVALID_BOUNDS,
+ E_INVALID_FORMAT,
+ E_INVALID_FILENAME,
+ E_NULL_CONTROLLER,
+ E_INVALID_SIZE,
+ E_NULL_DATA
+ };
+
+ explicit GraphToImageExporter(QObject* parent = nullptr);
+ ReturnCode setParameters(const double fromX, const double fromY, const double toX, const double toY, const int width, const int height,
+ const QByteArray format, const QString& filename, const std::shared_ptr<SignalController> ctrl);
+ QList<QByteArray> supportedImageFormats();
+
+private:
+ const std::shared_ptr<SignalController> m_ctrl;
+ double* m_data;
+ QString m_filename;
+ double m_fromIdx;
+ double m_fromY;
+ double m_toIdx;
+ double m_toY;
+ int m_height;
+ int m_width;
+ QImageWriter m_writer;
+
+signals:
+
+public slots:
+
+};
+
+#endif // GRAPHTOIMAGEEXPORTER_H
double fromY() const;
QString imageFormat() const;
int imageHeight() const;
+ bool includePeaks() const;
QString path() const;
QString selectedSignal() const;
double toX() const;
</item>
</layout>
</item>
+ <item>
+ <widget class="QCheckBox" name="qck_includeInteg">
+ <property name="text">
+ <string>Include integrated peaks</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="Line" name="line">
<property name="orientation">
*/
#include "gui/graphview.h"
+#include "logger.h"
#include <QtGui/QPainter>
#include <QDebug>
-GraphView::GraphView(QWidget* parent) :
- QWidget(parent),
- m_ctxMenuOpen(false),
- m_backbuffer(nullptr),
- m_plainGraph(nullptr),
+const double GraphView::DEFAULT_Y_MARGIN = 0.05;
+const QString GraphView::ME_SENDER_STR("GraphView");
+
+GraphView::GraphView(std::shared_ptr<SignalController> controller, QWidget* parent) :
+ QWidget(parent), SignalDrawer(controller),
m_mouseMode(GraphView::MouseMode::CROSSHAIR),
- m_drawData(nullptr),
- m_graphCrosshairX(-1),
- m_graphCrosshairY(-1)
+ m_graphCrosshairXPix(-1),
+ m_graphCrosshairYPix(-1)
{
- m_graphDrawer = std::unique_ptr<GraphDrawer>(new GraphDrawer);
+ setDefaultZoom();
setMouseTracking(true);
setCursor(Qt::BlankCursor);
+
+ connect(&m_ctxMenu, SIGNAL(deletePeak(QPoint)), this, SLOT(onCtxMenuDeletePeak(QPoint)));
+ connect(&m_ctxMenu, SIGNAL(zoomOut()), this, SLOT(onCtxMenuZoomOut()));
}
-/* Public functions */
+/** Public methods **/
+
+bool GraphView::refresh(QRegion reg)
+{
+ bool ret = draw(m_relXMin, m_relYMin, m_relXMax, m_relYMax);
+ if (ret) {
+ if (reg.isEmpty())
+ update();
+ else
+ update(reg);
+ } else
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " unable to draw pixmap");
+
+ return ret;
+}
void GraphView::mouseDoubleClickEvent(QMouseEvent* ev)
{
case Qt::LeftButton:
break;
case Qt::RightButton:
- break;
default:
break;
}
void GraphView::mouseMoveEvent(QMouseEvent* ev)
{
+ const int xPix = ev->x();
+ const int yPix = ev->y();
+
switch (m_mouseMode) {
case GraphView::MouseMode::CROSSHAIR:
- this->drawCrosshair(ev->x(), ev->y());
+ drawCrosshair(xPix, yPix);
break;
case GraphView::MouseMode::ZOOM:
- this->drawZoomRect(ev->x(), ev->y());
+ drawZoomRect(xPix, yPix);
break;
case GraphView::MouseMode::INTEGRATE:
- this->drawIntegrationBaseline(ev->x(), ev->y());
+ drawIntegrationBaseline(xPix, yPix);
break;
}
- emit crosshairMoved(ev->x(), ev->y());
+ updateValuesUnderCrosshair(xPix);
+ emit crosshairMoved(xPix, yPix);
}
void GraphView::mousePressEvent(QMouseEvent* ev)
{
- if (m_ctxMenuOpen)
- return;
-
switch (ev->button()) {
case Qt::LeftButton:
switch (m_mouseMode) {
case GraphView::MouseMode::CROSSHAIR:
if (m_graphCtrlMode == GraphControlModes::ZOOM) {
- m_zoomRectStartX = ev->x();
- m_zoomRectStartY = ev->y();
- m_zoomRectLastX = ev->x();
- m_zoomRectLastY = ev->y();
- this->eraseCrosshair(true);
+ m_zoomRectStartXPix = ev->x();
+ m_zoomRectStartYPix = ev->y();
+ m_zoomRectLastXPix = ev->x();
+ m_zoomRectLastYPix = ev->y();
+ eraseCrosshair(true);
m_mouseMode = GraphView::MouseMode::ZOOM;
} else if (m_graphCtrlMode == GraphControlModes::INTEGRATE) {
- m_integrateStartX = ev->x();
- m_integrateStartY = ev->y();
- m_integrateStopX = ev->x();
- m_integrateStopY = ev->y();
- this->eraseCrosshair(true);
- m_graphCrosshairX = -1;
+ m_integrateStartXPix = ev->x();
+ m_integrateStartYPix = ev->y();
+ m_integrateStopXPix = ev->x();
+ m_integrateStopYPix = ev->y();
+ eraseCrosshair(true);
+ m_graphCrosshairXPix = -1;
m_mouseMode = GraphView::MouseMode::INTEGRATE;
}
break;
case GraphView::MouseMode::ZOOM:
- if (m_zoomRectLastX < m_zoomRectStartX)
- std::swap(m_zoomRectLastX, m_zoomRectStartX);
- if (m_zoomRectLastY < m_zoomRectStartY)
- std::swap(m_zoomRectLastY, m_zoomRectStartY);
- emit zoomed(m_zoomRectStartX, m_zoomRectStartY, m_zoomRectLastX, m_zoomRectLastY);
+ if (m_zoomRectLastXPix < m_zoomRectStartXPix)
+ std::swap(m_zoomRectLastXPix, m_zoomRectStartXPix);
+ if (m_zoomRectLastYPix > m_zoomRectStartYPix)
+ std::swap(m_zoomRectLastYPix, m_zoomRectStartYPix);
+
+ zoom(m_zoomRectStartXPix, m_zoomRectStartYPix, m_zoomRectLastXPix, m_zoomRectLastYPix);
m_mouseMode = GraphView::MouseMode::CROSSHAIR;
break;
case GraphView::MouseMode::INTEGRATE:
- if (m_integrateStartX > m_integrateStopX)
- std::swap(m_integrateStartX, m_integrateStopX);
- emit integrated(m_integrateStartX, m_integrateStartY, m_integrateStopX, m_integrateStopY);
- this->eraseIntegrationBaseline(true);
- m_integrateStartX = -1;
+ if (m_integrateStartXPix > m_integrateStopXPix)
+ std::swap(m_integrateStartXPix, m_integrateStopXPix);
+
+ PeakDrawData pdData = m_controller->integratePeak(xPixToRel(m_integrateStartXPix), yPixToRel(m_integrateStartYPix),
+ xPixToRel(m_integrateStopXPix), yPixToRel(m_integrateStopYPix));
+ eraseIntegrationBaseline(true);
+ update(renderPeak(pdData));
+ m_integrateStartXPix = -1;
m_mouseMode = GraphView::MouseMode::CROSSHAIR;
break;
}
+
break;
case Qt::RightButton:
switch (m_mouseMode) {
case GraphView::MouseMode::CROSSHAIR:
- m_ctxMenuOpen = true;
- this->eraseCrosshair(true);
- emit showContextMenuReq(ev->x(), ev->y(), ev->globalPos());
+ eraseCrosshair(true);
+ showContextMenu(ev->pos(), ev->globalPos());
break;
case GraphView::MouseMode::ZOOM:
- this->eraseZoomRect(true);
+ eraseZoomRect(true);
m_mouseMode = GraphView::MouseMode::CROSSHAIR;
break;
case GraphView::MouseMode::INTEGRATE:
- this->eraseIntegrationBaseline(true);
+ eraseIntegrationBaseline(true);
+ m_integrateStartXPix = -1;
m_mouseMode = GraphView::MouseMode::CROSSHAIR;
break;
default:
void GraphView::paintEvent(QPaintEvent* ev)
{
QPainter p(this);
- if (m_backbuffer != nullptr)
- p.drawPixmap(0, 0, width(), height(), *m_backbuffer);
+ if (m_pixmap != nullptr)
+ p.drawPixmap(0, 0, dwidth(), dheight(), *m_pixmap);
}
void GraphView::resizeEvent(QResizeEvent* ev)
{
- if (ev->size().width() > 1 && ev->size().height() > 1) {
- emit resized(ev->size().width(), ev->size().height());
- emit redrawNeeded();
+ if (setDimensions(ev->size().width(), ev->size().height())) {
+ draw(m_relXMin, m_relYMin, m_relXMax, m_relYMax);
+ emit resized(dwidth(), dheight());
}
}
-/* Private functions */
+/** Private methods **/
-void GraphView::drawCrosshair(const int x, const int y)
+void GraphView::drawCrosshair(const int xPix, const int yPix)
{
QPainter p;
- int w, h;
- if (m_backbuffer == nullptr) {
- qDebug() << "NPTR";
+ if (m_pixmap == nullptr) {
+ //qDebug() << "NPTR";
return;
}
- w = this->width();
- h = this->height();
-
QRegion reg = eraseCrosshair();
- p.begin(m_backbuffer);
+ p.begin(m_pixmap);
p.setPen(Qt::black);
/* Draw new crosshair */
- p.drawLine(0, y, w, y); /* Horizontal */
- p.drawLine(x, 0, x, h); /* Vertical */
+ p.drawLine(0, yPix, dwidth(), yPix); /* Horizontal */
+ p.drawLine(xPix, 0, xPix, dheight()); /* Vertical */
p.end();
/* New lines */
- reg += QRect(0, y, w, 1);
- reg += QRect(x, 0, 1, h);
+ reg += QRect(0, yPix, width(), 1);
+ reg += QRect(xPix, 0, 1, height());
- m_graphCrosshairX = x;
- m_graphCrosshairY = y;
+ m_graphCrosshairXPix = xPix;
+ m_graphCrosshairYPix = yPix;
update(reg);
}
{
QPainter p;
QRegion reg;
- int w = this->width();
- int h = this->height();
int lstartX, lstartY, lstopX, lstopY;
- if (m_backbuffer == nullptr)
+ if (m_pixmap == nullptr)
return;
reg = eraseIntegrationBaseline();
- if (m_integrateStartX > m_integrateStopX) {
- lstartX = (m_integrateStopX > 1) ? m_integrateStopX - 1 : 0;
- lstopX = (m_integrateStartX < w-1) ? m_integrateStartX + 1 : w-1;
+ if (m_integrateStartXPix > m_integrateStopXPix) {
+ lstartX = (m_integrateStopXPix > 1) ? m_integrateStopXPix - 1 : 0;
+ lstopX = (m_integrateStartXPix < dwidth()-1) ? m_integrateStartXPix + 1 : dwidth()-1;
} else {
- lstartX = (m_integrateStartX > 1) ? m_integrateStartX -1 : 0;
- lstopX = (m_integrateStopX < w-1) ? m_integrateStopX + 1 : w-1;
+ lstartX = (m_integrateStartXPix > 1) ? m_integrateStartXPix -1 : 0;
+ lstopX = (m_integrateStopXPix < dwidth()-1) ? m_integrateStopXPix + 1 : dwidth()-1;
}
- if (m_integrateStartY > m_integrateStopY) {
- lstartY = (m_integrateStopY > 1) ? m_integrateStopY - 1 : 0;
- lstopY = (m_integrateStartY < h-1) ? m_integrateStartY + 1 : h-1;
+ if (m_integrateStartYPix > m_integrateStopYPix) {
+ lstartY = (m_integrateStopYPix > 1) ? m_integrateStopYPix - 1 : 0;
+ lstopY = (m_integrateStartYPix < dheight()-1) ? m_integrateStartYPix + 1 : dheight()-1;
} else {
- lstartY = (m_integrateStartY > 1) ? m_integrateStartY - 1 : 0;
- lstopY = (m_integrateStopY < h-1) ? m_integrateStopY + 1 : h-1;
+ lstartY = (m_integrateStartYPix > 1) ? m_integrateStartYPix - 1 : 0;
+ lstopY = (m_integrateStopYPix < dheight()-1) ? m_integrateStopYPix + 1 : dheight()-1;
}
- p.begin(m_backbuffer);
+ p.begin(m_pixmap);
/* Draw new line */
p.setPen(Qt::black);
- p.drawLine(m_integrateStartX, m_integrateStartY, x, y);
+ p.drawLine(m_integrateStartXPix, m_integrateStartYPix, x, y);
p.end();
reg += QRect(lstartX, lstartY, lstopX, lstopY);
- m_integrateStopX = x;
- m_integrateStopY = y;
+ m_integrateStopXPix = x;
+ m_integrateStopYPix = y;
update(reg);
}
-
-void GraphView::drawGraph()
-{
- int w = this->width();
- int h = this->height();
- QPixmap* fresh = m_graphDrawer->drawGraph(m_drawData, m_drawDataLen, w, h, m_drawDataMin, m_drawDataMax);
- if (fresh == nullptr)
- return;
-
- if (m_backbuffer != nullptr)
- delete m_backbuffer;
- m_backbuffer = fresh;
- if (m_plainGraph != nullptr)
- delete m_plainGraph;
- m_plainGraph = new QPixmap(*m_backbuffer);
-}
-
void GraphView::drawZoomRect(const int x, const int y)
{
QPainter p;
QRegion reg;
int lstartX, lstartY, lstopX, lstopY;
- if (m_backbuffer == nullptr)
+ if (m_pixmap == nullptr)
return;
- if (x < m_zoomRectStartX) {
+ if (x < m_zoomRectStartXPix) {
lstartX = x;
- lstopX = m_zoomRectStartX;
+ lstopX = m_zoomRectStartXPix;
} else {
- lstartX = m_zoomRectStartX;
+ lstartX = m_zoomRectStartXPix;
lstopX = x;
}
- if (y < m_zoomRectStartY) {
+ if (y < m_zoomRectStartYPix) {
lstartY = y;
- lstopY = m_zoomRectStartY;
+ lstopY = m_zoomRectStartYPix;
} else {
- lstartY = m_zoomRectStartY;
+ lstartY = m_zoomRectStartYPix;
lstopY = y;
}
reg = eraseZoomRect();
- p.begin(m_backbuffer);
+ p.begin(m_pixmap);
p.setPen(Qt::green);
// Top line
p.drawLine(lstartX, lstartY, lstopX, lstartY);
reg += QRect(lstopX, lstartY, 1, lstopY - lstartY + 1); //Right line;
reg += QRect(lstartX, lstopY, lstopX - lstartX, 1); // Bottom line
- m_zoomRectLastX = x;
- m_zoomRectLastY = y;
+ m_zoomRectLastXPix = x;
+ m_zoomRectLastYPix = y;
update(reg);
}
-QRegion GraphView::eraseCrosshair(bool apply)
+QRegion GraphView::eraseCrosshair(const bool apply)
{
QPainter p;
- int w, h;
- if (m_backbuffer == nullptr)
+ if (m_pixmap == nullptr)
return QRegion();
- w = this->width();
- h = this->height();
-
- if (m_graphCrosshairX != -1 || m_graphCrosshairY != -1) {
+ if (m_graphCrosshairXPix != -1 || m_graphCrosshairYPix != -1) {
QRegion reg;
- p.begin(m_backbuffer);
- p.drawPixmap(m_graphCrosshairX, 0, *m_plainGraph, m_graphCrosshairX, 0, 1, h);
- p.drawPixmap(0, m_graphCrosshairY, *m_plainGraph, 0, m_graphCrosshairY, w, 1);
+ p.begin(m_pixmap);
+ p.drawPixmap(m_graphCrosshairXPix, 0, *m_background, m_graphCrosshairXPix, 0, 1, dheight());
+ p.drawPixmap(0, m_graphCrosshairYPix, *m_background, 0, m_graphCrosshairYPix, dwidth(), 1);
p.end();
- reg = QRect(0, m_graphCrosshairY, w, 1);
- reg += QRect(m_graphCrosshairX, 0, 1, h);
+ reg = QRect(0, m_graphCrosshairYPix, dwidth(), 1);
+ reg += QRect(m_graphCrosshairXPix, 0, 1, dheight());
if (apply)
update(reg);
QPainter p;
QRegion reg;
int lstartX, lstartY, lstopX, lstopY;
- int w, h;
- if (m_backbuffer == nullptr)
+ if (m_pixmap == nullptr)
return QRegion();
- if (m_integrateStartX < 0)
+ if (m_integrateStartXPix < 0)
return QRegion();
- w = this->width();
- h = this->height();
-
- p.begin(m_backbuffer);
- if (m_integrateStartX > m_integrateStopX) {
- lstartX = (m_integrateStopX > 1) ? m_integrateStopX - 1 : 0;
- lstopX = (m_integrateStartX < w-1) ? m_integrateStartX + 1 : w-1;
+ p.begin(m_pixmap);
+ if (m_integrateStartXPix > m_integrateStopXPix) {
+ lstartX = (m_integrateStopXPix > 1) ? m_integrateStopXPix - 1 : 0;
+ lstopX = (m_integrateStartXPix < dwidth()-1) ? m_integrateStartXPix + 1 : dwidth()-1;
} else {
- lstartX = (m_integrateStartX > 1) ? m_integrateStartX -1 : 0;
- lstopX = (m_integrateStopX < w-1) ? m_integrateStopX + 1 : w-1;
+ lstartX = (m_integrateStartXPix > 1) ? m_integrateStartXPix -1 : 0;
+ lstopX = (m_integrateStopXPix < dwidth()-1) ? m_integrateStopXPix + 1 : dwidth()-1;
}
- if (m_integrateStartY > m_integrateStopY) {
- lstartY = (m_integrateStopY > 1) ? m_integrateStopY - 1 : 0;
- lstopY = (m_integrateStartY < h-1) ? m_integrateStartY + 1 : h-1;
+ if (m_integrateStartYPix > m_integrateStopYPix) {
+ lstartY = (m_integrateStopYPix > 1) ? m_integrateStopYPix - 1 : 0;
+ lstopY = (m_integrateStartYPix < dheight()-1) ? m_integrateStartYPix + 1 : dheight()-1;
} else {
- lstartY = (m_integrateStartY > 1) ? m_integrateStartY - 1 : 0;
- lstopY = (m_integrateStopY < h-1) ? m_integrateStopY + 1 : h-1;
+ lstartY = (m_integrateStartYPix > 1) ? m_integrateStartYPix - 1 : 0;
+ lstopY = (m_integrateStopYPix < dheight()-1) ? m_integrateStopYPix + 1 : dheight()-1;
}
- p.drawPixmap(lstartX, lstartY, *m_plainGraph, lstartX, lstartY, lstopX - lstartX+1, lstopY - lstartY+1); //FIXME: +1 should not be needed!
+ p.drawPixmap(lstartX, lstartY, *m_background, lstartX, lstartY, lstopX - lstartX+1, lstopY - lstartY+1); //FIXME: +1 should not be needed!
p.end();
reg = QRect(lstartX, lstartY, lstopX - lstartX +1, lstopY - lstartY + 1);
return reg;
}
-QRegion GraphView::eraseZoomRect(bool apply)
+QRegion GraphView::eraseZoomRect(const bool apply)
{
int lstartX, lstartY, lstopX, lstopY;
QPainter p;
QRegion reg;
- if (m_backbuffer == nullptr)
+ if (m_pixmap == nullptr)
return QRegion();
- if (m_zoomRectLastX < m_zoomRectStartX) {
- lstartX = m_zoomRectLastX;
- lstopX = m_zoomRectStartX;
+ if (m_zoomRectLastXPix < m_zoomRectStartXPix) {
+ lstartX = m_zoomRectLastXPix;
+ lstopX = m_zoomRectStartXPix;
} else {
- lstartX = m_zoomRectStartX;
- lstopX = m_zoomRectLastX;
+ lstartX = m_zoomRectStartXPix;
+ lstopX = m_zoomRectLastXPix;
}
- if (m_zoomRectLastY < m_zoomRectStartY) {
- lstartY = m_zoomRectLastY;
- lstopY = m_zoomRectStartY;
+ if (m_zoomRectLastYPix < m_zoomRectStartYPix) {
+ lstartY = m_zoomRectLastYPix;
+ lstopY = m_zoomRectStartYPix;
} else {
- lstartY = m_zoomRectStartY;
- lstopY = m_zoomRectLastY;
+ lstartY = m_zoomRectStartYPix;
+ lstopY = m_zoomRectLastYPix;
}
/* Erase any existing lines */
- p.begin(m_backbuffer);
+ p.begin(m_pixmap);
// TODO: It might not be necessary to erase all lines every time - OPTIMIZE THIS !!!
// Top line
- p.drawPixmap(lstartX, lstartY, *m_plainGraph, lstartX, lstartY, lstopX - lstartX, 1);
+ p.drawPixmap(lstartX, lstartY, *m_background, lstartX, lstartY, lstopX - lstartX, 1);
// Left line
- p.drawPixmap(lstartX, lstartY, *m_plainGraph, lstartX, lstartY, 1, lstopY - lstartY);
+ p.drawPixmap(lstartX, lstartY, *m_background, lstartX, lstartY, 1, lstopY - lstartY);
// Right line
- p.drawPixmap(lstopX, lstartY, *m_plainGraph, lstopX, lstartY, 1, lstopY - lstartY + 1);
+ p.drawPixmap(lstopX, lstartY, *m_background, lstopX, lstartY, 1, lstopY - lstartY + 1);
// Bottom line
- p.drawPixmap(lstartX, lstopY, *m_plainGraph, lstartX, lstopY, lstopX - lstartX + 1, 1);
+ p.drawPixmap(lstartX, lstopY, *m_background, lstartX, lstopY, lstopX - lstartX + 1, 1);
p.end();
reg = QRect(lstartX, lstartY, lstopX - lstartX, 1); // Top line
return reg;
}
-/* Public slots */
-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)
+void GraphView::showContextMenu(const QPoint& pos, const QPoint& globalPos)
+{
+ m_ctxMenu.setRelPixPos(pos);
+ m_ctxMenu.exec(globalPos);
+}
+
+void GraphView::updateValuesUnderCrosshair(const int xPix)
+{
+ double x = xPixToRel(xPix);
+ Signal::TimeValuePair tvp = m_controller->getXYValues(x);
+
+ emit crosshairValuesUpdated(tvp.first, tvp.second);
+}
+
+void GraphView::unzoom()
{
- int w = this->width();
- int h = this->height();
- double xStep = static_cast<double>(w) / m_drawDataLen;
- double yStep = static_cast<double>(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);
+ setDefaultZoom();
+ if (draw(m_relXMin, m_relYMin, m_relXMax, m_relYMax))
update();
- }
+ else
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " unable to draw pixmap");
}
-void GraphView::onUpdateGraph(double* data, size_t len, double min, double max)
+void GraphView::setDefaultZoom()
{
- if (m_drawData != nullptr)
- delete[] m_drawData;
+ double range = SignalController::RELATIVE_MAX - SignalController::RELATIVE_MIN;
- m_drawData = data;
- m_drawDataLen = len;
- m_drawDataMax = max;
- m_drawDataMin = min;
+ m_relXMax = SignalController::RELATIVE_MAX;
+ m_relXMin = SignalController::RELATIVE_MIN;
+ m_relYMax = SignalController::RELATIVE_MAX + (range * DEFAULT_Y_MARGIN);
+ m_relYMin = SignalController::RELATIVE_MIN - (range * DEFAULT_Y_MARGIN);
+}
- this->drawGraph();
- this->update();
+void GraphView::zoom(const int fromXPix, const int fromYPix, const int toXPix, const int toYPix)
+{
+ bool ret = draw(xPixToRel(fromXPix), yPixToRel(fromYPix), xPixToRel(toXPix), yPixToRel(toYPix));
+ if (ret)
+ update();
+ else
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " unable to draw pixmap");
}
-GraphView::~GraphView()
+/** Private slots **/
+void GraphView::onCtxMenuDeletePeak(const QPoint pixPos)
{
- if (m_backbuffer != nullptr)
- delete m_backbuffer;
- if (m_plainGraph != nullptr)
- delete m_plainGraph;
- if (m_drawData != nullptr)
- delete[] m_drawData;
+ const PeakDrawData pdData = m_controller->deletePeak(xPixToRel(pixPos.x()));
+ QRegion reg = erasePeak(pdData);
+ refresh(reg);
}
+
+void GraphView::onCtxMenuZoomOut()
+{
+ unzoom();
+}
+
+/* Public slots */
#ifndef GRAPHVIEW_H
#define GRAPHVIEW_H
-#include <QtGui/QMouseEvent>
-#include <QtWidgets/QWidget>
-#include "graphdrawer.h"
+#include "gui/graphviewcontextmenu.h"
+#include "signaldrawer.h"
#include "mathhelpers.h"
#include "metatypes.h"
+#include <QtGui/QMouseEvent>
+#include <QtWidgets/QWidget>
-class GraphView : public QWidget
+class GraphView : public QWidget, protected SignalDrawer
{
Q_OBJECT
public:
INTEGRATE
};
- explicit GraphView(QWidget* parent = nullptr);
- ~GraphView();
+ explicit GraphView(std::shared_ptr<SignalController> controller, QWidget* parent = nullptr);
void leaveEvent(QEvent* );
void mouseDoubleClickEvent(QMouseEvent* );
void mouseMoveEvent(QMouseEvent* ev);
void mousePressEvent(QMouseEvent* ev);
void paintEvent(QPaintEvent* ev);
+ bool refresh(QRegion reg = QRegion());
private:
- void drawCrosshair(const int x, const int y);
- void drawGraph();
+ void drawCrosshair(const int xPix, const int yPix);
void drawIntegrationBaseline(const int x, const int y);
void drawZoomRect(const int x, const int y);
- QRegion eraseCrosshair(bool apply = false);
- QRegion eraseIntegrationBaseline(bool apply = false);
- QRegion eraseZoomRect(bool apply = false);
-
+ QRegion eraseCrosshair(const bool apply = false);
+ QRegion eraseIntegrationBaseline(const bool apply = false);
+ QRegion eraseZoomRect(const bool apply = false);
void resizeEvent(QResizeEvent* ev);
+ void unzoom();
+ void updateValuesUnderCrosshair(const int xPix);
+ void setDefaultZoom();
+ void showContextMenu(const QPoint& pos, const QPoint& globalPos);
+ void zoom(const int fromXPix, const int fromYPix, const int toXPix, const int toYPix);
- std::unique_ptr<GraphDrawer> m_graphDrawer;
- bool m_ctxMenuOpen;
- QPixmap* m_backbuffer;
- QPixmap* m_plainGraph;
+ GraphViewContextMenu m_ctxMenu;
MouseMode m_mouseMode;
GraphControlModes m_graphCtrlMode;
- double* m_drawData;
- size_t m_drawDataLen;
- double m_drawDataMax;
- double m_drawDataMin;
/* Crosshair */
- int m_graphCrosshairX;
- int m_graphCrosshairY;
+ int m_graphCrosshairXPix;
+ int m_graphCrosshairYPix;
/* Integration baseline */
- int m_integrateStartX;
- int m_integrateStartY;
- int m_integrateStopX;
- int m_integrateStopY;
+ int m_integrateStartXPix;
+ int m_integrateStartYPix;
+ int m_integrateStopXPix;
+ int m_integrateStopYPix;
/* Zooming rectangle */
- int m_zoomRectStartX;
- int m_zoomRectStartY;
- int m_zoomRectLastX;
- int m_zoomRectLastY;
+ int m_zoomRectStartXPix;
+ int m_zoomRectStartYPix;
+ int m_zoomRectLastXPix;
+ int m_zoomRectLastYPix;
+
+ static const double DEFAULT_Y_MARGIN;
+ static const QString ME_SENDER_STR;
+
+private slots:
+ void onCtxMenuDeletePeak(const QPoint pixPos);
+ void onCtxMenuZoomOut();
public slots:
void onControlModeChanged(GraphControlModes mode) { m_graphCtrlMode = mode; }
- void onCtxMenuClosed() { m_ctxMenuOpen = false; }
- void 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);
- void onUpdateGraph(double* data, size_t len, double min, double max);
signals:
+ void crosshairValuesUpdated(const double time, const double value);
void crosshairErased();
void crosshairMoved(const int x, const int y);
- void integrated(const int fromX, const int fromY, const int toX, const int toY);
void mouseCursorLeft();
- void redrawNeeded();
void resized(const int x, const int y);
- void showContextMenuReq(const int x, const int y, const QPoint& globalPos);
void zoomed(const int fromX, const int fromY, const int toX, const int toY);
};
m_acZoomOut = addAction("Zoom out");
addSeparator();
m_acDeletePeak = addAction("Delete peak");
+
+ connect(m_acDeletePeak, SIGNAL(triggered()), this, SLOT(onDeletePeakTriggered()));
+ connect(m_acZoomOut, SIGNAL(triggered()), this, SLOT(onZoomOutTriggered()));
+}
+
+void GraphViewContextMenu::onDeletePeakTriggered()
+{
+ emit deletePeak(m_relPixPos);
+}
+
+void GraphViewContextMenu::onZoomOutTriggered()
+{
+ emit zoomOut();
}
Q_OBJECT
public:
explicit GraphViewContextMenu(QWidget* parent = nullptr);
+ void setRelPixPos(const QPoint& relPixPos) { m_relPixPos = relPixPos; }
+private:
QAction* m_acDeletePeak;
QAction* m_acZoomOut;
-private:
+ QPoint m_relPixPos;
-signals:
+ static const QString ME_SENDER_STR;
-public slots:
+private slots:
+ void onDeletePeakTriggered();
+ void onZoomOutTriggered();
+
+signals:
+ void deletePeak(const QPoint pos);
+ void zoomOut();
};
//#include <QDebug>
-SignalView::SignalView(QWidget* parent) :
+SignalView::SignalView(std::shared_ptr<SignalController> controller, QWidget* parent) :
QWidget(parent),
+ m_controller(controller),
ui(new Ui::SignalView)
{
ui->setupUi(this);
- m_graphView = new GraphView(this);
+ m_graphView = new GraphView(controller, this);
ui->qw_container->setLayout(new QVBoxLayout());
ui->qw_container->layout()->addWidget(m_graphView);
+
+ connect(m_graphView, SIGNAL(crosshairValuesUpdated(double,double)), this, SLOT(onUpdateCrosshairValues(double,double)));
+ connect(m_graphView, SIGNAL(mouseCursorLeft()), this, SLOT(onRemoveCurrentValues()));
}
/* Public functions */
ui->ql_yUnits->setText(text);
}
-void SignalView::onUpdateCurrentValues(double x, double y)
+void SignalView::onUpdateCrosshairValues(const double time, const double value)
{
QLocale l = QLocale::system();
- ui->qle_xValue->setText(l.toString(x));
- ui->qle_yValue->setText(l.toString(y));
+ ui->qle_xValue->setText(l.toString(time));
+ ui->qle_yValue->setText(l.toString(value));
}
void SignalView::onRemoveCurrentValues()
{
Q_OBJECT
public:
- explicit SignalView(QWidget* parent = nullptr);
+ explicit SignalView(std::shared_ptr<SignalController> controller, QWidget* parent = nullptr);
~SignalView();
void mouseDoubleClickEvent(QMouseEvent* ev);
void setDataTableModel(SignalDataTableModel* model);
GraphView* m_graphView;
private:
+ std::shared_ptr<SignalController> m_controller;
Ui::SignalView* ui;
public slots:
- void onUpdateCurrentValues(double x, double y);
+ void onUpdateCrosshairValues(const double time, const double value);
void onRemoveCurrentValues();
private slots:
--- /dev/null
+#include "imagedrawer.h"
+
+#include <QDebug>
+
+ImageDrawer::ImageDrawer(const int width, const int height, QObject* parent) :
+ QObject(parent),
+ m_height(height),
+ m_width(width)
+{
+}
+
+void ImageDrawer::onUpdateGraph(double* data, size_t len, double min, double max)
+{
+ if (data == nullptr)
+ return;
+ m_drawDataMin = min;
+ m_drawDataMax = max;
+
+ //m_pixmap = m_graphDrawer->drawGraph(data, len, m_width, m_height, min, max);
+}
+
+void ImageDrawer::onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakStartX, const double peakStartY,
+ const QString& time, const QString& area)
+{
+ double xStep = static_cast<double>(m_width);
+ double yStep = static_cast<double>(m_height) / (m_drawDataMax - m_drawDataMin);
+ int startX = floor(fromX * xStep + 0.5);
+ int stopX = floor(toX * xStep + 0.5);
+ int startY = floor((m_height - yStep * (fromY - m_drawDataMin)) + 0.5);
+ int stopY = floor((m_height - yStep * (toY - m_drawDataMin)) + 0.5);
+ int peakX = floor(peakStartX * xStep + 0.5);
+ int peakY = floor(m_height - yStep * (peakStartY - m_drawDataMin) + 0.5);
+
+ if (m_pixmap == nullptr)
+ return;
+
+ qDebug() << "drawing peak";
+
+ //m_graphDrawer->overlayIntegratedPeak(m_pixmap, startX, startY, stopX, stopY, peakX, peakY, time, area);
+}
--- /dev/null
+#ifndef IMAGEDRAWER_H
+#define IMAGEDRAWER_H
+
+#include <QtCore/QObject>
+
+class ImageDrawer : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ImageDrawer(const int width, const int height, QObject* parent = nullptr);
+ const QPixmap* pixmap() const { return m_pixmap; }
+
+private:
+ QPixmap* m_pixmap;
+ int m_drawDataMin;
+ int m_drawDataMax;
+
+ const int m_height;
+ const int m_width;
+
+signals:
+
+public slots:
+ void onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakStartX, const double peakStartY,
+ const QString& time, const QString& area);
+ void onUpdateGraph(double* data, size_t len, double min, double max);
+
+};
+
+#endif // IMAGEDRAWER_H
#include "integrator.h"
#include "logger.h"
+#include <QDebug>
+
const QString Integrator::ME_SENDER_STR("Integrator");
Integrator::Integrator(std::shared_ptr<Signal> signal, QObject* parent) :
m_signal(signal)
{}
-Integrator::ReturnCode Integrator::deletePeak(size_t idx)
+std::shared_ptr<IntegratedPeak> Integrator::deletePeak(size_t idx)
{
+ std::shared_ptr<IntegratedPeak> peak;
std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::iterator it = m_peaks.begin();
+
while (it != m_peaks.end() && it->first <= idx) {
if (it->first <= idx && it->second->toIdx() > idx) { /* Peak is surrounding the cursor */
+ peak = it->second;
m_peaks.erase(it);
- return ReturnCode::SUCCESS;
+ return peak;
}
it++;
}
- return ReturnCode::E_NO_PEAK;
+ return nullptr;
}
Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak)
return ReturnCode::E_INVAL;
}
+ qDebug() << "INTEG" << startIdx << stopIdx << startY << stopY;
+
slope = (stopY - startY) / (stopIdx - startIdx);
/* Try to find first intersection */
if (startY < m_signal->valueAt(startIdx)) {
expectDownward = true;
- //qDebug() << "Expecting downward peak";
+ qDebug() << "Expecting downward peak";
} else {
expectDownward = false;
- //qDebug() << "Expecting upward peak";
+ qDebug() << "Expecting upward peak";
}
for (i = startIdx; i <= stopIdx; i++) {
double value = m_signal->valueAt(i);
};
explicit Integrator(std::shared_ptr<Signal> signal, QObject* parent = nullptr);
- ReturnCode deletePeak(size_t idx);
+ std::shared_ptr<IntegratedPeak> deletePeak(size_t idx);
ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak);
const std::shared_ptr<IntegratedPeak> peakByIdx(const int idx) const;
std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); }
#include <QtCore/QObject>
#include <QtCore/QDateTime>
+#define __QFUNC__ QString(__func__) + QString("()")
+
class LocalLogger;
typedef std::shared_ptr<LocalLogger> LocalLoggerPtr;
explicit Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, const uint16_t wavelengthAbs,
const uint16_t wavelengthRef, const std::vector<TimeValuePair>& values, QObject* parent = nullptr);
+ uint count() const { return m_values.size(); }
std::string descriptiveName() const;
Equipment equipment() const { return m_equipment; }
std::vector<TimeValuePair>::const_iterator iteratorFrom(const size_t idx) const;
double samplingRate() const { return m_samplingRate; }
double valueAt(const size_t idx) const;
const std::vector<TimeValuePair>& values() const { return m_values; }
- std::vector<TimeValuePair>::const_iterator valuesBegin() const { return m_values.begin(); }
+ std::vector<TimeValuePair>::const_iterator pairsBegin() const { return m_values.cbegin(); }
size_t valuesCount() const { return m_values.size(); }
- std::vector<TimeValuePair>::const_iterator valuesEnd() const { return m_values.end(); }
+ std::vector<TimeValuePair>::const_iterator pairsEnd() const { return m_values.cend(); }
uint16_t wavelengthAbsorbed() const { return m_wavelengthAbs; }
uint16_t wavelengthReference() const { return m_wavelengthRef; }
XUnit xunit() const { return m_xunit; }
#include <QDebug>
+const double SignalController::RELATIVE_MAX = 100.0;
+const double SignalController::RELATIVE_MIN = 0.0;
const QString SignalController::ME_SENDER_STR("SignalController");
SignalController::SignalController(std::shared_ptr<Signal> signal, QObject* parent) :
m_integrator = std::shared_ptr<Integrator>(new Integrator(signal));
m_integTblModel = new IntegrationTableModel(m_integrator);
m_dtblModel = new SignalDataTableModel(signal);
-
- m_yMin = m_signal->minimum() - m_signal->minimum()*0.05;
- m_yMax = m_signal->maximum() + m_signal->maximum()*0.05;
- m_fromIdx = 0; m_toIdx = m_signal->valuesCount()-1;
-
- connect(m_ctxMenu.m_acZoomOut, SIGNAL(triggered()), this, SLOT(onCtxMenuUnzoom()));
- connect(m_ctxMenu.m_acDeletePeak, SIGNAL(triggered()), this, SLOT(onCtxMenuDeletePeak()));
-}
-
-double SignalController::currentStartX() const
-{
- return m_signal->pairAt(m_fromIdx).first;
}
-double SignalController::currentStartY() const
-{
- return m_yMin;
-}
-
-double SignalController::currentStopX() const
-{
- return m_signal->pairAt(m_toIdx).first;
-}
+/** Public methods **/
-double SignalController::currentStopY() const
+PeakDrawData SignalController::deletePeak(const double x)
{
- return m_yMax;
-}
+ size_t idx = relToIdx(x);
+ std::shared_ptr<IntegratedPeak> peak;
-/* Public methods */
-void SignalController::draw()
-{
- drawGraph();
- drawAllPeaks();
-}
+ if (idx > m_signal->count()-1) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " idx value " + QString::number(idx) + " out of bounds!");
+ return PeakDrawData();
+ }
-/* Private methods */
+ m_integTblModel->prepReset();
+ peak = m_integrator->deletePeak(idx);
-void SignalController::drawAllPeaks()
-{
- std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator cit = m_integrator->peaksCBegin();
- while (cit != m_integrator->peaksCEnd())
- drawIntegratedPeak((cit++)->second);
+ if (peak == nullptr) {
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + " no peak to delete (idx " + QString::number(idx) + ")");
+ m_integTblModel->doneReset();
+ return PeakDrawData();
+ }
+ m_integTblModel->doneReset();
+ return genPeakDrawData(peak);
}
-void SignalController::drawFullGraph()
+std::shared_ptr<GraphDrawData> SignalController::getGraphDrawData(const double fromX, const double toX)
{
- m_yMin = m_signal->minimum() - m_signal->minimum()*0.05;
- m_yMax = m_signal->maximum() + m_signal->maximum()*0.05;
- if (m_signal->valuesCount() < 1)
- return;
- m_fromIdx = 0; m_toIdx = m_signal->valuesCount()-1;
+ size_t fromIdx, toIdx;
+ double* ddata;
+ size_t ddataLen;
- qDebug() << m_yMin << m_yMax;
+ if (toX <= fromX) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " fromX (" + QString::number(fromX) + ") lower than toX (" + QString::number(toX) + ")");
+ return std::shared_ptr<GraphDrawData>(new GraphDrawData());
+ }
- drawGraph();
-}
+ fromIdx = relToIdx(fromX);
+ toIdx = relToIdx(toX);
-void SignalController::drawGraph()
-{
- size_t len = m_toIdx - m_fromIdx;
- double* arr = generateDrawData(m_fromIdx, m_toIdx);
- if (arr != nullptr)
- emit viewDrawGraph(arr, len, m_yMin, m_yMax);
-}
-
-void SignalController::drawIntegratedPeak(const std::shared_ptr<IntegratedPeak> peak)
-{
- int fromX, toX;
- double fromY, toY;
- bool valley;
- QLocale l;
- if (peak->toIdx() < m_fromIdx || peak->fromIdx() > m_toIdx) /* Peak is not in view X-wise, skip it */
- return;
-
- /* Check if the start of the baseline is in view */
- if (peak->fromIdx()-1 >= m_fromIdx) {
- fromX = peak->fromIdx() - m_fromIdx;
- fromY = peak->fromY();
- } else {
- fromX = 0;
- double bls = peak->baselineSlope();
- fromY = bls * (m_fromIdx - peak->fromIdx()) + peak->fromY();
- qDebug() << "Start OOR" << fromY << bls;
+ if (toIdx >= m_signal->count()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " toIdx (" + QString::number(toIdx) + ") out of bounds, max (" +
+ QString::number(m_signal->count()-1) + ") !");
+ return std::shared_ptr<GraphDrawData>(new GraphDrawData());
}
- /* Check if the end of the baseline is in view */
- if (peak->toIdx() <= m_toIdx) {
- toX = peak->toIdx() - m_fromIdx;
- toY = peak->toY();
- } else {
- double bls = peak->baselineSlope();
- toX = m_toIdx - m_fromIdx;
- toY = bls * (m_toIdx - peak->fromIdx()) + peak->fromY();
- qDebug() << "Stop OOR" << toY << bls;
+
+ ddataLen = toIdx - fromIdx + 1;
+ ddata = new double[ddataLen];
+ for (size_t idx = fromIdx; idx <= toIdx; idx++) {
+ double current = valueToRel(m_signal->valueAt(idx));
+ ddata[idx - fromIdx] = current;
}
- /*qDebug("Drawing integration");
- qDebug() << "SX" << fromX << "SY" << fromY << "EX" << toX << "EY" << toY;
- qDebug() << "Slope P" << peak->baselineSlope() << "Slope M" << (toY-fromY)/(toX-fromX);
- qDebug("---");*/
-
- l = QLocale::system();
- const QString peakTime = l.toString(peak->peakTime(), 'f', 4);
- const QString peakArea = QString("A: ") + l.toString(peak->auc(), 'f', 4);
- if (peak->type() == IntegratedPeak::Type::PEAK)
- valley = false;
- else
- valley = true;
- emit viewDrawIntegration(fromX, fromY, toX, toY, peak->peakIdx() - m_fromIdx, m_signal->valueAt(peak->peakIdx()), peakTime, peakArea, valley);
+ return std::shared_ptr<GraphDrawData>(new GraphDrawData(ddata, ddataLen));
}
-double* SignalController::generateDrawData(size_t from, size_t to)
+std::vector<PeakDrawData> SignalController::getPeaksDrawData(const double fromX, const double fromY, const double toX, const double toY)
{
- double* arr;
- size_t len;
+ std::vector<PeakDrawData> peaks;
+ size_t fromIdx, toIdx;
+ std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator cit = m_integrator->peaksCBegin();
- if (from > to) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "From index lower than to index");
- return nullptr;
+ if (toX <= fromX) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " toX is lower than fromX");
+ return peaks;
}
- if (from == to)
- return nullptr;
- if (to >= m_signal->valuesCount() || from >= m_signal->valuesCount()) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid value index");
- return nullptr;
+ if (toY <= fromY) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " toY is lower than fromY");
+ return peaks;
}
- len = to - from;
-
- arr = new double[len];
- for (uint idx = 0; idx < len; idx++)
- arr[idx] = m_signal->valueAt(idx + from);
-
- return arr;
-}
-bool SignalController::updateConstraints(const int fromX, const int fromY, const int toX, const int toY)
-{
- size_t xRange = m_toIdx - m_fromIdx;
- double yRange;
- if (m_viewWidth < 1) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid viewWidth value " + QString::number(m_viewWidth));
- return false;
- }
- if (m_viewHeight < 1) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid viewHeight value " + QString::number(m_viewHeight));
- return false;
- }
- if (fromX > toX) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "fromX > toX");
- return false;
- }
- if (fromY > toY) {
- Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "fromY > toY");
- return false;
+ fromIdx = relToIdx(fromX);
+ toIdx = relToIdx(toX);
+ if (toIdx > m_signal->count()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " toIdx (" + QString::number(toIdx) + ") out of bounds, max (" +
+ QString::number(m_signal->count()-1) + ") !");
+ return peaks;
}
- m_toIdx = (xRange * toX) / m_viewWidth + m_fromIdx;
- m_fromIdx = (xRange * fromX) / m_viewWidth + m_fromIdx;
+ while (cit != m_integrator->peaksCEnd()) {
+ std::shared_ptr<IntegratedPeak> peak = cit->second;
- yRange = m_yMax - m_yMin;
- m_yMin = (yRange * toY / -m_viewHeight) + m_yMax;
- m_yMax = (yRange * fromY / -m_viewHeight) + m_yMax;
+ if (peak->toIdx() < fromIdx || peak->fromIdx() > toIdx) /* Peak is not in view X-wise, skip it */
+ continue;
- //qDebug() << fromX << fromY << toX << toY;
- //qDebug() << m_fromIdx << m_toIdx << m_yMin << m_yMax;
-
- return true;
-}
-
-double SignalController::yValToCoord(double y)
-{
- return m_viewHeight / (m_yMax - m_yMin) * (y - m_yMin);
-}
-
-/* Public slots */
-
-void SignalController::onCtxMenuUnzoom()
-{
- drawFullGraph();
- drawAllPeaks();
-}
-
-void SignalController::onCtxMenuDeletePeak()
-{
- size_t xRange = m_toIdx - m_fromIdx;
- size_t idx = (xRange * m_ctxMenuX) / m_viewWidth + m_fromIdx;
-
- m_integTblModel->prepReset();
- Integrator::ReturnCode ret = m_integrator->deletePeak(idx);
-
- switch (ret) {
- case Integrator::ReturnCode::SUCCESS:
- onViewRedrawNeeded();
- break;
- case Integrator::ReturnCode::E_NO_PEAK:
- Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "No peak to delete.");
- break;
- default:
- break;
+ peaks.push_back(genPeakDrawData(peak));
+ cit++;
}
- m_integTblModel->doneReset();
+ return peaks;
}
-void SignalController::onViewCrosshairErased()
+Signal::TimeValuePair SignalController::getXYValues(const double x)
{
- emit viewRemoveCurrentValues();
-}
-
-void SignalController::onViewCrosshairMoved(const int x, const int y)
-{
- Q_UNUSED(y);
+ size_t idx = relToIdx(x);
+ if (idx >= m_signal->count()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " idx value " + QString::number(idx) + " out of bounds!");
+ return Signal::TimeValuePair(0, 0);
+ }
- size_t xRange = m_toIdx - m_fromIdx;
- int valueIdx = (xRange * x) / m_viewWidth + m_fromIdx;
- Signal::TimeValuePair tvp = m_signal->pairAt(valueIdx);
- emit viewUpdateCurrentValues(tvp.first, tvp.second);
+ return m_signal->pairAt(idx);
}
-void SignalController::onViewIntegrated(const int fromX, const int fromY, const int toX, const int toY)
+PeakDrawData SignalController::integratePeak(const double fromX, const double fromY, const double toX, const double toY)
{
- size_t xRange = m_toIdx - m_fromIdx;
- size_t startIdx = (xRange * fromX) / m_viewWidth + m_fromIdx;
- size_t stopIdx = (xRange * toX) / m_viewWidth + m_fromIdx;
- double yRange = m_yMax - m_yMin;
- double blStartY = (yRange * (m_viewHeight - fromY) / m_viewHeight) + m_yMin;
- double blStopY = (yRange * (m_viewHeight - toY) / m_viewHeight) + m_yMin;
+ size_t fromIdx, toIdx;
+ double fromVal, toVal;
Integrator::ReturnCode ret;
std::shared_ptr<IntegratedPeak> peak;
+ fromIdx = relToIdx(fromX);
+ toIdx = relToIdx(toX);
+ if (fromIdx >= m_signal->count()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " fromIdx (" + QString::number(fromIdx) + ") out of bounds!");
+ return PeakDrawData();
+ }
+ if (toIdx >= m_signal->count()) {
+ Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " toIdx (" + QString::number(toIdx) + ") out of bounds!");
+ return PeakDrawData();
+ }
+ fromVal = relToValue(fromY);
+ toVal = relToValue(toY);
+
m_integTblModel->prepReset();
- ret = m_integrator->integrate(startIdx, stopIdx, blStartY, blStopY, peak);
+ ret = m_integrator->integrate(fromIdx, toIdx, fromVal, toVal, peak);
switch (ret) {
case Integrator::ReturnCode::SUCCESS:
- drawIntegratedPeak(peak);
+ m_integTblModel->doneReset();
+ return genPeakDrawData(peak);
break;
case Integrator::ReturnCode::E_NO_FIRST_INTERSECT:
- Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "no first intersect");
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + "no first intersection");
break;
case Integrator::ReturnCode::E_NO_SECOND_INTERSECT:
- Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, "no first intersect");
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + "no second intersection");
break;
default:
break;
}
- m_integTblModel->doneReset();
+
+ return PeakDrawData();
+}
+
+/** Private methods **/
+
+PeakDrawData SignalController::genPeakDrawData(const std::shared_ptr<IntegratedPeak> peak)
+{
+ return PeakDrawData(idxToRel(peak->fromIdx()), valueToRel(peak->fromY()),
+ idxToRel(peak->toIdx()), valueToRel(peak->toY()),
+ idxToRel(peak->peakIdx()), valueToRel(m_signal->valueAt(peak->peakIdx())),
+ peak->peakTime(), peak->auc());
}
-void SignalController::onViewRedrawNeeded()
+double SignalController::idxToRel(const size_t idx)
{
- drawGraph();
- drawAllPeaks();
+ return idx * (RELATIVE_MAX - RELATIVE_MIN) / m_signal->count();
}
-void SignalController::onViewResized(const int w, const int h)
+double SignalController::valueToRel(const double value)
{
- qDebug() << "Setting GW size" << w << h;
- m_viewHeight = h;
- m_viewWidth = w;
+ const double y = m_signal->maximum() - m_signal->minimum();
+ const double ret = (value - m_signal->minimum()) * (RELATIVE_MAX - RELATIVE_MIN) / y;
+ //qDebug() << __QFUNC__ << value << ret;
+ return ret;
}
-void SignalController::onViewShowContextMenu(const int x, const int y, const QPoint& globalPos)
+size_t SignalController::relToIdx(const double rel)
{
- m_ctxMenuX = x; m_ctxMenuY = y;
- m_ctxMenu.exec(globalPos);
- emit viewCtxMenuClosed();
+ size_t ret = (m_signal->count() - 1) * (rel - RELATIVE_MIN) / (RELATIVE_MAX - RELATIVE_MIN);
+ //qDebug() << __QFUNC__ << rel << ret << m_signal->count();
+ return ret;
}
-void SignalController::onViewZoomed(const int fromX, const int fromY, const int toX, const int toY)
+double SignalController::relToValue(const double rel)
{
- if (!updateConstraints(fromX, fromY, toX, toY))
- return;
- drawGraph();
- drawAllPeaks();
+ const double y = m_signal->maximum() - m_signal->minimum();
+ const double val = (rel - RELATIVE_MIN) * y / (RELATIVE_MAX - RELATIVE_MIN) + m_signal->minimum();
+ return val;
}
+/** Public slots **/
+
SignalController::~SignalController()
{
delete m_dtblModel;
#ifndef SIGNALCONTROLLER_H
#define SIGNALCONTROLLER_H
-#include "gui/graphviewcontextmenu.h"
#include "integrationtablemodel.h"
#include "integrator.h"
#include "signal.h"
#include <memory>
#include <QtCore/QObject>
+struct GraphDrawData {
+ GraphDrawData() :
+ ddata(nullptr), ddataLen(0) {}
+ GraphDrawData(const double* ddata, const size_t ddataLen) :
+ ddata(ddata), ddataLen(ddataLen) {}
+ ~GraphDrawData()
+ {
+ if (ddata)
+ delete[] ddata;
+ }
+
+ const double* ddata;
+ const size_t ddataLen;
+};
+
+struct PeakDrawData {
+ PeakDrawData() : fromX(0), fromY(0), toX(0), toY(0), peakX(0), peakY(0), auc(0), time(0) {}
+ PeakDrawData(const double fromX, const double fromY, const double toX, const double toY,
+ const double peakX, const double peakY, const double auc, const double time) :
+ fromX(fromX), fromY(fromY), toX(toX), toY(toY), peakX(peakX), peakY(peakY), auc(auc), time(time) {}
+
+ const double fromX, fromY, toX, toY;
+ const double peakX, peakY;
+ const double auc, time;
+};
+
class SignalController : public QObject
{
Q_OBJECT
public:
explicit SignalController(std::shared_ptr<Signal> signal, QObject* parent = nullptr);
~SignalController();
- double currentYMax() const { return m_yMax; }
+ /*double currentYMax() const { return m_yMax; }
double currentYMin() const { return m_yMin; }
double currentStartX() const;
double currentStartY() const;
double currentStopX() const;
double currentStopY() const;
- void draw();
+ void draw();*/
SignalDataTableModel* dataTableModel() { return m_dtblModel; }
- double* generateDrawData(size_t from, size_t to);
+ PeakDrawData deletePeak(const double x);
+ //double* generateDrawData(size_t from, size_t to);
+ Signal::TimeValuePair getXYValues(const double x);
+ std::shared_ptr<GraphDrawData> getGraphDrawData(const double fromX, const double toX);
+ std::vector<PeakDrawData> getPeaksDrawData(const double fromX, const double fromY, const double toX, const double toY);
+ double fromXAbs() const { return m_signal->timeAt(0); }
+ double toXAbs() const { return m_signal->timeAt(m_signal->count()-1); }
+ double fromYAbs() const { return m_signal->valueAt(0); }
+ double toYAbs() const { return m_signal->valueAt(m_signal->count()-1); }
+ PeakDrawData integratePeak(const double fromX, const double fromY, const double toX, const double toY);
IntegrationTableModel* integrationTableModel() { return m_integTblModel;}
const std::shared_ptr<Signal> signal() const { return m_signal; }
const std::shared_ptr<Integrator> cIntegrator() const { return m_integrator; }
+ static const double RELATIVE_MAX;
+ static const double RELATIVE_MIN;
+
private:
- GraphViewContextMenu m_ctxMenu;
- int m_ctxMenuX;
- int m_ctxMenuY;
+ //GraphViewContextMenu m_ctxMenu;
+ //int m_ctxMenuX;
+ //int m_ctxMenuY;
SignalDataTableModel* m_dtblModel;
- uint m_fromIdx;
- uint m_toIdx;
+ //uint m_fromIdx;
+ //uint m_toIdx;
IntegrationTableModel* m_integTblModel;
std::shared_ptr<Integrator> m_integrator;
std::shared_ptr<Signal> m_signal;
- int m_viewHeight;
- int m_viewWidth;
- double m_yMax;
- double m_yMin;
-
- void drawAllPeaks();
- void drawFullGraph();
- void drawGraph();
+ //int m_viewHeight;
+ //int m_viewWidth;
+ //double m_yMax;
+ //double m_yMin;
+
+ double idxToRel(const size_t idx);
+ double valueToRel(const double value);
+ size_t relToIdx(const double rel);
+ double relToValue(const double rel);
+
+ //void drawAllPeaks();
+ //void drawFullGraph();
+ //void drawGraph();
void drawIntegratedPeak(const std::shared_ptr<IntegratedPeak> peak);
- bool updateConstraints(const int fromX, const int fromY, const int toX, const int toY);
- double yValToCoord(double y);
+ PeakDrawData genPeakDrawData(const std::shared_ptr<IntegratedPeak> peak);
+ //bool updateConstraints(const int fromX, const int fromY, const int toX, const int to);
+ //double yValToCoord(double y);
static const QString ME_SENDER_STR;
public slots:
- void onCtxMenuUnzoom();
+ /*void onCtxMenuUnzoom();
void onCtxMenuDeletePeak();
void onViewCrosshairErased();
void onViewCrosshairMoved(const int x, const int y);
void onViewRedrawNeeded();
void onViewResized(const int w, const int h);
void onViewShowContextMenu(const int x, const int y, const QPoint& globalPos);
- void onViewZoomed(const int fromX, const int fromY, const int toX, const int toY);
+ bool onViewZoomed(const int fromX, const int fromY, const int toX, const int toY);
+ bool onViewZoomedByValues(const double fromX, const double fromY, const double toX, const double toY);*/
signals:
- void viewCtxMenuClosed();
- void viewDrawGraph(double* data, size_t len, double min, double max);
- void viewDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakX, const double peakY, const QString& peakTime,
- const QString& peakArea, const bool valley);
- void viewUpdateCurrentValues(double x, double y);
- void viewRemoveCurrentValues();
+ //void viewCtxMenuClosed();
+ //void viewDrawGraph(double* data, size_t len, double min, double max);
+ //void viewDrawIntegration(int startX, double startY, int stopX, double stopY, int peakStartX, double peakStartY, const QString& time, const QString& area);
+ //void viewUpdateCurrentValues(double x, double y);
+ //void viewRemoveCurrentValues();
void fillDataList();
-
-
};
#endif // SIGNALCONTROLLER_H
--- /dev/null
+#include "logger.h"
+#include "signaldrawer.h"
+
+#include <QDebug>
+
+const QString SignalDrawer::ME_SENDER_STR("SignalDrawer");
+
+SignalDrawer::SignalDrawer(std::shared_ptr<SignalController> controller) :
+ m_controller(controller),
+ m_background(nullptr),
+ m_pixmap(nullptr)
+{
+}
+
+/** Public methods **/
+
+Constraints SignalDrawer::currentConstraints()
+{
+ return Constraints(m_relXMin, m_relYMin, m_relXMax, m_relYMax);
+}
+
+bool SignalDrawer::draw(const double fromX, const double fromY, const double toX, const double toY)
+{
+ bool ret;
+
+ setNewRelativeConstraints(fromX, fromY, toX, toY);
+
+ ret = drawGraph(fromX, fromY, toX, toY);
+ if (!ret) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw graph");
+ restoreRelativeConstraints();
+ return ret;
+ }
+ ret = drawPeaks(fromX, fromY, toX, toY);
+ if (!ret) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw integrated peaks");
+ restoreRelativeConstraints();
+ return ret;
+ }
+
+ return ret;
+}
+
+bool SignalDrawer::setDimensions(const int width, const int height)
+{
+ if (width < 0 || height < 0) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " invalid dimensions (" + QString::number(width) + ", " + QString::number(height) + ")");
+ return false;
+ }
+
+ m_width = width;
+ m_height = height;
+
+ return draw();
+}
+
+/** Protected methods **/
+
+bool SignalDrawer::drawGraph(const double fromX, const double fromY, const double toX, const double toY)
+{
+ std::shared_ptr<GraphDrawData> gdData = m_controller->getGraphDrawData(fromX, toX);
+ if (gdData->ddataLen == 0)
+ return false;
+
+ m_gdData = gdData;
+
+ return renderGraph(fromY, toY);
+}
+
+bool SignalDrawer::drawPeaks(const double fromX, const double fromY, const double toX, const double toY)
+{
+ std::vector<PeakDrawData> pdData = m_controller->getPeaksDrawData(fromX, fromY, toX, toY);
+ if (pdData.size() < 1)
+ return true;
+
+ for (const PeakDrawData& pd : pdData) {
+ QRegion reg = renderPeak(pd);
+ if (reg.isEmpty()) return false;
+ }
+
+ return true;
+}
+
+QRegion SignalDrawer::erasePeak(const PeakDrawData& pd)
+{
+ QPainter p;
+ QFont font("arial", 10);
+ QFontMetrics fm(font);
+ QString aucText, timeText;
+ int tTextHeight, tTextWidth, aTextWidth;
+ int fromXPix, fromYPix;
+ int toXPix, toYPix;
+ int peakX, peakY;
+ int beginXPix, endXPix;
+
+ if (m_background == nullptr) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " null pointer to pixmap");
+ return QRegion();
+ }
+ /* No peak */
+ if (pd.auc == 0)
+ return QRegion();
+
+ fromXPix = relToXPix(pd.fromX); fromYPix = relToYPix(pd.fromY);
+ toXPix = relToXPix(pd.toX); toYPix = relToYPix(pd.toY);
+ peakX = relToXPix(pd.peakX); peakY = relToYPix(pd.peakY);
+ aucText = m_locale.toString(pd.auc, 'f', 4);
+ timeText = m_locale.toString(pd.time, 'f', 4);
+ tTextWidth = fm.width(timeText);
+ if (peakY - tTextWidth < 2)
+ peakY += tTextWidth - peakY + 2;
+ tTextHeight = fm.height();
+ aTextWidth = fm.width(aucText);
+
+ if (peakX - tTextHeight < fromXPix)
+ beginXPix = (peakX - tTextHeight > 0) ? peakX - tTextHeight : 0;
+ else
+ beginXPix = fromXPix;
+ qDebug() << __QFUNC__ << beginXPix << fromXPix << tTextHeight;
+ if (peakX + 5 + aTextWidth > toXPix)
+ endXPix = peakX + 5 + aTextWidth;
+ else
+ endXPix = toXPix;
+
+ return QRegion(beginXPix, 0, endXPix - beginXPix, m_height);
+}
+
+bool SignalDrawer::renderGraph(const double fromY, const double toY)
+{
+ QPixmap* pixmap;
+ QPainter p;
+ double xStep, yStep;
+ int fromXPix = 0, fromYPix;
+
+ if (m_width < 1 || m_height < 1) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " invalid dimensions (" + QString::number(m_width) + ", " + QString::number(m_height) + ")");
+ return false;
+ }
+ if (m_gdData->ddataLen < 1) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " no data to draw");
+ return false;
+ }
+
+ pixmap = new QPixmap(m_width, m_height);
+ p.begin(pixmap);
+ p.fillRect(0, 0, m_width, m_height, Qt::white);
+ p.setPen(QColor(Qt::blue));
+
+ xStep = static_cast<double>(m_width) / m_gdData->ddataLen;
+ yStep = static_cast<double>(m_height) / (toY - fromY);
+ Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + " yStep: " + QString::number(yStep)
+ + " fY " + QString::number(fromY) + " tY " + QString::number(toY));
+ fromYPix = m_height - yStep * (m_gdData->ddata[0] - fromY);
+ for (size_t i = 1; i < m_gdData->ddataLen; i++) {
+ int toXPix = xStep * i;
+ int toYPix = m_height - yStep * (m_gdData->ddata[i] - fromY);
+ p.drawLine(fromXPix, fromYPix, toXPix, toYPix);
+ fromXPix = toXPix;
+ fromYPix = toYPix;
+ }
+
+ p.end();
+
+ if (m_pixmap)
+ delete m_pixmap;
+ m_pixmap = pixmap;
+ if (m_background)
+ delete m_background;
+ m_background = new QPixmap(*m_pixmap);
+
+ return true;
+}
+
+QRegion SignalDrawer::renderPeak(const PeakDrawData& pd)
+{
+ QPainter p;
+ QFont font("arial", 10);
+ QFontMetrics fm(font);
+ QString aucText, timeText;
+ int tTextHeight, tTextWidth, aTextWidth;
+ int fromXPix, fromYPix;
+ int toXPix, toYPix;
+ int peakX, peakY;
+ int beginXPix, endXPix;
+
+ if (m_background == nullptr) {
+ Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " null pointer to pixmap");
+ return QRegion();
+ }
+ /* No peak */
+ if (pd.auc == 0)
+ return QRegion();
+
+ fromXPix = relToXPix(pd.fromX); fromYPix = relToYPix(pd.fromY);
+ toXPix = relToXPix(pd.toX); toYPix = relToYPix(pd.toY);
+ peakX = relToXPix(pd.peakX); peakY = relToYPix(pd.peakY);
+ aucText = m_locale.toString(pd.auc, 'f', 4);
+ timeText = m_locale.toString(pd.time, 'f', 4);
+
+ p.begin(m_background);
+ p.setPen(Qt::red);
+ p.drawLine(fromXPix, fromYPix, toXPix, toYPix);
+
+ /* Draw AREA and TIME caption */
+ p.setFont(font);
+ p.setPen(Qt::black);
+ tTextWidth = fm.width(timeText);
+ if (peakY - tTextWidth < 2)
+ peakY += tTextWidth - peakY + 2;
+ tTextHeight = fm.height();
+ p.save();
+ p.translate(peakX, peakY);
+ p.rotate(-90);
+ p.drawText(0, 0, timeText);
+ p.rotate(+90);
+ p.restore();
+ aTextWidth = fm.width(aucText);
+ p.drawText(peakX + 5, peakY, aucText);
+ p.end();
+
+ if (peakX - tTextHeight < fromXPix)
+ beginXPix = (peakX - tTextHeight > 0) ? peakX - tTextHeight : 0;
+ else
+ beginXPix = fromXPix;
+ qDebug() << __QFUNC__ << beginXPix << fromXPix << tTextHeight;
+ if (peakX + 5 + aTextWidth > toXPix)
+ endXPix = peakX + 5 + aTextWidth;
+ else
+ endXPix = toXPix;
+
+ /* Copy peak to foreground pixmap */
+ p.begin(m_pixmap);
+ p.drawPixmap(beginXPix, 0, *m_background, beginXPix, 0, endXPix - beginXPix, m_height);
+ p.end();
+
+ return QRegion(beginXPix, 0, endXPix - beginXPix, m_height);
+}
+
+/** Private functions **/
+
+int SignalDrawer::relToXPix(const double rel)
+{
+ const int ret = m_width / (m_relXMax - m_relXMin) * (rel - m_relXMin);
+ //qDebug() << __QFUNC__ << ret;
+ return ret;
+}
+
+int SignalDrawer::relToYPix(const double rel)
+{
+ const int ret = m_height - (m_height / (m_relYMax - m_relYMin) * (rel - m_relYMin));
+ //qDebug() << __QFUNC__ << ret;
+ return ret;
+}
+
+double SignalDrawer::xPixToRel(const int pix)
+{
+ const double ret = (pix * (m_relXMax - m_relXMin) / m_width) + m_relXMin;
+ //qDebug() << __QFUNC__ << ret;
+ return ret;
+}
+
+double SignalDrawer::yPixToRel(const int pix)
+{
+ const double range = m_relYMax - m_relYMin;
+ const int invPix = m_height - pix;
+ const double ret = (range / m_height * invPix) + m_relYMin;
+ //qDebug() << __QFUNC__ << ret;
+ return ret;
+}
+
+/** Private methods **/
+
+void SignalDrawer::restoreRelativeConstraints()
+{
+ m_relXMin = m_oldRelXMin;
+ m_relXMax = m_oldRelXMax;
+ m_relYMin = m_oldRelYMin;
+ m_relYMax = m_oldRelYMax;
+}
+
+void SignalDrawer::setNewRelativeConstraints(const double fromX, const double fromY, const double toX, const double toY)
+{
+ m_oldRelXMin = m_relXMin;
+ m_oldRelXMax = m_relXMax;
+ m_oldRelYMin = m_relYMin;
+ m_oldRelYMax = m_relYMax;
+
+ m_relXMin = fromX;
+ m_relXMax = toX;
+ m_relYMin = fromY;
+ m_relYMax = toY;
+}
+
+SignalDrawer::~SignalDrawer()
+{
+ delete m_pixmap;
+}
--- /dev/null
+#ifndef SIGNALDRAWER_H
+#define SIGNALDRAWER_H
+
+#include "signalcontroller.h"
+#include <QtCore/QLocale>
+#include <QtGui/QFont>
+#include <QtGui/QPainter>
+#include <QtGui/QPixmap>
+#include <memory>
+
+struct Constraints {
+ Constraints(const double fromX, const double fromY, const double toX, const double toY) :
+ fromX(fromX), fromY(fromY), toX(toX), toY(toY) {}
+
+ const double fromX, fromY, toX, toY;
+};
+
+class SignalDrawer
+{
+public:
+ SignalDrawer(std::shared_ptr<SignalController> controller);
+ ~SignalDrawer();
+ Constraints currentConstraints();
+ int dheight() const { return m_height; }
+ bool draw(const double fromX = SignalController::RELATIVE_MIN, const double fromY = SignalController::RELATIVE_MIN,
+ const double toX = SignalController::RELATIVE_MAX, const double toY = SignalController::RELATIVE_MAX);
+ bool drawGraph(const double fromX, const double fromY, const double toX, const double toY);
+ bool drawPeaks(const double fromX, const double fromY, const double toX, const double toY);
+ QRegion erasePeak(const PeakDrawData& pd);
+ int dwidth() const { return m_width; }
+ bool renderGraph(const double fromY, const double toY);
+ QRegion renderPeak(const PeakDrawData& pd);
+ bool setDimensions(const int width, const int height);
+
+protected:
+ std::shared_ptr<SignalController> m_controller;
+ QLocale m_locale;
+ QPixmap* m_background;
+ QPixmap* m_pixmap;
+
+ double m_relXMax;
+ double m_relXMin;
+ double m_relYMax;
+ double m_relYMin;
+ std::shared_ptr<GraphDrawData> m_gdData;
+
+ int relToXPix(const double rel);
+ int relToYPix(const double rel);
+ double xPixToRel(const int pix);
+ double yPixToRel(const int pix);
+
+private:
+ int m_height;
+ int m_width;
+
+ double m_oldRelXMax;
+ double m_oldRelXMin;
+ double m_oldRelYMax;
+ double m_oldRelYMin;
+
+ void setNewRelativeConstraints(const double fromX, const double fromY, const double toX, const double toY);
+ void restoreRelativeConstraints();
+
+ static const QString ME_SENDER_STR;
+
+};
+
+#endif // SIGNALDRAWER_H
else idx++;
}
- if (idx == m_singleRunKeys.size())
- return -1;
+ /* if (idx == m_singleRunKeys.size())
+ * Unknown key */
+ return -1;
}
int SingleRunsSelectorModel::rowCount(const QModelIndex& parent) const