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),
m_toIdx(toIdx),
m_toTime(toTime),
m_toY(toY),
- m_type(type)
+ m_type(type),
+ m_relBlSlope(relBlSlope),
+ m_relBlQ(relBlQ)
{
}
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;
}
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;
}
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; }
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; }
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;
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:
return allPeaks;
}
-Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak)
+Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak,
+ double relBlSlope, double relBlQ)
{
size_t peakValueIdx;
size_t startIntersIdx, stopIntersIdx;
std::swap(startY, stopY);
}
- qDebug() << "INTEG" << startIdx << stopIdx << startY << stopY;
-
slope = (stopY - startY) / static_cast<double>(stopIdx - startIdx);
/* Try to find first intersection */
if (startY < m_signal->valueAt(startIdx)) {
peak = std::shared_ptr<IntegratedPeak>(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();
void addPeak(std::shared_ptr<IntegratedPeak> peak);
std::shared_ptr<const IntegratedPeak> deletePeak(size_t idx);
std::vector<std::shared_ptr<const IntegratedPeak>> allPeaks();
- ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak);
+ ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr<IntegratedPeak>& peak,
+ double relBlSlope, double relBlQ);
std::shared_ptr<const IntegratedPeak> peakByListIdx(const size_t idx);
//std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); }
//std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator peaksCEnd() const { return m_peaks.cend(); }
std::shared_ptr<GraphDrawData> SignalController::getGraphDrawData(const double fromX, const double toX)
{
size_t fromIdx, toIdx;
- double* ddata;
+ std::pair<double, double>* ddata;
size_t ddataLen;
if (toX <= fromX) {
}
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<GraphDrawData>(new GraphDrawData());
+ return std::shared_ptr<GraphDrawData>(new GraphDrawData());*/
+ toIdx = m_signal->count()-1;
}
ddataLen = toIdx - fromIdx + 1;
- ddata = new double[ddataLen];
+ ddata = new std::pair<double, double>[ddataLen];
for (size_t idx = fromIdx; idx <= toIdx; idx++) {
- double current = valueToRel(m_signal->valueAt(idx));
- ddata[idx - fromIdx] = current;
+ std::pair<double, double> p(idxToRel(idx), valueToRel(m_signal->valueAt(idx)));
+ ddata[idx - fromIdx] = p;
}
return std::shared_ptr<GraphDrawData>(new GraphDrawData(ddata, ddataLen));
std::vector<PeakDrawData> peaks;
size_t fromIdx, toIdx;
std::vector<std::shared_ptr<const IntegratedPeak>> allPeaks;
- // std::multimap<size_t, std::shared_ptr<IntegratedPeak>>::const_iterator cit = m_integrator->peaksCBegin();
if (toX <= fromX) {
Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " toX is lower than fromX");
case Axis::VALUE:
fromAbs = relToValue(from);
toAbs = relToValue(to);
+
+ qDebug() << __QFUNC__ << fromAbs << toAbs;
break;
}
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<double, double>(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<IntegratedPeak> peak;
+ qDebug() << __QFUNC__ << fromX << fromY << toX << toY;
+
fromIdx = relToIdx(fromX);
toIdx = relToIdx(toX);
if (fromIdx >= m_signal->count()) {
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:
PeakDrawData SignalController::genPeakDrawData(const std::shared_ptr<const IntegratedPeak> 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());
}
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;
}
struct GraphDrawData {
GraphDrawData() :
ddata(nullptr), ddataLen(0) {}
- GraphDrawData(const double* ddata, const size_t ddataLen) :
+ GraphDrawData(const std::pair<double, double>* ddata, const size_t ddataLen) :
ddata(ddata), ddataLen(ddataLen) {}
~GraphDrawData()
{
delete[] ddata;
}
- const double* ddata;
+ const std::pair<double, 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,
+ 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;
};
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) + ")");
p.fillRect(0, 0, m_width, m_height, Qt::white);
p.setPen(QColor(Qt::blue));
- xStep = static_cast<double>(m_gWidth) / m_gdData->ddataLen;
+ /*xStep = static_cast<double>(m_gWidth) / m_gdData->ddataLen;
yStep = static_cast<double>(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;
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;
}
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);
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);
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;
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;
}
{
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;
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;
}
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;