+ =? The next step after the GPS module was its practical application in my project. Perhaps someone this post will be more interesting. First, some basic data: Required:
Offline map service
Integration with QML
There is:
libosmscout is a library that provides OSM wrapped data with a convenient API.
Qt5Location with dev branch
Summary of the previous 160 episodes
Since time immemorial, Qt had a wonderful QtMobility process bundle and was so wonderful that it lived, lived, and was bent. Yes, of course, it has not gone anywhere, and is even used in my N9 and someone’s Blackberry, but the fact is that Digia will no longer support this API at-all.
But in Digia, it’s not fools who work, they gradually undertook to drag QtMobility pieces into Qt5. QtLocation became one of such components. In Qt 5.3, you can only see a piece of QtLocation, which Digia refers to as QtPositioning. I must say a nice thing, fed her NMEA from a local socket, and she answered you objektik on a silver platter. All this is great, but why should I position if there is no card? Here Digia probably asked the same question, and in Qt5.4 I hope she releases QtLocation with all its buns. ')
Getting started
I will not describe in the article how to collect Qt from sources, since there is a lot of subtleties associated with the platform under and on which the build takes place. Go straight to the software part.
First, create a directory in which the plugin will be located, for example, <path to QtLocation source code> / src / plugins / geoservices / osmscout Then we create the project file osmscout.pro (there can be any other name) with the following content:
As for the Q_PLUGIN_METADATA macro, it is processed in the same way as many qmake macros by the preprocessor. We are only important arguments: IID "org.qt-project.qt.geoservice.serviceproviderfactory / 5.0" is a common interface identifier that we implement FILE "osmscout_plugin.json" - a file with a detailed description, and what we implemented.
About the mysterious and mystical file osmscout_plugin.json
Regarding the file format, I think there are no questions, but the content is big. Only the source code can give an answer to these questions so far, perhaps in the future it will be somewhere documented by Digia itself.
So, the fields:
"Keys": <array [string]> - I honestly find it difficult to answer what it is and what it is eaten with.
I did not find any specific references in the code, and I didn’t search for it myself. Probably for some reason you need.
"Provider": <string> is the name of the provider for use in the QML / metaobject interface
"Experimental": <bool> - here is an interesting point. If you set the Experimental flag to true,
then all else being equal, your plugin will not be visible in the application.
To make such plugins available, you need to set "allowExperimental"
flag in the QDeclarativeGeoServiceProvider of your map. How to do it later in the QML part
"Features": <array [string]> - you can cram a nefpikhuemy into the field, so the description is slightly lower
Features are divided into categories:
RoutingFeature - routing features
NoRoutingFeatures - Routing is not supported (KO: this option can be omitted)
OnlineRoutingFeature - Online Routing Support
OfflineRoutingFeature - Offline Routing Support
LocalizedRoutingFeature - Localized Routing Support
PlaceRecommendationsFeature - Support recommended by Point-of-interest according to keywords.
SearchSuggestionsFeature - Offer support according to part of a search query.
LocalizedPlacesFeature - Localization Support for Point-of-interes
NotificationsFeature - Support for Notification of Changes Point-of-interes
PlaceMatchingFeature - Point-of-interes comparison poddzhka from two different providers
AnyPlacesFeatures - it's time for you to relax
From myself I will add:
The file describing the interfaces of your plugin is a kind of promise to the user of what he can do with it. Conclusion: do not promise more than your plugin can do, stabilizing functions with something like:
As was seen above, the interface of our plugin will return to the user QGeoMappingManagerEngine. Now I’m actively picking vector maps with continuous rendering, but so far nothing sane enough to show is ready. Therefore, I will tell about the already existing and tolerably working tile tile service.
It will be necessary to inherit from QGeoTiledMappingManagerEngine, which carries a stack of duties on the part of the programmer. Based on RAII in the constructor, do the following:
QGeoCameraCapabilities cameraCaps; cameraCaps.setMinimumZoomLevel(0.0); cameraCaps.setMaximumZoomLevel(19.0); setCameraCapabilities(cameraCaps); // // // .. setTileSize(QSize(256, 256));// . OSM , // OSM Google. setCacheHint(QGeoTiledMappingManagerEngine::MemoryCache);// , // , // . QList<QGeoMapType> mapTypes; mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Day Street Map"), tr("OpenStreetMap street map"), false, false, OsmScoutDefaultDayMap); setSupportedMapTypes(mapTypes);// . // QGeoTileFetcherOsmScout *tileFetcher = new QGeoTileFetcherOsmScout(this);// setTileFetcher(tileFetcher);
Go deeper
There are two key classes that must be implemented to get the result: QGeoTileFetcher heir and QGeoTiledMapReply heir.
QGeoTileFetcher requires only one interface to be redefined:
This method should return a pointer to a class object object derived from QGeoTiledMapReply in accordance with the QGeoTileSpec. QGeoTileSpec defines a tile specification.
The key fields are the following:
zoom - the level of approximation for which the tile is requested
x - the position of the tile in the projection of the mercator horizontally
y is the position of the tile in the vertical projection of the mercator
For some, it may be useful to lag behind 2 fields mapId, version.
A small educational program on the coordinate grid of tiles
For those who do not know the tiles in OSM and even in Google have numbers staked under them. The numbers are distributed from left to right, from top to bottom on the Mercator projection, divided into 2 zoom sectors. Read more about it here . For me, the most important of this article was the formula for converting tile numbers into geographic coordinates, since libosmscout, which I used, supported communication only by means of geographic coordinates:
By QGeoTileFetcher nothing more to say. But on QGeoTiledMapReply there is. An heir to this class must perform 4 functions:
void setMapImageData (const QByteArray & data) - put the tile data in QGeoTiledMapReply
void setMapImageFormat (const QString & format) - set the format in which the tile data is located
void setFinished (bool finished) - tell QGeoTileFetcher that we have finished working with this QGeoTiledMapReply
void setError (Error error, const QString & errorString) - setting the error code in case something went wrong
Small recommendation:
The getTileImage method (const QGeoTileSpec & spec) is called in the graphical thread of the application, this leads to an unpleasant moment - if it takes any meaningful time, the GUI hangs. Exit getTileImage the faster the better, render / download / process tiles in a separate thread.
When everything is ready
Qt is a very ideological framework and any idea in it leads to a result. In the case of our plugin, after successful implementation, it will be enough for us to create a new QML project, and after writing just a couple of lines, get the map: