From db964cd20d226da6e56ee9fef696867a6117d74d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Thu, 31 Jul 2014 09:58:39 +0200 Subject: [PATCH] Add feature to integrate peak by baseline --- datafilesloader.cpp | 6 +-- datamanager.cpp | 7 +-- gui/graphview.cpp | 47 ++++++++++++++++-- gui/graphview.h | 9 +++- gui/mainwindow.cpp | 19 ++++++-- gui/mainwindow.h | 3 +- gui/mainwindow.ui | 17 ++++++- helpers.h | 30 ++++++++++++ integratedpeak.cpp | 8 +++- integratedpeak.h | 11 ++++- integrator.cpp | 110 ++++++++++++++++++++++++++----------------- integrator.h | 7 +-- metatypes.h | 3 +- signal.cpp | 12 +++-- signal.h | 20 +++++--- signalcontroller.cpp | 19 ++++++-- signalcontroller.h | 12 +++-- signaldrawer.cpp | 61 +++++++++++++----------- 18 files changed, 288 insertions(+), 113 deletions(-) diff --git a/datafilesloader.cpp b/datafilesloader.cpp index 0d1f1b8..b5fdfd8 100644 --- a/datafilesloader.cpp +++ b/datafilesloader.cpp @@ -34,7 +34,7 @@ DataFilesLoader::DataFilesLoader(QObject *parent) : m_supportedFileTypes << "*.ch"; } -DataFilesLoader::ReturnCode DataFilesLoader::loadSingleRun(const QDir& path, std::vector& loadedData) +DataFilesLoader::ReturnCode DataFilesLoader::loadSingleRun(const QDir& path, std::vector& loadedData) { ReturnCode ret = ReturnCode::SUCCESS; @@ -57,8 +57,6 @@ DataFilesLoader::ReturnCode DataFilesLoader::loadSingleRun(const QDir& path, std QMessageBox::warning(nullptr, "Error reading file '" + s + "'", errDesc); hpcs_free(mdata); - ret = ReturnCode::E_READ_ERROR; - break; } } @@ -72,5 +70,5 @@ DataFilesLoader::ReturnCode DataFilesLoader::loadSingleRun(const QDir& path, std Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, QString::number(loadedData.size()) + " files were found and successfully parsed"); - return ret; + return ReturnCode::SUCCESS; } diff --git a/datamanager.cpp b/datamanager.cpp index f80786d..010e23e 100644 --- a/datamanager.cpp +++ b/datamanager.cpp @@ -349,7 +349,8 @@ std::shared_ptr DataManager::loadSingleRun(QDir& dir) Signal::TimeValuePair stvp(md->data[idx].time, md->data[idx].value); values.push_back(stvp); } - _s = std::shared_ptr(new Signal(eqp, res, samplingRate, yu, md->dad_wavelength_msr, md->dad_wavelength_ref, values)); + _s = std::shared_ptr(new Signal(eqp, res, samplingRate, yu, md->dad_wavelength_msr.wavelength, md->dad_wavelength_msr.interval, + md->dad_wavelength_ref.wavelength, md->dad_wavelength_ref.interval, values)); if (!date.isValid()) { llog->log(Logger::WARNING, ME_SENDER_STR, QString("Date ") + date.toString() + QString("is invalid.")); @@ -424,8 +425,8 @@ void DataManager::showOneSignal(std::shared_ptr ctrl) swp->setDataTableModel(ctrl->dataTableModel()); swp->setIntegrationTableModel(ctrl->integrationTableModel()); if (ctrl->signal()->resource() == Signal::Resource::CE_DAD) - swp->setTypeText(ctrl->signal()->resourceAsString() + " Sig: " + QString::number(ctrl->signal()->wavelengthAbsorbed()) + " nm, Ref: " + - QString::number(ctrl->signal()->wavelengthReference()) + " nm"); + swp->setTypeText(ctrl->signal()->resourceAsString() + " Sig: " + QString::number(ctrl->signal()->wavelengthMeasured().wavelength) + " nm, Ref: " + + QString::number(ctrl->signal()->wavelengthReference().wavelength) + " nm"); else swp->setTypeText(ctrl->signal()->resourceAsString()); swp->setXUnits(ctrl->signal()->xunitAsString()); diff --git a/gui/graphview.cpp b/gui/graphview.cpp index 9f7c3fc..5b9a643 100644 --- a/gui/graphview.cpp +++ b/gui/graphview.cpp @@ -21,6 +21,7 @@ */ +#include "helpers.h" #include "gui/graphview.h" #include "logger.h" #include @@ -120,14 +121,19 @@ void GraphView::mousePressEvent(QMouseEvent* ev) case Qt::LeftButton: switch (m_mouseMode) { case GraphView::MouseMode::CROSSHAIR: - if (m_graphCtrlMode == GraphControlModes::ZOOM) { + switch (m_graphCtrlMode) { + case GraphControlModes::ZOOM: 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) { + break; + case GraphControlModes::INTEGRATE_BASELINE: + m_integrateStartBLYPix = relToYPix(m_controller->valueToRel(m_controller->getXYValues(xPixToRel(ev->x())).second)); + m_integrateStopBLYPix = m_integrateStartBLYPix; + case GraphControlModes::INTEGRATE_INTERSECT: m_integrateStartXPix = ev->x(); m_integrateStartYPix = ev->y(); m_integrateStopXPix = ev->x(); @@ -143,7 +149,7 @@ void GraphView::mousePressEvent(QMouseEvent* ev) break; case GraphView::MouseMode::INTEGRATE: PeakDrawData pdData = m_controller->integratePeak(xPixToRel(m_integrateStartXPix), yPixToRel(m_integrateStartYPix), - xPixToRel(m_integrateStopXPix), yPixToRel(m_integrateStopYPix)); + xPixToRel(m_integrateStopXPix), yPixToRel(m_integrateStopYPix), m_integrationType); eraseIntegrationBaseline(true); QRegion reg = renderPeak(pdData, m_background); copyPixmapRegion(reg, m_background, m_pixmap); @@ -233,6 +239,18 @@ void GraphView::drawIntegrationBaseline(const int x, const int y) reg = eraseIntegrationBaseline(); + if (m_integrationType == IntegrationType::BASELINE) { + m_integrateStopBLYPix = relToYPix(m_controller->valueToRel(m_controller->getXYValues(xPixToRel(x)).second)); + + p.begin(m_pixmap); + p.setPen(Qt::black); + p.drawLine(m_integrateStartXPix, m_integrateStartYPix, m_integrateStartXPix, m_integrateStartBLYPix); + p.drawLine(x, y, x, m_integrateStopBLYPix); + p.end(); + reg += QRect(m_integrateStartXPix, m_integrateStopXPix, m_integrateStartXPix, m_integrateStopBLYPix); + reg += QRect(x, y, x, m_integrateStopBLYPix); + } + if (m_integrateStartXPix > m_integrateStopXPix) { lstartX = (m_integrateStopXPix > 1) ? m_integrateStopXPix - 1 : 0; lstopX = (m_integrateStartXPix < dwidth()-1) ? m_integrateStartXPix + 1 : dwidth()-1; @@ -254,6 +272,8 @@ void GraphView::drawIntegrationBaseline(const int x, const int y) p.drawLine(m_integrateStartXPix, m_integrateStartYPix, x, y); p.end(); + + reg += QRect(lstartX, lstartY, lstopX, lstopY); m_integrateStopXPix = x; @@ -347,6 +367,25 @@ QRegion GraphView::eraseIntegrationBaseline(bool apply) if (m_integrateStartXPix < 0) return QRegion(); + if (m_integrationType == IntegrationType::BASELINE) { + int top, bottom, left, right; + top = Helpers::minof(m_integrateStartYPix, m_integrateStopYPix, m_integrateStartBLYPix, m_integrateStopBLYPix); + bottom = Helpers::maxof(m_integrateStartYPix, m_integrateStopYPix, m_integrateStartBLYPix, m_integrateStopBLYPix); + left = std::min(m_integrateStartXPix, m_integrateStopXPix); + right = std::max(m_integrateStartXPix, m_integrateStopXPix); + + p.begin(m_pixmap); + p.drawPixmap(left, top, *m_background, left, top, right - left+1, bottom - top+1); + //p.drawPixmap(lstartX, lstartY, *m_background, lstartX, lstartY, lstopX - lstartX+1, lstopY - lstartY+1); //FIXME: +1 should not be needed! + /*p.begin(m_pixmap); + p.setPen(Qt::yellow); + p.drawLine(m_integrateStartXPix, m_integrateStartYPix, m_integrateStartXPix, m_integrateStartBLYPix); + p.drawLine(x, y, x, m_integrateStopBLYPix); + p.end();*/ + reg += QRect(left, top, right - left+1, bottom - top+1); + p.end(); + } + p.begin(m_pixmap); if (m_integrateStartXPix > m_integrateStopXPix) { lstartX = (m_integrateStopXPix > 1) ? m_integrateStopXPix - 1 : 0; @@ -366,7 +405,7 @@ QRegion GraphView::eraseIntegrationBaseline(bool apply) 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); + reg += QRect(lstartX, lstartY, lstopX - lstartX +1, lstopY - lstartY + 1); if (apply) update(reg); diff --git a/gui/graphview.h b/gui/graphview.h index 2718ef7..eaa7009 100644 --- a/gui/graphview.h +++ b/gui/graphview.h @@ -82,6 +82,9 @@ private: int m_graphCrosshairXPix; int m_graphCrosshairYPix; /* Integration baseline */ + IntegrationType m_integrationType; + int m_integrateStartBLYPix; + int m_integrateStopBLYPix; int m_integrateStartXPix; int m_integrateStartYPix; int m_integrateStopXPix; @@ -100,7 +103,11 @@ private slots: void onCtxMenuZoomOut(); public slots: - void onControlModeChanged(GraphControlModes mode) { m_graphCtrlMode = mode; } + void onControlModeChanged(GraphControlModes mode) + { m_graphCtrlMode = mode; + if (mode == GraphControlModes::INTEGRATE_BASELINE) m_integrationType = IntegrationType::BASELINE; + else if (mode == GraphControlModes::INTEGRATE_INTERSECT) m_integrationType = IntegrationType::INTERSECTION; + } signals: void crosshairValuesUpdated(const double time, const double value); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 68d6d7f..f220bed 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -64,7 +64,8 @@ void MainWindow::connectActions() #endif { /* Controls panel */ - connect(ui->qpb_integrate, SIGNAL(pressed()), this, SLOT(onIntegrateSelected())); + connect(ui->qpb_integrateBaseline, SIGNAL(pressed()), this, SLOT(onIntegrateBaselineSelected())); + connect(ui->qpb_integrateIntersect, SIGNAL(pressed()), this, SLOT(onIntegrateIntersectSelected())); connect(ui->qpb_zoom, SIGNAL(pressed()), this, SLOT(onZoomSelected())); /* DATA menu */ @@ -85,8 +86,10 @@ void MainWindow::connectActions() /* Public slots */ void MainWindow::onAddToDashboard(SignalView* sw) { - if (ui->qpb_integrate->isChecked()) - sw->m_graphView->onControlModeChanged(GraphControlModes::INTEGRATE); + if (ui->qpb_integrateBaseline->isChecked()) + sw->m_graphView->onControlModeChanged(GraphControlModes::INTEGRATE_BASELINE); + else if(ui->qpb_integrateIntersect->isChecked()) + sw->m_graphView->onControlModeChanged(GraphControlModes::INTEGRATE_INTERSECT); else if(ui->qpb_zoom->isChecked()) sw->m_graphView->onControlModeChanged(GraphControlModes::ZOOM); @@ -144,10 +147,16 @@ void MainWindow::onAboutAnyanka() aa.exec(); } -void MainWindow::onIntegrateSelected() +void MainWindow::onIntegrateBaselineSelected() { - emit controlModeChanged(GraphControlModes::INTEGRATE); + emit controlModeChanged(GraphControlModes::INTEGRATE_BASELINE); } + +void MainWindow::onIntegrateIntersectSelected() +{ + emit controlModeChanged(GraphControlModes::INTEGRATE_INTERSECT); +} + void MainWindow::onLoadSequence() { m_loadDataFileDialog->setWindowTitle("Load sequence"); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index f181d2d..88cc398 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -73,7 +73,8 @@ private slots: void onExportGraphToImage() { emit exportGraphToImage(); } void onExportPeaks() { emit exportPeaks(); } void onExportRawData() { emit exportRawData(); } - void onIntegrateSelected(); + void onIntegrateBaselineSelected(); + void onIntegrateIntersectSelected(); void onLoadSequence(); void onLoadSingleRun(); void onSaveChanges() { emit saveChanges(); } diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 2748af2..4a0d984 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -68,9 +68,22 @@ - + - Integrate + Integrate by intersection + + + true + + + true + + + + + + + Integrate by baseline true diff --git a/helpers.h b/helpers.h index f492ed2..fcf3cb7 100644 --- a/helpers.h +++ b/helpers.h @@ -54,5 +54,35 @@ public: return name.mid(dotIdx+1).toLower(); } + template static T maxof(T n, ...) + { + T idx; + T val, largest; + va_list vl; + va_start(vl, n); + largest = va_arg(vl, T); + for (idx = 1; idx < n; idx++) { + val = va_arg(vl, T); + largest = (largest > val) ? largest : val; + } + va_end(vl); + return largest; + } + + template static T minof(T n, ...) + { + T idx; + T val, largest; + va_list vl; + va_start(vl, n); + largest = va_arg(vl, T); + for (idx = 1; idx < n; idx++) { + val = va_arg(vl, T); + largest = (largest < val) ? largest : val; + } + va_end(vl); + return largest; + } + }; #endif // MATHHELPERS_H diff --git a/integratedpeak.cpp b/integratedpeak.cpp index b0c4216..d4b1756 100644 --- a/integratedpeak.cpp +++ b/integratedpeak.cpp @@ -27,6 +27,7 @@ const QString IntegratedPeak::KEY_AUC("auc"); const QString IntegratedPeak::KEY_FROMIDX("fromIdx"); const QString IntegratedPeak::KEY_FROMTIME("fromTime"); const QString IntegratedPeak::KEY_FROMY("fromY"); +const QString IntegratedPeak::KEY_ITYPE("itype"); const QString IntegratedPeak::KEY_PEAKIDX("peakIdx"); const QString IntegratedPeak::KEY_PEAKTIME("peakTime"); const QString IntegratedPeak::KEY_PEAKY("peakY"); @@ -39,13 +40,14 @@ const QString IntegratedPeak::KEY_RELBLQ("relBlQ"); IntegratedPeak::IntegratedPeak(IntegratedPeak::Type type, double auc, size_t peakIdx, double peakTime, double peakY, size_t fromIdx, size_t toIdx, double fromTime, double toTime, double fromY, double toY, - double relBlSlope, double relBlQ, QObject* parent) : + double relBlSlope, double relBlQ, IntegrationType itype, QObject* parent) : QObject(parent), JSONSerializable(), m_auc(auc), m_fromIdx(fromIdx), m_fromTime(fromTime), m_fromY(fromY), + m_itype(itype), m_peakIdx(peakIdx), m_peakTime(peakTime), m_peakY(peakY), @@ -85,6 +87,9 @@ bool IntegratedPeak::deserialize(const QJsonValue& value) if (!jso.contains(KEY_FROMY)) return false; m_fromY = jso.value(KEY_FROMY).toDouble(); + if (!jso.contains(KEY_ITYPE)) + m_itype = IntegrationType::INTERSECTION; + m_itype = jso.value(KEY_ITYPE).toBool() ? IntegrationType::BASELINE : IntegrationType::INTERSECTION; if (!jso.contains(KEY_PEAKIDX)) return false; @@ -138,6 +143,7 @@ QJsonValue IntegratedPeak::serialize() const jso.insert(KEY_FROMIDX, QJsonValue(static_cast(m_fromIdx))); jso.insert(KEY_FROMTIME, QJsonValue(m_fromTime)); jso.insert(KEY_FROMY, QJsonValue(m_fromY)); + jso.insert(KEY_ITYPE, QJsonValue( (m_itype == IntegrationType::BASELINE) ? true : false) ); jso.insert(KEY_PEAKIDX, QJsonValue(static_cast(m_peakIdx))); jso.insert(KEY_PEAKTIME, QJsonValue(m_peakTime)); jso.insert(KEY_PEAKY, QJsonValue(m_peakY)); diff --git a/integratedpeak.h b/integratedpeak.h index af38729..1e1e2db 100644 --- a/integratedpeak.h +++ b/integratedpeak.h @@ -27,6 +27,12 @@ #include "jsonserializable.h" #include +enum class IntegrationType { + NONE, + INTERSECTION, + BASELINE +}; + class IntegratedPeak : public QObject, public JSONSerializable { Q_OBJECT @@ -39,13 +45,14 @@ public: explicit IntegratedPeak() : m_type(Type::INVALID) {} explicit IntegratedPeak(Type type, double auc, size_t peakIdx, double peakTime, double peakY, size_t fromIdx, size_t toIdx, double fromTime, double toTime, - double fromY, double toY, double relBlSlope, double relBlQ, QObject* parent = nullptr); + double fromY, double toY, double relBlSlope, double relBlQ, IntegrationType itype, QObject* parent = nullptr); double auc() const { return m_auc; } double baselineSlope() const; size_t fromIdx() const { return m_fromIdx; } double fromY() const { return m_fromY; } double fromTime() const { return m_fromTime;} double height() const; + IntegrationType itype() const { return m_itype; } size_t peakIdx() const { return m_peakIdx; } double peakTime() const { return m_peakTime; } double peakY() const { return m_peakY; } @@ -65,6 +72,7 @@ private: size_t m_fromIdx; double m_fromTime; double m_fromY; + IntegrationType m_itype; size_t m_peakIdx; double m_peakTime; double m_peakY; @@ -79,6 +87,7 @@ private: static const QString KEY_FROMIDX; static const QString KEY_FROMTIME; static const QString KEY_FROMY; + static const QString KEY_ITYPE; static const QString KEY_PEAKIDX; static const QString KEY_PEAKTIME; static const QString KEY_PEAKY; diff --git a/integrator.cpp b/integrator.cpp index 98b775f..5633cc8 100644 --- a/integrator.cpp +++ b/integrator.cpp @@ -84,16 +84,10 @@ Integrator::PeakList Integrator::allPeaks() } Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, IntegratedPeakSPtr& peak, - double relBlSlope, double relBlQ) + double relBlSlope, double relBlQ, IntegrationType itype) { - size_t peakValueIdx; - size_t startIntersIdx, stopIntersIdx; - size_t i; - double auc = 0.0; double slope; - double startYVal, stopYVal; - bool expectDownward; - IntegratedPeak::Type peakType; + bool down; if (startIdx > m_signal->valuesCount()-1) { Logger::log(Logger::Level::ERROR, ME_SENDER_STR, "Invalid startIdx value " + QString::number(startIdx)); @@ -110,25 +104,45 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do } slope = (stopY - startY) / static_cast(stopIdx - startIdx); - /* Try to find first intersection */ - if (startY < m_signal->valueAt(startIdx)) { - expectDownward = true; - //qDebug() << "Expecting downward peak"; - } else { - expectDownward = false; - //qDebug() << "Expecting upward peak"; + + switch (itype) { + case IntegrationType::INTERSECTION: { + if (startY < m_signal->valueAt(startIdx)) + down = true; + else + down = false; + ReturnCode ret = findIntersections(startIdx, startY, stopIdx, stopY, down, slope); + if (ret != ReturnCode::SUCCESS) + return ret; + break; } + default: + if (startY > m_signal->valueAt(startIdx)) + down = true; + else down = false; + break; + } + + return integrateInternal(startIdx, startY, stopIdx, stopY, down, slope, peak, relBlSlope, relBlQ, itype); +} + +Integrator::ReturnCode Integrator::findIntersections(size_t& startIdx, double& startY, size_t& stopIdx, double& stopY, bool& down, const double slope) +{ + size_t origStartIdx = startIdx; + size_t i; + + /* Try to find first intersection */ for (i = startIdx; i <= stopIdx; i++) { double value = m_signal->valueAt(i); - double blY = slope * static_cast(i - startIdx) + startY; + double blY = slope * static_cast(i - origStartIdx) + startY; - if (expectDownward && blY > value) { /* Found first intersection */ - startIntersIdx = i; - startYVal = blY; + if (down && blY > value) { /* Found first intersection */ + startIdx = i; + startY = blY; break; - } else if (!expectDownward && blY < value) { /* Found first intersection */ - startIntersIdx = i; - startYVal = blY; + } else if (!down && blY < value) { /* Found first intersection */ + startIdx = i; + startY = blY; break; } } @@ -140,15 +154,15 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do /* Try to find second intersection */ for (; i <= stopIdx; i++) { double value = m_signal->valueAt(i); - double blY = slope * static_cast(i - startIdx) + startY; + double blY = slope * static_cast(i - origStartIdx) + startY; - if (expectDownward && blY < value) { - stopIntersIdx = i; - stopYVal = blY; + if (down && blY < value) { + stopIdx = i; + stopY = blY; break; - } else if (!expectDownward && blY > value) { - stopIntersIdx = i; - stopYVal = blY; + } else if (!down && blY > value) { + stopIdx = i; + stopY = blY; break; } } @@ -157,11 +171,21 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do return ReturnCode::E_NO_SECOND_INTERSECT; } + return ReturnCode::SUCCESS; +} + +Integrator::ReturnCode Integrator::integrateInternal(const size_t startIdx, const double startY, const size_t stopIdx, const double stopY, + const bool down, const double slope, IntegratedPeakSPtr& peak, + double relBlSlope, double relBlQ, IntegrationType itype) +{ + double auc = 0.0; + size_t peakValueIdx = startIdx; + IntegratedPeak::Type peakType; + /* Integrate */ - peakValueIdx = startIntersIdx; - for (i = startIntersIdx+1; i < stopIntersIdx; i++) { - double blXA = slope * (i - startIntersIdx) + startY; - double blXB = slope * (i - startIntersIdx) + startY; + for (size_t i = startIdx+1; i < stopIdx; i++) { + double blXA = slope * (i - startIdx) + startY; + double blXB = slope * (i - startIdx) + startY; double valA = m_signal->valueAt(i-1); double valB = m_signal->valueAt(i); double tA = m_signal->timeAt(i-1); @@ -169,26 +193,26 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do double avgH = (valB + valA)/2 - (blXB + blXA)/2; double area = avgH * (tB - tA); auc += area; - if (expectDownward && valB < m_signal->valueAt(peakValueIdx)) peakValueIdx = i; - else if (!expectDownward && valB > m_signal->valueAt(peakValueIdx)) peakValueIdx = i; + if (down && valB < m_signal->valueAt(peakValueIdx)) peakValueIdx = i; + else if (!down && valB > m_signal->valueAt(peakValueIdx)) peakValueIdx = i; //qDebug() << area << auc; } /* Convert AUC to positive and seconds */ auc = fabs(auc) * 60; /* Add peak to list */ - if (expectDownward) peakType = IntegratedPeak::Type::VALLEY; + if (down) peakType = IntegratedPeak::Type::VALLEY; else peakType = IntegratedPeak::Type::PEAK; - /*qDebug("Peak integrated"); - qDebug() << "SXC" << fromX << "SYC" << fromY << "EXC" << toX << "EYC" << toY << "Slope" << slope; - qDebug() << "1st(X, Y, vY)" << startIntersIdx << m_signal->valueAt(startIntersIdx) << startYVal; - qDebug() << "2nd(X, Y, vY)" << stopIntersIdx << m_signal->valueAt(stopIntersIdx) << stopYVal; - qDebug("---");*/ + qDebug("Peak integrated"); + //qDebug() << "SXC" << fromX << "SYC" << fromY << "EXC" << toX << "EYC" << toY << "Slope" << slope; + qDebug() << "1st(X, Y, vY)" << startIdx << m_signal->valueAt(startIdx) << startY; + qDebug() << "2nd(X, Y, vY)" << stopIdx << m_signal->valueAt(stopIdx) << stopY; + qDebug("---"); peak = std::shared_ptr(new IntegratedPeak(peakType, auc, peakValueIdx, m_signal->timeAt(peakValueIdx), m_signal->valueAt(peakValueIdx), - startIntersIdx, stopIntersIdx, m_signal->timeAt(startIntersIdx), m_signal->timeAt(stopIntersIdx), - startYVal, stopYVal, relBlSlope, relBlQ)); + startIdx, stopIdx, m_signal->timeAt(startIdx), m_signal->timeAt(stopIdx), + startY, stopY, relBlSlope, relBlQ, itype)); emit addingPeak(m_peakCount); addPeakToMap(peak); emit peakAdded(); diff --git a/integrator.h b/integrator.h index b5248d5..71e89a6 100644 --- a/integrator.h +++ b/integrator.h @@ -52,14 +52,15 @@ public: PeakList allPeaks(); IntegratedPeakCSPtr deletePeak(size_t idx); ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak, - double relBlSlope, double relBlQ); + double relBlSlope, double relBlQ, IntegrationType itype); IntegratedPeakCSPtr peakByLinearIdx(const size_t idx); - //std::multimap>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); } - //std::multimap>::const_iterator peaksCEnd() const { return m_peaks.cend(); } size_t peakCount() const { return m_peakCount; } private: void addPeakToMap(IntegratedPeakCSPtr peak); + ReturnCode findIntersections(size_t& startIdx, double& startY, size_t& stopIdx, double& stopY, bool& down, const double slope); + ReturnCode integrateInternal(const size_t startIdx, const double startY, const size_t stopIdx, const double stopY, const bool down, + const double slope, IntegratedPeakSPtr& peak, double relBlSlope, double relBlQ, const IntegrationType itype); size_t m_peakCount; PeakMap m_peakMap; diff --git a/metatypes.h b/metatypes.h index 2c13c89..62eccee 100644 --- a/metatypes.h +++ b/metatypes.h @@ -32,7 +32,8 @@ Q_DECLARE_METATYPE(SignalViewPtr); enum class GraphControlModes { ZOOM, - INTEGRATE + INTEGRATE_INTERSECT, + INTEGRATE_BASELINE }; Q_DECLARE_METATYPE(GraphControlModes); diff --git a/signal.cpp b/signal.cpp index 25ed6b5..1792715 100644 --- a/signal.cpp +++ b/signal.cpp @@ -34,15 +34,18 @@ const QString Signal::MILLIAU_SI("mAU"); const QString Signal::MILLIVOLTS_SI("mV"); const QString Signal::WATTS_SI("W"); -Signal::Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, uint16_t wavelengthAbs, uint16_t wavelengthRef, +Signal::Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, + const uint16_t wlMsr, const uint16_t wlMsrInt, const uint16_t wlRef, const uint16_t wlRefInt, const std::vector& values, QObject* parent) : QObject(parent), m_equipment(equipment), m_resource(resource), m_samplingRate(samplingRate), m_values(values), - m_wavelengthAbs(wavelengthAbs), - m_wavelengthRef(wavelengthRef), + m_wavelengthMeasured(wlMsr), + m_wavelengthMeasuredInterval(wlMsrInt), + m_wavelengthReference(wlRef), + m_wavelengthReferenceInterval(wlRefInt), m_xunit(XUnit::MINUTE), m_yunit(yunit) { @@ -58,7 +61,8 @@ QString Signal::descriptiveName() const { QString name = resourceAsString(); if (m_resource == Resource::CE_DAD) - name += "_SIG" + QString::number(m_wavelengthAbs) + "_REF" + QString::number(m_wavelengthRef); + name += "_SIG" + QString::number(m_wavelengthMeasured) + "/" + QString::number(m_wavelengthMeasuredInterval) + "_REF" + + QString::number(m_wavelengthReference) + "/" + QString::number(m_wavelengthReferenceInterval); return name; } diff --git a/signal.h b/signal.h index c18abc7..367a946 100644 --- a/signal.h +++ b/signal.h @@ -53,9 +53,15 @@ public: MILLIVOLTS, WATTS }; + struct Wavelength { + Wavelength (uint16_t w, uint16_t i) : wavelength(w), interval(i) {} + uint16_t wavelength; + uint16_t interval; + }; - 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& values, QObject* parent = nullptr); + explicit Signal(const Equipment equipment, const Resource resource, const double samplingRate, const YUnit yunit, const uint16_t wlMsr, + const uint16_t wlMsrInt, const uint16_t wlRef, const uint16_t wlRefInt, + const std::vector& values, QObject* parent = nullptr); uint count() const { return m_values.size(); } QString descriptiveName() const; Equipment equipment() const { return m_equipment; } @@ -72,8 +78,8 @@ public: std::vector::const_iterator pairsBegin() const { return m_values.cbegin(); } size_t valuesCount() const { return m_values.size(); } std::vector::const_iterator pairsEnd() const { return m_values.cend(); } - uint16_t wavelengthAbsorbed() const { return m_wavelengthAbs; } - uint16_t wavelengthReference() const { return m_wavelengthRef; } + Wavelength wavelengthMeasured() const { return Wavelength(m_wavelengthMeasured, m_wavelengthMeasuredInterval); } + Wavelength wavelengthReference() const { return Wavelength(m_wavelengthReference, m_wavelengthReferenceInterval); } XUnit xunit() const { return m_xunit; } QString xunitAsString() const; YUnit yunit() const { return m_yunit; } @@ -86,8 +92,10 @@ private: const Resource m_resource; const double m_samplingRate; const std::vector m_values; - const uint16_t m_wavelengthAbs; - const uint16_t m_wavelengthRef; + const uint16_t m_wavelengthMeasured; + const uint16_t m_wavelengthMeasuredInterval; + const uint16_t m_wavelengthReference; + const uint16_t m_wavelengthReferenceInterval; const XUnit m_xunit; const YUnit m_yunit; diff --git a/signalcontroller.cpp b/signalcontroller.cpp index 5cad2bc..ed1ebbc 100644 --- a/signalcontroller.cpp +++ b/signalcontroller.cpp @@ -212,7 +212,8 @@ Signal::TimeValuePair SignalController::getXYValues(const double x) return std::pair(m_signal->timeAt(idx), m_signal->valueAt(idx+1)); } -PeakDrawData SignalController::integratePeak(const double fromX, const double fromY, const double toX, const double toY) +PeakDrawData SignalController::integratePeak(const double fromX, const double fromY, const double toX, const double toY, + const IntegrationType itype) { size_t fromIdx, toIdx; double fromVal, toVal; @@ -236,7 +237,7 @@ PeakDrawData SignalController::integratePeak(const double fromX, const double fr fromVal = relToValue(fromY); toVal = relToValue(toY); - ret = m_integrator->integrate(fromIdx, toIdx, fromVal, toVal, peak, relBlSlope, relBlQ); + ret = m_integrator->integrate(fromIdx, toIdx, fromVal, toVal, peak, relBlSlope, relBlQ, itype); switch (ret) { case Integrator::ReturnCode::SUCCESS: @@ -280,6 +281,17 @@ PeakDrawData SignalController::genPeakDrawData(const std::shared_ptrvalueAt(peak->fromIdx()); double toY = m_signal->valueAt(peak->toIdx()); + switch (peak->itype()) { + case IntegrationType::INTERSECTION: + fromY = m_signal->valueAt(peak->fromIdx()); + toY = m_signal->valueAt(peak->toIdx()); + break; + case IntegrationType::BASELINE: + fromY = peak->fromY(); + toY = peak->toY(); + break; + } + //qDebug() << __QFUNC__ << beforeFromY << fromY // << beforeToY << toY; //qDebug() << m_signal->timeAt(peak->fromIdx() - 0) << m_signal->timeAt(peak->fromIdx() + 1) << peak->fromTime(); @@ -288,7 +300,8 @@ PeakDrawData SignalController::genPeakDrawData(const std::shared_ptrtoIdx()), valueToRel(toY), idxToRel(peak->toIdx()-1), valueToRel(beforeToY), peak->relBlSlope(), peak->relBlQ(), idxToRel(peak->peakIdx()), valueToRel(m_signal->valueAt(peak->peakIdx())), - peak->peakTime(), peak->auc()); + peak->peakTime(), peak->auc(), peak->itype(), + valueToRel(m_signal->valueAt(peak->fromIdx())), valueToRel(m_signal->valueAt(peak->toIdx()))); } double SignalController::idxToRel(const size_t idx) diff --git a/signalcontroller.h b/signalcontroller.h index 4f5f8f5..ea8bf6d 100644 --- a/signalcontroller.h +++ b/signalcontroller.h @@ -63,21 +63,25 @@ struct GraphDrawData { struct PeakDrawData { PeakDrawData() : fromX(0), fromY(0), toX(0), toY(0), beforeFromX(0), beforeFromY(0), beforeToX(0), - beforeToY(0), blSlope(0), blQ(0), peakX(0), peakY(0), auc(0), time(0) {} + beforeToY(0), blSlope(0), blQ(0), peakX(0), peakY(0), auc(0), time(0), itype(IntegrationType::NONE), + blFromY(0), blToY(0) {} PeakDrawData(const double fromX, const double fromY, const double beforeFromX, const double beforeFromY, const double toX, const double toY, const double beforeToX, const double beforeToY, const double blSlope, const double blQ, - const double peakX, const double peakY, const double auc, const double time) : + const double peakX, const double peakY, const double auc, const double time, + const IntegrationType itype, const double blFromY, const double blToY) : fromX(fromX), fromY(fromY), toX(toX), toY(toY), beforeFromX(beforeFromX), beforeFromY(beforeFromY), beforeToX(beforeToX), beforeToY(beforeToY), blSlope(blSlope), blQ(blQ), - peakX(peakX), peakY(peakY), auc(auc), time(time) {} + peakX(peakX), peakY(peakY), auc(auc), time(time), itype(itype), blFromY(blFromY), blToY(blToY) {} const double fromX, fromY, toX, toY; const double beforeFromX, beforeFromY, beforeToX, beforeToY; const double blSlope, blQ; const double peakX, peakY; const double auc, time; + const IntegrationType itype; + const double blFromY, blToY; }; struct RulerDrawData { @@ -111,7 +115,7 @@ public: 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); + PeakDrawData integratePeak(const double fromX, const double fromY, const double toX, const double toY, const IntegrationType itype); IntegrationTableModel* integrationTableModel() { return m_integTblModel;} void setGUIViewport(const double fromX, const double fromY, const double toX, const double toY); virtual QJsonValue serialize() const; diff --git a/signaldrawer.cpp b/signaldrawer.cpp index a709ba4..2486309 100644 --- a/signaldrawer.cpp +++ b/signaldrawer.cpp @@ -27,7 +27,7 @@ const QString SignalDrawer::ME_SENDER_STR("SignalDrawer"); const int SignalDrawer::AXIS_LABEL_BORDER_OFFSET(2); -const int SignalDrawer::AXIS_LABEL_SCALE_OFFSET(2); +const int SignalDrawer::AXIS_LABEL_SCALE_OFFSET(3); const int SignalDrawer::SCALE_MARGIN_TIME(16); const int SignalDrawer::SCALE_MARGIN_VALUE(48); @@ -308,14 +308,13 @@ void SignalDrawer::renderValueScaleTick(QPainter* const p, const double rel, con QRegion SignalDrawer::erasePeak(const PeakDrawData& pd) { - //QPainter p; QFont font("arial", 10); QFontMetrics fm(font); QString aucText, timeText; QRegion peakReg; int tTextHeight, tTextWidth, aTextWidth; - int fromXPix, fromYPix; - int toXPix, toYPix; + int fromXPix; + int toXPix; int peakX, peakY; int beginXPix, endXPix; @@ -327,8 +326,8 @@ QRegion SignalDrawer::erasePeak(const PeakDrawData& pd) if (pd.auc == 0) return QRect(); - fromXPix = relToXPix(pd.fromX); fromYPix = relToYPix(pd.fromY); - toXPix = relToXPix(pd.toX); toYPix = relToYPix(pd.toY); + fromXPix = relToXPix(pd.fromX); + toXPix = relToXPix(pd.toX); peakX = relToXPix(pd.peakX); peakY = relToYPix(pd.peakY); aucText = m_locale.toString(pd.auc, 'f', 4); timeText = m_locale.toString(pd.time, 'f', 4); @@ -347,7 +346,7 @@ QRegion SignalDrawer::erasePeak(const PeakDrawData& pd) else endXPix = toXPix; - peakReg = QRect(beginXPix, 0, endXPix - beginXPix, m_height); + peakReg = QRect(beginXPix, 0, endXPix - beginXPix + 1, m_height); if (peakReg.intersects(m_xAxisLabelRect)) { peakReg += m_xAxisLabelRect; } @@ -422,25 +421,29 @@ QRegion SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) if (pd.auc == 0) return QRect(); - /* Psycho: Calculate precise position of the beginning and end of the baseline */ - double fromSlope = (pd.fromY - pd.beforeFromY) / (pd.fromX - pd.beforeFromX); - double toSlope = (pd.toY - pd.beforeToY) / (pd.toX - pd.beforeToX); - double qf = pd.beforeFromY - fromSlope * pd.beforeFromX; - double qt = pd.beforeToY - toSlope * pd.beforeToX; - double precFromX = linesIntersection(fromSlope, qf, pd.blSlope, pd.blQ); - double precToX = linesIntersection(toSlope, qt, pd.blSlope, pd.blQ); - double precFromY = precFromX * pd.blSlope + pd.blQ; - double precToY = precToX * pd.blSlope + pd.blQ; - - /*qDebug() << __QFUNC__ << "idxStep" << pd.idxStep; - qDebug() << __QFUNC__ << "blSlope" << pd.blSlope << "blQ" << pd.blQ; - qDebug() << __QFUNC__ << "fromSlope" << fromSlope; - qDebug() << __QFUNC__ << "qf" << qf << "qt" << qt; - qDebug() << __QFUNC__ << precFromX << pd.beforeFromX; - qDebug() << __QFUNC__ << precFromY << pd.beforeFromY;*/ - - fromXPix = relToXPix(precFromX); fromYPix = relToYPix(precFromY); - toXPix = relToXPix(precToX); toYPix = relToYPix(precToY); + switch (pd.itype) { + case IntegrationType::INTERSECTION: + { + /* Psycho: Calculate precise position of the beginning and end of the baseline */ + double fromSlope = (pd.fromY - pd.beforeFromY) / (pd.fromX - pd.beforeFromX); + double toSlope = (pd.toY - pd.beforeToY) / (pd.toX - pd.beforeToX); + double qf = pd.beforeFromY - fromSlope * pd.beforeFromX; + double qt = pd.beforeToY - toSlope * pd.beforeToX; + double precFromX = linesIntersection(fromSlope, qf, pd.blSlope, pd.blQ); + double precToX = linesIntersection(toSlope, qt, pd.blSlope, pd.blQ); + double precFromY = precFromX * pd.blSlope + pd.blQ; + double precToY = precToX * pd.blSlope + pd.blQ; + + fromXPix = relToXPix(precFromX); fromYPix = relToYPix(precFromY); + toXPix = relToXPix(precToX); toYPix = relToYPix(precToY); + } + break; + default: + fromXPix = relToXPix(pd.fromX); fromYPix = relToYPix(pd.fromY); + toXPix = relToXPix(pd.toX); toYPix = relToYPix(pd.toY); + break; + } + peakX = relToXPix(pd.peakX); peakY = relToYPix(pd.peakY); aucText = m_locale.toString(pd.auc, 'f', 4); timeText = QString("A:") + m_locale.toString(pd.time, 'f', 4); @@ -448,6 +451,10 @@ QRegion SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) p.begin(target); p.setPen(Qt::red); p.drawLine(fromXPix, fromYPix, toXPix, toYPix); + if (pd.itype == IntegrationType::BASELINE) { + p.drawLine(fromXPix, fromYPix, fromXPix, relToYPix(pd.blFromY)); + p.drawLine(toXPix, toYPix, toXPix, relToYPix(pd.blToY)); + } /* Draw AREA and TIME caption */ p.setFont(font); @@ -474,7 +481,7 @@ QRegion SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) else endXPix = toXPix; - peakReg = QRect(beginXPix, 0, endXPix - beginXPix, m_height); + peakReg = QRect(beginXPix, 0, endXPix - beginXPix + 1, m_height); p.end(); if (peakReg.intersects(m_xAxisLabelRect)) { -- 2.43.5