//----------------------------------------------------------------------------- void QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap ¶meters) { QString cacheDir; if (parameters.contains(QStringLiteral("mapping.cache.directory"))) cacheDir = parameters.value(QStringLiteral("mapping.cache.directory")).toString(); else { cacheDir = getQGCMapEngine()->getCachePath(); if(!QFileInfo(cacheDir).exists()) { if(!QDir::root().mkpath(cacheDir)) { qWarning() << "Could not create mapping disk cache directory: " << cacheDir; cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/"); } } } if(!QFileInfo(cacheDir).exists()) { if(!QDir::root().mkpath(cacheDir)) { qWarning() << "Could not create mapping disk cache directory: " << cacheDir; cacheDir.clear(); } } //-- Memory Cache uint32_t memLimit = 0; if (parameters.contains(QStringLiteral("mapping.cache.memory.size"))) { bool ok = false; memLimit = parameters.value(QStringLiteral("mapping.cache.memory.size")).toString().toUInt(&ok); if (!ok) memLimit = 0; } if(!memLimit) { //-- Value saved in MB memLimit = getQGCMapEngine()->getMaxMemCache() * (1024 * 1024); } //-- It won't work with less than 1M of memory cache if(memLimit < 1024 * 1024) memLimit = 1024 * 1024; //-- Disable Qt's disk cache (set memory cache otherwise Qtlocation won't work) #if QT_VERSION >= 0x050600 QAbstractGeoTileCache *pTileCache = new QGeoFileTileCache(cacheDir); setTileCache(pTileCache); #else QGeoTileCache* pTileCache = createTileCacheWithDir(cacheDir); #endif if(pTileCache) { //-- We're basically telling it to use 100k of disk for cache. It doesn't like // values smaller than that and I could not find a way to make it NOT cache. pTileCache->setMaxDiskUsage(1024 * 100); pTileCache->setMaxMemoryUsage(memLimit); } }
//----------------------------------------------------------------------------- void UrlFactory::_tryCorrectGoogleVersions(QNetworkAccessManager* networkManager) { QMutexLocker locker(&_googleVersionMutex); if (_googleVersionRetrieved) { return; } _googleVersionRetrieved = true; if(networkManager) { QNetworkRequest qheader; QNetworkProxy proxy = networkManager->proxy(); QNetworkProxy tProxy; tProxy.setType(QNetworkProxy::DefaultProxy); networkManager->setProxy(tProxy); QSslConfiguration conf = qheader.sslConfiguration(); conf.setPeerVerifyMode(QSslSocket::VerifyNone); qheader.setSslConfiguration(conf); QString url = "http://maps.google.com/maps/api/js?v=3.2&sensor=false"; qheader.setUrl(QUrl(url)); QByteArray ua; ua.append(getQGCMapEngine()->userAgent()); qheader.setRawHeader("User-Agent", ua); _googleReply = networkManager->get(qheader); connect(_googleReply, &QNetworkReply::finished, this, &UrlFactory::_googleVersionCompleted); connect(_googleReply, &QNetworkReply::destroyed, this, &UrlFactory::_replyDestroyed); connect(_googleReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &UrlFactory::_networkReplyError); networkManager->setProxy(proxy); } }
//----------------------------------------------------------------------------- void QGeoTiledMapReplyQGC::networkReplyFinished() { if (!_reply) { return; } if (_reply->error() != QNetworkReply::NoError) { return; } QByteArray a = _reply->readAll(); setMapImageData(a); QString format = getQGCMapEngine()->urlFactory()->getImageFormat((UrlFactory::MapType)tileSpec().mapId(), a); if(!format.isEmpty()) { setMapImageFormat(format); getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format); } setFinished(true); _reply->deleteLater(); _reply = 0; }
//----------------------------------------------------------------------------- QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent) : QGeoTiledMapReply(spec, parent) , _reply(NULL) , _request(request) , _networkManager(networkManager) { if(_request.url().isEmpty()) { if(!_badMapBox.size()) { QFile b(":/res/notile.png"); if(b.open(QFile::ReadOnly)) _badMapBox = b.readAll(); } setMapImageData(_badMapBox); setMapImageFormat("png"); setFinished(true); setCached(false); } else { QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom()); connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply); connect(task, &QGCMapTask::error, this, &QGeoTiledMapReplyQGC::cacheError); getQGCMapEngine()->addTask(task); } }
//----------------------------------------------------------------------------- QString UrlFactory::_getURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager) { switch (type) { case GoogleMap: { // http://mt1.google.com/vt/lyrs=m QString server = "mt"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... _getSecGoogleWords(x, y, sec1, sec2); _tryCorrectGoogleVersions(networkManager); return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleMap).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2); } break; case GoogleSatellite: { // http://mt1.google.com/vt/lyrs=s QString server = "khm"; QString request = "kh"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... _getSecGoogleWords(x, y, sec1, sec2); _tryCorrectGoogleVersions(networkManager); return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleSatellite).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2); } break; case GoogleLabels: { QString server = "mts"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... _getSecGoogleWords(x, y, sec1, sec2); _tryCorrectGoogleVersions(networkManager); return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleLabels).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2); } break; case GoogleTerrain: { QString server = "mt"; QString request = "vt"; QString sec1 = ""; // after &x=... QString sec2 = ""; // after &zoom=... _getSecGoogleWords(x, y, sec1, sec2); _tryCorrectGoogleVersions(networkManager); return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleTerrain).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2); } break; /* case OpenStreetMap: { char letter = "abc"[_getServerNum(x, y, 3)]; return QString("https://%1.tile.openstreetmap.org/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y); } break; case OpenStreetOsm: { char letter = "abc"[_getServerNum(x, y, 3)]; return QString("http://%1.tah.openstreetmap.org/Tiles/tile/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y); } break; case OpenStreetMapSurfer: { // http://tiles1.mapsurfer.net/tms_r.ashx?x=37378&y=20826&z=16 return QString("http://tiles1.mapsurfer.net/tms_r.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); } break; case OpenStreetMapSurferTerrain: { // http://tiles2.mapsurfer.net/tms_t.ashx?x=9346&y=5209&z=14 return QString("http://tiles2.mapsurfer.net/tms_t.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom); } break; */ case BingMap: { QString key = _tileXYToQuadKey(x, y, zoom); return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language); } break; case BingSatellite: { QString key = _tileXYToQuadKey(x, y, zoom); return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language); } break; case BingHybrid: { QString key = _tileXYToQuadKey(x, y, zoom); return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language); } case MapQuestMap: { char letter = "1234"[_getServerNum(x, y, 4)]; return QString("http://otile%1.mqcdn.com/tiles/1.0.0/map/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y); } break; case MapQuestSat: { char letter = "1234"[_getServerNum(x, y, 4)]; return QString("http://otile%1.mqcdn.com/tiles/1.0.0/sat/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y); } break; case MapBoxStreets: case MapBoxLight: case MapBoxDark: case MapBoxSatellite: case MapBoxHybrid: case MapBoxWheatPaste: case MapBoxStreetsBasic: case MapBoxComic: case MapBoxOutdoors: case MapBoxRunBikeHike: case MapBoxPencil: case MapBoxPirates: case MapBoxEmerald: case MapBoxHighContrast: { QString mapBoxToken = getQGCMapEngine()->getMapBoxToken(); if(!mapBoxToken.isEmpty()) { QString server = "https://api.mapbox.com/v4/"; switch(type) { case MapBoxStreets: server += "mapbox.streets"; break; case MapBoxLight: server += "mapbox.light"; break; case MapBoxDark: server += "mapbox.dark"; break; case MapBoxSatellite: server += "mapbox.satellite"; break; case MapBoxHybrid: server += "mapbox.streets-satellite"; break; case MapBoxWheatPaste: server += "mapbox.wheatpaste"; break; case MapBoxStreetsBasic: server += "mapbox.streets-basic"; break; case MapBoxComic: server += "mapbox.comic"; break; case MapBoxOutdoors: server += "mapbox.outdoors"; break; case MapBoxRunBikeHike: server += "mapbox.run-bike-hike"; break; case MapBoxPencil: server += "mapbox.pencil"; break; case MapBoxPirates: server += "mapbox.pirates"; break; case MapBoxEmerald: server += "mapbox.emerald"; break; case MapBoxHighContrast: server += "mapbox.high-contrast"; break; default: return QString::null; } server += QString("/%1/%2/%3.jpg80?access_token=%4").arg(zoom).arg(x).arg(y).arg(mapBoxToken); return server; } } break; default: qWarning("Unknown map id %d\n", type); break; } return QString::null; }
//----------------------------------------------------------------------------- QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) : QGeoTiledMappingManagerEngine() { QGeoCameraCapabilities cameraCaps; cameraCaps.setMinimumZoomLevel(2.0); cameraCaps.setMaximumZoomLevel(MAX_MAP_ZOOM); cameraCaps.setSupportsBearing(true); setCameraCapabilities(cameraCaps); setTileSize(QSize(256, 256)); /* * Most of these don't seem kosher at all. This was based on original code from OpenPilot and heavily modified to be used in QGC. */ //-- IMPORTANT // Changes here must reflect those in QGCMapEngine.cpp QList<QGeoMapType> mapTypes; mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Google Street Map", "Google street map", false, false, UrlFactory::GoogleMap); mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Google Satellite Map", "Google satellite map", false, false, UrlFactory::GoogleSatellite); mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Google Terrain Map", "Google terrain map", false, false, UrlFactory::GoogleTerrain); /* TODO: * Proper google hybrid maps requires collecting two separate bimaps and overlaying them. * * mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Google Hybrid Map", "Google hybrid map", false, false, UrlFactory::GoogleHybrid); * */ // Bing mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Bing Street Map", "Bing street map", false, false, UrlFactory::BingMap); mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Bing Satellite Map", "Bing satellite map", false, false, UrlFactory::BingSatellite); mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Bing Hybrid Map", "Bing hybrid map", false, false, UrlFactory::BingHybrid); /* See: https://wiki.openstreetmap.org/wiki/Tile_usage_policy mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Open Street Map", "Open Street map", false, false, UrlFactory::OpenStreetMap); */ // MapQuest mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapQuest Street Map", "MapQuest street map", false, false, UrlFactory::MapQuestMap); mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapQuest Satellite Map", "MapQuest satellite map", false, false, UrlFactory::MapQuestSat); /* * These are OK as you need your own token for accessing it. Out-of-the box, QGC does not even offer these unless you enter a proper MapBox token. */ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Street Map", "MapBox Street Map", false, false, UrlFactory::MapBoxStreets); mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapBox Satellite Map", "MapBox Satellite Map", false, false, UrlFactory::MapBoxSatellite); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox High Contrast Map", "MapBox High Contrast Map", false, false, UrlFactory::MapBoxHighContrast); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Light Map", "MapBox Light Map", false, false, UrlFactory::MapBoxLight); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Dark Map", "MapBox Dark Map", false, false, UrlFactory::MapBoxDark); mapTypes << QGeoMapType(QGeoMapType::HybridMap, "MapBox Hybrid Map", "MapBox Hybrid Map", false, false, UrlFactory::MapBoxHybrid); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Wheat Paste Map", "MapBox Wheat Paste Map", false, false, UrlFactory::MapBoxWheatPaste); mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Streets Basic Map", "MapBox Streets Basic Map", false, false, UrlFactory::MapBoxStreetsBasic); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Comic Map", "MapBox Comic Map", false, false, UrlFactory::MapBoxComic); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Outdoors Map", "MapBox Outdoors Map", false, false, UrlFactory::MapBoxOutdoors); mapTypes << QGeoMapType(QGeoMapType::CycleMap, "MapBox Run, Byke and Hike Map", "MapBox Run, Byke and Hike Map", false, false, UrlFactory::MapBoxRunBikeHike); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pencil Map", "MapBox Pencil Map", false, false, UrlFactory::MapBoxPencil); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pirates Map", "MapBox Pirates Map", false, false, UrlFactory::MapBoxPirates); mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Emerald Map", "MapBox Emerald Map", false, false, UrlFactory::MapBoxEmerald); setSupportedMapTypes(mapTypes); //-- Users (QML code) can define a different user agent if (parameters.contains(QStringLiteral("useragent"))) { getQGCMapEngine()->setUserAgent(parameters.value(QStringLiteral("useragent")).toString().toLatin1()); } #if QT_VERSION >= 0x050500 _setCache(parameters); #endif setTileFetcher(new QGeoTileFetcherQGC(this)); *error = QGeoServiceProvider::NoError; errorString->clear(); #if QT_VERSION >= 0x050500 if (parameters.contains(QStringLiteral("mapping.copyright"))) m_customCopyright = parameters.value(QStringLiteral("mapping.copyright")).toString().toLatin1(); #endif }