QtLocation 5.9

With Qt 5.9, the QtLocation module has received a substantial amount of new features, as briefly summarized in the release post. The goal of this post is to provide additional details about what's now possible with QtLocation 5.9.

Rotating and tilting maps

One long-standing limitation of the built-in tile renderer was the inability to draw rotated or tilted maps and map items. We finally removed this limitation, and in 5.9 maps as well as the map items added to them can be rotated and tilted. This also applies to MapQuickItems, which can be tilted by setting the appropriate zoomLevel value to them. With the support for tilting and rotation come two new dedicated gestures in the gesture area of the map: two fingers rotation, and two fingers vertical drag for tilting.

It is now possible to rotate and tilt maps. Items on it will be transformed accordingly. In this figure a MapQuickItem embedding a QtMultimedia Video element is used to overlay a video of the shore. It is now possible to rotate and tilt maps. Items on it will be transformed accordingly. In this figure a MapQuickItem embedding a QtMultimedia Video element is used to overlay a video of the shore.

In addition to this, a new fieldOfView property has been added to the Map, to control the camera field of view when the map is tilted. Note that this property, like the tilt and the zoomLevel properties, have lower and upper bounds. In some cases these bounds will prevent changing the property (e.g., a plug-in using a third-party renderer that does not allow changing the field of view will return a lower bound for the field of view equal to the upper bound).

Tile overzooming

Another long-standing limitation that got us many complaints over the last years was the inability of using cached data to approximate tile content not yet provisioned.
Lower zoom level tiles are now used to approximate higher zoom levels tiles, until these are fully provisioned. This finally prevents, where possible, the appearance of empty tiles revealing the (usually gray) background.

The difference in loading the map tiles, 5.8 (top) vs 5.9 (bottom) The difference in loading the map tiles, 5.8 (top) vs 5.9 (bottom)

Improved third party map renderer support and the MapboxGL plugin

Prior to 5.9, the only way to display a map using QtLocation was to cut it into raster tiles, and feed the tiles to the built in tiled map renderer. Some have created plug-ins that embedded third party map renderer, but in the end they all had to do the rasterization-to-tiles step, in order to get the map on the screen.

QtLocation 5.9 removes this roadblock, allowing to draw custom QSG nodes in a custom QGeoMap implementation, so that it is finally possible to plug a third party renderer directly into the QtQuick scene graph.
This can be done in different ways, the most common being rendering the map off-screen into a texture, and then rendering the texture in the QtQuick scene graph, or using a QSGRenderNode to issue graphics commands directly.
The second approach is more efficient, but also more complex to set up and with more corner cases to handle.

How this performs can be seen by trying out the new Mapbox GL plugin, that, in cooperation with Mapbox, has been included in Qt for most of the supported platforms. This plug-in renders Mapbox Vector Tiles using the mapbox-gl-native renderer, supporting both online and offline map sources. This plug-in also allows to select either of the two rendering approaches mentioned above (although it should be noted that the QSGRenderNode approach is experimental and may introduce problems).

The MapboxGL plugin in action The MapboxGL plugin in action

Handing map items rendering over to the plug-in

In addition to handing the map rendering over to the plug-in, it is also possible for a QGeoMap implementation to define which types of map items it can to render by itself. With QtLocation 5.9, if a plug-in instantiates a QGeoMap that reports the ability of drawing MapPolylines, these items are handed over to the plug-in, and the default rendering path for items of that type will be disabled. They will behave just like before, but their visual appearance will depend entirely on how the plug-in renders them. The MapboxGL plugin can, for example, render native MapRectangles, MapCircles, MapPolylines and MapPolygons. They will be anti-aliased and their style can be customized using Mapbox style specifications.
On the downside, the rendering of these items entirely depends on the plugin. So, on a MapboxGL map for example, they not support borders, so setting border properties on the items will have no effect. They also do not currently support visiblity and opacity for the items, although this is something that may get fixed very soon.

MapPolyline rendered on a map using the MapboxGL plugin. The polyline has been styled using MapParameters A MapPolyline rendered on a map using the MapboxGL plugin. The polyline has been styled using MapParameters

Exposing Plug-in - specific mapping features

Enabling the integration of third-party mapping engines opens up for the opportunity of using features that are specific to the one or the other engine. For example, the mapbox-gl-native library offers a very flexible API for changing the style of map elements at runtime.
To allow plugins to expose engine-specific features, we have introduced a new QML type, MapParameter. Elements of type MapParameter are essentially duck-typed, as properties have to be defined by the programmer according to what the documentation of the plug-in requires. In the case of the Mapbox GL plugin, a map parameter to control the visibility of a Mapbox style layer named "road-label-small" would look like this:

MapParameter {
type: "layout"
property var layer: "road-label-small"
property var visibility: "none"

Note that properties in map parameters are dynamic. They can be changed at runtime and the effects will be immediate.

Improved stacking of multiple Maps

Combining multiple map layers has been challenging with the previous Qt releases. That's because different Map elements would have different zoom level ranges, and these ranges would also be enforced. In addition, map copyright notices could only be turned on or off, with the result of having them overlapping on screen.
In 5.9 the Map element allows the zoomLevel property to go beyond the minimum or maximum supported zoom levels, if set programmatically (that is, not through mouse or gestures interaction) and the used plug-in supports overzooming.
This way it is possible to use property bindings on the zoomLevel property of all the overlay maps to be driven by the value in a base map "layer".

In addition, it is now possible to manually add elements of type MapCopyrightNotice on top of the maps, and source their content from the map elements. In this way they can be freely arranged, and also styled using custom CSS code.

Finally, one problem that was previously common when changing maps at runtime was that map items added to a map would be gone when the map would be replaced with another map sourced from a different plug-in.
For this reason, we include a new plug-in called itemsoverlay, whose only purpose is to provide a completely empty, transparent, map that costs almost nothing to render. The intended use is to have one Map element using this plug-in on top of the map stack, where to keep map items, so that the layers underneath can be freely removed.

Other improvements

A new method, fitViewportToVisibleMapItems, has been added to the Map element, to only consider visible items when fitting the viewport. A new QML type, MapItemGroup, has been introduced, to combine multiple map items together, like in a separate qml file. Note that it is currently not possible to use MapItemGroups in combination with MapItemViews.

Blog Topics: