qml实现高德地图(2)

这里只实现一个地图映射引擎
1.编译插件
pro文件:

TARGET = GD
QT += location-private positioning-private network

PLUGIN_TYPE = geoservices
PLUGIN_CLASS_NAME = GDProviderFactory
load(qt_plugin)

HEADERS += \
    gdproviderfactory.h \
    gdqgeotiledmap.h \
    gdqgeotiledmappingmanagerengine.h \
    gdqgeotiledmapreply.h \
    gdqgeotilefetcher.h


SOURCES += \
    gdproviderfactory.cpp \
    gdqgeotiledmap.cpp \
    gdqgeotiledmappingmanagerengine.cpp \
    gdqgeotiledmapreply.cpp \
    gdqgeotilefetcher.cpp

DISTFILES += \
    README.md \
    gd_plugin.json

插件类(也是qml调用的入口):

#ifndef GDPROVIDERFACTORY_H
#define GDPROVIDERFACTORY_H

#include <QObject>
#include <QtCore/QObject>
#include <QtLocation/QGeoServiceProviderFactory>

class GDProviderFactory : public QObject,public QGeoServiceProviderFactory
{
    Q_OBJECT
    Q_INTERFACES(QGeoServiceProviderFactory)
    Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/5.0"
                      FILE "gd_plugin.json")
public:
    //只实现一个插件
    QGeoMappingManagerEngine *createMappingManagerEngine(const QVariantMap &parameters,
                                                         QGeoServiceProvider::Error *error,
                                                         QString *errorString) const;
signals:

};

#endif // GDPROVIDERFACTORY_H

#include "gdproviderfactory.h"
#include "gdqgeotiledmappingmanagerengine.h"
QGeoMappingManagerEngine *GDProviderFactory::createMappingManagerEngine(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString) const
{
    return new GDQGeoTiledMappingManagerEngine(parameters, error, errorString);

}

地图瓦片管理类、设置地图一些属性

#ifndef GDQGEOTILEDMAPPINGMANAGERENGINE_H
#define GDQGEOTILEDMAPPINGMANAGERENGINE_H

#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>

class GDQGeoTiledMappingManagerEngine : public QGeoTiledMappingManagerEngine
{
    Q_OBJECT

public:
    GDQGeoTiledMappingManagerEngine(const QVariantMap &parameters,
                                       QGeoServiceProvider::Error *error,
                                       QString *errorString);

    QGeoMap *createMap() override;

private:
    QString m_cacheDirectory;

};

#endif // GDQGEOTILEDMAPPINGMANAGERENGINE_H

#include "gdqgeotiledmappingmanagerengine.h"
#include "gdqgeotilefetcher.h"
#include "QtLocation/private/qgeotilespec_p.h"
#include "QtLocation/private/qgeofiletilecache_p.h"
#include "QtLocation/private/qgeocameracapabilities_p.h"
#include "gdqgeotiledmap.h"

GDQGeoTiledMappingManagerEngine::GDQGeoTiledMappingManagerEngine(const QVariantMap &parameters, QGeoServiceProvider::Error *error, QString *errorString)
    :QGeoTiledMappingManagerEngine()
{
    Q_UNUSED(error);
    Q_UNUSED(errorString);


    //地图视角相关设置,对应到 QML Map 类型的属性
    QGeoCameraCapabilities capabilities;
    capabilities.setMinimumZoomLevel(1.96);
    capabilities.setMaximumZoomLevel(20.88);
    capabilities.setSupportsBearing(true);
    capabilities.setSupportsTilting(true);
    capabilities.setMinimumTilt(0);
    capabilities.setMaximumTilt(80);
    capabilities.setMinimumFieldOfView(20.0);
    capabilities.setMaximumFieldOfView(120.0);
    capabilities.setOverzoomEnabled(true);
    setCameraCapabilities(capabilities);

   //瓦片大小
    int tile = parameters.value(QStringLiteral("amap.amap.tilesize"), 256).toInt();
    setTileSize(QSize(tile, tile));

    //支持地图样式
    QList<QGeoMapType> types;
    //QGeoCameraCapabilities cameraCapabilities;
    types << QGeoMapType(QGeoMapType::StreetMap, tr("Road Map"), tr("Normal map view in daylight mode"), false,false, 1, "amap", capabilities);
    types << QGeoMapType(QGeoMapType::TerrainMap, tr("Terrain"), tr("Terrain map view in daylight mode"), false, false, 2, "amap", capabilities);
    types << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Satellite"), tr("Satellite map view in daylight mode"), false, false, 3, "amap", capabilities);
    types << QGeoMapType(QGeoMapType::HybridMap, tr("Hybrid"), tr("Satellite map view with streets in daylight mode"), false, false, 4, "amap", capabilities);
    setSupportedMapTypes(types);

    //瓦片获取,默认接口是通过网络请求获取
    GDQGeoTileFetcher *fetcher = new GDQGeoTileFetcher(parameters, this, tileSize());
    setTileFetcher(fetcher);

    if (parameters.contains(QStringLiteral("amap.cachefolder")))
        m_cacheDirectory = parameters.value(QStringLiteral("amap.cachefolder")).toString().toLatin1();
    else
        m_cacheDirectory = QAbstractGeoTileCache::baseCacheDirectory() + QLatin1String("amap");

    QAbstractGeoTileCache *tileCache = new QGeoFileTileCache(m_cacheDirectory);
    tileCache->setMaxDiskUsage(100 * 1024 * 1024);
    setTileCache(tileCache);

    *error = QGeoServiceProvider::NoError;
    errorString->clear();
}

QGeoMap *GDQGeoTiledMappingManagerEngine::createMap()
{
    return new GDQGeoTiledMap(this);
}

瓦片获取类:

#ifndef GDQGEOTILEFETCHER_H
#define GDQGEOTILEFETCHER_H

#include <QtLocation/private/qgeotilefetcher_p.h>
#include "gdqgeotiledmappingmanagerengine.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMutex>

class GDQGeoTileFetcher : public QGeoTileFetcher
{
    Q_OBJECT
public:
    GDQGeoTileFetcher(const QVariantMap &parameters, GDQGeoTiledMappingManagerEngine *engine, const QSize &tileSize);


    QGeoTiledMapReply *getTileImage(const QGeoTileSpec &spec);


private:
    QString _getURL(int type, int x, int y, int zoom);
    void _getSecAmapWords(int x, int y, QString &sec1, QString &sec2);
    void _getSessionToken();
    void _tryCorrectAmapVersions(QNetworkAccessManager *networkManager);

private slots:
    void _networkReplyError(QNetworkReply::NetworkError error);
    void _replyDestroyed();
    void _amapVersionCompleted();


private:
    QString m_apiKey;
    QString m_signature;
    QString m_client;
    QString m_baseUri;



    bool            _amapVersionRetrieved;
    QNetworkReply*  _amapReply;
    QMutex          _amapVersionMutex;
    QByteArray      _userAgent;
    QString         _language;


    // Amap version strings
    QString         _versionAmapMap;
    QString         _versionAmapSatellite;
    QString         _versionAmapLabels;
    QString         _versionAmapTerrain;
    QString         _secAmapWord;

    QNetworkRequest netRequest;
    QNetworkAccessManager *m_networkManager;


};

#endif // GDQGEOTILEFETCHER_H

#include "gdqgeotilefetcher.h"
#include "gdqgeotiledmapreply.h"
#include <QNetworkProxy>
#include <QDebug>
#include <QSize>
#include <QDir>
#include <QUrl>
#include <QUrlQuery>
#include <QTime>
#include <QtCore/QJsonDocument>
#include <math.h>
#include <map>
#include <QJsonObject>


GDQGeoTileFetcher::GDQGeoTileFetcher(const QVariantMap &parameters, GDQGeoTiledMappingManagerEngine *engine, const QSize &tileSize)
         :QGeoTileFetcher(engine)
{
    if(parameters.contains(QStringLiteral("amap.maps.apikey")))
        m_apiKey = parameters.value(QStringLiteral("amap.maps.apikey")).toString();
    else
        m_apiKey = parameters.value(QStringLiteral("amap.apikey")).toString();

    m_signature = parameters.value(QStringLiteral("amap.maps.signature")).toString();
    m_client = parameters.value(QStringLiteral("amap.maps.client")).toString();
    m_baseUri = QStringLiteral("http://maps.amap.com/maps/api/staticmap");

    if (parameters.contains(QStringLiteral("amap.useragent")))
        _userAgent = parameters.value(QStringLiteral("amap.useragent")).toString().toLatin1();
    else
        _userAgent = "";


    QStringList langs = QLocale::system().uiLanguages();
    if (langs.length() > 0) {
        _language = langs[0];
    }

    // Amap version strings
    _versionAmapMap            = "m@338000000";
    _versionAmapSatellite      = "198";
    _versionAmapLabels         = "h@336";
    _versionAmapTerrain        = "t@132,r@338000000";
    _secAmapWord               = "Galileo";


    //    _tryCorrectAmapVersions(m_networkManager);

    //    netRequest.setRawHeader("Referrer", "https://www.amap.com/maps/preview");
    //    netRequest.setRawHeader("Accept", "*/*");
    //    netRequest.setRawHeader("User-Agent", _userAgent);

        /*  2017: support new Amap Maps Tile API (yet under development)
            You have to be whitelisted to use the Tile API. I can't tell how to get whitelisted.
            see https://developers.amap.com/maps/documentation/tile/
            To use the new feature getUrl() and parsing the response has to be adapted. Maybe more than that...
        */
    //    _getSessionToken();
}

QGeoTiledMapReply *GDQGeoTileFetcher::getTileImage(const QGeoTileSpec &spec)
{
    QString surl = _getURL(spec.mapId(), spec.x(), spec.y(), spec.zoom());
    // qDebug()<<"_getURL:" << surl;
    QUrl url(surl);

    netRequest.setUrl(url);

    QNetworkReply *netReply = m_networkManager->get(netRequest);

    QGeoTiledMapReply *mapReply = new GDQGeoTiledMapReply(netReply, spec);

    return mapReply;
}

QString GDQGeoTileFetcher::_getURL(int type, int x, int y, int zoom)
{
    // qDebug() << "Type:" << type;
    switch (type) {
    case 0:
    case 1: //Road Map
    {
        QString sec1    = ""; // after &x=...
        QString sec2    = ""; // after &zoom=...
        _getSecAmapWords(x, y, sec1, sec2);

        return QString("http://wprd03.is.autonavi.com/appmaptile?style=7&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
    }
    break;
    case 2: //Satallite Map
    {
        QString sec1    = ""; // after &x=...
        QString sec2    = ""; // after &zoom=...
        _getSecAmapWords(x, y, sec1, sec2);
        return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
    }
    break;
    case 3: //Terrain Map
    {
        QString sec1    = ""; // after &x=...
        QString sec2    = ""; // after &zoom=...
        _getSecAmapWords(x, y, sec1, sec2);
        return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=6&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
    }
    break;
    case 4: //Hybrid Map
    {
        QString sec1    = ""; // after &x=...
        QString sec2    = ""; // after &zoom=...
        _getSecAmapWords(x, y, sec1, sec2);
        return QString("http://wprd03.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=8&x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
    }
    break;
    }
    return "";
}

void GDQGeoTileFetcher::_getSecAmapWords(int x, int y, QString &sec1, QString &sec2)
{
    sec1 = ""; // after &x=...
    sec2 = ""; // after &zoom=...
    int seclen = ((x * 3) + y) % 8;
    sec2 = _secAmapWord.left(seclen);
    if (y >= 10000 && y < 100000) {
        sec1 = "&s=";
    }
}

void GDQGeoTileFetcher::_getSessionToken()
{
    QUrl sessionUrl("https://www.amap.com/tile/v1/createSession");

    QUrlQuery queryItems;
    queryItems.addQueryItem("key", m_apiKey);
    queryItems.addQueryItem("mapType", "roadmap");
    queryItems.addQueryItem("language", _language);
    queryItems.addQueryItem("region", "de");

    sessionUrl.setQuery(queryItems);
    netRequest.setUrl(sessionUrl);
    QNetworkReply *sessionReply = m_networkManager->get(netRequest);


    if (sessionReply->error() != QNetworkReply::NoError)
        return;

    QJsonDocument document = QJsonDocument::fromJson(sessionReply->readAll());
    if (!document.isObject())
        return;

    QJsonObject object = document.object();
    QJsonValue status = object.value(QStringLiteral("session"));
    printf(status.toString().toLatin1().data());
}

void GDQGeoTileFetcher::_tryCorrectAmapVersions(QNetworkAccessManager *networkManager)
{
    QMutexLocker locker(&_amapVersionMutex);
    if (_amapVersionRetrieved) {
        return;
    }
    _amapVersionRetrieved = true;
    if(networkManager)
    {
        QNetworkRequest qheader;
        QNetworkProxy proxy = networkManager->proxy();
        QNetworkProxy tProxy;
        tProxy.setType(QNetworkProxy::DefaultProxy);
        networkManager->setProxy(tProxy);
        QSslConfiguration conf = qheader.sslConfiguration();
        conf.setPeerVerifyMode(QSslSocket::VerifyNone);
        qheader.setSslConfiguration(conf);

        QString url = "http://maps.amap.com/maps/api/js?v=3.2&sensor=false";
        qheader.setUrl(QUrl(url));
        qheader.setRawHeader("User-Agent", _userAgent);
        _amapReply = networkManager->get(qheader);
        connect(_amapReply, &QNetworkReply::finished, this, &GDQGeoTileFetcher::_amapVersionCompleted);
        connect(_amapReply, &QNetworkReply::destroyed, this, &GDQGeoTileFetcher::_replyDestroyed);
        connect(_amapReply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
                this, &GDQGeoTileFetcher::_networkReplyError);
        networkManager->setProxy(proxy);
    }
}

void GDQGeoTileFetcher::_networkReplyError(QNetworkReply::NetworkError error)
{
    qWarning() << "Could not connect to amap maps. Error:" << error;
    if(_amapReply)
    {
        _amapReply->deleteLater();
        _amapReply = NULL;
    }
}

void GDQGeoTileFetcher::_replyDestroyed()
{
    _amapReply = NULL;
}

void GDQGeoTileFetcher::_amapVersionCompleted()
{
    if (!_amapReply || (_amapReply->error() != QNetworkReply::NoError)) {
        qDebug() << "Error collecting Amap maps version info";
        return;
    }
    QString html = QString(_amapReply->readAll());

    QRegExp reg("\"*https?://mt\\D?\\d..*/vt\\?lyrs=m@(\\d*)", Qt::CaseInsensitive);
    if (reg.indexIn(html) != -1) {
        QStringList gc = reg.capturedTexts();
        _versionAmapMap = QString("m@%1").arg(gc[1]);
    }
    reg = QRegExp("\"*https?://khm\\D?\\d.amap.com/kh\\?v=(\\d*)", Qt::CaseInsensitive);
    if (reg.indexIn(html) != -1) {
        QStringList gc = reg.capturedTexts();
        _versionAmapSatellite = gc[1];
    }
    reg = QRegExp("\"*https?://mt\\D?\\d..*/vt\\?lyrs=t@(\\d*),r@(\\d*)", Qt::CaseInsensitive);
    if (reg.indexIn(html) != -1) {
        QStringList gc = reg.capturedTexts();
        _versionAmapTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]);
    }

    _amapReply->deleteLater();
    _amapReply = NULL;
}

瓦片请求网络

#ifndef GDQGEOTILEDMAPREPLY_H
#define GDQGEOTILEDMAPREPLY_H

#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotilespec_p.h>
#include <QtLocation/private/qgeotiledmapreply_p.h>
#include <QtCore/QPointer>

class GDQGeoTiledMapReply : public QGeoTiledMapReply
{
    Q_OBJECT
public:
    GDQGeoTiledMapReply(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);

    void abort();

    QNetworkReply *networkReply() const;

private Q_SLOTS:
    void networkFinished();
    void networkError(QNetworkReply::NetworkError error);

private:
    QPointer<QNetworkReply> m_reply;
};

#endif // GDQGEOTILEDMAPREPLY_H

#include "gdqgeotiledmapreply.h"

GDQGeoTiledMapReply::GDQGeoTiledMapReply(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
     :QGeoTiledMapReply(spec,parent),
       m_reply(reply)
{
    connect(m_reply,
            SIGNAL(finished()),
            this,
            SLOT(networkFinished()));

    connect(m_reply,
            SIGNAL(error(QNetworkReply::NetworkError)),
            this,
            SLOT(networkError(QNetworkReply::NetworkError)));
}

void GDQGeoTiledMapReply::abort()
{
    if (!m_reply)
        return;

    m_reply->abort();
}

QNetworkReply *GDQGeoTiledMapReply::networkReply() const
{
    return m_reply;

}

void GDQGeoTiledMapReply::networkFinished()
{
    if (!m_reply)
        return;

    if (m_reply->error() != QNetworkReply::NoError)
        return;

    setMapImageData(m_reply->readAll());
    const int _mid = tileSpec().mapId();
    if (_mid == 2)
        setMapImageFormat("jpeg");
    else
        setMapImageFormat("png");
    setFinished(true);

    m_reply->deleteLater();
    m_reply = 0;
}

void GDQGeoTiledMapReply::networkError(QNetworkReply::NetworkError error)
{
    Q_UNUSED(error);
    if (!m_reply)
        return;

    setFinished(true);
    setCached(false);
    m_reply->deleteLater();
    m_reply = 0;
}

创造地图:

#ifndef GDQGEOTILEDMAP_H
#define GDQGEOTILEDMAP_H

#include "QtLocation/private/qgeotiledmap_p.h"
#include <QtGui/QImage>
#include <QtCore/QPointer>
#include "gdqgeotiledmappingmanagerengine.h"

class GDQGeoTiledMap : public QGeoTiledMap
{
public:
    explicit GDQGeoTiledMap(GDQGeoTiledMappingManagerEngine *engine,QObject *parent = nullptr);

    //QString getViewCopyright();
   // void evaluateCopyrights(const QSet<QGeoTileSpec> &visibleTiles);

private:
    QImage m_copyrightsSlab;
    QString m_lastCopyrightsString;
    QPointer<GDQGeoTiledMappingManagerEngine> m_engine;
};

#endif // GDQGEOTILEDMAP_H
#include "gdqgeotiledmap.h"



GDQGeoTiledMap::GDQGeoTiledMap(GDQGeoTiledMappingManagerEngine *engine, QObject *parent)
    :QGeoTiledMap(engine, parent),
    m_engine(engine)
{

}


二、qml调用插件
将生成的插件动态库放到C:\Qt5.15.2\5.15.2\msvc2019_64\plugins\geoservices目录下,qml直接调用。

import QtQuick 2.12
import QtQuick.Window 2.12
import QtPositioning 5.12
import QtLocation 5.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Map{
        anchors.fill:parent
        plugin: Plugin{name: "amap"}
    }
}

插件json文件:

{
    "Keys": ["amap"],
    "Provider": "amap",
    "Version": 200,
    "Experimental": false,
    "Features": [
        "OnlineGeocodingFeature",
        "ReverseGeocodingFeature",
        "OnlineRoutingFeature",
        "AlternativeRoutesFeature",
        "OnlineMappingFeature",
        "SearchSuggestionsFeature"
    ]
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

屁小猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值