2

I've setup a local tile server to use with my application but when I create my QML Map object and specify the plugin to use a custom host, the application does not use the local tiles. Cycling through supportedMapTypes and setting the activeMapType property on the map object will display some tiles, but they appear to be some set of default tiles and not the tiles from my local tile server.

Map
{
    id: map
    objectName: "basemap"
    anchors.fill: parent
    plugin: Plugin
    {
        name: "osm"
        PluginParameter
        {
            name: "osm.mapping.custom.host"
            value: "http://localhost:8080/data/openmaptiles_satellite_lowres/"
        }
    }
    zoomLevel: 1
    activeMapType: // varies depending on selection from another object in application
    center: QtPositioning.coordinate(0, 0)
}

I know the tile server is functioning properly as I can reach it in the browser by navigating to localhost:8080 and I can access arbitrary tiles using http://localhost:8080/data/openmaptiles_satellite_lowres/{z}/{y}/{x}.jpg

UPDATE

I'm trying to override the default provider repository files as suggested below by TomasL but the application doesn't seem to be using the plugin parameters specified.

Map component in Mapper.qml

Map {
  id: basemap
  objectName: "basemap"
  anchors.fill: parent
  plugin: ProvidersPlugin {}

  activeMapType: supportedMapTypes[1] // To use the satellite file in providers repository
  center: QtPositioning.coordinate(0, 0)
  zoomLevel: 2
  minimumZoomLevel: 0
  maximumZoomLevel: 5
}

ProvidersPlugin.qml

import QtLocation 5.5
import QtPositioning 5.5

Plugin {
  id: mapPlugin

  name: "osm"

  PluginParameter {
    name: "osm.mapping.providersrepository.address"
    value: Qt.resolvedUrl('./providers')
  }
}

./providers/satellite

{
  "Enabled" : true,
  "UrlTemplate" : "http://localhost:8080/data/openmaptiles_satellite_lowres/%z/%x/%y.jpg",
  "ImageFormat" : "jpg",
  "QImageFormat" : "Indexed8",
  "MapCopyRight" : "Test",
  "DataCopyRight" : "Hello World",
  "MinimumZoomLevel" : 0,
  "MaximumZoomLevel" : 5,
}

With the code above, my application still tries to reach out to the default server otile1.mqcdn.com

HotWax
  • 83
  • 8

2 Answers2

1

The problem is that the media you are using provides jpg images but the Qt OSM plugin only supports png formats. One solution is to clone the Qt Location module, modify the source code so that the image format can be set, compiled and installed.

To simplify that task I have created a patch for Qt 5.15.1:

tile_image_format.patch

diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
index 22c32342..d4747a0a 100644
--- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
@@ -217,11 +217,16 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian
         if (parameters.contains(QStringLiteral("osm.mapping.copyright")))
             m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString();
 
+        QString format = "png";
+        if(parameters.contains(QStringLiteral("osm.mapping.custom.format"))){
+            format = parameters.value(QStringLiteral("osm.mapping.custom.format")).toString();
+        }
+
         m_providers.push_back(
             new QGeoTileProviderOsm( nmCached,
                 QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8, pluginName, cameraCaps),
-                { new TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"),
-                    QStringLiteral("png"),
+                { new TileProvider(tmsServer + QStringLiteral("%z/%x/%y.") + format,
+                    format,
                     mapCopyright,
                     dataCopyright) }, cameraCaps
                 ));

The steps outlined above can be summarized as:

git clone -b 5.15.1 https://github.com/qt/qtlocation.git
cd qtlocation/src/plugins/geoservices/osm
wget https://raw.githubusercontent.com/eyllanesc/stackoverflow/master/questions/64391146/tile_image_format.patch
git apply tile_image_format.patch
qmake
make
make install

On the other hand you must point activeMapType in MapType.CustomMap:

Map
{
    id: map
    anchors.fill: parent
    plugin: Plugin
    {
        name: "osm"
        PluginParameter
        {
            name: "osm.mapping.custom.host"
            value: "http://localhost:8080/data/openmaptiles_satellite_lowres/"
        }
        PluginParameter
        {
            name: "osm.mapping.custom.format"
            value: "jpg"
        }
    }
    zoomLevel: 1
    center: QtPositioning.coordinate(0, 0)
    activeMapType: MapType.CustomMap
}

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • This is the solution that ended up working for me with a slight modification. The QT version I am using (and am limited to using) was lower than 5.15 so I had to go into the source code and apply the patch by hand. – HotWax Nov 19 '20 at 18:54
0

A simple way to do this with no Qt patch needed, is use the OpenStreetMap plugin as it is, but set another providers repository address to the plugin.

import QtLocation 5.12

Plugin {
    id: pluginN

    property string projectname: ""
    name: "osm"
    PluginParameter {
             name: "osm.mapping.providersrepository.address"
             value: "qrc:/Common/Engine/Source/Plugins/N/NRedirect/"  //or wherever you place your redirect files
         }

    PluginParameter { name: "osm.mapping.copyright"; value: "(c) N /OpenStreetMap" }
}

You may then put all map layer redirect files named cycle, hiking, night-transit, satellite, street, terrain, transit in the qrc:/Common/Engine/Source/Plugins/N/NRedirect folder. If you will e.g. only use satellite layer, then skip all the other files. The satellite file could then look like this (this is where the real magic is!)

    {
        "UrlTemplate" : "http://localhost:8080/data/openmaptiles_satellite_lowres/%z/%x/%y.jpg",
        "ImageFormat" : "jpg",
        "QImageFormat" : "Indexed8",
        "MapCopyRight" : "OpenStreetMap",
        "DataCopyRight" : "OpenStreetMap",
        "Timestamp" : "2019-02-01"
    }

Please note that in your example url, http://localhost:8080/data/openmaptiles_satellite_lowres/{z}/{y}/{x}.jpg , the order of z/x/y is different than in most examples. If the server is set up this way, you would need to change the UrlTemplate above.

More details on this are found in the source code for the osm plugin: https://github.com/qt/qtlocation/blob/dev/src/plugins/geoservices/osm/qgeotileproviderosm.cpp#L392-L568

TomasL
  • 96
  • 1
  • 2
  • 10
  • I'm trying to use this method, but the map object seems to be completely ignoring the plugin. I've created a directory within the application called `providers` that has a `satellite` file laid out as you described above. According to [this blog post](https://www.qt.io/blog/2017/03/09/provisioning-openstreetmap-providers-in-qtlocation) I can use `file:///`. I'm using `value: Qt.resolvedUrl('./providers')` which returns the correct value but the application is not using the local tiles. I've also tried adjusting `activeMapType` but with no success. – HotWax Oct 19 '20 at 17:56
  • @HotWax: have you set up the Map component to use your custom plugin? Like plugin: YourPluginName {} In my app, I've put the top code in the answer in a YourPluginName.qml file and use it as mentioned in the map. – TomasL Oct 21 '20 at 13:34
  • @HotWax Also note that if you set the `osm.mapping.custom.host` parameter, you would need to set `activeMapType` to `MapType.CustomMap`, as mentioned in one of the answers of https://stackoverflow.com/questions/41790875/how-to-run-openstreetmap-offline-in-qml-qt – TomasL Oct 21 '20 at 16:45
  • I've tried to put the plugin in another file as suggested and use it in my map component but despite doing this the application still tries to reach out to `otile1.mqcdn.com` instead of the the tile server listed in the `satellite` file – HotWax Oct 21 '20 at 17:25
  • @HotWax I think you need to post your updated code in order to be able to comment this. Have you e.g remembered to remove your pluginparameter for `osm.mapping.custom.host`, as you now try to use `osm.mapping.providersrepository.address` instead? – TomasL Oct 22 '20 at 12:55
  • I have removed `osm.mapping.custom.host` but still no luck. I've updated my question with the current code, – HotWax Oct 22 '20 at 13:14
  • @HotWax Thanks for the code samples, it's much easier to comment the real code. I just saw that your plugin code imports Qt 5.5 libs, and the provisioning providers where introduced in Qt 5.6.2, as mentioned in https://www.qt.io/blog/2017/03/09/provisioning-openstreetmap-providers-in-qtlocation. Just try to increase the version numbers. – TomasL Oct 23 '20 at 10:52