QGroundControl(QGC)飞控地面站二次开发-修改地图 更新至v4.0.5

一、问题

QGC的地图在国内某些地方,只用bing可用,其他都不能使用。而且bing卫星图也没有道路和标签信息,还死慢死慢的。据说bing其实就没有国内的卫星地图版权,在网页上查查看bing地图,时没有卫星图的,只有切换到en-US上才有卫星图。

二、解决

国内的地图百度、高德、腾讯、搜狗、天地图,有标签、速度快,看上去不错,但只是看上去。两个问题(其实是3个):地图更新太慢、最大到18级就没有了效果不好。

谷歌地图本来在QGC上就有,奈何QGC上集成的是www.google.com/maps所以上不了,但是谷歌在国内是有地图服务许可的,卫星图效果非常好,可以支持到24级(再大没有试),远大于QGC默认编译的20级,速度也非常快。对比了一下Google地图至少在我上班这个地方卫星图是最新的。

三、步骤

1. 找瓦片(title/切片)

  1. 百度 谷歌地图(http://www.google.cn/maps
  • 现在谷歌地图国内好像也没有服务了,仅供参考
  1. 菜单选卫星图像

  2. 浏览器 F12 看网络

    之前的URL都失效了,这里特别感谢CSDN上CX0660同学,提供了URL

    找到卫星切片地址(西安钟楼)
    http://mt2.google.cn/vt/lyrs=s@847&gl=cn&x=52601&y=26122&z=16

    西安钟楼

    解释下参数

    • x/y:web墨卡托横纵坐标
    • z 就是地图的层级 zoom
    • lyrs 可以去以下几个值,lyrs=s@847写成lyrs=s一样ok
      m:路线图
      t:地形图
      ​p:带标签的地形图
      ​s:卫星图
      y:带标签的卫星图
      ​h:标签层(路名、地名等)
  3. 找到无偏移瓦片URL
    把参数lyrs替换一下发现都能用(xyz,就不要手动改了,不知道切片规则的话就是404)
    坑点:国内地图都是带偏移的,谷歌为了拿到地图服务许可,也必须入乡随俗,本来当个地图看没问题,但真要用到飞行上就偏得太远,你用这个瓦片地址到QGC上定位就知道了。而且这种“火星坐标”最大得问题是每个地方偏移量还不一样,需要专门做数据库,还要改大量代码,不值当。那么google.cn有没有无偏移得地图呢?还真有,上面url去掉gl=cn这个参数就ok,手贱试出来的,注意只对卫星图有效,也就是lyrs=s有效,另外lyrs=y在卫星图上无偏移,标签道路上有偏移,这个也算比较理想的地图了吧,你可以自己改参数试试。

  4. 能用的url

    • 卫星无偏移:http://mt2.google.cn/vt/lyrs=s&x=52601&y=26122&z=16
    • 卫星混合,标签偏移:http://mt2.google.cn/vt/lyrs=y&x=52601&y=26122&z=16
    • 卫星混合偏移: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)已经继承到QGC中,因为没有Token,所以不显示,但是下面两个瓦片不需要token,支持到19级,需要把判断esri token的地方注释掉

    • ArcGis街道 http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile//16/26122/52601
    • ArcGis卫星 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稳定版为蓝本创建分支,随便取个名字叫cunstom405
git checkout -b cunstom405 v4.0.5

2.2 尝试编译

要搭建编译环境,打开QT Creator,把工程编译一遍,这一步过不去后面的就呵呵了,这也是一个比较坑爹的地方,QGC官方给的说明不太对,请参考下面的文档:

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

  2. 工程目录/.travis.yml

    对应qt版本和安卓ndk版本在第二个文档内是肯定正确的,github使用Travis-CI自动编译

2.3 添加Google.cn地图 ,可参照此办法添加其它地图

  • 创建头文件 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没有排序 
  //第一个空格前是供应商名称,而后是地图类型
  _providersTable["Google.cn 卫星"]    = new GoogleCNSatelliteMapProvider(this);
  _providersTable["Google.cn 混合 标签偏移"]     = new GoogleCNHybridMapProvider(this);
  _providersTable["Google.cn 地形"]    = new GoogleCNTerrainMapProvider(this);
  ...
}
...

不像之前地图列表是没有顺序的,如果想要排序,自行修改,这里就不改了好像也没啥影响

 // src/QtLocationPlugin/QGCMapEngine.cpp
// 可修改地图供应商的排序,这里未修改
QStringList
QGCMapEngine::getMapNameList()
{
    return QStringList(getQGCMapEngine()->urlFactory()->getProviderTable().keys());
}

// src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc
// 可修改地图供应商的类型排序,这里未修改
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 编译、测试、收工

可以按照设计正常显示地图,本来还想加OpenStreet,在浏览器上没问题,但在QGC上死活不出来,应该是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稳定版为蓝本创建分支,随便取个名字叫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":      "卫星,卫星混合(仅标签偏移),*卫星混合(全偏移),街道,*街道(偏移),地形,*地形(偏移)",
    "enumValues":       "0,1,2,3,4,5,6",
    "defaultValue":     0
}
]
  1. /src/Settings/FlightMapSettings.h 定义地图提供商和地图类型
...
   // 必须和上json的数据个数顺序对应
    typedef enum {
        mapProviderGoogle,
        mapProviderEsri
    } MapProvider_t;

    // 必须和上json的数据个数顺序对应
    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:卫星混合(全偏移)
    GoogleStatelliteWithLable = 21,
    //卫星混合(标签偏移)
    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:
        //卫星混合(全偏移)
        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:
        //卫星混合(标签偏移)
        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连接,第一个字符串是 供应商名+一个空格+地图类型,第二个字符串是简介,随便写

    //108:卫星(无偏移)
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay,   "Google.cn 卫星",     "Google.cn 卫星",         false,  false,  UrlFactory::GoogleSatellite);
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::TerrainMap,        "Google.cn *地形(偏移)",       "Google.cn *地形(偏移)",           false,  false,  UrlFactory::GoogleTerrain);
    //卫星混合(全偏移)
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay,   "Google.cn *卫星混合(全偏移)", "Google.cn *卫星混合(全偏移)",false,  false,  UrlFactory::GoogleStatelliteWithLable);
    //卫星混合(标签偏移)
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay,   "Google.cn 卫星混合(仅标签偏移)","Google.cn 卫星混合(仅标签偏移)", false,  false,  UrlFactory::GoogleStatelliteWithLableNofix);

     // Esri
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::StreetMap,         "Esri 街道",          "ArcGIS Online World 街道",   true,   false,  UrlFactory::EsriWorldStreet);
    mapTypes << QGCGEOMAPTYPE(QGeoMapType::SatelliteMapDay,   "Esri 卫星",           "ArcGIS Online World 卫星",      true,   false,  UrlFactory::EsriWorldSatellite);
   ...
  1. /src/QtLocationPlugin/QGCMapEngine.cpp修改离线地图
//48:字符串要求同上节
stQGeoTileCacheQGCMapTypes kMapTypes[] = {
     {"Google.cn 卫星",       UrlFactory::GoogleSatellite},
     {"Google.cn 卫星混合(仅标签偏移)",       UrlFactory::GoogleStatelliteWithLableNofix},
     {"Google.cn *卫星混合(全偏移)",       UrlFactory::GoogleStatelliteWithLable},
     {"Google.cn *地形(偏移)",       UrlFactory::GoogleTerrain},
     {"Esri 卫星",       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;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容