一、問題
QGC的地圖在國內(nèi)某些地方,只用bing可用,其他都不能使用。而且bing衛(wèi)星圖也沒有道路和標簽信息,還死慢死慢的。據(jù)說bing其實就沒有國內(nèi)的衛(wèi)星地圖版權(quán),在網(wǎng)頁上查查看bing地圖,時沒有衛(wèi)星圖的,只有切換到en-US上才有衛(wèi)星圖。
二、解決
國內(nèi)的地圖百度、高德、騰訊、搜狗、天地圖,有標簽、速度快,看上去不錯,但只是看上去。兩個問題(其實是3個):地圖更新太慢、最大到18級就沒有了效果不好。
谷歌地圖本來在QGC上就有,奈何QGC上集成的是www.google.com/maps所以上不了,但是谷歌在國內(nèi)是有地圖服務(wù)許可的,衛(wèi)星圖效果非常好,可以支持到24級(再大沒有試),遠大于QGC默認編譯的20級,速度也非???。對比了一下Google地圖至少在我上班這個地方衛(wèi)星圖是最新的。
三、步驟
1. 找瓦片(title/切片)
- 百度 谷歌地圖(http://www.google.cn/maps)
- 現(xiàn)在谷歌地圖國內(nèi)好像也沒有服務(wù)了,僅供參考
菜單選衛(wèi)星圖像
-
瀏覽器 F12 看網(wǎng)絡(luò)
之前的URL都失效了,這里特別感謝CSDN上CX0660同學(xué),提供了URL
找到衛(wèi)星切片地址(西安鐘樓)
http://mt2.google.cn/vt/lyrs=s@847&gl=cn&x=52601&y=26122&z=16
西安鐘樓解釋下參數(shù)
- x/y:web墨卡托橫縱坐標
- z 就是地圖的層級 zoom
- lyrs 可以去以下幾個值,lyrs=s@847寫成lyrs=s一樣ok
m:路線圖
t:地形圖
?p:帶標簽的地形圖
?s:衛(wèi)星圖
y:帶標簽的衛(wèi)星圖
?h:標簽層(路名、地名等)
找到無偏移瓦片URL
把參數(shù)lyrs替換一下發(fā)現(xiàn)都能用(xyz,就不要手動改了,不知道切片規(guī)則的話就是404)
坑點:國內(nèi)地圖都是帶偏移的,谷歌為了拿到地圖服務(wù)許可,也必須入鄉(xiāng)隨俗,本來當個地圖看沒問題,但真要用到飛行上就偏得太遠,你用這個瓦片地址到QGC上定位就知道了。而且這種“火星坐標”最大得問題是每個地方偏移量還不一樣,需要專門做數(shù)據(jù)庫,還要改大量代碼,不值當。那么google.cn有沒有無偏移得地圖呢?還真有,上面url去掉gl=cn這個參數(shù)就ok,手賤試出來的,注意只對衛(wèi)星圖有效,也就是lyrs=s有效,另外lyrs=y在衛(wèi)星圖上無偏移,標簽道路上有偏移,這個也算比較理想的地圖了吧,你可以自己改參數(shù)試試。-
能用的url
- 衛(wèi)星無偏移:
http://mt2.google.cn/vt/lyrs=s&x=52601&y=26122&z=16
- 衛(wèi)星混合,標簽偏移:
http://mt2.google.cn/vt/lyrs=y&x=52601&y=26122&z=16
- 衛(wèi)星混合偏移:
http://mt2.google.cn/vt/lyrs=y&gl=cn&x=52601&y=26122&z=16
- 地形帶標簽(反正大于15層也不顯示等高線了,偏移看不出來):
http://mt2.google.cn/vt/lyrs=p&gl=cn&x=6051&y=2997&z=13
- 街道偏移(當個地圖也可以):
http://mt2.google.cn/vt/lyrs=m&gl=cn&x=52601&y=26122&z=16
- 衛(wèi)星無偏移:
-
其他地圖瓦片
ArcGis(esri)已經(jīng)繼承到QGC中,因為沒有Token,所以不顯示,但是下面兩個瓦片不需要token,支持到19級,需要把判斷esri token的地方注釋掉
- ArcGis街道
http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile//16/26122/52601
- ArcGis衛(wèi)星
http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/16/26122/52601
- ArcGis街道
2. 更新20200412,基于4.0.5修改源碼
QGC 4.0 以后修改就方便很多了
2.1 首先當然是下源碼
#下載
git clone https://github.com/mavlink/qgroundcontrol.git --recursive
#查看tag
git tag
#查看分支
git branch
#以v4.0.5穩(wěn)定版為藍本創(chuàng)建分支,隨便取個名字叫cunstom405
git checkout -b cunstom405 v4.0.5
2.2 嘗試編譯
要搭建編譯環(huán)境,打開QT Creator,把工程編譯一遍,這一步過不去后面的就呵呵了,這也是一個比較坑爹的地方,QGC官方給的說明不太對,請參考下面的文檔:
-
工程目錄/.travis.yml對應(yīng)qt版本和安卓ndk版本在第二個文檔內(nèi)是肯定正確的,github使用Travis-CI自動編譯
2.3 添加Google.cn地圖 ,可參照此辦法添加其它地圖
-
創(chuàng)建頭文件
src/QtLocationPlugin/GoogleCnMapProvider.h,添加google.cn定義這里就不寫CPP文件了,就這么幾行代碼,哈哈,野路子走慣了
#ifndef GOOGLECNMAPPROVIDER_H
#define GOOGLECNMAPPROVIDER_H
#include "MapProvider.h"
#include <QNetworkReply>
#include <QMutex>
static const quint32 AVERAGE_GOOGLE_CN_SAT_MAP = 56887;
static const quint32 AVERAGE_GOOGLE_CN_TERRAIN_MAP = 19391;
class GoogleCNSatelliteMapProvider : public MapProvider {
Q_OBJECT
public:
GoogleCNSatelliteMapProvider(QObject* parent = nullptr)
: MapProvider(QStringLiteral("http://www.google.cn/maps"), QStringLiteral("jpg"),
AVERAGE_GOOGLE_CN_SAT_MAP, QGeoMapType::SatelliteMapDay, parent) {}
protected:
QString _getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) override{
Q_UNUSED(networkManager)
return QString("http://mt2.google.cn/vt/lyrs=s&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
}
};
class GoogleCNHybridMapProvider : public MapProvider {
Q_OBJECT
public:
GoogleCNHybridMapProvider(QObject* parent = nullptr)
: MapProvider(QStringLiteral("http://www.google.cn/maps"), QStringLiteral("jpg"),
AVERAGE_GOOGLE_CN_TERRAIN_MAP, QGeoMapType::SatelliteMapDay, parent) {}
protected:
QString _getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) override{
Q_UNUSED(networkManager)
return QString("http://mt2.google.cn/vt/lyrs=y&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
}
};
class GoogleCNTerrainMapProvider : public MapProvider {
Q_OBJECT
public:
GoogleCNTerrainMapProvider(QObject* parent = nullptr)
: MapProvider(QStringLiteral("http://www.google.cn/maps"), QStringLiteral("png"),
AVERAGE_GOOGLE_CN_TERRAIN_MAP, QGeoMapType::TerrainMap, parent) {}
protected:
QString _getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager) override{
Q_UNUSED(networkManager)
return QString("http://mt2.google.cn/vt/lyrs=p&gl=cn&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
}
};
#endif // GOOGLECNMAPPROVIDER_H
- 將定義好的地圖添加到地圖列表中去
src/QtLocationPlugin/QGCMapUrlEngine.cpp
...
#include "GoogleCnMapProvider.h"
...
UrlFactory::UrlFactory() : _timeout(5 * 1000) {
...
//位置隨便加,APP中使用QHash沒有排序
//第一個空格前是供應(yīng)商名稱,而后是地圖類型
_providersTable["Google.cn 衛(wèi)星"] = new GoogleCNSatelliteMapProvider(this);
_providersTable["Google.cn 混合 標簽偏移"] = new GoogleCNHybridMapProvider(this);
_providersTable["Google.cn 地形"] = new GoogleCNTerrainMapProvider(this);
...
}
...
不像之前地圖列表是沒有順序的,如果想要排序,自行修改,這里就不改了好像也沒啥影響
// src/QtLocationPlugin/QGCMapEngine.cpp
// 可修改地圖供應(yīng)商的排序,這里未修改
QStringList
QGCMapEngine::getMapNameList()
{
return QStringList(getQGCMapEngine()->urlFactory()->getProviderTable().keys());
}
// src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc
// 可修改地圖供應(yīng)商的類型排序,這里未修改
QStringList
QGCMapEngineManager::mapTypeList(QString provider)
{
// Extract type name from MapName ( format : "Provider Type")
QStringList mapList = getQGCMapEngine()->getMapNameList();
mapList = mapList.filter(QRegularExpression(provider));
mapList.replaceInStrings(QRegExp("^([^\\ ]*) (.*)$"),"\\2");
mapList.removeDuplicates();
return mapList;
}
2.4 編譯、測試、收工
可以按照設(shè)計正常顯示地圖,本來還想加OpenStreet,在瀏覽器上沒問題,但在QGC上死活不出來,應(yīng)該是OpenStreet沒有許可只能在瀏覽器上使用。
以下4.0之前的修改方式,僅供參考------------------------------------------------------------
2. 改源碼,基于3.5.3修改
2.1 克隆源碼
#下載
git clone https://github.com/mavlink/qgroundcontrol.git --recursive
#查看tag
git tag
#查看分支
git branch
#以v3.5.3穩(wěn)定版為藍本創(chuàng)建分支,隨便取個名字叫cunstom353
git checkout -b cunstom353 v3.5.3
2.2 修改
-
/src/Settings/FlightMap.SettingsGroup.json用于顯示
[
{
"name": "mapProvider",
"shortDescription": "Currently selected map provider for flight maps",
"type": "uint32",
"enumStrings": "Google.cn,Esri",
"enumValues": "0,1",
"defaultValue": 0
},
{
"name": "mapType",
"shortDescription": "Currently selected map type for flight maps,* means can't use to feight",
"type": "uint32",
"enumStrings": "衛(wèi)星,衛(wèi)星混合(僅標簽偏移),*衛(wèi)星混合(全偏移),街道,*街道(偏移),地形,*地形(偏移)",
"enumValues": "0,1,2,3,4,5,6",
"defaultValue": 0
}
]
-
/src/Settings/FlightMapSettings.h定義地圖提供商和地圖類型
...
// 必須和上json的數(shù)據(jù)個數(shù)順序?qū)?yīng)
typedef enum {
mapProviderGoogle,
mapProviderEsri
} MapProvider_t;
// 必須和上json的數(shù)據(jù)個數(shù)順序?qū)?yīng)
typedef enum {
mapTypeSatellite,
mapTypeSatelliteMix,
maptypeSatelliteMixOffset,
mapTypeStreet,
mapTypeStreetOffset,
mapTypeTerrain,
mapTypeTerrainOffset
} MapType_t;
...
/src/Settings/FlightMapSettings.cc
/* 33:這兩處注釋掉 不然esri地圖顯示不出來
if(qgcApp()->toolbox()->settingsManager()->appSettings()->mapboxToken()->rawValue().toString().isEmpty()) {
_excludeProvider(mapProviderMapbox);
}
if(qgcApp()->toolbox()->settingsManager()->appSettings()->esriToken()->rawValue().toString().isEmpty()) {
_excludeProvider(mapProviderEsri);
}
*/
//80:地圖提供商沒有的地圖類型
void FlightMapSettings::_newMapProvider(QVariant value)
{
FactMetaData* metaData = _nameToMetaDataMap[mapTypeName];
QStringList enumStrings = _savedMapTypeStrings;
QVariantList enumValues = _savedMapTypeValues;
switch (value.toInt()) {
case mapProviderGoogle:
_removeEnumValue(mapTypeStreet,enumStrings,enumValues);
_removeEnumValue(mapTypeStreetOffset,enumStrings,enumValues);
_removeEnumValue(mapTypeTerrain,enumStrings,enumValues);
break;
case mapProviderEsri:
_removeEnumValue(mapTypeSatelliteMix,enumStrings,enumValues);
_removeEnumValue(maptypeSatelliteMixOffset,enumStrings,enumValues);
_removeEnumValue(mapTypeStreetOffset,enumStrings,enumValues);
_removeEnumValue(mapTypeTerrain,enumStrings,enumValues);
_removeEnumValue(mapTypeTerrainOffset,enumStrings,enumValues);
break;
...
-
/src/QtLocationPlugin/QGCMapUrlEngine.h原來沒有的地圖類型加到URL庫中
...
//41:衛(wèi)星混合(全偏移)
GoogleStatelliteWithLable = 21,
//衛(wèi)星混合(標簽偏移)
GoogleStatelliteWithLableNofix = 22,
...
-
/src/QtLocationPlugin/QGCMapUrlEngine.cpp定義瓦片URL
...
//230
case GoogleMap:
return QString("http://www.google.cn/maps/vt?lyrs=m&gl=cn&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
case GoogleSatellite:
return QString("http://www.google.cn/maps/vt?lyrs=s&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
case GoogleLabels:
return QString("http://www.google.cn/maps/vt?lyrs=h&gl=cn&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
case GoogleTerrain:
return QString("http://www.google.cn/maps/vt?lyrs=p&gl=cn&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
case GoogleStatelliteWithLable:
//衛(wèi)星混合(全偏移)
return QString("http://www.google.cn/maps/vt?lyrs=y&gl=cn&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
case GoogleStatelliteWithLableNofix:
//衛(wèi)星混合(標簽偏移)
return QString("http://www.google.cn/maps/vt?lyrs=y&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
...
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);
...
-
/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp將前臺地圖類型和后臺URL連接,第一個字符串是 供應(yīng)商名+一個空格+地圖類型,第二個字符串是簡介,隨便寫
//108:衛(wèi)星(無偏移)
mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay, "Google.cn 衛(wèi)星", "Google.cn 衛(wèi)星", false, false, UrlFactory::GoogleSatellite);
mapTypes << QGCGEOMAPTYPE(QGeoMapType::TerrainMap, "Google.cn *地形(偏移)", "Google.cn *地形(偏移)", false, false, UrlFactory::GoogleTerrain);
//衛(wèi)星混合(全偏移)
mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay, "Google.cn *衛(wèi)星混合(全偏移)", "Google.cn *衛(wèi)星混合(全偏移)",false, false, UrlFactory::GoogleStatelliteWithLable);
//衛(wèi)星混合(標簽偏移)
mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay, "Google.cn 衛(wèi)星混合(僅標簽偏移)","Google.cn 衛(wèi)星混合(僅標簽偏移)", false, false, UrlFactory::GoogleStatelliteWithLableNofix);
// Esri
mapTypes << QGCGEOMAPTYPE(QGeoMapType::StreetMap, "Esri 街道", "ArcGIS Online World 街道", true, false, UrlFactory::EsriWorldStreet);
mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay, "Esri 衛(wèi)星", "ArcGIS Online World 衛(wèi)星", true, false, UrlFactory::EsriWorldSatellite);
...
-
/src/QtLocationPlugin/QGCMapEngine.cpp修改離線地圖
//48:字符串要求同上節(jié)
stQGeoTileCacheQGCMapTypes kMapTypes[] = {
{"Google.cn 衛(wèi)星", UrlFactory::GoogleSatellite},
{"Google.cn 衛(wèi)星混合(僅標簽偏移)", UrlFactory::GoogleStatelliteWithLableNofix},
{"Google.cn *衛(wèi)星混合(全偏移)", UrlFactory::GoogleStatelliteWithLable},
{"Google.cn *地形(偏移)", UrlFactory::GoogleTerrain},
{"Esri 衛(wèi)星", UrlFactory::EsriWorldSatellite},
{"Esri 街道", UrlFactory::EsriWorldStreet},
};
//380:注釋掉下面這兩處,好像不注釋也沒問題
QStringList
QGCMapEngine::getMapNameList()
{
QStringList mapList;
for(size_t i = 0; i < NUM_MAPS; i++) {
mapList << kMapTypes[i].name;
}
/*
if(!qgcApp()->toolbox()->settingsManager()->appSettings()->mapboxToken()->rawValue().toString().isEmpty()) {
for(size_t i = 0; i < NUM_MAPBOXMAPS; i++) {
mapList << kMapboxTypes[i].name;
}
}
if(!qgcApp()->toolbox()->settingsManager()->appSettings()->esriToken()->rawValue().toString().isEmpty()) {
for(size_t i = 0; i < NUM_ESRIMAPS; i++) {
mapList << kEsriTypes[i].name;
}
}*/
return mapList;
}