diff options
author | Paolo Angelelli <paolo.angelelli@theqtcompany.com> | 2016-08-15 12:12:25 +0200 |
---|---|---|
committer | Paolo Angelelli <paolo.angelelli@theqtcompany.com> | 2016-08-30 11:01:14 +0000 |
commit | 52c8bfa6be4fc6c47f99c9f37c142554932c7228 (patch) | |
tree | d70ffc9c7bc690c980a05e1c1d950d06b1db6919 /src | |
parent | 832030f271105a96bdde70b0526df659f21de565 (diff) | |
download | qtlocation-52c8bfa6be4fc6c47f99c9f37c142554932c7228.tar.gz |
Add OSM plugin parameter osm.mapping.highdpi_tiles
This patch adds a mean to enable/disable high dpi support for the
OSM plugin too, following the same approach taken for the mapbox and
here plugins.
In order to do so, it has been necessary to rework QGeoTileProviderOsm.
It can now be constructed with an arbitrary number of TileProviders,
as opposed to the previous approach with one primary and one fallback
tileprovider.
It has also been necessary to disable Nearest interpolation for high
dpi tiles, as it appears to produce considerable artifacts.
So in presence of highdpi tiles, Linear interpolation is now always
used.
Change-Id: Id7d20fd5a320f3d5ef41b9fa28447a5c4f5398be
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/location/doc/src/plugins/osm.qdoc | 7 | ||||
-rw-r--r-- | src/location/maps/qgeotiledmapscene.cpp | 14 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/providers/5.8/street | 11 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/providers/5.8/street-hires | 9 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotiledmaposm.cpp | 5 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp | 145 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h | 2 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotilefetcherosm.cpp | 3 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotilefetcherosm.h | 2 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotileproviderosm.cpp | 472 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qgeotileproviderosm.h | 241 |
11 files changed, 559 insertions, 352 deletions
diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc index fa75a197..1459909d 100644 --- a/src/location/doc/src/plugins/osm.qdoc +++ b/src/location/doc/src/plugins/osm.qdoc @@ -90,6 +90,13 @@ a prefix. The plugin, however, still contains fallback hardcoded provider data, in case the provider repository becomes unreachable. Setting this parameter to \b true makes the plugin use the hardcoded urls only and therefore prevents the plugin from fetching provider data from the remote repository. \row + \li osm.mapping.highdpi_tiles + \li Whether or not to request high dpi tiles. Valid values are \b true and \b false. The default value is \b false. + Please note that not all map types are available in high dpi. Setting this parameter to true might even have no effect if + no map type is available in high dpi at the moment. Provider information files for high dpi tiles are named + \tt{street-hires}, \tt{satellite-hires}, \tt{cycle-hires}, \tt{transit-hires}, \tt{night-transit-hires}, \tt{terrain-hires} and \tt{hiking-hires}. + These are fetched from the same location used for the low dpi counterparts. +\row \li osm.routing.host \li Url string set when making network requests to the routing server. This parameter should be set to a valid server url with the correct osrm API. If not specified the default \l {http://router.project-osrm.org/viaroute}{url} will be used. diff --git a/src/location/maps/qgeotiledmapscene.cpp b/src/location/maps/qgeotiledmapscene.cpp index 33c0bb8c..3896a51e 100644 --- a/src/location/maps/qgeotiledmapscene.cpp +++ b/src/location/maps/qgeotiledmapscene.cpp @@ -661,9 +661,12 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, delete node; } else { if (isTextureLinear != d->m_linearScaling) { - node->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest); - if (node->texture()->textureSize().width() > d->m_tileSize) + if (node->texture()->textureSize().width() > d->m_tileSize) { + node->setFiltering(QSGTexture::Linear); // With mipmapping QSGTexture::Nearest generates artifacts node->setMipmapFiltering(QSGTexture::Linear); + } else { + node->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest); + } dirtyBits |= QSGNode::DirtyMaterial; } if (dirtyBits != 0) @@ -680,9 +683,12 @@ void QGeoTiledMapRootNode::updateTiles(QGeoTiledMapTileContainerNode *root, // note: setTexture will update coordinates so do it here, before we buildGeometry tileNode->setTexture(textures.value(s)); if (d->buildGeometry(s, tileNode) && qgeotiledmapscene_isTileInViewport(tileNode->rect(), root->matrix())) { - tileNode->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest); - if (tileNode->texture()->textureSize().width() > d->m_tileSize) + if (tileNode->texture()->textureSize().width() > d->m_tileSize) { + tileNode->setFiltering(QSGTexture::Linear); // with mipmapping QSGTexture::Nearest generates artifacts tileNode->setMipmapFiltering(QSGTexture::Linear); + } else { + tileNode->setFiltering(d->m_linearScaling ? QSGTexture::Linear : QSGTexture::Nearest); + } root->addChild(s, tileNode); } else { delete tileNode; diff --git a/src/plugins/geoservices/osm/providers/5.8/street b/src/plugins/geoservices/osm/providers/5.8/street index 9819f619..b3bccf1d 100644 --- a/src/plugins/geoservices/osm/providers/5.8/street +++ b/src/plugins/geoservices/osm/providers/5.8/street @@ -1,9 +1,10 @@ { - "UrlTemplate" : "https://maps.wikimedia.org/osm-intl/%z/%x/%y@2x.png", - "ImageFormat" : "png", + "UrlTemplate" : "http://korona.geog.uni-heidelberg.de/tiles/roads/x=%x&y=%y&z=%z", + "ImageFormat" : "jpg", "QImageFormat" : "Indexed8", - "MaximumZoomLevel" : 18, - "ID" : "wmf-intl-2x", - "MapCopyRight" : "<a href='https://wikimediafoundation.org/wiki/Terms_of_Use'>WikiMedia Foundation</a>", + "ID" : "oms-street", + "MaximumZoomLevel" : 20, + "MapCopyRight" : "<a href='http://giscience.uni-hd.de/'>GIScience Research Group @ University of Heidelberg</a>", + "StyleCopyRight" : "<a href='http://www.geog.uni-heidelberg.de/personen/gis_rylov.html'>Maxim Rylov</a>", "DataCopyRight" : "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors" } diff --git a/src/plugins/geoservices/osm/providers/5.8/street-hires b/src/plugins/geoservices/osm/providers/5.8/street-hires new file mode 100644 index 00000000..9819f619 --- /dev/null +++ b/src/plugins/geoservices/osm/providers/5.8/street-hires @@ -0,0 +1,9 @@ +{ + "UrlTemplate" : "https://maps.wikimedia.org/osm-intl/%z/%x/%y@2x.png", + "ImageFormat" : "png", + "QImageFormat" : "Indexed8", + "MaximumZoomLevel" : 18, + "ID" : "wmf-intl-2x", + "MapCopyRight" : "<a href='https://wikimediafoundation.org/wiki/Terms_of_Use'>WikiMedia Foundation</a>", + "DataCopyRight" : "<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors" +} diff --git a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp index f16e602a..d94a40a6 100644 --- a/src/plugins/geoservices/osm/qgeotiledmaposm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmaposm.cpp @@ -71,10 +71,13 @@ void QGeoTiledMapOsm::evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles) return; int providerId = tile.mapId() - 1; - if (providerId < 0 || providerId >= m_engine->providers().size() || !m_engine->providers().at(providerId)->isValid()) + if (providerId < 0 || providerId >= m_engine->providers().size()) return; m_mapId = tile.mapId(); + if (!m_engine->providers().at(providerId)->isValid()) + return; + onProviderDataUpdated(m_engine->providers().at(providerId)); } diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp index 4f25204a..152df9b6 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp @@ -73,66 +73,93 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian domain = customAddress; } - m_providers.push_back( - new QGeoTileProviderOsm(domain + "street", - nm, + bool highdpi = false; + if (parameters.contains(QStringLiteral("osm.mapping.highdpi_tiles"))) { + const QString param = parameters.value(QStringLiteral("osm.mapping.highdpi_tiles")).toString().toLower(); + if (param == "true") + highdpi = true; + } + + /* TileProviders setup */ + QVector<TileProvider *> providers_street; + QVector<TileProvider *> providers_satellite; + QVector<TileProvider *> providers_cycle; + QVector<TileProvider *> providers_transit; + QVector<TileProvider *> providers_nighttransit; + QVector<TileProvider *> providers_terrain; + QVector<TileProvider *> providers_hiking; + if (highdpi) { + providers_street.push_back(new TileProvider(domain + "street-hires")); + providers_satellite.push_back(new TileProvider(domain + "satellite-hires")); + providers_cycle.push_back(new TileProvider(domain + "cycle-hires")); + providers_transit.push_back(new TileProvider(domain + "transit-hires")); + providers_nighttransit.push_back(new TileProvider(domain + "night-transit-hires")); + providers_terrain.push_back(new TileProvider(domain + "terrain-hires")); + providers_hiking.push_back(new TileProvider(domain + "hiking-hires")); + } + providers_street.push_back(new TileProvider(domain + "street")); + providers_satellite.push_back(new TileProvider(domain + "satellite")); + providers_cycle.push_back(new TileProvider(domain + "cycle")); + providers_transit.push_back(new TileProvider(domain + "transit")); + providers_nighttransit.push_back(new TileProvider(domain + "night-transit")); + providers_terrain.push_back(new TileProvider(domain + "terrain")); + providers_hiking.push_back(new TileProvider(domain + "hiking")); + // Backups + providers_street.push_back( + new TileProvider(QStringLiteral("http://c.tile.openstreetmap.org/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap.org</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + // No available satellite backup + providers_cycle.push_back( + new TileProvider(QStringLiteral("http://c.tile.opencyclemap.org/cycle/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_transit.push_back( + new TileProvider(QStringLiteral("http://c.tile2.opencyclemap.org/transport/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_nighttransit.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/transport-dark/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors")) ); + providers_terrain.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/landscape/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + providers_hiking.push_back( + new TileProvider(QStringLiteral("http://a.tile.thunderforest.com/outdoors/%z/%x/%y.png"), + QStringLiteral("png"), + QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), + QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"))); + + + /* QGeoTileProviderOsms setup */ + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::StreetMap, tr("Street Map"), tr("Street map view in daylight mode"), false, false, 1), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.openstreetmap.org/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap.org</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "satellite", - nm, + providers_street )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite Map"), tr("Satellite map view in daylight mode"), false, false, 2), - QGeoTileProviderOsm::TileProvider() - )); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "cycle", - nm, + providers_satellite )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::CycleMap, tr("Cycle Map"), tr("Cycle map view in daylight mode"), false, false, 3), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile.opencyclemap.org/cycle/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "transit", - nm, + providers_cycle )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TransitMap, tr("Transit Map"), tr("Public transit map view in daylight mode"), false, false, 4), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://c.tile2.opencyclemap.org/transport/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "night-transit", - nm, + providers_transit )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TransitMap, tr("Night Transit Map"), tr("Public transit map view in night mode"), false, true, 5), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/transport-dark/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "terrain", - nm, + providers_nighttransit )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain Map"), tr("Terrain map view"), false, false, 6), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/landscape/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); - m_providers.push_back( - new QGeoTileProviderOsm(domain + "hiking", - nm, + providers_terrain )); + m_providers.push_back( new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::PedestrianMap, tr("Hiking Map"), tr("Hiking map view"), false, false, 7), - QGeoTileProviderOsm::TileProvider(QStringLiteral("http://a.tile.thunderforest.com/outdoors/%z/%x/%y.png"), - QStringLiteral("png"), - QStringLiteral("<a href='http://www.thunderforest.com/'>Thunderforest</a>"), - QStringLiteral("<a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors") - ))); + providers_hiking )); if (parameters.contains(QStringLiteral("osm.mapping.custom.host")) || parameters.contains(QStringLiteral("osm.mapping.host"))) { @@ -154,14 +181,13 @@ QGeoTiledMappingManagerEngineOsm::QGeoTiledMappingManagerEngineOsm(const QVarian m_customCopyright = parameters.value(QStringLiteral("osm.mapping.copyright")).toString(); m_providers.push_back( - new QGeoTileProviderOsm("", - nm, + new QGeoTileProviderOsm( nm, QGeoMapType(QGeoMapType::CustomMap, tr("Custom URL Map"), tr("Custom url map view set via urlprefix parameter"), false, false, 8), - QGeoTileProviderOsm::TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"), + { new TileProvider(tmsServer + QStringLiteral("%z/%x/%y.png"), QStringLiteral("png"), mapCopyright, - dataCopyright - ))); + dataCopyright) } + )); m_providers.last()->disableRedirection(); } @@ -257,9 +283,8 @@ void QGeoTiledMappingManagerEngineOsm::onProviderResolutionFinished(const QGeoTi updateMapTypes(); } -void QGeoTiledMappingManagerEngineOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error) +void QGeoTiledMappingManagerEngineOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider) { - Q_UNUSED(error) if (!provider->isResolved()) return; updateMapTypes(); diff --git a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h index 7536e655..b1f0a13c 100644 --- a/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h +++ b/src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.h @@ -65,7 +65,7 @@ public: protected Q_SLOTS: void onProviderResolutionFinished(const QGeoTileProviderOsm *provider); - void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void onProviderResolutionError(const QGeoTileProviderOsm *provider); protected: void updateMapTypes(); diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp index 98621411..0d7fa58e 100644 --- a/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp +++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.cpp @@ -100,9 +100,8 @@ void QGeoTileFetcherOsm::onProviderResolutionFinished(const QGeoTileProviderOsm emit providerDataUpdated(provider); } -void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error) +void QGeoTileFetcherOsm::onProviderResolutionError(const QGeoTileProviderOsm *provider) { - Q_UNUSED(error) if ((m_ready = providersResolved(m_providers))) { qWarning("QGeoTileFetcherOsm: all providers resolved"); readyUpdated(); diff --git a/src/plugins/geoservices/osm/qgeotilefetcherosm.h b/src/plugins/geoservices/osm/qgeotilefetcherosm.h index 8d69cc56..c3f33faa 100644 --- a/src/plugins/geoservices/osm/qgeotilefetcherosm.h +++ b/src/plugins/geoservices/osm/qgeotilefetcherosm.h @@ -69,7 +69,7 @@ protected: protected Q_SLOTS: void onProviderResolutionFinished(const QGeoTileProviderOsm *provider); - void onProviderResolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void onProviderResolutionError(const QGeoTileProviderOsm *provider); private: QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec); diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp index 3d46a425..afa8e45f 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.cpp +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.cpp @@ -44,150 +44,271 @@ QT_BEGIN_NAMESPACE static const int maxValidZoom = 30; -QGeoTileProviderOsm::QGeoTileProviderOsm(const QString &urlRedir, - QNetworkAccessManager *nm, - const QGeoMapType &mapType, - const QGeoTileProviderOsm::TileProvider &providerFallback) - : m_nm(nm), m_urlRedirector(urlRedir), - m_providerFallback(providerFallback), - m_mapType(mapType), m_status(Idle) +QGeoTileProviderOsm::QGeoTileProviderOsm(QNetworkAccessManager *nm, + const QGeoMapType &mapType, + const QVector<TileProvider *> &providers) +: m_nm(nm), m_provider(nullptr), m_mapType(mapType), m_status(Idle) { - if (!m_urlRedirector.isValid()) - disableRedirection(); + for (int i = 0; i < providers.size(); ++i) { + TileProvider *p = providers[i]; + if (!m_provider) + m_providerId = i; + addProvider(p); + } + + if (!m_provider || m_provider->isValid()) + m_status = Resolved; } QGeoTileProviderOsm::~QGeoTileProviderOsm() { +} + +QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const +{ + if (m_status != Resolved || !m_provider) + return QUrl(); + return m_provider->tileAddress(x, y, z); +} + +QString QGeoTileProviderOsm::mapCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->mapCopyRight(); +} + +QString QGeoTileProviderOsm::dataCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->dataCopyRight(); +} + +QString QGeoTileProviderOsm::styleCopyRight() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->styleCopyRight(); +} + +QString QGeoTileProviderOsm::format() const +{ + if (m_status != Resolved || !m_provider) + return QString(); + return m_provider->format(); +} + +const QGeoMapType &QGeoTileProviderOsm::mapType() const +{ + return m_mapType; +} + +bool QGeoTileProviderOsm::isValid() const +{ + if (m_status != Resolved || !m_provider) + return false; + return m_provider->isValid(); +} +bool QGeoTileProviderOsm::isResolved() const +{ + return (m_status == Resolved); } void QGeoTileProviderOsm::resolveProvider() { - switch (m_status) { - case Resolving: - case Invalid: - case Valid: - return; - case Idle: - m_status = Resolving; - break; - } + if (m_status == Resolved || m_status == Resolving) + return; - QNetworkRequest request; - request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("QGeoTileFetcherOsm")); - request.setUrl(m_urlRedirector); - QNetworkReply *reply = m_nm->get(request); - connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError))); + m_status = Resolving; + // Provider can't be null while on Idle status. + connect(m_provider, &TileProvider::resolutionFinished, this, &QGeoTileProviderOsm::onResolutionFinished); + connect(m_provider, &TileProvider::resolutionError, this, &QGeoTileProviderOsm::onResolutionError); + m_provider->resolveProvider(); } void QGeoTileProviderOsm::disableRedirection() { - m_status = Invalid; - m_provider.m_valid = false; + if (m_provider && m_provider->isValid()) + return; + bool found = false; + for (TileProvider *p: m_providerList) { + if (p->isValid() && !found) { + m_provider = p; + found = true; + } + p->disconnect(this); + } } -void QGeoTileProviderOsm::handleError(QNetworkReply::NetworkError error) +void QGeoTileProviderOsm::onResolutionFinished(TileProvider *provider) { - switch (error) { - case QNetworkReply::ConnectionRefusedError: - case QNetworkReply::TooManyRedirectsError: - case QNetworkReply::InsecureRedirectError: - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::ContentOperationNotPermittedError: - case QNetworkReply::ContentNotFoundError: - case QNetworkReply::AuthenticationRequiredError: - case QNetworkReply::ContentGoneError: - case QNetworkReply::OperationNotImplementedError: - case QNetworkReply::ServiceUnavailableError: - // Errors we don't expect to recover from in the near future, which - // prevent accessing the redirection info but not the actual providers. - m_status = Invalid; - default: - break; + Q_UNUSED(provider) + // provider and m_provider are the same, at this point. m_status is Resolving. + m_status = Resolved; + emit resolutionFinished(this); +} + +void QGeoTileProviderOsm::onResolutionError(TileProvider *provider) +{ + Q_UNUSED(provider) + // provider and m_provider are the same at this point. m_status is Resolving. + if (m_provider->isInvalid()) { + m_provider = nullptr; + m_status = Resolved; + if (m_providerId >= m_providerList.size() -1) { // no hope left + emit resolutionError(this); + return; + } + // Advance the pointer in the provider list, and possibly start resolution on the next in the list. + for (int i = m_providerId + 1; i < m_providerList.size(); ++i) { + m_providerId = i; + TileProvider *p = m_providerList[m_providerId]; + if (!p->isInvalid()) { + m_provider = p; + if (!p->isValid()) { + m_status = Idle; + //m_status = Resolving; + //p->resolveProvider(); + } + } + } + if (!m_provider) + emit resolutionError(this); + } else if (m_provider->isValid()) { + m_status = Resolved; + emit resolutionFinished(this); + } else { // still not resolved. But network error is recoverable. + m_status = Idle; + //m_provider->resolveProvider(); } } -QUrl QGeoTileProviderOsm::tileAddress(int x, int y, int z) const +void QGeoTileProviderOsm::addProvider(TileProvider *provider) { - if (m_provider.isValid()) - return m_provider.tileAddress(x,y,z); - if (m_providerFallback.isValid()) - return m_providerFallback.tileAddress(x,y,z); - return QUrl(); + if (!provider) + return; + QScopedPointer<TileProvider> p(provider); + if (provider->status() == TileProvider::Invalid) + return; // if the provider is already resolved and invalid, no point in adding it. + + provider = p.take(); + provider->setNetworkManager(m_nm); + provider->setParent(this); + m_providerList.append(provider); + if (!m_provider) + m_provider = provider; } -QString QGeoTileProviderOsm::mapCopyRight() const + +/* + QGeoTileProviderOsm::TileProvder +*/ + +static void sort2(int &a, int &b) { - if (m_provider.isValid()) - return m_provider.mapCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.mapCopyRight(); - return QString(); + if (a > b) { + int temp=a; + a=b; + b=temp; + } } -QString QGeoTileProviderOsm::dataCopyRight() const +TileProvider::TileProvider() : m_status(Invalid), m_nm(nullptr) { - if (m_provider.isValid()) - return m_provider.dataCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.dataCopyRight(); - return QString(); + } -QString QGeoTileProviderOsm::styleCopyRight() const +TileProvider::TileProvider(const QUrl &urlRedirector) : m_status(Idle), m_urlRedirector(urlRedirector), m_nm(nullptr) { - if (m_provider.isValid()) - return m_provider.styleCopyRight(); - if (m_providerFallback.isValid()) - return m_providerFallback.styleCopyRight(); - return QString(); + if (!m_urlRedirector.isValid()) + m_status = Invalid; } -QString QGeoTileProviderOsm::format() const +TileProvider::TileProvider(const QString &urlTemplate, + const QString &format, + const QString ©RightMap, + const QString ©RightData, + int minimumZoomLevel, + int maximumZoomLevel) +: m_status(Invalid), m_nm(nullptr), m_urlTemplate(urlTemplate), + m_format(format), m_copyRightMap(copyRightMap), m_copyRightData(copyRightData), + m_minimumZoomLevel(minimumZoomLevel), m_maximumZoomLevel(maximumZoomLevel) { - if (m_provider.isValid()) - return m_provider.format(); - if (m_providerFallback.isValid()) - return m_providerFallback.format(); - return QString(); + setupProvider(); } -const QGeoMapType &QGeoTileProviderOsm::mapType() const +TileProvider::~TileProvider() { - return m_mapType; } -bool QGeoTileProviderOsm::isValid() const +void TileProvider::resolveProvider() { - return (m_provider.isValid() || m_providerFallback.isValid()); + if (!m_nm) + return; + + switch (m_status) { + case Resolving: + case Invalid: + case Valid: + return; + case Idle: + m_status = Resolving; + break; + } + + QNetworkRequest request; + request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("QGeoTileFetcherOsm")); + request.setUrl(m_urlRedirector); + QNetworkReply *reply = m_nm->get(request); + connect(reply, SIGNAL(finished()), this, SLOT(onNetworkReplyFinished()) ); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onNetworkReplyError(QNetworkReply::NetworkError))); } -bool QGeoTileProviderOsm::isResolved() const +void TileProvider::handleError(QNetworkReply::NetworkError error) { - return (m_status == Valid || m_status == Invalid); + switch (error) { + case QNetworkReply::ConnectionRefusedError: + case QNetworkReply::TooManyRedirectsError: + case QNetworkReply::InsecureRedirectError: + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentOperationNotPermittedError: + case QNetworkReply::ContentNotFoundError: + case QNetworkReply::AuthenticationRequiredError: + case QNetworkReply::ContentGoneError: + case QNetworkReply::OperationNotImplementedError: + case QNetworkReply::ServiceUnavailableError: + // Errors we don't expect to recover from in the near future, which + // prevent accessing the redirection info but not the actual providers. + qWarning() << "QGeoTileProviderOsm network error:" << error; + m_status = Invalid; + default: + break; + } } -void QGeoTileProviderOsm::onNetworkReplyFinished() +void TileProvider::onNetworkReplyFinished() { QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); reply->deleteLater(); switch (m_status) { - case Resolving: - m_status = Idle; - case Idle: // should not happen - case Invalid: // should not happen - break; - case Valid: // should not happen - return; + case Resolving: + m_status = Idle; + case Idle: // should not happen + case Invalid: // should not happen + break; + case Valid: // should not happen + emit resolutionFinished(this); + return; } + QObject errorEmitter; + QMetaObject::Connection errorEmitterConnection = connect(&errorEmitter, &QObject::destroyed, [this](){ this->resolutionError(this); }); + if (reply->error() != QNetworkReply::NoError) { handleError(reply->error()); - if (m_status == Invalid) - emit resolutionError(this, reply->error()); return; } m_status = Invalid; @@ -241,12 +362,10 @@ void QGeoTileProviderOsm::onNetworkReplyFinished() QJsonDocument d = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { qWarning() << "QGeoTileProviderOsm: Error parsing redirection data: "<<error.errorString() << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } if (!d.isObject()) { qWarning() << "QGeoTileProviderOsm: Invalid redirection data" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } const QJsonObject json = d.object(); @@ -263,56 +382,175 @@ void QGeoTileProviderOsm::onNetworkReplyFinished() || !copyRightMap.isString() || !copyRightData.isString()) { qWarning() << "QGeoTileProviderOsm: Incomplete redirection data" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } + m_urlTemplate = urlTemplate.toString(); + m_format = imageFormat.toString(); + m_copyRightMap = copyRightMap.toString(); + m_copyRightData = copyRightData.toString(); + const QJsonValue enabled = json.value(QLatin1String("Enabled")); if (enabled.isBool() && ! enabled.toBool()) { qWarning() << "QGeoTileProviderOsm: Tileserver disabled" << "at "<<m_urlRedirector; - emit resolutionFinished(this); return; } - QString styleCopyRight; const QJsonValue copyRightStyle = json.value(QLatin1String("StyleCopyRight")); if (copyRightStyle != QJsonValue::Undefined && copyRightStyle.isString()) - styleCopyRight = copyRightStyle.toString(); + m_copyRightStyle = copyRightStyle.toString(); - int minZL = 0; - int maxZL = 19; + m_minimumZoomLevel = 0; + m_maximumZoomLevel = 19; const QJsonValue minZoom = json.value(QLatin1String("MinimumZoomLevel")); if (minZoom.isDouble()) - minZL = qBound(0, int(minZoom.toDouble()), maxValidZoom); + m_minimumZoomLevel = qBound(0, int(minZoom.toDouble()), maxValidZoom); const QJsonValue maxZoom = json.value(QLatin1String("MaximumZoomLevel")); if (maxZoom.isDouble()) - maxZL = qBound(0, int(maxZoom.toDouble()), maxValidZoom); - - m_provider = TileProvider(urlTemplate.toString(), - imageFormat.toString(), - copyRightMap.toString(), - copyRightData.toString(), - minZL, - maxZL); - m_provider.setStyleCopyRight(styleCopyRight); - - if (m_provider.isValid()) - m_status = Valid; + m_maximumZoomLevel = qBound(0, int(maxZoom.toDouble()), maxValidZoom); - emit resolutionFinished(this); + setupProvider(); + if (isValid()) { + QObject::disconnect(errorEmitterConnection); + emit resolutionFinished(this); + } } -void QGeoTileProviderOsm::onNetworkReplyError(QNetworkReply::NetworkError error) +void TileProvider::onNetworkReplyError(QNetworkReply::NetworkError error) { if (m_status == Resolving) m_status = Idle; - qWarning() << "QGeoTileProviderOsm::onNetworkReplyError " << error; handleError(error); - static_cast<QNetworkReply *>(sender())->deleteLater(); - if (m_status == Invalid) - emit resolutionError(this, error); + emit resolutionError(this); +} + +void TileProvider::setupProvider() +{ + if (m_urlTemplate.isEmpty()) + return; + + if (m_format.isEmpty()) + return; + + if (m_minimumZoomLevel < 0 || m_minimumZoomLevel > 30) + return; + + if (m_maximumZoomLevel < 0 || m_maximumZoomLevel > 30 || m_maximumZoomLevel < m_minimumZoomLevel) + return; + + // Currently supporting only %x, %y and &z + int offset[3]; + offset[0] = m_urlTemplate.indexOf(QLatin1String("%x")); + if (offset[0] < 0) + return; + + offset[1] = m_urlTemplate.indexOf(QLatin1String("%y")); + if (offset[1] < 0) + return; + + offset[2] = m_urlTemplate.indexOf(QLatin1String("%z")); + if (offset[2] < 0) + return; + + int sortedOffsets[3]; + std::copy(offset, offset + 3, sortedOffsets); + sort2(sortedOffsets[0] ,sortedOffsets[1]); + sort2(sortedOffsets[1] ,sortedOffsets[2]); + sort2(sortedOffsets[0] ,sortedOffsets[1]); + + int min = sortedOffsets[0]; + int max = sortedOffsets[2]; + int mid = sortedOffsets[1]; + + // Initing LUT + for (int i=0; i<3; i++) { + if (offset[0] == sortedOffsets[i]) + paramsLUT[i] = 0; + else if (offset[1] == sortedOffsets[i]) + paramsLUT[i] = 1; + else + paramsLUT[i] = 2; + } + + m_urlPrefix = m_urlTemplate.mid(0 , min); + m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2); + + paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2); + paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2); + m_status = Valid; } +bool TileProvider::isValid() const +{ + return m_status == Valid; +} + +bool TileProvider::isInvalid() const +{ + return m_status == Invalid; +} + +bool TileProvider::isResolved() const +{ + return (m_status == Valid || m_status == Invalid); +} + +QString TileProvider::mapCopyRight() const +{ + return m_copyRightMap; +} + +QString TileProvider::dataCopyRight() const +{ + return m_copyRightData; +} + +QString TileProvider::styleCopyRight() const +{ + return m_copyRightStyle; +} + +QString TileProvider::format() const +{ + return m_format; +} + +void TileProvider::setStyleCopyRight(const QString ©right) +{ + m_copyRightStyle = copyright; +} + +QUrl TileProvider::tileAddress(int x, int y, int z) const +{ + if (z < m_minimumZoomLevel || z > m_maximumZoomLevel) + return QUrl(); + int params[3] = { x, y, z}; + QString url; + url += m_urlPrefix; + url += QString::number(params[paramsLUT[0]]); + url += paramsSep[0]; + url += QString::number(params[paramsLUT[1]]); + url += paramsSep[1]; + url += QString::number(params[paramsLUT[2]]); + url += m_urlSuffix; + return QUrl(url); +} + +void TileProvider::setNetworkManager(QNetworkAccessManager *nm) +{ + m_nm = nm; +} + +TileProvider::Status TileProvider::status() const +{ + return m_status; +} + + QT_END_NAMESPACE + + + + diff --git a/src/plugins/geoservices/osm/qgeotileproviderosm.h b/src/plugins/geoservices/osm/qgeotileproviderosm.h index f396b3b5..d9f80482 100644 --- a/src/plugins/geoservices/osm/qgeotileproviderosm.h +++ b/src/plugins/geoservices/osm/qgeotileproviderosm.h @@ -40,186 +40,102 @@ #include <QtLocation/private/qgeomaptype_p.h> #include <QtCore/QUrl> +#include <QtCore/QVector> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> #include <QtCore/QPointer> #include <QTimer> #include <algorithm> +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonObject> QT_BEGIN_NAMESPACE -class QGeoTileProviderOsm: public QObject +class TileProvider: public QObject { Q_OBJECT - - friend class QGeoTileFetcherOsm; - friend class QGeoMapReplyOsm; - friend class QGeoTiledMappingManagerEngineOsm; public: - struct TileProvider { - - static inline void sort2(int &a, int &b) - { - if (a > b) { - int temp=a; - a=b; - b=temp; - } - } - - TileProvider() : m_valid(false) - { - - } - - TileProvider(const QString &urlTemplate, - const QString &format, - const QString ©RightMap, - const QString ©RightData, - int minimumZoomLevel = 0, - int maximumZoomLevel = 19) : m_valid(false) - { - if (urlTemplate.isEmpty()) - return; - m_urlTemplate = urlTemplate; - - if (format.isEmpty()) - return; - m_format = format; - - m_copyRightMap = copyRightMap; - m_copyRightData = copyRightData; - - if (minimumZoomLevel < 0 || minimumZoomLevel > 30) - return; - m_minimumZoomLevel = minimumZoomLevel; - - if (maximumZoomLevel < 0 || maximumZoomLevel > 30 || maximumZoomLevel < minimumZoomLevel) - return; - m_maximumZoomLevel = maximumZoomLevel; - - // Currently supporting only %x, %y and &z - int offset[3]; - offset[0] = m_urlTemplate.indexOf(QLatin1String("%x")); - if (offset[0] < 0) - return; - - offset[1] = m_urlTemplate.indexOf(QLatin1String("%y")); - if (offset[1] < 0) - return; - - offset[2] = m_urlTemplate.indexOf(QLatin1String("%z")); - if (offset[2] < 0) - return; - - int sortedOffsets[3]; - std::copy(offset, offset + 3, sortedOffsets); - sort2(sortedOffsets[0] ,sortedOffsets[1]); - sort2(sortedOffsets[1] ,sortedOffsets[2]); - sort2(sortedOffsets[0] ,sortedOffsets[1]); - - int min = sortedOffsets[0]; - int max = sortedOffsets[2]; - int mid = sortedOffsets[1]; - - // Initing LUT - for (int i=0; i<3; i++) { - if (offset[0] == sortedOffsets[i]) - paramsLUT[i] = 0; - else if (offset[1] == sortedOffsets[i]) - paramsLUT[i] = 1; - else - paramsLUT[i] = 2; - } - - m_urlPrefix = m_urlTemplate.mid(0 , min); - m_urlSuffix = m_urlTemplate.mid(max + 2, m_urlTemplate.size() - max - 2); + enum Status {Idle, + Resolving, + Valid, + Invalid }; - paramsSep[0] = m_urlTemplate.mid(min + 2, mid - min - 2); - paramsSep[1] = m_urlTemplate.mid(mid + 2, max - mid - 2); - m_valid = true; - } + TileProvider(); + // "Online" constructor. Needs resolution to fetch the parameters + TileProvider(const QUrl &urlRedirector); + // Offline constructor. Doesn't need URLRedirector and networkmanager + TileProvider(const QString &urlTemplate, + const QString &format, + const QString ©RightMap, + const QString ©RightData, + int minimumZoomLevel = 0, + int maximumZoomLevel = 19); - ~TileProvider() - { - } + ~TileProvider(); + void setNetworkManager(QNetworkAccessManager *nm); - inline bool isValid() const - { - return m_valid; - } + void resolveProvider(); + void handleError(QNetworkReply::NetworkError error); + void setupProvider(); - inline QString mapCopyRight() const - { - return m_copyRightMap; - } + inline bool isValid() const; + inline bool isInvalid() const; + inline bool isResolved() const; + inline Status status() const; - inline QString dataCopyRight() const - { - return m_copyRightData; - } + inline QString mapCopyRight() const; + inline QString dataCopyRight() const; + inline QString styleCopyRight() const; + inline QString format() const; + QUrl tileAddress(int x, int y, int z) const; - inline QString styleCopyRight() const - { - return m_copyRightStyle; - } + // Optional properties, not needed to construct a provider + void setStyleCopyRight(const QString ©right); - inline QString format() const - { - return m_format; - } + Status m_status; + QUrl m_urlRedirector; // The URL from where to fetch the URL template in case of a provider to resolve. + QNetworkAccessManager *m_nm; + QString m_urlTemplate; + QString m_format; + QString m_copyRightMap; + QString m_copyRightData; + QString m_copyRightStyle; + QString m_urlPrefix; + QString m_urlSuffix; + int m_minimumZoomLevel; + int m_maximumZoomLevel; + + int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z + QString paramsSep[2]; // what goes in between %x, %y and %z - // Optional properties, not needed to construct a provider - void setStyleCopyRight(const QString ©right) - { - m_copyRightStyle = copyright; - } +Q_SIGNALS: + void resolutionFinished(TileProvider *provider); + void resolutionError(TileProvider *provider); - QUrl tileAddress(int x, int y, int z) const - { - if (z < m_minimumZoomLevel || z > m_maximumZoomLevel) - return QUrl(); - int params[3] = { x, y, z}; - QString url; - url += m_urlPrefix; - url += QString::number(params[paramsLUT[0]]); - url += paramsSep[0]; - url += QString::number(params[paramsLUT[1]]); - url += paramsSep[1]; - url += QString::number(params[paramsLUT[2]]); - url += m_urlSuffix; - return QUrl(url); - } +public Q_SLOTS: + void onNetworkReplyFinished(); + void onNetworkReplyError(QNetworkReply::NetworkError error); - bool m_valid; - QString m_urlTemplate; - QString m_format; - QString m_copyRightMap; - QString m_copyRightData; - QString m_copyRightStyle; - QString m_urlPrefix; - QString m_urlSuffix; - int m_minimumZoomLevel; - int m_maximumZoomLevel; +friend class QGeoTileProviderOsm; +}; - int paramsLUT[3]; //Lookup table to handle possibly shuffled x,y,z - QString paramsSep[2]; // what goes in between %x, %y and %z - }; +class QGeoTileProviderOsm: public QObject +{ + Q_OBJECT + friend class QGeoTileFetcherOsm; + friend class QGeoMapReplyOsm; + friend class QGeoTiledMappingManagerEngineOsm; +public: enum Status {Idle, Resolving, - Valid, - Invalid }; - - QGeoTileProviderOsm(const QString &urlRedir, - QNetworkAccessManager *nm, - const QGeoMapType &mapType, - const TileProvider &providerFallback); + Resolved }; + QGeoTileProviderOsm(QNetworkAccessManager *nm, + const QGeoMapType &mapType, + const QVector<TileProvider *> &providers); ~QGeoTileProviderOsm(); - - QUrl tileAddress(int x, int y, int z) const; QString mapCopyRight() const; QString dataCopyRight() const; @@ -231,24 +147,27 @@ public: Q_SIGNALS: void resolutionFinished(const QGeoTileProviderOsm *provider); - void resolutionError(const QGeoTileProviderOsm *provider, QNetworkReply::NetworkError error); + void resolutionError(const QGeoTileProviderOsm *provider); public Q_SLOTS: - void onNetworkReplyFinished(); - void onNetworkReplyError(QNetworkReply::NetworkError error); void resolveProvider(); + void disableRedirection(); + +protected Q_SLOTS: + void onResolutionFinished(TileProvider *provider); + void onResolutionError(TileProvider *provider); protected: - void disableRedirection(); - void handleError(QNetworkReply::NetworkError error); + void addProvider(TileProvider *provider); + +/* Data members */ QNetworkAccessManager *m_nm; - QUrl m_urlRedirector; // The URL from where to fetch the URL template - TileProvider m_provider; - TileProvider m_providerFallback; + QVector<TileProvider *> m_providerList; + TileProvider *m_provider; + int m_providerId; QGeoMapType m_mapType; Status m_status; - QTimer m_retryTimer; }; QT_END_NAMESPACE |