From ff0e8f6d4bdd0a7bb3b99e9387d42cebecc58cca Mon Sep 17 00:00:00 2001 From: Gus Grubba Date: Fri, 21 Apr 2017 00:46:15 -0400 Subject: [PATCH] Restoring MapBox Experimenting with Esri --- src/QtLocationPlugin/QGCMapEngine.cpp | 45 ++++++++++++++++++- src/QtLocationPlugin/QGCMapEngine.h | 3 ++ src/QtLocationPlugin/QGCMapUrlEngine.cpp | 36 ++++++++++++--- src/QtLocationPlugin/QGCMapUrlEngine.h | 8 +++- .../QGeoTiledMappingManagerEngineQGC.cpp | 30 +++++-------- .../QGeoTiledMappingManagerEngineQGC.h | 2 - .../QMLControl/OfflineMap.qml | 19 ++++++++ .../QMLControl/QGCMapEngineManager.cc | 14 ++++++ .../QMLControl/QGCMapEngineManager.h | 4 ++ src/Settings/FlightMap.SettingsGroup.json | 4 +- src/Settings/FlightMapSettings.cc | 27 +++++++---- src/Settings/FlightMapSettings.h | 5 ++- 12 files changed, 158 insertions(+), 39 deletions(-) diff --git a/src/QtLocationPlugin/QGCMapEngine.cpp b/src/QtLocationPlugin/QGCMapEngine.cpp index d23351a11..03d031d1a 100644 --- a/src/QtLocationPlugin/QGCMapEngine.cpp +++ b/src/QtLocationPlugin/QGCMapEngine.cpp @@ -52,9 +52,9 @@ stQGeoTileCacheQGCMapTypes kMapTypes[] = { {"Bing Satellite Map", UrlFactory::BingSatellite}, {"Bing Hybrid Map", UrlFactory::BingHybrid}, {"Statkart Topo2", UrlFactory::StatkartTopo}, + /* {"MapQuest Street Map", UrlFactory::MapQuestMap}, {"MapQuest Satellite Map", UrlFactory::MapQuestSat} - /* {"Open Street Map", UrlFactory::OpenStreetMap} */ }; @@ -80,7 +80,16 @@ stQGeoTileCacheQGCMapTypes kMapBoxTypes[] = { #define NUM_MAPBOXMAPS (sizeof(kMapBoxTypes) / sizeof(stQGeoTileCacheQGCMapTypes)) +stQGeoTileCacheQGCMapTypes kEsriTypes[] = { + {"Esri Street Map", UrlFactory::EsriWorldStreet}, + {"Esri Satellite Map", UrlFactory::EsriWorldSatellite}, + {"Esri Terrain Map", UrlFactory::EsriTerrain} +}; + +#define NUM_ESRIMAPS (sizeof(kEsriTypes) / sizeof(stQGeoTileCacheQGCMapTypes)) + static const char* kMapBoxTokenKey = "MapBoxToken"; +static const char* kEsriTokenKey = "EsriToken"; static const char* kMaxDiskCacheKey = "MaxDiskCache"; static const char* kMaxMemCacheKey = "MaxMemoryCache"; @@ -322,6 +331,10 @@ QGCMapEngine::getTypeFromName(const QString& name) if(name.compare(kMapBoxTypes[i].name, Qt::CaseInsensitive) == 0) return kMapBoxTypes[i].type; } + for(i = 0; i < NUM_ESRIMAPS; i++) { + if(name.compare(kEsriTypes[i].name, Qt::CaseInsensitive) == 0) + return kEsriTypes[i].type; + } return UrlFactory::Invalid; } @@ -338,6 +351,11 @@ QGCMapEngine::getMapNameList() mapList << kMapBoxTypes[i].name; } } + if(!getEsriToken().isEmpty()) { + for(size_t i = 0; i < NUM_ESRIMAPS; i++) { + mapList << kEsriTypes[i].name; + } + } return mapList; } @@ -350,6 +368,15 @@ QGCMapEngine::setMapBoxToken(const QString& token) _mapBoxToken = token; } +//----------------------------------------------------------------------------- +void +QGCMapEngine::setEsriToken(const QString& token) +{ + QSettings settings; + settings.setValue(kEsriTokenKey, token); + _esriToken = token; +} + //----------------------------------------------------------------------------- QString QGCMapEngine::getMapBoxToken() @@ -361,6 +388,17 @@ QGCMapEngine::getMapBoxToken() return _mapBoxToken; } +//----------------------------------------------------------------------------- +QString +QGCMapEngine::getEsriToken() +{ + if(_esriToken.isEmpty()) { + QSettings settings; + _esriToken = settings.value(kEsriTokenKey).toString(); + } + return _esriToken; +} + //----------------------------------------------------------------------------- quint32 QGCMapEngine::getMaxDiskCache() @@ -467,10 +505,15 @@ QGCMapEngine::concurrentDownloads(UrlFactory::MapType type) case UrlFactory::BingSatellite: case UrlFactory::BingHybrid: case UrlFactory::StatkartTopo: + case UrlFactory::EsriWorldStreet: + case UrlFactory::EsriWorldSatellite: + case UrlFactory::EsriTerrain: return 12; + /* case UrlFactory::MapQuestMap: case UrlFactory::MapQuestSat: return 8; + */ default: break; } diff --git a/src/QtLocationPlugin/QGCMapEngine.h b/src/QtLocationPlugin/QGCMapEngine.h index 8ecedd980..29eb0ff4b 100644 --- a/src/QtLocationPlugin/QGCMapEngine.h +++ b/src/QtLocationPlugin/QGCMapEngine.h @@ -79,7 +79,9 @@ public: void setUserAgent (const QString& ua) { _userAgent = ua; } UrlFactory::MapType hashToType (const QString& hash); QString getMapBoxToken (); + QString getEsriToken (); void setMapBoxToken (const QString& token); + void setEsriToken (const QString& token); quint32 getMaxDiskCache (); void setMaxDiskCache (quint32 size); quint32 getMaxMemCache (); @@ -120,6 +122,7 @@ private: QString _cachePath; QString _cacheFile; QString _mapBoxToken; + QString _esriToken; UrlFactory* _urlFactory; QString _userAgent; quint32 _maxDiskCache; diff --git a/src/QtLocationPlugin/QGCMapUrlEngine.cpp b/src/QtLocationPlugin/QGCMapUrlEngine.cpp index 43eebe1e3..078e5b80b 100644 --- a/src/QtLocationPlugin/QGCMapUrlEngine.cpp +++ b/src/QtLocationPlugin/QGCMapUrlEngine.cpp @@ -30,6 +30,10 @@ #include #endif +static const unsigned char pngSignature[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00}; +static const unsigned char jpegSignature[] = {0xFF, 0xD8, 0xFF, 0x00}; +static const unsigned char gifSignature[] = {0x47, 0x49, 0x46, 0x38, 0x00}; + //----------------------------------------------------------------------------- UrlFactory::UrlFactory() : _timeout(5 * 1000) @@ -72,10 +76,12 @@ UrlFactory::getImageFormat(MapType type, const QByteArray& image) QString format; if(image.size() > 2) { - if((char)image[0] == (char)0xff && (char)image[1] == (char)0xd8) - format = "jpg"; - else if((char)image[0] == (char)0x89 && (char)image[1] == (char)0x50) + if (image.startsWith(reinterpret_cast(pngSignature))) format = "png"; + else if (image.startsWith(reinterpret_cast(jpegSignature))) + format = "jpg"; + else if (image.startsWith(reinterpret_cast(gifSignature))) + format = "gif"; else { switch (type) { case GoogleMap: @@ -83,12 +89,14 @@ UrlFactory::getImageFormat(MapType type, const QByteArray& image) case GoogleTerrain: case GoogleHybrid: case BingMap: - case OpenStreetMap: case StatkartTopo: format = "png"; break; + /* case MapQuestMap: case MapQuestSat: + case OpenStreetMap: + */ case MapBoxStreets: case MapBoxLight: case MapBoxDark: @@ -128,7 +136,6 @@ UrlFactory::getTileURL(MapType type, int x, int y, int zoom, QNetworkAccessManag return request; request.setUrl(QUrl(url)); request.setRawHeader("Accept", "*/*"); - request.setRawHeader("User-Agent", _userAgent); switch (type) { #ifndef QGC_NO_GOOGLE_MAPS case GoogleMap: @@ -157,9 +164,20 @@ UrlFactory::getTileURL(MapType type, int x, int y, int zoom, QNetworkAccessManag request.setRawHeader("Referrer", "https://www.openstreetmap.org/"); break; */ + + case EsriWorldStreet: + case EsriWorldSatellite: + case EsriTerrain: { + QByteArray token = getQGCMapEngine()->getEsriToken().toLatin1(); + request.setRawHeader("User-Agent", QByteArrayLiteral("Qt Location based application")); + request.setRawHeader("User-Token", token); + } + return request; + default: break; } + request.setRawHeader("User-Agent", _userAgent); return request; } @@ -281,6 +299,7 @@ UrlFactory::_getURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* 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)]; @@ -293,6 +312,13 @@ UrlFactory::_getURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* 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 EsriWorldStreet: + return QString("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/%1/%2/%3").arg(zoom).arg(y).arg(x); + case EsriWorldSatellite: + return QString("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/%1/%2/%3").arg(zoom).arg(y).arg(x); + case EsriTerrain: + return QString("http://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/%1/%2/%3").arg(zoom).arg(y).arg(x); case MapBoxStreets: case MapBoxLight: diff --git a/src/QtLocationPlugin/QGCMapUrlEngine.h b/src/QtLocationPlugin/QGCMapUrlEngine.h index 68634a8da..ecd841e08 100644 --- a/src/QtLocationPlugin/QGCMapUrlEngine.h +++ b/src/QtLocationPlugin/QGCMapUrlEngine.h @@ -50,8 +50,10 @@ public: BingSatellite = 555, BingHybrid = 666, + /* MapQuestMap = 700, MapQuestSat = 701, + */ MapBoxStreets = 6000, MapBoxLight = 6001, @@ -66,7 +68,11 @@ public: MapBoxPencil = 6010, MapBoxPirates = 6011, MapBoxEmerald = 6012, - MapBoxHighContrast = 6013 + MapBoxHighContrast = 6013, + + EsriWorldStreet = 7000, + EsriWorldSatellite = 7001, + EsriTerrain = 7002 }; UrlFactory (); diff --git a/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp index c7032bb40..33751da01 100644 --- a/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp +++ b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp @@ -87,10 +87,9 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian 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. + * Google and Bing 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 @@ -103,19 +102,24 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian #endif /* TODO: - * Proper google hybrid maps requires collecting two separate bimaps and overlaying them. + * Proper google hybrid maps requires collecting two separate bitmaps 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); + 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); // Statkart - mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Statkart Topo2", "Statkart Topo2", false, false, UrlFactory::StatkartTopo); + mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Statkart Topo2", "Statkart Topo2", false, false, UrlFactory::StatkartTopo); + + // Esri + mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Esri Street Map", "ArcGIS Online World Street Map", true, false, UrlFactory::EsriWorldStreet); + mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Esri Satellite Map", "ArcGIS Online World Imagery", true, false, UrlFactory::EsriWorldSatellite); + mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Esri Terrain Map", "World Terrain Base", false, false, UrlFactory::EsriTerrain); /* See: https://wiki.openstreetmap.org/wiki/Tile_usage_policy mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Open Street Map", "Open Street map", false, false, UrlFactory::OpenStreetMap); @@ -161,11 +165,6 @@ QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVarian *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 } //----------------------------------------------------------------------------- @@ -190,13 +189,6 @@ QGeoTiledMappingManagerEngineQGC::createMap() return new QGeoTiledMapQGC(this); } -//----------------------------------------------------------------------------- -QString -QGeoTiledMappingManagerEngineQGC::customCopyright() const -{ - return m_customCopyright; -} - #endif #if QT_VERSION >= 0x050500 diff --git a/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h index 2d6d1dc63..f3fe98aab 100644 --- a/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h +++ b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h @@ -74,11 +74,9 @@ public: QGeoMapData *createMapData(); #else QGeoMap *createMap(); - QString customCopyright() const; #endif private: #if QT_VERSION >= 0x050500 - QString m_customCopyright; void _setCache(const QVariantMap ¶meters); #endif }; diff --git a/src/QtLocationPlugin/QMLControl/OfflineMap.qml b/src/QtLocationPlugin/QMLControl/OfflineMap.qml index c2c449bcd..6ec0b3295 100644 --- a/src/QtLocationPlugin/QMLControl/OfflineMap.qml +++ b/src/QtLocationPlugin/QMLControl/OfflineMap.qml @@ -89,8 +89,10 @@ QGCView { function updateMap() { for (var i = 0; i < _map.supportedMapTypes.length; i++) { + console.log(_map.supportedMapTypes[i].name) if (mapType === _map.supportedMapTypes[i].name) { _map.activeMapType = _map.supportedMapTypes[i] + console.log("Update Map:" + " " + _map.activeMapType) handleChanges() return } @@ -226,6 +228,7 @@ QGCView { function accept() { QGroundControl.mapEngineManager.mapboxToken = mapBoxToken.text + QGroundControl.mapEngineManager.esriToken = esriToken.text QGroundControl.mapEngineManager.maxDiskCache = parseInt(maxCacheSize.text) QGroundControl.mapEngineManager.maxMemCache = parseInt(maxCacheMemSize.text) optionDialog.hideDialog() @@ -285,6 +288,22 @@ QGCView { text: qsTr("With an access token, you can use MapBox Maps.") font.pointSize: _adjustableFontPointSize } + + Item { width: 1; height: 1 } + + QGCLabel { text: qsTr("Esri Access Token") } + + QGCTextField { + id: esriToken + maximumLength: 256 + width: ScreenTools.defaultFontPixelWidth * 30 + text: QGroundControl.mapEngineManager.esriToken + } + + QGCLabel { + text: qsTr("With an access token, you can use Esri Maps.") + font.pointSize: _adjustableFontPointSize + } } // GridLayout } // QGCFlickable } // QGCViewDialog - optionsDialog diff --git a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc index 21f0a4692..cb46026f1 100644 --- a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc +++ b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc @@ -209,6 +209,20 @@ QGCMapEngineManager::setMapboxToken(QString token) getQGCMapEngine()->setMapBoxToken(token); } +//----------------------------------------------------------------------------- +QString +QGCMapEngineManager::esriToken() +{ + return getQGCMapEngine()->getEsriToken(); +} + +//----------------------------------------------------------------------------- +void +QGCMapEngineManager::setEsriToken(QString token) +{ + getQGCMapEngine()->setEsriToken(token); +} + //----------------------------------------------------------------------------- quint32 QGCMapEngineManager::maxMemCache() diff --git a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h index a0c640ad8..97aab0d82 100644 --- a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h +++ b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h @@ -48,6 +48,7 @@ public: Q_PROPERTY(QmlObjectListModel* tileSets READ tileSets NOTIFY tileSetsChanged) Q_PROPERTY(QStringList mapList READ mapList CONSTANT) Q_PROPERTY(QString mapboxToken READ mapboxToken WRITE setMapboxToken NOTIFY mapboxTokenChanged) + Q_PROPERTY(QString esriToken READ esriToken WRITE setEsriToken NOTIFY esriTokenChanged) Q_PROPERTY(quint32 maxMemCache READ maxMemCache WRITE setMaxMemCache NOTIFY maxMemCacheChanged) Q_PROPERTY(quint32 maxDiskCache READ maxDiskCache WRITE setMaxDiskCache NOTIFY maxDiskCacheChanged) Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) @@ -85,6 +86,7 @@ public: QString tileSizeStr (); QStringList mapList (); QString mapboxToken (); + QString esriToken (); QmlObjectListModel* tileSets () { return &_tileSets; } quint32 maxMemCache (); quint32 maxDiskCache (); @@ -97,6 +99,7 @@ public: bool importReplace () { return _importReplace; } void setMapboxToken (QString token); + void setEsriToken (QString token); void setMaxMemCache (quint32 size); void setMaxDiskCache (quint32 size); void setImportReplace (bool replace) { _importReplace = replace; emit importReplaceChanged(); } @@ -114,6 +117,7 @@ signals: void tileCountChanged (); void tileSizeChanged (); void mapboxTokenChanged (); + void esriTokenChanged (); void tileSetsChanged (); void maxMemCacheChanged (); void maxDiskCacheChanged (); diff --git a/src/Settings/FlightMap.SettingsGroup.json b/src/Settings/FlightMap.SettingsGroup.json index f76bf56fd..915dbb47c 100644 --- a/src/Settings/FlightMap.SettingsGroup.json +++ b/src/Settings/FlightMap.SettingsGroup.json @@ -3,8 +3,8 @@ "name": "MapProvider", "shortDescription": "Currently selected map provider for flight maps", "type": "uint32", - "enumStrings": "Bing,Google,Statkart", - "enumValues": "0,1,2", + "enumStrings": "Bing,Google,Statkart,MapBox,Esri", + "enumValues": "0,1,2,3,4", "defaultValue": 0 }, { diff --git a/src/Settings/FlightMapSettings.cc b/src/Settings/FlightMapSettings.cc index e904f18f2..bd34366f8 100644 --- a/src/Settings/FlightMapSettings.cc +++ b/src/Settings/FlightMapSettings.cc @@ -8,6 +8,7 @@ ****************************************************************************/ #include "FlightMapSettings.h" +#include "QGCMapEngine.h" #include #include @@ -27,17 +28,18 @@ FlightMapSettings::FlightMapSettings(QObject* parent) // Save the original version since we modify based on map provider _savedMapTypeStrings = _nameToMetaDataMap[mapTypeSettingsName]->enumStrings(); - _savedMapTypeValues = _nameToMetaDataMap[mapTypeSettingsName]->enumValues(); + _savedMapTypeValues = _nameToMetaDataMap[mapTypeSettingsName]->enumValues(); #ifdef QGC_NO_GOOGLE_MAPS - // Find google in the list and remove it - FactMetaData* metaData = _nameToMetaDataMap[mapProviderSettingsName]; - QVariantList enumValues = metaData->enumValues(); - QStringList enumStrings = metaData->enumStrings(); - _removeEnumValue(mapProviderGoogle, enumStrings, enumValues); - metaData->setEnumInfo(enumStrings, enumValues); + //-- Remove Google + _excludeProvider(mapProviderGoogle); #endif - + if(getQGCMapEngine()->getMapBoxToken().isEmpty()) { + _excludeProvider(mapProviderMapBox); + } + if(getQGCMapEngine()->getEsriToken().isEmpty()) { + _excludeProvider(mapProviderEsri); + } _newMapProvider(mapProvider()->rawValue()); } @@ -60,6 +62,15 @@ Fact* FlightMapSettings::mapType(void) return _mapTypeFact; } +void FlightMapSettings::_excludeProvider(MapProvider_t provider) +{ + FactMetaData* metaData = _nameToMetaDataMap[mapProviderSettingsName]; + QVariantList enumValues = metaData->enumValues(); + QStringList enumStrings = metaData->enumStrings(); + _removeEnumValue(provider, enumStrings, enumValues); + metaData->setEnumInfo(enumStrings, enumValues); +} + void FlightMapSettings::_removeEnumValue(int value, QStringList& enumStrings, QVariantList& enumValues) { bool found = false; diff --git a/src/Settings/FlightMapSettings.h b/src/Settings/FlightMapSettings.h index 85c7ea623..5b2373430 100644 --- a/src/Settings/FlightMapSettings.h +++ b/src/Settings/FlightMapSettings.h @@ -23,7 +23,9 @@ public: typedef enum { mapProviderBing, mapProviderGoogle, - mapProviderStarkart + mapProviderStarkart, + mapProviderMapBox, + mapProviderEsri } MapProvider_t; // This enum must match the json meta data @@ -52,6 +54,7 @@ private slots: private: void _removeEnumValue(int value, QStringList& enumStrings, QVariantList& enumValues); + void _excludeProvider(MapProvider_t provider); SettingsFact* _mapProviderFact; SettingsFact* _mapTypeFact; -- 2.22.0