041-Third generation software development-QCustcomPlot waveform annotation

Header image

Third generation software development-QCustcomPlot waveform annotation

Article directory

  • Third generation software development-QCustcomPlot waveform annotation
    • Project Introduction
    • QCustcomPlot waveform annotation
      • Effect
      • initialization
      • draw


Keywords:
Qt
Qml
Keyword 3,
Keyword 4,
Keyword 5

Project introduction

Welcome to our QML & C++ project! This project combines the power of QML (Qt Meta-Object Language) and C++ to develop excellent user interfaces and high-performance backend logic.

In the project, we leveraged QML’s declarative syntax and visual design capabilities to create a modern user interface. Through intuitive coding and reusable components, we can quickly develop rich and diverse interface effects and animation effects. At the same time, we use QML’s powerful integration capabilities to easily integrate C++’s underlying logic and data model into the front-end interface.

On the backend side, we use C++ to write high-performance algorithms, data processing, and computational logic. C++ is a powerful programming language that offers excellent performance and scalability. Our team is committed to optimizing code and reducing resource consumption to ensure that our projects run efficiently on a variety of platforms and devices.

Whether you’re interested in QML and C++ development or need us to build complex user interfaces and backend logic for you, we’re ready to support you. Please feel free to contact us and let’s build a modern, high-performance QML & C++ project together!

Important?

?The price of this column will increase after the third generation soft development update.

QCustcomPlot waveform annotation

Effect

Let’s take a look at the effect first. If the waveform is captured, the starting point, highest point and lowest point will be marked on the corresponding curve, as shown in the figure below.

image-20230807225118468

Hey hey hey, whether you have seen it before or learned the first waveform detection method from the previous article, you should see part of the QCustcomPlot waveform annotation content in it. Today our principle is still the same. Try today’s annotation. It’s a bit too much.

The link is here: https://dreamlife.blog.csdn.net/article/details/128716820

image-20230807183545114

Initialization

The following code has no technical content. It just initializes all the controls we need to use, and then hides it. In this way, if the waveform is not captured by default, it will not be there, and the user will not know that we What was done?

/**
 * @brief XXXX::initWavesCatched initialization amplitude
 */
void XXXX::initWavesCatched()
{
    /// Data flattening captures the waveform signal
    if(m_dataChannel == 1)
    {
        connect(m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData, & amp;Turing_ElectroPhysiologyPullData::signal_wavesCatched,
                this, &XXXX::slot_wavesCatched);
    }
    else if(m_dataChannel == 2)
    {
        connect(m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData, & amp;Turing_ElectroPhysiologyPullData::signal_wavesCatched,
                this, &XXXX::slot_wavesCatched);
    }
    QPen pen;
    pen.setColor("#2DAAE1");
    pen.setWidth(2);
    pen.setStyle(Qt::SolidLine);

    m_labelTime = new QCPItemText(m_qCustomPlot);
    m_labelTime->setLayer("overlay");
    m_labelTime->setClipToAxisRect(false);
    m_labelTime->setPadding(QMargins(5, 5, 5, 5));
    m_labelTime->setFont(QFont("宋体", 16));
    m_labelTime->setColor(QColor("#2DAAE1"));
    m_labelTime->setVisible(false);

    m_lineTime = new QCPItemLine(m_qCustomPlot);
    m_lineTime->setPen(pen);
    m_lineTime->setLayer("overlay");
    m_lineTime->setClipToAxisRect(false);
    m_lineTime->setVisible(false);

    m_lineStart = new QCPItemLine(m_qCustomPlot);
    m_lineStart->setPen(pen);
    m_lineStart->setLayer("overlay");
    m_lineStart->setClipToAxisRect(false);
    m_lineStart->setVisible(false);

    m_lineMax = new QCPItemLine(m_qCustomPlot);
    m_lineMax->setPen(pen);
    m_lineMax->setLayer("overlay");
    m_lineMax->setClipToAxisRect(false);
    m_lineMax->setVisible(false);

    m_lineMin = new QCPItemLine(m_qCustomPlot);
    m_lineMin->setPen(pen);
    m_lineMin->setLayer("overlay");
    m_lineMin->setClipToAxisRect(false);
    m_lineMin->setVisible(false);


    m_labelAmplitude = new QCPItemText(m_qCustomPlot);
    m_labelAmplitude->setLayer("overlay");
    m_labelAmplitude->setClipToAxisRect(false);
    m_labelAmplitude->setPadding(QMargins(5, 5, 5, 5));
    m_labelAmplitude->setFont(QFont("宋体", 16));
    m_labelAmplitude->setColor(QColor("#2DAAE1"));
    m_labelAmplitude->setVisible(false);

    m_lineAmplitudeTop = new QCPItemLine(m_qCustomPlot);
    m_lineAmplitudeTop->setPen(pen);
    m_lineAmplitudeTop->setLayer("overlay");
    m_lineAmplitudeTop->setClipToAxisRect(false);
    m_lineAmplitudeTop->setVisible(false);


    m_lineAmplitudeBottom = new QCPItemLine(m_qCustomPlot);
    m_lineAmplitudeBottom->setPen(pen);
    m_lineAmplitudeBottom->setLayer("overlay");
    m_lineAmplitudeBottom->setClipToAxisRect(false);
    m_lineAmplitudeBottom->setVisible(false);

}

Draw

After the above initialization, here we use one of Qt’s classics, the signal slot. Remember in the previous article, if we catch the waveform, a signal will be triggered. The slot to which the signal is connected is this function. The function of this function It is to draw the corresponding lines, arrows, and data based on the waveform coordinates in the previous article.

/**
 * @brief XXXX::slot_wavesCatched algorithm waveform drawing
 * @param chanelIndex
 * @param startIndex
 * @param crestIndex
 * @param troughIndex
 * @param endIndex
 */
void XXXX::slot_wavesCatched(int chanelIndex, int startIndex, int crestIndex, int troughIndex, int endIndex)
{
// qDebug() << "slot_wavesCatched 1 " << chanelIndex;
    if(startIndex == crestIndex)
    {
        closeWavesCatched();
        return;
    }

    if(chanelIndex + 1 != m_dataChannel)
        return;


    // Calculate the x and y unit pixel sizes respectively
    // Get the x-axis object
    // Get the x-axis range
    // Get the drawing area size
    // Calculate unit pixel size
    m_xPixelSize = m_qCustomPlot->xAxis->range().size() / m_qCustomPlot->viewport().width();
    m_yPixelSize = m_qCustomPlot->yAxis->range().size() / m_qCustomPlot->viewport().height();


    m_yStartValue= m_qCustomPlot->graph(0)->data()->at(startIndex)->value;
    m_yCrestValue= m_qCustomPlot->graph(0)->data()->at(crestIndex)->value;
    m_yTroughValue= m_qCustomPlot->graph(0)->data()->at(troughIndex)->value;
// double yEndValue= m_qCustomPlot->graph(chanelIndex)->data()->at(endIndex)->value;

// qDebug() << "m_yCrestValue" << m_yCrestValue << "m_yTroughValue" << m_yTroughValue;



    m_yCrestValue= m_qCustomPlot->graph(0)->data()->at(crestIndex)->value;
    m_yTroughValue= m_qCustomPlot->graph(0)->data()->at(troughIndex)->value;


    m_lineStart->setVisible(true);
    m_lineStart->start->setCoords(startIndex,m_yStartValue);
    m_lineStart->end->setCoords(startIndex,m_yStartValue-100*m_yPixelSize);


    if(startIndex-100*m_xPixelSize > 0)
    {
        m_labelTime->setVisible(true);
        setStimDelay((startIndex + m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData->g_userProfile->stimMaskDelay())*0.125);
        m_labelTime->setText(QString::number((startIndex + m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData->g_userProfile->stimMaskDelay())*0.125, 'f', 1) + "ms");
        m_labelTime->position->setCoords(startIndex-100*m_xPixelSize, m_yStartValue-50*m_yPixelSize);


        m_lineTime->setVisible(true);
        m_lineTime->start->setParentAnchor(m_labelTime->right);
        m_lineTime->end->setCoords(startIndex-1,m_yStartValue-50*m_yPixelSize);
        m_lineTime->setHead(QCPLineEnding::esSpikeArrow);//Set arrow type (triangle, rhombus, square, etc.)
    }
    else
    {
        m_labelTime->setVisible(true);
        setStimDelay((startIndex + m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData->g_userProfile->stimMaskDelay())*0.125);
        m_labelTime->setText(QString::number((startIndex + m_turing_ElectroPhysiology->g_turing_ElectroPhysiologyPullData->g_userProfile->stimMaskDelay())*0.125,'f',1) + "ms");
        m_labelTime->position->setCoords(startIndex + 50*m_xPixelSize, m_yStartValue-50*m_yPixelSize);


        m_lineTime->setVisible(true);
        m_lineTime->start->setParentAnchor(m_labelTime->left);
        m_lineTime->end->setCoords(startIndex + 1,m_yStartValue-50*m_yPixelSize);
        m_lineTime->setHead(QCPLineEnding::esSpikeArrow);//Set arrow type (triangle, rhombus, square, etc.)
    }


    if(crestIndex <troughIndex)
    {
        m_lineMax->setVisible(true);
        m_lineMax->start->setCoords(crestIndex,m_yCrestValue);
        m_lineMax->end->setCoords(endIndex,m_yCrestValue);

        m_lineMin->setVisible(true);
        m_lineMin->start->setCoords(crestIndex,m_yTroughValue);
        m_lineMin->end->setCoords(endIndex,m_yTroughValue);
    }
    else
    {
        m_lineMax->setVisible(true);
        m_lineMax->start->setCoords(troughIndex,m_yCrestValue);
        m_lineMax->end->setCoords(endIndex,m_yCrestValue);

        m_lineMin->setVisible(true);
        m_lineMin->start->setCoords(troughIndex,m_yTroughValue);
        m_lineMin->end->setCoords(endIndex,m_yTroughValue);
    }


    m_labelAmplitude->setVisible(true);
    m_labelAmplitude->setText(QString("%1uV").arg(int(m_yCrestValue - m_yTroughValue)));
    m_labelAmplitude->position->setCoords(troughIndex, (m_yCrestValue + m_yTroughValue)/2);

    m_lineAmplitudeTop->setVisible(true);
    m_lineAmplitudeTop->start->setParentAnchor(m_labelAmplitude->top);
    m_lineAmplitudeTop->end->setCoords(troughIndex,m_yCrestValue-1);
    m_lineAmplitudeTop->setHead(QCPLineEnding::esSpikeArrow);//Set arrow type (triangle, rhombus, square, etc.)


    m_lineAmplitudeBottom->setVisible(true);
    m_lineAmplitudeBottom->start->setParentAnchor(m_labelAmplitude->bottom);
    m_lineAmplitudeBottom->end->setCoords(troughIndex,m_yTroughValue + 1);
    m_lineAmplitudeBottom->setHead(QCPLineEnding::esSpikeArrow);//Set arrow type (triangle, rhombus, square, etc.)

    m_qCustomPlot->replot(QCustomPlot::rpQueuedReplot);

}

Blog Signature 2021