Large amount of QML MapItems



  • Hi everyone :)

    I am currently trying to plot a large amount of items onto a QML Map (30,000 - 120,000 points). These items shall be updated dependent of the position of a QSlider. Performance decreases strongly from about 1,000 items upwards, when I use 30,000 it takes several minutes until the QML Map has all the data visualized and is responsive again. I have a machine which is absolutely capable of fulfilling this task in general, so I think the problem is QML. I am using Qt 5.8.

    Is there any way to improve this performance or is it just not possible with a QML-map to plot so many MapItems at a time? I tried MapCircles, Polylines, Polygons and MapQuickItems with images, but for me it seems like the performance issue just arises from adding this amount of MapItems, as I could not see a significant difference in processing time between these types.

    I have more data on the map visualized, which should not be refreshed every time the QSlider is moved. Even though I tried just to clear all MapItems and add the new ones for performance tests, but even this did not improve the performance.

    My code (a bit abstracted) looks like this:

    ///-------------- Widget.cpp-----------------///
    void ProcessInput(int qslider_pos) {
          QVariantList lat_vec;
          QVariantList lon_vec;
    
          // Fill vectors with lateral and longitudinal positions
          // ...
    
          // Clean current points on map and draw new ones
          SendToQmlFuncRemovePoints();
          SendToQmlFuncAddPoints(lat_vec, lon_vec);
    }
    
    void QmlConnector::SendToQmlFuncRemovePoints()
    {
        QVariant returnedValue;
        QMetaObject::invokeMethod(QmlMapSingleton::instance()->GetRoot(), "remove_points",
            Q_RETURN_ARG(QVariant, returnedValue));
    }
    
    void QmlConnector::SendToQmlFuncAddPoints(QVariantList input_one, QVariantList input_two)
    {
        QVariant returnedValue;
        QMetaObject::invokeMethod(QmlMapSingleton::instance()->GetRoot(), "add_points",
            Q_RETURN_ARG(QVariant, returnedValue),
            Q_ARG(QVariant, QVariant::fromValue(input_one)), Q_ARG(QVariant, QVariant::fromValue(input_two)));
    }
    
    ///-------------- Map.qml -----------------///
    
    Map {
         anchors.fill: parent
         property variant points: ({})
         property int pointCounter: 0
    
         Plugin
         {
            id: osmplugin
            name: "osm"
            PluginParameter { name: "osm.mapping.highdpi_tiles"; value: true }
         }
    
         Component.onCompleted: {
             points = new Array();
         }
        id: map
        plugin: osmplugin
    
        //Javascript functions
        function add_points(array_lat, array_lon) {
            var myArray = new Array()
            var component = Qt.createComponent("mapcircle.qml");
            for (var i=0; i<array_lat.length; i++)
            {
                var object = component.createObject(map, { "center": QtPositioning.coordinate(array_lat[i], array_lon[i]})
                map.addMapItem(object)
                myArray.push(object)
            }
            map.points = myArray
        }
    
        function remove_points() {
            var count = map.points.length
            for (var i = 0; i<count; i++){
                map.removeMapItem(map.points[i])
                map.points[i].destroy()
            }
            map.points = []
        }
    }
    
    ///-------------- mapcircle.qml -----------------///
    import QtQuick 2.0
    import QtLocation 5.6
    
    MapCircle {
          radius: 1
          border.width: 0
          color: 'green'
    }
    


  • Do you need all items at once? If not, you could try to group nearby data points together into one marker point. I did something similar for one of my applications, where there is also the possibility that there will be ten thousand of data points someday.

    What I am doing is, I am offloading the grouping of the data points to a database server. When the user opens the map, I am looking at the current zoom level and the visible rectangle. Based on that information, I am sending a request to my database server, which uses the geohash algorithm (https://en.wikipedia.org/wiki/Geohash) to group nearby data points together.

    e.q: If I am looking at the map with the biggest zoom level it doesn't matter to me, if there are data points that are 100km apart - the data points would be so narrow that I can't click on them anyway. So I can easily group all data points within a certain distance together. If the user zooms in or the current visible rectangle changed, I am again sending a request to the server which again returns the data based on the zoom level and visible rectangle.



  • @Schluchti Hi, thanks for the response :)

    Some kind of clustering would be my plan B, I also already thought about some grid-visualization or something similiar to just reduce the amount of points, so your Geohash-tip goes exactly in that direction. But as OpenGL is the basis of QML Maps (when I understood that correctly), I thought it should be possible to visualize all of the points, because OpenGL is kind of fast. So before I wanted to implement my plan B I wanted to reach out to some more experienced Qml-users to see if there's a native method to visualize that many points while having a good performance.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.