📜 ⬆️ ⬇️

Briefly on how to make your Qt geoservice plugin

image + image =?
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:


There is:

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:

TARGET = qtgeoservices_osmscout #  ,       libqtgeoservices_osmscout.so QT += location-private positioning-private network #  Qt,     , #          #  PLUGIN_TYPE = geoservices # ,       PLUGIN_CLASS_NAME = QGeoServiceProviderFactoryOsmScout #  ,         load(qt_plugin) # qt_plugin.prf         


Fine! What are we all great. Now you can open a project in QtCreator and enjoy life to start developing the plugin itself.

Add the class that we promised qt_plugin to QGeoServiceProviderFactoryOsmScout.

 class QGeoServiceProviderFactoryOsmScout: public QObject, public QGeoServiceProviderFactory { Q_OBJECT //    ,     ! Q_INTERFACES(QGeoServiceProviderFactory) //    qmake     //    .      -  . Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0" FILE "osmscout_plugin.json") //    ,      . public: QGeoMappingManagerEngine *createMappingManagerEngine(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const; //      ,     . }; 


In addition to the createMappingManagerEngine method, you can also implement one of the following interfaces:

  virtual QGeoCodingManagerEngine *createGeocodingManagerEngine(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const; //    virtual QGeoRoutingManagerEngine *createRoutingManagerEngine(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const; //    virtual QPlaceManagerEngine *createPlaceManagerEngine(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const //    Point-of-interest. 


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:



Features are divided into categories:
  1. 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
    • RouteUpdatesFeature - Supports Dynamic Path Update
    • AlternativeRoutesFeature - Support for multiple alternatives.
    • ExcludeAreasRoutingFeature - Supports Exclusive Routing Factors
    • AnyRoutingFeatures - Supporting all that your heart desires for laying routes

  2. GeocodingFeature - geocoding features
    • NoGeocodingFeatures - Geocoding is not supported.
    • OnlineGeocodingFeature - Online Geocoding Support
    • OfflineGeocodingFeature - Offline Geocoding Support
    • ReverseGeocodingFeature - Reverse geocoding support
    • LocalizedGeocodingFeature - Geocoding support with localization
    • AnyGeocodingFeatures - All of the above except for NoGeocodingFeatures

  3. MappingFeature - features cartography
    • NoMappingFeatures - Mapping is not supported
    • OnlineMappingFeature - Online Map Support
    • OfflineMappingFeature - Offline Maps Support
    • LocalizedMappingFeature - Support for maps with localization
    • AnyMappingFeatures - All of the above except for NoMappingFeatures

  4. PlacesFeature Features Point-of-interest
    • NoPlacesFeatures - Point-of-interest is not supported.
    • OnlinePlacesFeature - Online Support Point-of-interest
    • OfflinePlacesFeature - Support Offline Point-of-interest
    • SavePlaceFeature - Support for saving custom points on the map
    • RemovePlaceFeature - Supports Point-of-interes removal on map
    • SaveCategoryFeature - Creating and saving custom categories Point-of-interest
    • RemoveCategoryFeature - Remove Point-of-interest categories
    • 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:
 qDebug() << "Wanna LocalizedPlacesFeature? Comming soon..."; 

This is neither for you nor for the user.


My interface is quite simple, in the end I got this:
 { "Keys": ["osmscout"], "Provider": "osmscout", "Version": 100, "Experimental": false, "Features": [ "OfflineMappingFeature" ] } 


Implementation of the map service


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:
  QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec); 


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:


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:

Converting tile numbers to geo-coordinates


By QGeoTileFetcher nothing more to say. But on QGeoTiledMapReply there is. An heir to this class must perform 4 functions:


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:

 import QtQuick 2.0 import QtLocation 5.3 import QtPositioning 5.2 Rectangle { id: rect width: 800 height: 600 Map { id: map anchors.fill: parent plugin: Plugin { name:"osmscout" //     allowExperimental: true //    } } } 


Why did I write all this


The finished plugin can be found in my qt-location fork at gitorious:
qt.gitorious.org/qt/qtlocation-semlanik/source/798639ef13821155730cb83abac7e7821506df31 :
It uses libosmscout as an offline framework, my fork from it at sourceforge:
sourceforge.net/u/semlanik/libosmscout/ci/master/tree
And of course, it all works in conjunction with the GPS module :



This is all done for my OpenAutomotive project.

Thanks to all mastered.

Source: https://habr.com/ru/post/233809/


All Articles