QGroundControl(QGC)飛控地面站二次開發(fā)-修改地圖 更新至v4.0.5

一、問題

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/切片)

  1. 百度 谷歌地圖(http://www.google.cn/maps
  • 現(xiàn)在谷歌地圖國內(nèi)好像也沒有服務(wù)了,僅供參考
  1. 菜單選衛(wèi)星圖像

  2. 瀏覽器 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:標簽層(路名、地名等)
  3. 找到無偏移瓦片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ù)試試。

  4. 能用的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
  5. 其他地圖瓦片

    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

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官方給的說明不太對,請參考下面的文檔:

  1. https://dev.qgroundcontrol.com/en/getting_started/

  2. 工程目錄/.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 修改

  1. /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
}
]
  1. /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;
...
  1. /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;
...

  1. /src/QtLocationPlugin/QGCMapUrlEngine.h 原來沒有的地圖類型加到URL庫中
    ...
    //41:衛(wèi)星混合(全偏移)
    GoogleStatelliteWithLable = 21,
    //衛(wèi)星混合(標簽偏移)
    GoogleStatelliteWithLableNofix = 22,
    ...
  1. /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);
    ...
  1. /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);
   ...
  1. /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;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容