Aggiornamento dati



  • Buongiorno a tutti,
    sto cercando di inserire dei dati, in un grafico a dispersione, ogni volta che sono disponibili nella Queue. Quando eseguo il programma però i punti non vengono plottati sul grafico. Riuscite ad aiutarmi a risolvere questo problema? Di sotto riporto il codice che ho scritto.
    Un grazie in anticipo

    N.B. la funzione estrai_dati riceve una stringa di dati e ne ricava tre float xpos, ypos e zpos, che sono i dati che verranno plottati in seguito

    #include <QtDataVisualization>
    #include <QtWidgets>
    #include <QDialog>
    #include <QtCore>
    #include <stdio.h>
    #include <stdlib.h>
    #include "mygrafic3d.h"
    
    #define LIMITE 10
    #define DIM 10
    #define EPSILON 0.02
    #define G 9.81
    #define T 1000
    
    using namespace QtDataVisualization;
    
    mygrafic3d::mygrafic3d(Q3DScatter *scatter)
        : m_graph(scatter),
          m_fontSize(40.0f),
          m_style(QAbstract3DSeries::MeshSphere),
          m_smooth(true),
          m_array(0),
          m_series(new QScatter3DSeries)/*,
          inizio(0.0f),
          fine(100.0f)*/
    
    {
        //Modifiche visive
        m_graph->activeTheme()->setType(Q3DTheme::ThemeQt);
        QFont font = m_graph->activeTheme()->font();
        font.setPointSize(m_fontSize);
        m_graph->activeTheme()->setFont(font);
        m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
        m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
    
        m_graph->axisX()->setTitle("X");
        m_graph->axisY()->setTitle("Y");
        m_graph->axisZ()->setTitle("Z");
    
        m_graph->axisX()->setTitleVisible(true);
        m_graph->axisY()->setTitleVisible(true);
        m_graph->axisZ()->setTitleVisible(true);
    
        //creo un QScatterDataProxy e il QScatter3DSeries associato
        QScatterDataProxy *proxy = new QScatterDataProxy;
        m_series = new QScatter3DSeries(proxy);
        m_series->setItemLabelFormat(QStringLiteral("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"));
        m_series->setMeshSmooth(m_smooth);
        m_graph->addSeries(m_series);
    
        qDebug()<< "Parte la queque!";
        consume();
        qDebug()<< "fuori dalla queque!";
    }
    
    mygrafic3d::~mygrafic3d()
    {
        delete m_graph;
    }
    
    void mygrafic3d::consume()
    {
        for(;;)
        {
            qDebug()<< "Dentro Queque!";
            m_QueueMutex.lock();
            qDebug()<< "Dentro Queque lock!";
            while (m_Queue.isEmpty())
            {
                m_WaitAnyItem.wait(&m_QueueMutex);
            }
    
            QByteArray mykeypass = m_Queue.first();
            m_Queue.removeFirst();
    
            m_QueueMutex.unlock();
    
            if (*mykeypass == NULL)
            {
                break;
            }
    
            qDebug()<< "Chiama funzioni";
            estrai_dati(mykeypass);
            addData();
        }
    }
    
    void mygrafic3d::addData()
    {
        //m_series->dataProxy()->addItem(QVector3D (xpos, ypos, zpos));
    
        m_array = new QScatterDataArray;
        int arraysize = 100;
        if (arraysize != m_array->size())
            m_array->resize(arraysize);
        QScatterDataItem *ptrToDataArray = &m_array->first();
    
        ptrToDataArray->setPosition(QVector3D(xpos, ypos, zpos));
        ptrToDataArray++;
    
        m_series->dataProxy()->resetArray(m_array);
    }
    

  • Qt Champions 2018

    Stai bloccando l'event loop con for(;;). In pratica Qt non puo' plottare se tu non gli dai il controllo. Devi rimuovere il loop infinito e usare signal/slot per dire a mygrafic3d quando un altro dato e' nella coda



  • Se ho capito bene devo eliminare la funzione consume() e al suo posto usare il signal/slot e successivamente chiamare estrai_dati() e addData()?

    Domanda la funzione addData() è corretta per plottare i dati (xpos, ypos e zpos) sul grafico ogni volta che mi arrivano?


  • Qt Champions 2018

    @Lorenz_95 said in Aggiornamento dati:

    Se ho capito bene devo eliminare la funzione consume() e al suo posto usare il signal/slot e successivamente chiamare estrai_dati() e addData()?

    Corretto

    Domanda la funzione addData() è corretta per plottare i dati (xpos, ypos e zpos) sul grafico ogni volta che mi arrivano?

    si e no. E giusto il concetto ma non l'esecuzione. Tu al momento crei un nuovo array ogni volta, imposti l'ultimo valore (lasciando gli altri non definiti) e poi lo rimetti dentro al grafico. Quello che dovresti fare invece e' estrarre l'array vecchio (m_series->dataProxy()->array()) e aggiungere a quello il nuovo dato e poi chiamare resetArray



  • Quindi l'array lo imposto una volta prima della chiamata di addData() e poi inserisco i nuovi valori. Se ho capito bene il codice lo devo modificare così?

    // Prima della chiamata di addData
    m_array = new QScatterDataArray;
    
    //funzione addData    
    void mygrafic3d::addData()
    {
    	int arraysize = 100;
        if (arraysize != m_array->size())
            m_array->resize(arraysize);
    
    	QScatterDataItem *ptrToDataArray = &m_array->first();
    	
    	m_series->dataProxy()->array();
    
        ptrToDataArray->setPosition(QVector3D(xpos, ypos, zpos));
        ptrToDataArray++;
    
        m_series->dataProxy()->resetArray(m_array);
    }
    

  • Qt Champions 2018

    quasi.

    // Prima della chiamata di addData
    m_series->dataProxy()->resetArray( new QScatterDataArray);
    
    void mygrafic3d::addData()
    {
    	QScatterDataArray* array = m_series->dataProxy()->array();
    array->append(QScatterDataItem(QVector3D(xpos, ypos, zpos)));
        m_series->dataProxy()->resetArray(array );
    }
    


  • Grazie mille, vi farò sapere se funziona.
    Ultima cosa per il signal/slot (visto che non l ho mai usato) è sufficiente usare QObject :: connect()?


  • Qt Champions 2018

    Si, connect() e' il ponte tra il signal e lo slot



  • Quindi ogni volta che mi arriva un dato eseguo la connect() che passa il dato al codice scritto all'inizio del topic e affinché venga letto da mygrafic3d::mygrafic3d(Q3DScatter *scatter) devo aggiungere un altra funzione?


  • Qt Champions 2018

    @Lorenz_95 said in Aggiornamento dati:

    Quindi ogni volta che mi arriva un dato eseguo la connect()

    No.
    connect va chiamato una volta sola. crea un ponte tra un segnale e uno slot. in pratica connect dice "quando succede X fai Y". Ogni volta che ricevi un dato devi emettere un segnale (X) e in automatico verra' chiamato Y

    https://doc.qt.io/qt-5/signalsandslots.html



  • Quindi connect() viene chiamata nella classe dove eseguo le modifiche del dato che cambia. Nel mio caso la sostituisco al posto di consume().
    Dovrei usarla così nel mio caso? Dove "mykeypass" è un QByteArray mentre "cambiadato" è il segnale che viene emesso quando cambia il valore di "mykeypass" e sono entrambi definiti nella classe dove cambia il dato.

    connect(mykeypass, SIGNAL(cambiadato(const QByteArray &)), this, SLOT(estrai_dati(const QByteArray &)));

  • Qt Champions 2018

    connect(this, SIGNAL(cambiadato(const QByteArray &)), this, SLOT(estrai_dati(const QByteArray &)));

    il primo argomento deve essere un puntatore all'oggetto che emette il segnale



  • ok, ho guardato degli esempi e adesso mi è più chiaro come funziona.
    Infine quando chiamo void mygrafic3d::estrai_dati(const QByteArray &stringa) in "stringa" ho il valore che è cambiato dopo aver emesso il segnale "cambiadato" corretto?



  • @VRonin said in Aggiornamento dati:

    // Prima della chiamata di addData
    m_series->dataProxy()->resetArray( new QScatterDataArray);

    void mygrafic3d::addData()
    {
    QScatterDataArray* array = m_series->dataProxy()->array();
    array->append(QScatterDataItem(QVector3D(xpos, ypos, zpos)));
    m_series->dataProxy()->resetArray(array );
    }

    Il compilatore mi da errore in questa funzione, dicendo che:

    *****"error: cannot initialize a variable of type 'QtDataVisualization::QScatterDataArray *' (aka 'QVector<QtDataVisualization::QScatterDataItem> *') with an rvalue of type 'const QtDataVisualization::QScatterDataArray *' (aka 'const QVector<QtDataVisualization::QScatterDataItem> *')"*****
    
    **error: invalid conversion from 'const QScatterDataArray* {aka const QVector<QtDataVisualization::QScatterDataItem>*}' to 'QtDataVisualization::QScatterDataArray* {aka QVector<QtDataVisualization::QScatterDataItem>*}' [-fpermissive]
         QScatterDataArray *array = m_series->dataProxy()->array();
    ^**
    

    Io nel file .h ho già definito private: QScatterDataArray *m_array; questo può essere causa dell errore? Come modifico il codice che mi hai scritto?


  • Qt Champions 2018

    no, e' solo un problema di constness:

    void mygrafic3d::addData()
    {
    	QScatterDataArray* array = new QScatterDataArray(*m_series->dataProxy()->array());
    m_series->dataProxy()->resetArray(Q_NULLPTR);
    array->append(QScatterDataItem(QVector3D(xpos, ypos, zpos)));
        m_series->dataProxy()->resetArray(array );
    }
    


  • #include <QtDataVisualization>
    #include <QtWidgets>
    #include <QDialog>
    #include <QtCore>
    #include <QObject>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "mygrafic3d.h"
    #include "myserver.h"
    
    using namespace QtDataVisualization;
    
    mygrafic3d::mygrafic3d(Q3DScatter *scatter)
        : m_graph(scatter),
          m_fontSize(40.0f),
          m_style(QAbstract3DSeries::MeshSphere),
          m_smooth(true),
          m_series(new QScatter3DSeries)/*,
          m_array(new QScatterDataArray)*/
    {
        //Modifiche visive
        m_graph->activeTheme()->setType(Q3DTheme::ThemeQt);
        QFont font = m_graph->activeTheme()->font();
        font.setPointSize(m_fontSize);
        m_graph->activeTheme()->setFont(font);
        m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow);
        m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
    
        m_graph->axisX()->setTitle("X");
        m_graph->axisY()->setTitle("Y");
        m_graph->axisZ()->setTitle("Z");
    
        m_graph->axisX()->setTitleVisible(true);
        m_graph->axisY()->setTitleVisible(true);
        m_graph->axisZ()->setTitleVisible(true);
    
        //creo un QScatterDataProxy e il QScatter3DSeries associato
        QScatterDataProxy *proxy = new QScatterDataProxy;
        m_series = new QScatter3DSeries(proxy);
        m_series->setItemLabelFormat(QStringLiteral("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"));
        m_series->setMeshSmooth(m_smooth);
        m_graph->addSeries(m_series);
    
        // Prima della chiamata di addData
        m_series->dataProxy()->resetArray(new QScatterDataArray);
    	
        connect(&server, SIGNAL(Signal_Data(const QByteArray &)), this, SLOT(slot_data(const QByteArray &)));
        qDebug() << "segnale ricevuto";
    }
    
    
    mygrafic3d::~mygrafic3d()
    {
        delete m_graph;
    }
    
    
    void mygrafic3d::slot_data(const QByteArray &stringa)
    {
        strcpy(dato, stringa);
        qDebug()<< "Valore dato: " << dato;
    
        estrai_dati();
        addData();
    }
    
    
    void mygrafic3d::addData()
    {
        QScatterDataArray* array = new QScatterDataArray(*m_series->dataProxy()->array());
        m_series->dataProxy()->resetArray(Q_NULLPTR);
        array->append(QScatterDataItem(QVector3D(xpos, ypos, zpos)));
        m_series->dataProxy()->resetArray(array);
    }
    

    In definitiva quello che ho scritto adesso è questo, dovrebbe essere tutto corretto.
    Il mio unico dubbio è se ho scritto correttamente la connect() perchè non l avevo mai usata prima, potreste dargli un occhio?


  • Qt Champions 2018

    usa la connect di Qt5 cosi' non rischi typos. ServerClass qui e' il tipo di server.

    connect(&server, &ServerClass::Signal_Data, this, &mygrafic3d::slot_data);



  • void mygrafic3d::addData()
    {
       QScatterDataArray* array = new QScatterDataArray(*m_series->dataProxy()->array());
       m_series->dataProxy()->resetArray(Q_NULLPTR);
       array->append(QScatterDataItem(QVector3D(xpos, ypos, zpos)));
       m_series->dataProxy()->resetArray(array );
    }
    

    Ma in questa funzione non manca una funzione per plottare i dati sul grafico? Come ad esempio addSeries()?


  • Qt Champions 2018

    resetArray emette il segnale QScatterDataProxy::arrayReset che il grafico riceve e sa che deve aggiornarsi



  • This post is deleted!

  • Qt Champions 2018

    @Lorenz_95 said in Aggiornamento dati:

    Avete idea di quale possa essere il problema?

    Identico a quello di prima:
    @VRonin said in Aggiornamento dati:

    Stai bloccando l'event loop

    Nel codice che hai postato il pezzo piu' sospetto e':

    //aspetto che venga emesso nel client il segnale readyRead()
            if (socket->waitForReadyRead(3000))
    

    Mentre aspetti il grafico non puo' aggiornarsi. Se hai un loop infinito attorno a quel pezzo di codice il grafico non ha mai il tempo di aggiornarsi perche' stai occupando il thread con altre operazioni. Invece di fare un loop infinito e aspettare un segnale semplicemente connetti il segnale allo slot che esegue le operazioni



  • Risolto!
    Il problema stava proprio in quel codice perchè era messo al interno di un loop infinito, adesso il programma funziona.
    Grazie mille per l'aiuto


Log in to reply