QGroundControl(QGC)飞控地面站二次开发-修改地图

一、问题

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)

  2. 菜单选卫星图像

  3. 浏览器 F12 看网络

    找到卫星切片地址(西安钟楼)
    http://www.google.cn/maps/vt?lyrs=s@847&gl=cn&x=52601&y=26122&z=16
    QGroundControl(QGC)飞控地面站二次开发-修改地图_第1张图片

    解释下参数

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

  5. 能用的url

    • 卫星无偏移:http://www.google.cn/maps/vt?lyrs=s&x=52601&y=26122&z=16
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第2张图片
    • 卫星混合,标签偏移:http://www.google.cn/maps/vt?lyrs=y&x=52601&y=26122&z=16
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第3张图片
    • 卫星混合偏移:http://www.google.cn/maps/vt?lyrs=y&gl=cn&x=52601&y=26122&z=16
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第4张图片
    • 地形带标签(反正大于15层也不显示等高线了,偏移看不出来):http://www.google.cn/maps/vt?lyrs=p&gl=cn&x=6051&y=2997&z=13
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第5张图片
    • 街道偏移(当个地图也可以):http://www.google.cn/maps/vt?lyrs=m&gl=cn&x=52601&y=26122&z=16
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第6张图片
  6. 其他地图瓦片

    ArcGis(esri)已被集成在QGC中,因为没有Token,所以不显示,但是下面两个瓦片是不需要token的支持到19级,需要把判断esri token的地方注释掉

    • ArcGis街道 http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile//16/26122/52601
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第7张图片
    • ArcGis卫星 http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/16/26122/52601
      QGroundControl(QGC)飞控地面站二次开发-修改地图_第8张图片

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 尝试编译

要搭建编译环境,打开QT Creator,把工程编译一遍,这一步过不去后面的就呵呵了,这也是一个比较坑爹的地方,QGC官方给的说明不太对,请参考下面的文档:
1. https://dev.qgroundcontrol.com/en/getting_started/
2. 工程目录/.travis.yml
对于qt版本和安卓ndk版本在第二个文档内是肯定正确的,毕竟人家拿这个去自动生成Daily build

2.3 修改

  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;
}

2.5 编译、测试、收工

可以按照设计正常显示地图,本来还想加OpenStreet,在浏览器上没问题,但在QGC上死活不出来,应该是OpenStreet没有许可只能在浏览器上使用。

你可能感兴趣的:(QGroundControl(QGC)飞控地面站二次开发-修改地图)