[SOLVED] Adding multiple MapObjects to Map grows too slow / not scalable
-
Hi all,
I have a working QML Map (using the QtMobility's/Location Map element) and I'm adding several mapObjects to it at startup. The Objects are all MapCircles created inside a Repeater that uses a QAbstractListModel model - inside the repeater I use onItemAdded/Removed to call the map's specific addMapObject (removeMapObject) for this new mapObject.Everything works fine but it's simply too slow. Adding mapObjects takes longer at each insertion. Using anything more than a couple of dozens objects will lock my app for a couple of seconds already. (I'm planning on using around 400 so this approach is completely off)
( I uploaded some plots "here":http://cpscotti.com/blog/?p=87 )
There's something pretty wrong here and I'm not sure if it's on my side.
I’ve already tried many different ways to add objects to the map (in addition to Map.addMapObject) without much improvement. I reckon the problem is that some checks/redrawing (either O[n] or O[n logn] on the number of items already on the map) are performed at EVERY insertion and there’s no addMapObjectsList method that would first add all objects and then process/draw/check all items at the end on a single pass/go. . Am I missing something here??
I believe the related Qt's source are "here":https://qt.gitorious.org/qt-mobility/qt-mobility/blobs/master/src/location/maps/qgeomapdata.cpp#line454 and "here":https://qt.gitorious.org/qt-mobility/qt-mobility/blobs/master/src/location/maps/qgeomapgroupobject.cpp#line158 .
Things I've already tried:
Using MapObjectView with a specific landmarkModel, no help.
Adding all MapCircles to an qml array and only calling map.addMapObject() at the end for each object inside a loop (so that map would try redrawing the whole map for the each element).. nothing.
The minimal code I can come up to show this behaviour is:
@
import QtQuick 1.1
import com.meego 1.0import QtMobility.location 1.2
Page {
id: mainPageMap { id: map plugin: Plugin { name: "nokia" } mapType: Map.StreetMap zoomLevel: 16 center: Coordinate { latitude: 51.52300262451172 longitude: -0.1025390625 } anchors.fill: parent } Repeater { onItemAdded: { map.addMapObject(item) } onItemRemoved: { map.removeMapObject(item) } model: 30 MapCircle { center: Coordinate { //this will simply produce a grid of blue circles around central London latitude: 51.52300262451172+0.001*(parseInt(index/5)) longitude: -0.1025390625+0.001*(index%5) } radius: 5 color: "blue" } }
}
@
The bigger the model the longer the app will take to start up (quadratically!!)Any help is appreciated!
-
The problem is almost definitely not on your side - we've had a significant regression:
https://bugreports.qt.nokia.com/browse/QTMOBILITY-1664We're currently reworking the Map support for Qt 5 in order take advantage of Open GL etc... Unfortunately that means we don't have the capacity to do much about this bug in the Qt Mobility code base. We'd probably accept patches but I'm not sure if/when/how they'd make it into a release.
-
@david.laing, well... that wasn't exactly the kind of answer I was expecting.
I'm developing for the N9(|50) and it's quite a bummer that something like this is not being worked on even for a "future" platform. Wouldn't it make sense to revert the relevant code from 1.1.3 and "fix" the regression? (I'm supposing it's a simple thing, I might be wrong though.. )My complaining aside, I think it's worth mentioning here that there are a couple of workarounds :
-
As mentioned in that bug report (#QTMOBILITY-1664), adding groups to the map doesn't cost that much and adding a large number of items to a group doesn't cost much either. Hence, having a simple "Mother Of All Items" group might solve one's problem at least temporarily - panning/scrolling/redrawing will eventually get slow if you have too many (e.g. >~60) items at the screen (i.e. inside the designated LandmarkBoxFilter). But at least it is still "practical".
My big group's got ~800 children and as long as most of them are out of the screen, all's good. -
The other, even uglier, workaround is to draw you object as normal QML items on top of the map and at the positions taken from map.toScreenPosition(). This one's quick but ugly because (at least in the way I did it) the landmarks kind of drifts from the map when you are zooming in/out or panning, a bit annoying.
Oh, and one last - quite obvious but still - tip, use Images instead of actually drawing something! (e.g. MapImage instead of MapCircle)
-
-
Unfortunately I've got more bad news.
-
The code that introduces the regression was substantial and would be very difficult to revert (and I don't know if we're doing any more releases of Qt Mobility prior to Qt 5)
-
The work aroud in QTMOBILITY-1664 might actually stop working in the future, since it was only a workaround because another bug was masking it. Although if we don't do any more releases that fix might not trickle through, so it could be a non-issue.
I'd really genuinely like to fix this bug - and many of the others - but we have a very small number of people working on maps, positioning, routing and geocoding, and all of our time and then some is accounted for with the work on our plate.
-
-
Oh well...
First, thanks for the answers david!
And I do understand that it's not that simple or easy to fix this sort of stuff (due to all the reasons you mentioned).But, and this is a big honking but, I think we all should at least agree on a way to cope with this and sort of "maintain" this (or another) workaround at least until the official means become available.
After all, there's a new, all shiny, phone about to be released and to which some people will build apps using this part of Qt Mobility.Now more on the practical side, I was looking into the source and found this:
@
if (info && info->graphicsItem) {
// the child's z value will get updated in QGeoTiledMapGroupObjectInfo::childUpdated
// we do this in order to keep the same order of operations that we had previously
childObject->disconnect(childObject, SIGNAL(zValueChanged(int)), info, SLOT(zValueChanged(int)));
info->graphicsItem->setParentItem(graphicsItem);
tiledMapDataPrivate->update(mapObject());
// tiledMapDataPrivate->update(childObject);
}
@
The map being completely redrawn every time an item is added, instead of just the relevant boundingRect for that childObject (which is what the line you left commented out would do :D ). You did so just because there might exist items with different Z values? But then shouldn't QGraphicsView take care of that and redraw any other objects whose boundingRect intersects etc..?Anyhow, that explains why the Group workaround works (when adding to an Orphan MapGroup, info is null and thus no update is carried), right? It's not even that ugly :) and it should continue working I reckon.