Update a MapCircle on QML using a signal from C++

757 views Asked by At

I'm trying to update a MapCircle in QML from a signal in C++ and I'm veen having several issues with it all day.

In my class I have a Q_PROPERTY which is read only and holds the GPS positions of 4 UAVs in a QVariantList

class GCS: public QObject
{
    Q_PROPERTY(QVariantList getUavPosition READ getUavPosition NOTIFY uavPositionSet)

    public:
      QVariantList getUavPosition() ; 
    signals:
      void uavPositionSet();
     public slots:
       void setUavPosition();
       void triggerPosition();
     private: 
       QVariantList connected_uavs;
       QVector<QGeoCoordinate> uav_positions;         

};

I then define the functions as:

void GCS::setUavPosition()
{
  double i = 0.0;

     QGeoCoordinate uav_id;
     uav_id.setLatitude(0.5);
     uav_id.setLongitude(0.5 + i);
     uav_id.setAltitude(5);
     uav_positions.insert(0, uav_id);
     connected_uavs.append( QVariant::fromValue(QGeoCoordinate(uav_positions[0].latitude(), uav_positions[0].longitude())));

      i+=0.15;  
    emit uavPositionSet();

}

 QVariantList GCS::getUavPosition() 
 {
   return connected_uavs;
 }

void GCS::triggerPosition()
{
  setUavPosition();
  ROS_INFO("Pos trig");
}

In my main function, I connect triggerPosition to a Timer so as to update the position periodically

int main(int argc, char *argv[])
{
     ros::init(argc, argv, "planner");
    QGuiApplication app(argc, argv);

     QQmlApplicationEngine engine;
     QQmlContext* context = engine.rootContext();
     GCS gcs;
     context->setContextProperty("planner", &gcs);    
     engine.load(QUrl(QStringLiteral("qrc:/planner.qml")));

     QTimer *timer = new QTimer();
     timer->setInterval(1000);
     QObject::connect(&gcs, SIGNAL(uavPositionSet()), &gcs, SLOT(setUavPosition()));
     QObject::connect(timer, SIGNAL(timeout()), &gcs, SLOT(triggerPosition()));
     timer->start();

    return app.exec();
}

However, when I run my program, there's a slight delay, my mouseArea becomes unusable and the program crashes. When I try to print the longitude to see if it updates, The initial value is printed out multiple times to the terminal but then the program crashes and there's is no MapCircle present on the map

The relevant part of My Qml file looks like this:

 Map{
        id: map
        anchors.fill:parent
        plugin: mapPlugin
        center: QtPositioning.coordinate(0.5, 0.5)
        zoomLevel:50

        MapCircle{
            id:uavPos
            radius:2
            color:'black'
            border.width:3   
        }

    Connections{
        id:uavConnection
        target: planner
        onUavPositionSet:{

        var data = planner.getUavPosition
        uavPos.center = QtPositioning.coordinate(data[0].latitude, data[0].longitude)
        console.log(data[0].longitude)
        }

        }

    }

Can someone please kindly point me in the right direction here?

1

There are 1 answers

3
eyllanesc On BEST ANSWER

If you are going to handle information from several elements then it is better to use a model (together with a Repeater to create several elements), so it is only necessary to modify the role of an item:

gcs.h

#ifndef GCS_H
#define GCS_H

#include <QObject>

class QStandardItemModel;
class QAbstractItemModel;

class GCS: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QObject* uavModel READ uavModel CONSTANT)
public:
    enum UAVRoles {
        PositionRole = Qt::UserRole + 1000
    };
    GCS(QObject *parent=nullptr);
    QObject *uavModel() const;
public Q_SLOTS:
    void triggerPosition();
private:
    QStandardItemModel* m_uavModel;
};

#endif // GCS_H

gcs.cpp

#include "gcs.h"

#include <QGeoCoordinate>
#include <QStandardItemModel>

#include <random>

GCS::GCS(QObject *parent):
    QObject(parent), m_uavModel(new QStandardItemModel(this))
{
    m_uavModel->setItemRoleNames({{PositionRole, "position"}});
    for(int i =0; i < 4; i++){
        QStandardItem *item = new QStandardItem;
        item->setData(QVariant::fromValue(QGeoCoordinate()), PositionRole);
        m_uavModel->appendRow(item);
    }
}

QObject *GCS::uavModel() const{
    return m_uavModel;
}

void GCS::triggerPosition(){
    std::mt19937 rng;
    rng.seed(std::random_device()());
    std::normal_distribution<> dist(-0.0001, +0.0001);

    if(QStandardItem *item = m_uavModel->item(0)){
        QGeoCoordinate uav_id;
        uav_id.setLatitude(0.5 + dist(rng));
        uav_id.setLongitude(0.5 + dist(rng));
        uav_id.setAltitude(5);
        item->setData(QVariant::fromValue(uav_id), PositionRole);
    }
}

main.cpp

#include "gcs.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
    GCS gcs;

    QQmlApplicationEngine engine;
    QQmlContext* context = engine.rootContext();
    context->setContextProperty("planner", &gcs);
    const QUrl url(QStringLiteral("qrc:/planner.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    QTimer timer;
    timer.setInterval(1000);
    QObject::connect(&timer, &QTimer::timeout, &gcs, &GCS::triggerPosition);
    timer.start();

    return app.exec();
}

planner.qml

import QtQuick 2.14
import QtQuick.Window 2.14
import QtLocation 5.14
import QtPositioning 5.14

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Plugin {
        id: mapPlugin
        name: "osm"
    }

    Map{
        id: map
        anchors.fill:parent
        plugin: mapPlugin
        center: QtPositioning.coordinate(0.5, 0.5)
        zoomLevel:50

        MapItemView{
            model: planner.uavModel
            delegate: MapCircle{
                id:uavPos
                radius: 2
                color:'black'
                border.width:3
                center: QtPositioning.coordinate(model.position.latitude, model.position.longitude)
            }
        }
    }
}