QGC地图开发

由于公司项目需要,使用了QGC中的地图部分代码,该部分是一个以sqlite为核心的瓦片存储和管理的库,其中对瓦片有三层缓存机制,分别是磁盘缓存,数据库缓存和内存缓存。现将使用过程中遇到的问题记录如下:

项目中需要使用多个地图,针对多个项目展示不同的地图,而qgc本身的机制其实只维护了一个地图。 解决方案:在创建qgc地图的接口中创建多个地图,针对每个地图创建新的缓存管理(此处需要修改缓存创建的机制)。但是这样做只解决了sqlite缓存的问题,仍有两个问题没有解决,即磁盘和内存缓存。内存缓存只在地图变化过程中使用,且根据其机制不会产生太大影响,可以暂时不管,但磁盘缓存会导致每张地图新建和初始化时加载一样的数据。由于未找到关闭磁盘缓存的办法,目前采用的方法是将磁盘缓存最大允许使用空间设置为0,从而达到不使用的目的,该方法在某台测试机器中将导致计算异常而崩溃,其他机器表现正常。
qgc目前只提供了网络地图源,甲方要求使用离线地图源。 解决方案:QGeoMapReplyQGC中定义了瓦片加载的顺序和机制:优先从缓存中读取,若读取失败,则从网络中获取,此时只需在失败后增加从本地获取的逻辑即可,如:

void QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString errorString)
{
    /qDebug() << "-----QGeoTiledMapReplyQGC::cacheError errStr: " << errorString; if(!getQGCMapEngine()->isInternetActive()) { if ((UrlFactory::MapType)tileSpec().mapId() == UrlFactory::MapType::AirmapElevation) { emit terrainDone(QByteArray(), QNetworkReply::NetworkSessionFailedError); } else { setError(QGeoTiledMapReply::CommunicationError, "Network not available"); setFinished(true); } } else { if(type != QGCMapTask::taskFetchTile) { qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task"; }/
    if (QGeoLocInterface::instance()->isLocal())
    {
        //tile not in cache. Get it from the local disk.
        HqTileFeatchMgr *locMgr = HqTileFeatchMgr::instance();
        _localReply = locMgr->newFeatch(_tileSpec);        
        connect(_localReply, &QGeoTileFeatchHQ::finished, this, &QGeoTiledMapReplyQGC::localReplyFinished);
        connect(_localReply, &QGeoTileFeatchHQ::error, this, &QGeoTiledMapReplyQGC::localReplyError);
    }
    else
    {
        //-- Tile not in cache. Get it off the Internet.
        loadFromInternet();
    }
    //- Wait for an answer up to 10 seconds
    connect(&_timer, &QTimer::timeout, this, &QGeoTiledMapReplyQGC::timeout);
    _timer.setSingleShot(true);
    _timer.start(10000);
    _requestCount++;
}

需要将自定义瓦片加载显示到地图中。 解决方案:该需求其实与离线地图的需求一致,按照墨卡托投影切分瓦片并创建对应的文件夹层级关系,后续步骤就与离线地图一致了,只需优先加载自定义瓦片即可。
qgc地图在加载和显示过程中特别慢,哪怕是离线地图加载速度也很慢。解决方案:该问题经调试发现其罪魁祸首是qgc使用sqlite作为数据库的机制导致的,因地图需要自动刷新,故每张生成的瓦片都需要更新每一级缓存,在sqlite的查询和更新中需要大量时间,从而导致显示延后。要解决该问题,可以从几个角度入手,一是限制sqlite数据库的大小,使其不至于缓存太多数据而导致查询时低效能,二是减少sqlite的存储,对于所有瓦片都需要从sqlite存和查(取)这种处理,减少其频次,三是直接取消sqlite的存取,直接从网络或者本地加载,可根据实际情况调整,在我的项目中,由于是本地图元,故直接取消了该缓存,且实际测试来看,从网络直接获取展示,速度也并不慢(但该方案会导致缩放不平滑)。参照如下:

void
 QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString errorString)
{
    /qDebug() << "-----QGeoTiledMapReplyQGC::cacheError errStr: " << errorString; if(!getQGCMapEngine()->isInternetActive()) { if ((UrlFactory::MapType)tileSpec().mapId() == UrlFactory::MapType::AirmapElevation) { emit terrainDone(QByteArray(), QNetworkReply::NetworkSessionFailedError); } else { setError(QGeoTiledMapReply::CommunicationError, "Network not available"); setFinished(true); } } else { if(type != QGCMapTask::taskFetchTile) { qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task"; }/
    if (QGeoLocInterface::instance()->isLocal())
    {
        //tile not in cache. Get it from the local disk.
        HqTileFeatchMgr *locMgr = HqTileFeatchMgr::instance();
        _localReply = locMgr->newFeatch(_tileSpec);        
        connect(_localReply, &QGeoTileFeatchHQ::finished, this, &QGeoTiledMapReplyQGC::localReplyFinished);
        connect(_localReply, &QGeoTileFeatchHQ::error, this, &QGeoTiledMapReplyQGC::localReplyError);
    }
    else
    {
        //-- Tile not in cache. Get it off the Internet.
        loadFromInternet();
    }
    //- Wait for an answer up to 10 seconds
    connect(&_timer, &QTimer::timeout, this, &QGeoTiledMapReplyQGC::timeout);
    _timer.setSingleShot(true);
    _timer.start(10000);
    _requestCount++;
}

QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent)
: QGeoTiledMapReply(spec, parent)
, _netReply(NULL)
, _request(request)
, _networkManager(networkManager)
, _tileSpec(spec)
{
    if(_request.url().isEmpty()) {
        if(!_badMapbox.size()) {
            QFile b(":/res/notile.png");
            if(b.open(QFile::ReadOnly))
            _badMapbox = b.readAll();
            }
        setMapImageData(_badMapbox);
        setMapImageFormat("png");
        setFinished(true);
        setCached(false);
   } 
   else {
    // remove sqlite cache
    // QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom()); 
    // connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply);
    // connect(task, &QGCMapTask::error, this, &QGeoTiledMapReplyQGC::cacheError);
    // getQGCMapEngine()->addTask(task);
    cacheError(QGCMapTask::taskFetchTile, "");
   }
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注