From: Michal MalĂ˝ Date: Thu, 13 Mar 2014 22:48:42 +0000 (+0100) Subject: Update data plotting logic so that the peak baseline is rendered X-Git-Tag: 0.2d~4 X-Git-Url: https://gitweb.devoid-pointer.net/?a=commitdiff_plain;h=24d861d3903b0c61a51d177d2e76af554a11dd3c;p=anyanka.git Update data plotting logic so that the peak baseline is rendered properly and Y-axis scale is more accurate --- diff --git a/integratedpeak.cpp b/integratedpeak.cpp index 2644491..b0c4216 100644 --- a/integratedpeak.cpp +++ b/integratedpeak.cpp @@ -34,9 +34,12 @@ const QString IntegratedPeak::KEY_TOIDX("toIdx"); const QString IntegratedPeak::KEY_TOTIME("toTime"); const QString IntegratedPeak::KEY_TOY("toY"); const QString IntegratedPeak::KEY_TYPE("type"); +const QString IntegratedPeak::KEY_RELBLSLOPE("relBlSlope"); +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, QObject* parent) : + size_t fromIdx, size_t toIdx, double fromTime, double toTime, double fromY, double toY, + double relBlSlope, double relBlQ, QObject* parent) : QObject(parent), JSONSerializable(), m_auc(auc), @@ -49,7 +52,9 @@ IntegratedPeak::IntegratedPeak(IntegratedPeak::Type type, double auc, size_t pea m_toIdx(toIdx), m_toTime(toTime), m_toY(toY), - m_type(type) + m_type(type), + m_relBlSlope(relBlSlope), + m_relBlQ(relBlQ) { } @@ -109,6 +114,13 @@ bool IntegratedPeak::deserialize(const QJsonValue& value) else m_type = Type::VALLEY; + if (!jso.contains(KEY_RELBLSLOPE)) + return false; + m_relBlSlope = jso.value(KEY_RELBLSLOPE).toDouble(); + if (!jso.contains(KEY_RELBLQ)) + return false; + m_relBlQ = jso.value(KEY_RELBLQ).toDouble(); + return true; } @@ -133,6 +145,8 @@ QJsonValue IntegratedPeak::serialize() const jso.insert(KEY_TOTIME, QJsonValue(m_toTime)); jso.insert(KEY_TOY, QJsonValue(m_toY)); jso.insert(KEY_TYPE, QJsonValue(type)); + jso.insert(KEY_RELBLSLOPE, QJsonValue(m_relBlSlope)); + jso.insert(KEY_RELBLQ, QJsonValue(m_relBlQ)); return jso; } diff --git a/integratedpeak.h b/integratedpeak.h index 89228e3..af38729 100644 --- a/integratedpeak.h +++ b/integratedpeak.h @@ -39,7 +39,7 @@ 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, QObject* parent = nullptr); + double fromY, double toY, double relBlSlope, double relBlQ, QObject* parent = nullptr); double auc() const { return m_auc; } double baselineSlope() const; size_t fromIdx() const { return m_fromIdx; } @@ -49,6 +49,8 @@ public: size_t peakIdx() const { return m_peakIdx; } double peakTime() const { return m_peakTime; } double peakY() const { return m_peakY; } + double relBlQ() const { return m_relBlQ; } + double relBlSlope() const { return m_relBlSlope; } size_t toIdx() const { return m_toIdx; } double toTime() const { return m_toTime; } double toY() const { return m_toY; } @@ -70,6 +72,8 @@ private: double m_toTime; double m_toY; Type m_type; + double m_relBlSlope; + double m_relBlQ; static const QString KEY_AUC; static const QString KEY_FROMIDX; @@ -82,6 +86,8 @@ private: static const QString KEY_TOTIME; static const QString KEY_TOY; static const QString KEY_TYPE; + static const QString KEY_RELBLSLOPE; + static const QString KEY_RELBLQ; public slots: diff --git a/integrator.cpp b/integrator.cpp index 6aa8ed0..41b1d27 100644 --- a/integrator.cpp +++ b/integrator.cpp @@ -77,7 +77,8 @@ std::vector> Integrator::allPeaks() return allPeaks; } -Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak) +Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak, + double relBlSlope, double relBlQ) { size_t peakValueIdx; size_t startIntersIdx, stopIntersIdx; @@ -102,8 +103,6 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do std::swap(startY, stopY); } - qDebug() << "INTEG" << startIdx << stopIdx << startY << stopY; - slope = (stopY - startY) / static_cast(stopIdx - startIdx); /* Try to find first intersection */ if (startY < m_signal->valueAt(startIdx)) { @@ -183,7 +182,7 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do 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)); + startYVal, stopYVal, relBlSlope, relBlQ)); emit addingPeak(m_peaksList.count()); m_peaksList.append(peak); emit peakAdded(); diff --git a/integrator.h b/integrator.h index b170f69..2dce9ac 100644 --- a/integrator.h +++ b/integrator.h @@ -46,7 +46,8 @@ public: void addPeak(std::shared_ptr peak); std::shared_ptr deletePeak(size_t idx); std::vector> allPeaks(); - ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak); + ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak, + double relBlSlope, double relBlQ); std::shared_ptr peakByListIdx(const size_t idx); //std::multimap>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); } //std::multimap>::const_iterator peaksCEnd() const { return m_peaks.cend(); } diff --git a/signalcontroller.cpp b/signalcontroller.cpp index 63406b0..a205aea 100644 --- a/signalcontroller.cpp +++ b/signalcontroller.cpp @@ -104,7 +104,7 @@ bool SignalController::deserialize(const QJsonValue& value) std::shared_ptr SignalController::getGraphDrawData(const double fromX, const double toX) { size_t fromIdx, toIdx; - double* ddata; + std::pair* ddata; size_t ddataLen; if (toX <= fromX) { @@ -113,19 +113,20 @@ std::shared_ptr SignalController::getGraphDrawData(const double f } fromIdx = relToIdx(fromX); - toIdx = relToIdx(toX); + toIdx = relToIdx(toX)+1; if (toIdx >= m_signal->count()) { - Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " toIdx (" + QString::number(toIdx) + ") out of bounds, max (" + + /*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(new GraphDrawData()); + return std::shared_ptr(new GraphDrawData());*/ + toIdx = m_signal->count()-1; } ddataLen = toIdx - fromIdx + 1; - ddata = new double[ddataLen]; + ddata = new std::pair[ddataLen]; for (size_t idx = fromIdx; idx <= toIdx; idx++) { - double current = valueToRel(m_signal->valueAt(idx)); - ddata[idx - fromIdx] = current; + std::pair p(idxToRel(idx), valueToRel(m_signal->valueAt(idx))); + ddata[idx - fromIdx] = p; } return std::shared_ptr(new GraphDrawData(ddata, ddataLen)); @@ -136,7 +137,6 @@ std::vector SignalController::getPeaksDrawData(const double fromX, std::vector peaks; size_t fromIdx, toIdx; std::vector> allPeaks; - // std::multimap>::const_iterator cit = m_integrator->peaksCBegin(); if (toX <= fromX) { Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " toX is lower than fromX"); @@ -183,6 +183,8 @@ RulerDrawData SignalController::getRulerDrawData(const double from, const double case Axis::VALUE: fromAbs = relToValue(from); toAbs = relToValue(to); + + qDebug() << __QFUNC__ << fromAbs << toAbs; break; } @@ -203,21 +205,26 @@ RulerDrawData SignalController::getRulerDrawData(const double from, const double Signal::TimeValuePair SignalController::getXYValues(const double x) { size_t idx = relToIdx(x); - if (idx >= m_signal->count()) { + if (idx >= m_signal->count()-1) { Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " idx value " + QString::number(idx) + " out of bounds!"); return Signal::TimeValuePair(0, 0); } - return m_signal->pairAt(idx); + /* Workaround for the way how the data are plotted on the screen */ + 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) { size_t fromIdx, toIdx; double fromVal, toVal; + double relBlSlope = (toY - fromY) / (toX - fromX); + double relBlQ = fromY - relBlSlope * fromX; Integrator::ReturnCode ret; std::shared_ptr peak; + qDebug() << __QFUNC__ << fromX << fromY << toX << toY; + fromIdx = relToIdx(fromX); toIdx = relToIdx(toX); if (fromIdx >= m_signal->count()) { @@ -231,7 +238,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); + ret = m_integrator->integrate(fromIdx, toIdx, fromVal, toVal, peak, relBlSlope, relBlQ); switch (ret) { case Integrator::ReturnCode::SUCCESS: @@ -270,8 +277,18 @@ QJsonValue SignalController::serialize() const PeakDrawData SignalController::genPeakDrawData(const std::shared_ptr peak) { - return PeakDrawData(idxToRel(peak->fromIdx()), valueToRel(peak->fromY()), - idxToRel(peak->toIdx()), valueToRel(peak->toY()), + double beforeFromY = m_signal->valueAt(peak->fromIdx() - 1); + double beforeToY = m_signal->valueAt(peak->toIdx() - 1); + double fromY = m_signal->valueAt(peak->fromIdx()); + double toY = m_signal->valueAt(peak->toIdx()); + + //qDebug() << __QFUNC__ << beforeFromY << fromY + // << beforeToY << toY; + //qDebug() << m_signal->timeAt(peak->fromIdx() - 0) << m_signal->timeAt(peak->fromIdx() + 1) << peak->fromTime(); + + return PeakDrawData(idxToRel(peak->fromIdx()), valueToRel(fromY), idxToRel(peak->fromIdx()-1), valueToRel(beforeFromY), + idxToRel(peak->toIdx()), 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()); } @@ -299,7 +316,7 @@ double SignalController::timeToRel(const double time) size_t SignalController::relToIdx(const double rel) { - size_t ret = (m_signal->count() - 1) * (rel - RELATIVE_MIN) / (RELATIVE_MAX - RELATIVE_MIN); + size_t ret = (m_signal->count()) * (rel - RELATIVE_MIN) / (RELATIVE_MAX - RELATIVE_MIN); //qDebug() << __QFUNC__ << rel << ret << m_signal->count(); return ret; } diff --git a/signalcontroller.h b/signalcontroller.h index 5a3db71..4f5f8f5 100644 --- a/signalcontroller.h +++ b/signalcontroller.h @@ -49,7 +49,7 @@ struct GUIViewport { struct GraphDrawData { GraphDrawData() : ddata(nullptr), ddataLen(0) {} - GraphDrawData(const double* ddata, const size_t ddataLen) : + GraphDrawData(const std::pair* ddata, const size_t ddataLen) : ddata(ddata), ddataLen(ddataLen) {} ~GraphDrawData() { @@ -57,17 +57,25 @@ struct GraphDrawData { delete[] ddata; } - const double* ddata; + const std::pair* 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, + 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) {} + 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) : - fromX(fromX), fromY(fromY), toX(toX), toY(toY), peakX(peakX), peakY(peakY), auc(auc), time(time) {} + 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) {} const double fromX, fromY, toX, toY; + const double beforeFromX, beforeFromY, beforeToX, beforeToY; + const double blSlope, blQ; const double peakX, peakY; const double auc, time; }; diff --git a/signaldrawer.cpp b/signaldrawer.cpp index 107f60d..1360909 100644 --- a/signaldrawer.cpp +++ b/signaldrawer.cpp @@ -287,8 +287,7 @@ QRect SignalDrawer::erasePeak(const PeakDrawData& pd) bool SignalDrawer::renderGraph(QPixmap* const target) { QPainter p; - double xStep, yStep; - int fromXPix = SCALE_MARGIN_VALUE, fromYPix; + int fromXPix, fromYPix; if (m_width < SCALE_MARGIN_VALUE || m_height < SCALE_MARGIN_VALUE) { Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " invalid dimensions (" + QString::number(m_width) + ", " + QString::number(m_height) + ")"); @@ -303,10 +302,10 @@ bool SignalDrawer::renderGraph(QPixmap* const target) p.fillRect(0, 0, m_width, m_height, Qt::white); p.setPen(QColor(Qt::blue)); - xStep = static_cast(m_gWidth) / m_gdData->ddataLen; + /*xStep = static_cast(m_gWidth) / m_gdData->ddataLen; yStep = static_cast(m_gHeight) / (m_relYMax - m_relYMin); /*Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + " yStep: " + QString::number(yStep) - + " fY " + QString::number(m_relYMin) + " tY " + QString::number(m_relYMax));*/ + + " fY " + QString::number(m_relYMin) + " tY " + QString::number(m_relYMax));* fromYPix = m_gHeight - yStep * (m_gdData->ddata[0] - m_relYMin); for (size_t i = 1; i < m_gdData->ddataLen; i++) { int toXPix = xStep * i + SCALE_MARGIN_VALUE; @@ -314,11 +313,20 @@ bool SignalDrawer::renderGraph(QPixmap* const target) p.drawLine(fromXPix, fromYPix, toXPix, toYPix); fromXPix = toXPix; fromYPix = toYPix; + }*/ + + fromXPix = relToXPix(m_gdData->ddata[0].first); + fromYPix = relToYPix(m_gdData->ddata[0].second); + for (size_t i = 1; i < m_gdData->ddataLen; i++) { + int toXPix = relToXPix(m_gdData->ddata[i].first); + int toYPix = relToYPix(m_gdData->ddata[i].second); + p.drawLine(fromXPix, fromYPix, toXPix, toYPix); + fromXPix = toXPix; + fromYPix = toYPix; } p.end(); - return true; } @@ -353,8 +361,25 @@ QRect SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) if (pd.auc == 0) return QRect(); - fromXPix = relToXPix(pd.fromX); fromYPix = relToYPix(pd.fromY); - toXPix = relToXPix(pd.toX); toYPix = relToYPix(pd.toY); + /* 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); 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); @@ -363,6 +388,14 @@ QRect SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) p.setPen(Qt::red); p.drawLine(fromXPix, fromYPix, toXPix, toYPix); + /** DEBUG **/ + p.setPen(Qt::yellow); + p.drawEllipse(QPoint(relToXPix(pd.beforeFromX), relToYPix(pd.beforeFromY)), 10, 10); + p.drawEllipse(QPoint(relToXPix(pd.beforeToX), relToYPix(pd.beforeToY)), 10, 10); + p.setPen(Qt::black); + p.drawEllipse(QPoint(relToXPix(pd.fromX), relToYPix(pd.fromY)), 10, 10); + p.drawEllipse(QPoint(relToXPix(pd.toX), relToYPix(pd.toY)), 10, 10); + /* Draw AREA and TIME caption */ p.setFont(font); p.setPen(Qt::black); @@ -378,9 +411,8 @@ QRect SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) p.restore(); aTextWidth = fm.width(aucText); p.drawText(peakX + 5, peakY, aucText); - p.end(); - if (peakX - tTextHeight < fromXPix) + if (peakX - tTextHeight < fromXPix) beginXPix = (peakX - tTextHeight > 0) ? peakX - tTextHeight : 0; else beginXPix = fromXPix; @@ -389,21 +421,30 @@ QRect SignalDrawer::renderPeak(const PeakDrawData& pd, QPixmap* const target) else endXPix = toXPix; + return QRect(beginXPix, 0, endXPix - beginXPix, m_height); } /** Private functions **/ +double SignalDrawer::linesIntersection(const double k1, const double q1, const double k2, const double q2) +{ + double ret = (q1 - q2) / (k2 - k1); + qDebug() << __QFUNC__ << ret; + + return ret; +} + int SignalDrawer::relToXPix(const double rel) { - const int ret = m_gWidth / (m_relXMax - m_relXMin) * (rel - m_relXMin) + SCALE_MARGIN_VALUE; + const double ret = m_gWidth / (m_relXMax - m_relXMin) * (rel - m_relXMin) + SCALE_MARGIN_VALUE; //qDebug() << __QFUNC__ << ret; return ret; } int SignalDrawer::relToYPix(const double rel) { - const int ret = m_gHeight - (m_gHeight / (m_relYMax - m_relYMin) * (rel - m_relYMin)); + const double ret = m_gHeight - (m_gHeight / (m_relYMax - m_relYMin) * (rel - m_relYMin)); //qDebug() << __QFUNC__ << ret; return ret; } @@ -412,7 +453,7 @@ double SignalDrawer::xPixToRel(const int pix) { double ret; if (pix < SCALE_MARGIN_VALUE) - return 0.0; + return m_relXMin; ret = ((pix - SCALE_MARGIN_VALUE) * (m_relXMax - m_relXMin) / m_gWidth) + m_relXMin; //qDebug() << __QFUNC__ << ret; return ret; @@ -423,7 +464,9 @@ double SignalDrawer::yPixToRel(const int pix) const double range = m_relYMax - m_relYMin; const int invPix = m_gHeight - pix; if (invPix < 0) - return 0; + return m_relYMin; + else if (invPix > m_gHeight) + return m_relXMax; return (range / m_gHeight * invPix) + m_relYMin; } diff --git a/signaldrawer.h b/signaldrawer.h index 767b9b7..0140e4d 100644 --- a/signaldrawer.h +++ b/signaldrawer.h @@ -97,6 +97,8 @@ protected: static const int SCALE_MARGIN_VALUE; private: + double linesIntersection(const double k1, const double q1, const double k2, const double q2); + int m_height; int m_width; int m_gHeight;