Briefly on how to make your Qt geoservice plugin

image + image =?
The next step after GPS module, became its practical application in my project. Maybe someone this post will be more interesting.

First, some source data:
Required:
the

    Offline mapping service the

  • Integration with QML


Features:
the
    the
  • libosmscout — library providing the OSM data in the wrapper with the friendly API
  • the
  • Qt5Location with dev branch

summary of the previous 160 series


In Qt since time immemorial was a wonderful beam-process QtMobility and he was so wonderful that he lived, he lived, and bent. Yes, of course, he is still here, and even used my N9 and someone's Blackberry, but the fact that Digia will no longer support this API at all.

But in Digia are working not fools, they gradually started to pull the pieces QtMobility in Qt5. One such component is a QtLocation. In Qt 5.3, you can see only a piece QtLocation, QtPositioning which refers to Digia. I must say nice stuff, gave her the NMEA from the local socket, and she'll answer obektik on a silver platter. Everything is great, but why should I position if there is no card? There Digia probably have asked the same question, and in Qt5.4 I hope she unreleased QtLocation with all its buns.

getting started


I won't be in the article to describe how to build Qt from source, since there is a plethora of intricacies associated with the platform on which the build. Go directly to the software part.

To start, create a directory in which there will be a plugin, for example <path to source code QtLocation>/src/plugins/geoservices/osmscout
Then create a project file osmscout.pro (can there be any other name) as follows:

the
TARGET = qtgeoservices_osmscout #the name of your library, in the end will be something like this libqtgeoservices_osmscout.so
QT += location-private placement-private network #specify the pieces of Qt that will be used in the project
#linking with libraries and add the paths to the header files
#happen automatically
PLUGIN_TYPE = geoservices #type of the plugin, then you just need to believe in the word
PLUGIN_CLASS_NAME = QGeoServiceProviderFactoryOsmScout # class name, which will be implemented by the access interfaces of the plugin
load(qt_plugin) #qt_plugin performed.prf for the final settings of the plugin based on the variables above


Great! What we have all done well. You can now open the project in QtCreator and to enjoy life to start developing the plugin.

Add a class that we promised qt_plugin' — QGeoServiceProviderFactoryOsmScout.

the
class QGeoServiceProviderFactoryOsmScout: public QObject, public QGeoServiceProviderFactory
{
Q_OBJECT //Who knows what it is leave I did not call you!
Q_INTERFACES(QGeoServiceProviderFactory) //This macro obviously slushaetsya qmake preprocessor like previous
//and unfold it into something beautiful. What is hard to say - not watching.
Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0"
FILE "osmscout_plugin.json") // This is a more interesting lines, they are slightly below.

public:
QGeoMappingManagerEngine *createMappingManagerEngine(const QVariantMap &parameters,
QGeoServiceProvider::Error *error,
QString *errorString) const; //interfaces for now I'll just mapping, I'm going to implement.
};


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

the
 virtual QGeoCodingManagerEngine *createGeocodingManagerEngine(const QVariantMap &parameters,
QGeoServiceProvider::Error *error,
QString *errorString) const; // the Interface provides geocoding
virtual QGeoRoutingManagerEngine *createRoutingManagerEngine(const QVariantMap &parameters,
QGeoServiceProvider::Error *error,
QString *errorString) const; // Interface provides routing
virtual QPlaceManagerEngine *createPlaceManagerEngine(const QVariantMap &parameters,
QGeoServiceProvider::Error *error,



About the Q_PLUGIN_METADATA macro, it is treated similarly many qmake macros by the preprocessor. We only important arguments:
IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0" is a common identifier of the interface that we are implementing
FILE "osmscout_plugin.json" file with a detailed description of what we certainly have realized.

About the mysterious and mysticism file osmscout_plugin.json

Regarding file format, I think the questions asked, but on the content of the questions large. The answer to these questions can give only the source code, perhaps in the future it will be somewhere documented most Digia.

So, the fields are:

the

    "Keys":<array[string]> - honestly hard to say what it is and what it eats.
    In the code, some specific references are not found, and did not look particularly. Probably why you need something.

    "Provider":<string> - provider name for use in QML/meta interface

    Version:<int> - the version of the provider, the format of <major>:<minor>:<patch>

    "Experimental":<bool> - there is an interesting point. If you put the Experimental flag to true
    other things being equal Your plugin will not be visible in the application.
    To make such plugins available, you need to set "allowExperimental"
    flag in QDeclarativeGeoServiceProvider your card. How to do it later in the QML part

    "Features":<array[string]> - in this field you can push nepijem, so the description just below


Features are divided into categories:
    the
  1. RoutingFeature — feature routing
    the

      NoRoutingFeatures — Routing is not supported(K. O.: this option can be omitted)

      OnlineRoutingFeature — Support online routing

      OfflineRoutingFeature — Supports offline routing

      LocalizedRoutingFeature — Support routing with localization

      RouteUpdatesFeature — Support dynamic updates

      AlternativeRoutesFeature — Support for multiple alternative routes

      ExcludeAreasRoutingFeature — Support for excluding factors routing

      AnyRoutingFeatures — Support for just what you want for routing


  2. the
  3. GeocodingFeature features geocoding
    the

      NoGeocodingFeatures — the Geocoding is not supported

      OnlineGeocodingFeature — Supports online geocoding

      OfflineGeocodingFeature — Support for offline geocoding

      ReverseGeocodingFeature — Support for reverse geocoding

      LocalizedGeocodingFeature — Support for geocoding localization

      AnyGeocodingFeatures — All of the above except NoGeocodingFeatures


  4. the
  5. MappingFeature features of cartography
    the

      NoMappingFeatures — Mapping not supported

      OnlineMappingFeature — Support for online maps

      OfflineMappingFeature — Support for offline maps

      LocalizedMappingFeature — Support for maps with localization

      AnyMappingFeatures -All of the above except NoMappingFeatures


  6. the
  7. PlacesFeature features Point-of-interest
    the

      NoPlacesFeatures — Point-of-interest is not supported

      OnlinePlacesFeature — Support online Point-of-interest

      OfflinePlacesFeature — Support for offline Point-of-interest

      SavePlaceFeature — Support to save custom points on the map

      RemovePlaceFeature — Support for removal of Point-of-interes, on the map

      SaveCategoryFeature — Creating and maintaining custom categories Point-of-interest

      RemoveCategoryFeature — Deleting categories Point-of-interest

      PlaceRecommendationsFeature — Support recommended Point-of-interest according to key words

      SearchSuggestionsFeature — Support suggestions according to the search query

      LocalizedPlacesFeature — localization Support for Point-of-interes

      NotificationsFeature — Support of notifications about changes in Point-of-interes

      PlaceMatchingFeature — Support comparison of Point-of-interes from two different providers

      AnyPlacesFeatures — You need to relax




From myself I will add:

a file with the description of the interfaces Your plugin is a kind of promise to the user what he can do with it.
Conclusion: do not promise more than can your plugin Stabia function something like:

Neither you nor the user to anything.


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


Implementation of map service


As was seen above, the interface of our plug-in undertakes to return the user QGeoMappingManagerEngine. I am now actively picking their vector maps with continuous rendering, but nothing yet sane enough to show not ready. So tell us about the already existing and well working tile tilova service.

You will need to inherit from QGeoTiledMappingManagerEngine, which carries a stack of responsibilities on the part of the programmer.
On the basis of RAII in the constructor, do the following:

the
 QGeoCameraCapabilities cameraCaps;
cameraCaps.setMinimumZoomLevel(0.0);
cameraCaps.setMaximumZoomLevel(19.0);
setCameraCapabilities(cameraCaps); //Set map supported levels of approximation
//here you can Express support for any vkusnyashek
//the  type  of the declination of the card relative to the horizon, etc.

setTileSize(QSize(256, 256));//Size of the tile. The selected standard for OSM size 
//which according to themselves is dictated by OSM Google.
setCacheHint(QGeoTiledMappingManagerEngine::MemoryCache);//This option exposed going
//since we generate the tiles according to the data from the hard disk
//store them in a disk cache makes no sense. 

QList<QGeoMapType> mapTypes;
mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Day Street Map"), tr("OpenStreetMap street map"), false, false, OsmScoutDefaultDayMap);
setSupportedMapTypes(mapTypes);//Types of supported card.
//Option is necessary for example in the presence of different styling or satellite maps

QGeoTileFetcherOsmScout *tileFetcher = new QGeoTileFetcherOsmScout(this);//Create loader tiles
setTileFetcher(tileFetcher);


Go deeper


There are two key class which you must implement to get the result:
The heir and the heir QGeoTileFetcher QGeoTiledMapReply.

QGeoTileFetcher requires overriding only one interface:
the
 QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec);


This method should return a pointer to an object of a class extended from QGeoTiledMapReply in accordance with QGeoTileSpec. QGeoTileSpec determines the specification of the tile.

Key in this are the following fields:
the

    zoom is the zoom level that is being requested.

    x — position of the tile in the Mercator projection horizontal

    y — position of the tile in the Mercator projection vertically



For someone might be useful ostavshiesya 2 fields mapId, version.

a Small educational program on a grid of tiles

For those who don't know the tiles in OSM and Google have staked out under him room.
Rooms are allocated left-to-right, top-to-bottom on the Mercator projection, broken into 2zoom sectors.
Read more you can read about it here.
For me, the most important from this article was the formula of reverse conversion of rooms and tiles in geographic coordinates, since libosmscout that I used maintained communication only by means of geographic coordinates:

Converting room tiles in geographic coordinates


For QGeoTileFetcher nothing more to say. But QGeoTiledMapReply is. The heir in this class must perform 4 functions:
the
    the
  • void setMapImageData(const QByteArray &data) — put data of the tile in the QGeoTiledMapReply
  • the
  • void setMapImageFormat(const QString &format) specify the format in which based on data of the tile
  • the
  • void setFinished(bool finished) is reported QGeoTileFetcher'that we were finished with this QGeoTiledMapReply
  • the
  • void setError(Error error, const QString &errorString) — set error code in case something went wrong


some advice:

Method getTileImage(const QGeoTileSpec &spec) is called in the graphics thread of the application, hence the unpleasant moment — if it takes any significant time, the GUI freezes. Exit getTileImage the sooner the better, rendering/downloading/processing map tiles do in a separate thread.

When ready


Qt very ideological framework and any idea in it leads to the result. In the case of our plugin after successful implementation it suffices to create a new QML project, and with just a few lines to the map:

the
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" //Name of our plugin to write here
allowExperimental: true //Allow experimental plugins
}
}
}


why I wrote it


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



This is all done for my OpenAutomotive of the project.

Thank you all mastered.
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Database replication PostgreSQL-based SymmetricDS

Yandex.Widget + adjustIFrameHeight + MooTools