Commit 741e3bbe authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #5137 from dogmaphobic/offlineMaps

Map Engine
parents cbdc5cd4 e95992b0
......@@ -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;
}
......
......@@ -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;
......
......@@ -30,6 +30,10 @@
#include <QStandardPaths>
#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<const char*>(pngSignature)))
format = "png";
else if (image.startsWith(reinterpret_cast<const char*>(jpegSignature)))
format = "jpg";
else if (image.startsWith(reinterpret_cast<const char*>(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:
......
......@@ -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 ();
......
......@@ -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
......
......@@ -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 &parameters);
#endif
};
......
......@@ -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
......
......@@ -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()
......@@ -246,8 +260,9 @@ QGCMapEngineManager::deleteTileSet(QGCCachedTileSet* tileSet)
if(tileSet->defaultSet()) {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setDeleting(true);
if(set) {
set->setDeleting(true);
}
}
QGCResetTask* task = new QGCResetTask();
connect(task, &QGCResetTask::resetCompleted, this, &QGCMapEngineManager::_resetCompleted);
......@@ -279,8 +294,7 @@ QGCMapEngineManager::_tileSetDeleted(quint64 setID)
int i = 0;
for(i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->setID() == setID) {
if (set && set->setID() == setID) {
setToDelete = set;
break;
}
......@@ -336,8 +350,7 @@ QGCMapEngineManager::_updateTotals(quint32 totaltiles, quint64 totalsize, quint3
{
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->defaultSet()) {
if (set && set->defaultSet()) {
set->setSavedTileSize(totalsize);
set->setSavedTileCount(totaltiles);
set->setTotalTileCount(defaulttiles);
......@@ -354,8 +367,7 @@ QGCMapEngineManager::findName(const QString& name)
{
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if (set->name() == name) {
if (set && set->name() == name) {
return true;
}
}
......@@ -367,8 +379,9 @@ void
QGCMapEngineManager::selectAll() {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setSelected(true);
if(set) {
set->setSelected(true);
}
}
}
......@@ -377,8 +390,9 @@ void
QGCMapEngineManager::selectNone() {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setSelected(false);
if(set) {
set->setSelected(false);
}
}
}
......@@ -388,8 +402,7 @@ QGCMapEngineManager::selectedCount() {
int count = 0;
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if(set->selected()) {
if(set && set->selected()) {
count++;
}
}
......@@ -450,7 +463,6 @@ QGCMapEngineManager::exportSets(QString path) {
QVector<QGCCachedTileSet*> sets;
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if(set->selected()) {
sets.append(set);
}
......
......@@ -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 ();
......
......@@ -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
},
{
......
......@@ -8,6 +8,7 @@
****************************************************************************/
#include "FlightMapSettings.h"
#include "QGCMapEngine.h"
#include <QQmlEngine>
#include <QtQml>
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment