Compare commits

...

1 Commits
main ... shiyi

Author SHA1 Message Date
shiyi a32b576031 chore: 补充搜救载荷地图模块源码 3 months ago

4
.gitignore vendored

@ -10,4 +10,6 @@ app/
/debug/ /debug/
/release/ /release/
/.idea/ /.idea/
/.vscode/ /.vscode/
/Src/RescueLoad/map/tianditu/TianDiTu/build/
/Src/RescueLoad/map/tianditu/TianDiTu/lib/

@ -0,0 +1,29 @@

project(tilogger)
# find_package (Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
tilogger.cpp
tilogger.h
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt${QT_VERSION_MAJOR}::Core
)
# interface
target_include_directories(${PROJECT_NAME}
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)

@ -0,0 +1,6 @@
CONFIG += c++11
SOURCES += $$PWD/tilogger.cpp
HEADERS += $$PWD/tilogger.h

@ -0,0 +1,125 @@
/**************************************************************************
* tilog.cpp
* =======================================================================
*
* 2021-3-29
* 499131808@qq.com
* Q Q 499131808
*
*
*
* ======================================================================
*
*
*
* ======================================================================
*
***************************************************************************/
#include "tilogger.h"
#include <stdio.h>
#include <stdlib.h>
#include <QDateTime>
#include <QDir>
#include <QGlobalStatic>
Q_GLOBAL_STATIC(TiLogger, tiLogger) //注意这个是必须的
void outputMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
TiLogger::instance()->writeMsg(type, context, msg);
}
void TiLogger::writeMsg(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
QMutexLocker l(&m_mutex);
//组合自定义数据
static QString logType, sendmsg, writemsg;
QDateTime currentTime = QDateTime::currentDateTime();
QString logTime = currentTime.toString("yyyy-MM-dd hh:mm:ss.zzz");
const char* fileName = context.file ? context.file : "";
const char* function = context.function ? context.function : "";
QString line = QString::number(context.line);
switch (type) {
case QtDebugMsg:
logType = "debug";
break;
case QtInfoMsg:
logType = "info";
break;
case QtWarningMsg:
logType = "warning";
break;
case QtCriticalMsg:
logType = "critical";
break;
case QtFatalMsg:
logType = "fatal";
break;
}
writemsg = QString("[%1: %2 %3 %4 %5] %6").arg(logType, logTime, fileName, line, function, msg);
if (_isFile) {
QString newfileName
= m_path
+ QString("%1_log.txt").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh"));
if (m_file.fileName() != newfileName) {
if (m_file.isOpen())
m_file.close();
m_file.setFileName(newfileName);
m_file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
m_textStream.setDevice(&m_file);
}
m_textStream << writemsg << Qt::endl;
m_textStream.flush();
}
if (_isConsole) {
fprintf(stdout, "%s\n", writemsg.toLocal8Bit().data());
fflush(stdout);
}
if (_isSignals) {
sendmsg = QString("[%1: %2] %3").arg(logType, logTime, msg);
emit sigLogger(sendmsg);
}
}
TiLogger::TiLogger()
{
QMutexLocker l(&m_mutex);
qInstallMessageHandler(outputMessage);
QDir dir;
if (!dir.exists(m_path))
dir.mkpath(m_path);
}
TiLogger::~TiLogger()
{
QMutexLocker l(&m_mutex);
if (m_file.isOpen())
m_file.close();
}
TiLogger* TiLogger::instance() { return tiLogger(); }
void TiLogger::writeToFile(bool enable, const QString &path)
{
QMutexLocker l(&m_mutex);
_isFile = enable;
if (!path.isEmpty() && m_path != path)
m_path = path;
}
void TiLogger::enableSignals(bool enable)
{
QMutexLocker l(&m_mutex);
_isSignals = enable;
}
void TiLogger::writeToConsole(bool enable)
{
QMutexLocker l(&m_mutex);
_isConsole = enable;
}

@ -0,0 +1,78 @@
/**************************************************************************
* tilog.h
* =======================================================================
*
* 2021-3-29
* 499131808@qq.com
* Q Q 499131808
*
*
*
* ======================================================================
*
*
*
* ======================================================================
*
***************************************************************************/
#pragma once
#include <QFile>
#include <QMutex>
#include <QObject>
#include <QTextStream>
#include <iostream>
#include <QDebug>
#include <QThread>
#define TILOGGER TiLogger::instance()
//重新定义qDebug相关宏
#undef QT_MESSAGELOG_FUNC
#define QT_MESSAGELOG_FUNC static_cast<const char*>(__FUNCTION__)
#undef QT_MESSAGELOG_FILE
#define QT_MESSAGELOG_FILE static_cast<const char*>(__FILE__)
#undef QT_MESSAGELOG_LINE
#define QT_MESSAGELOG_LINE __LINE__
#define THREAD QThread::currentThread()
//这里可参考qDebug的宏定义
#define LOG_DEBUG QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
#define LOG_WARN QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).warning
#define LOG_INFO QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).info
#define LOG_CRIT QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).critical
#define LOG_FATAL QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal
#define LOG_DEBUG_THREAD() LOG_DEBUG() << THREAD
#define LOG_WARN_THREAD() LOG_WARN() << THREAD
#define LOG_INFO_THREAD() LOG_INFO() << THREAD
class TiLogger : public QObject {
Q_OBJECT
public:
TiLogger();
~TiLogger();
static TiLogger* instance();
signals:
void sigLogger(const QString& log);
public:
/// 是否启用将日志写入到文件,可选择日志存放日志
void writeToFile(bool enable, const QString& path = "./Log/");
/// 是否启用将日志通过信号的方式发送出
void enableSignals(bool enable);
// 是否启用日志输出到控制台
void writeToConsole(bool enable);
// 用于格式化日志,外部不要调用
void writeMsg(QtMsgType type, const QMessageLogContext& context, const QString& msg);
private:
bool _isFile = false;
bool _isSignals = false;
bool _isConsole = false;
QMutex m_mutex;
QFile m_file;
QString m_path = "./Log/";
QTextStream m_textStream;
};

@ -0,0 +1,43 @@
#TEMPLATE = lib
CONFIG += c++11 plugin static
QT += core
QT += location location-private positioning-private qml positioning sql network core5compat quick
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
#TARGET = TianDiTu
include($$PWD/Log/Log.pri)
INCLUDEPATH += $$PWD/Log
HEADERS += \
$$PWD/tigeotilefetcher.h \
$$PWD/timapcacheworker.h \
$$PWD/timapengine.h \
$$PWD/timapenginedata.h \
$$PWD/timapprovider.h \
$$PWD/timapurlengine.h \
$$PWD/tiqgeocodereply.h \
$$PWD/tiqgeofiletilecache.h \
$$PWD/tiqgeoserviceproviderfactory.h \
$$PWD/tiqgeotiledmappingmanagerengine.h \
$$PWD/tiqgeotiledmapreply.h \
$$PWD/titianditumapprovider.h \
SOURCES += \
$$PWD/tigeotilefetcher.cpp \
$$PWD/timapcacheworker.cpp \
$$PWD/timapengine.cpp \
$$PWD/timapprovider.cpp \
$$PWD/timapurlengine.cpp \
$$PWD/tiqgeocodereply.cpp \
$$PWD/tiqgeofiletilecache.cpp \
$$PWD/tiqgeoserviceproviderfactory.cpp \
$$PWD/tiqgeotiledmappingmanagerengine.cpp \
$$PWD/tiqgeotiledmapreply.cpp \
$$PWD/titianditumapprovider.cpp \
$$PWD/init.cpp
DISTFILES += \
$$PWD/timap_plugin.json \

@ -0,0 +1,52 @@
TEMPLATE = lib
CONFIG += c++11 static plugin
QT += location location-private positioning-private qml positioning sql network core5compat quick
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TianDiTu
DESTDIR = $$PWD/lib
include($$PWD/Log/Log.pri)
INCLUDEPATH += $$PWD/Log
HEADERS += \
$$PWD/tigeotilefetcher.h \
$$PWD/timapcacheworker.h \
$$PWD/timapengine.h \
$$PWD/timapenginedata.h \
$$PWD/timapprovider.h \
$$PWD/timapurlengine.h \
$$PWD/tiqgeocodereply.h \
$$PWD/tiqgeofiletilecache.h \
$$PWD/tiqgeoserviceproviderfactory.h \
$$PWD/tiqgeotiledmappingmanagerengine.h \
$$PWD/tiqgeotiledmapreply.h \
$$PWD/titianditumapprovider.h \
$$PWD/tibingmapprovider.h \
$$PWD/tiesrimapprovider.h \
$$PWD/tigooglemapprovider.h \
$$PWD/timapjsonengine.h
SOURCES += \
$$PWD/tigeotilefetcher.cpp \
$$PWD/timapcacheworker.cpp \
$$PWD/timapengine.cpp \
$$PWD/timapprovider.cpp \
$$PWD/timapurlengine.cpp \
$$PWD/tiqgeocodereply.cpp \
$$PWD/tiqgeofiletilecache.cpp \
$$PWD/tiqgeoserviceproviderfactory.cpp \
$$PWD/tiqgeotiledmappingmanagerengine.cpp \
$$PWD/tiqgeotiledmapreply.cpp \
$$PWD/titianditumapprovider.cpp \
$$PWD/init.cpp \
$$PWD/tibingmapprovider.cpp \
$$PWD/tiesrimapprovider.cpp \
$$PWD/tigooglemapprovider.cpp \
$$PWD/timapjsonengine.cpp
DISTFILES += \
$$PWD/timap_plugin.json \
TianDiTu.pri

@ -0,0 +1,2 @@
#include "QtPlugin"
Q_IMPORT_PLUGIN(TiQGeoServiceProviderFactory)

@ -0,0 +1,2 @@
搜救载荷地图模块静态库源代码
titianditumapprovider.cpp 中修改天地图的key注意key的类型

@ -0,0 +1,41 @@
#include "tibingmapprovider.h"
TiBingMapProvider::TiBingMapProvider(const QString& imageFormat, const quint32 averageSize,
const QGeoMapType::MapStyle mapType, QObject* parent) :
TiMapProvider(imageFormat, averageSize, mapType, parent)
{
}
static const QString RoadMapUrl
= QStringLiteral("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4");
QString TiBingRoadMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString key = tileXYToQuadKey(x, y, zoom);
return RoadMapUrl.arg(QString::number(getServerNum(x, y, 4)), key, _versionBingMaps, m_language);
}
static const QString SatteliteMapUrl
= QStringLiteral("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4");
QString TiBingSatelliteMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString key = tileXYToQuadKey(x, y, zoom);
return SatteliteMapUrl.arg(QString::number(getServerNum(x, y, 4)), key, _versionBingMaps,
m_language);
}
static const QString HybridMapUrl
= QStringLiteral("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4");
QString TiBingHybridMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString key = tileXYToQuadKey(x, y, zoom);
return HybridMapUrl.arg(QString::number(getServerNum(x, y, 4)), key, _versionBingMaps, m_language);
}

@ -0,0 +1,71 @@
#pragma once
#include "timapprovider.h"
class TiBingMapProvider : public TiMapProvider
{
Q_OBJECT
public:
TiBingMapProvider(const QString& imageFormat, const quint32 averageSize,
const QGeoMapType::MapStyle mapType, QObject* parent = nullptr);
~TiBingMapProvider() = default;
protected:
const QString _versionBingMaps = QStringLiteral("563");
};
static const quint32 AVERAGE_BING_STREET_MAP = 1297;
static const quint32 AVERAGE_BING_SAT_MAP = 19597;
// -----------------------------------------------------------
// Bing Road Map
class TiBingRoadMapProvider : public TiBingMapProvider
{
Q_OBJECT
public:
TiBingRoadMapProvider(QObject* parent = nullptr) :
TiBingMapProvider(QStringLiteral("png"), AVERAGE_BING_STREET_MAP, QGeoMapType::StreetMap, parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Bing Satellite Map
class TiBingSatelliteMapProvider : public TiBingMapProvider
{
Q_OBJECT
public:
TiBingSatelliteMapProvider(QObject* parent = nullptr) :
TiBingMapProvider(QStringLiteral("jpg"), AVERAGE_BING_SAT_MAP, QGeoMapType::SatelliteMapDay,
parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Bing Hybrid Map
class TiBingHybridMapProvider : public TiBingMapProvider
{
Q_OBJECT
public:
TiBingHybridMapProvider(QObject* parent = nullptr) :
TiBingMapProvider(QStringLiteral("jpg"), AVERAGE_BING_SAT_MAP, QGeoMapType::HybridMap, parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};

@ -0,0 +1,59 @@
#include "tiesrimapprovider.h"
TiEsriMapProvider::TiEsriMapProvider(const quint32 averageSize, const QGeoMapType::MapStyle mapType,
QObject* parent) :
TiMapProvider(QString(), averageSize, mapType, parent)
{
}
QNetworkRequest TiEsriMapProvider::getTileURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
//-- Build URL
QNetworkRequest request;
const QString url = getURL(x, y, zoom, networkManager);
if (url.isEmpty()) {
return request;
}
request.setUrl(QUrl(url));
request.setRawHeader(QByteArrayLiteral("Accept"), QByteArrayLiteral("*/*"));
const QByteArray token = "AAPK41e218608cc64bbfaecfd4243cb8fe6bkzEVp8H7IfCNN0M-uO-PU0-"
"Biah2W8IGndMLDnSBVj98ez-d388bBFoi9XkeXihU";
request.setRawHeader(QByteArrayLiteral("User-Agent"),
QByteArrayLiteral("Qt Location based application"));
request.setRawHeader(QByteArrayLiteral("User-Token"), token);
return request;
}
static const QString WorldStreetMapUrl
= QStringLiteral("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/"
"MapServer/tile/%1/%2/%3");
static const QString WorldSatelliteMapUrl
= QStringLiteral("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/"
"MapServer/tile/%1/%2/%3");
static const QString TerrainMapUrl
= QStringLiteral("http://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/"
"MapServer/tile/%1/%2/%3");
QString TiEsriWorldSatelliteMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
return WorldSatelliteMapUrl.arg(zoom).arg(y).arg(x);
}
QString TiEsriTerrainMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
return TerrainMapUrl.arg(zoom).arg(y).arg(x);
}
QString TiEsriWorldStreetMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
return WorldStreetMapUrl.arg(zoom).arg(y).arg(x);
}

@ -0,0 +1,54 @@
#pragma once
#include "timapprovider.h"
class TiEsriMapProvider : public TiMapProvider
{
Q_OBJECT
public:
TiEsriMapProvider(const quint32 averageSize, const QGeoMapType::MapStyle mapType,
QObject* parent = nullptr);
QNetworkRequest getTileURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
class TiEsriWorldStreetMapProvider : public TiEsriMapProvider
{
Q_OBJECT
public:
TiEsriWorldStreetMapProvider(QObject* parent = nullptr) :
TiEsriMapProvider(AVERAGE_TILE_SIZE, QGeoMapType::StreetMap, parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
class TiEsriWorldSatelliteMapProvider : public TiEsriMapProvider
{
Q_OBJECT
public:
TiEsriWorldSatelliteMapProvider(QObject* parent = nullptr) :
TiEsriMapProvider(AVERAGE_TILE_SIZE, QGeoMapType::SatelliteMapDay, parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
class TiEsriTerrainMapProvider : public TiEsriMapProvider
{
Q_OBJECT
public:
TiEsriTerrainMapProvider(QObject* parent = nullptr) :
TiEsriMapProvider(AVERAGE_TILE_SIZE, QGeoMapType::TerrainMap, parent)
{
}
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};

@ -0,0 +1,18 @@
#include "tigeotilefetcher.h"
#include "tiqgeotiledmapreply.h"
#include "timapprovider.h"
#include "tilogger.h"
#include "timapengine.h"
TiGeoTileFetcher::TiGeoTileFetcher(const QVariantMap& parameters, QGeoMappingManagerEngine* parent) :
QGeoTileFetcher(parent), m_networkManager(new QNetworkAccessManager(this))
{
}
//重写QGeoTileFetcher 的虚函数,由QGeoTileFetcher 调用
QGeoTiledMapReply* TiGeoTileFetcher::getTileImage(const QGeoTileSpec& spec)
{
QNetworkRequest request = TiMapEngine::instance()->getUrlEngine()->getTileUrl(
spec.mapId(), spec.x(), spec.y(), spec.zoom(), m_networkManager);
return new TiQGeoTiledMapReply(m_networkManager, request, spec);
}

@ -0,0 +1,18 @@
#pragma once
#include <private/qgeotilefetcher_p.h>
#include <QNetworkAccessManager>
class TiGeoTileFetcher : public QGeoTileFetcher
{
public:
TiGeoTileFetcher(const QVariantMap& parameters, QGeoMappingManagerEngine* parent);
// QGeoTileFetcher interface
private:
QGeoTiledMapReply* getTileImage(const QGeoTileSpec& spec) override;
private:
QNetworkAccessManager* m_networkManager = nullptr;
};

@ -0,0 +1,229 @@
#include "tigooglemapprovider.h"
#include <QNetworkProxy>
#include <QNetworkReply>
#include <QRegExp>
TiGoogleMapProvider::TiGoogleMapProvider(const QString& format, const quint32 averageSize,
const QGeoMapType::MapStyle mapType, QObject* parent) :
TiMapProvider(format, averageSize, mapType, parent)
{
// Google version strings
_versionGoogleMap = QStringLiteral("m@354000000");
_versionGoogleSatellite = QStringLiteral("692");
_versionGoogleLabels = QStringLiteral("h@336");
_versionGoogleTerrain = QStringLiteral("t@354,r@354000000");
_versionGoogleHybrid = QStringLiteral("y");
_secGoogleWord = QStringLiteral("Galileo");
}
void TiGoogleMapProvider::_networkReplyError(QNetworkReply::NetworkError error)
{
if (_googleReply) {
_googleReply->deleteLater();
_googleReply = nullptr;
}
}
void TiGoogleMapProvider::_googleVersionCompleted()
{
if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
qDebug() << "Error collecting Google maps version info";
return;
}
const QString html = QString(_googleReply->readAll());
#if defined(DEBUG_GOOGLE_MAPS)
QString filename = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
filename += QStringLiteral("/google.output");
QFile file(filename);
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << html << endl;
}
#endif
QRegExp reg(QStringLiteral("\"*https?://mt\\D?\\d..*/vt\\?lyrs=m@(\\d*)"), Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
_versionGoogleMap
= QString(QStringLiteral("m@%1")).arg(reg.capturedTexts().value(1, QString()));
}
reg = QRegExp(QStringLiteral("\"*https?://khm\\D?\\d.googleapis.com/kh\\?v=(\\d*)"),
Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
_versionGoogleSatellite = reg.capturedTexts().value(1);
}
reg = QRegExp(QStringLiteral("\"*https?://mt\\D?\\d..*/vt\\?lyrs=t@(\\d*),r@(\\d*)"),
Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) {
const QStringList gc = reg.capturedTexts();
_versionGoogleTerrain = QString(QStringLiteral("t@%1,r@%2")).arg(gc.value(1), gc.value(2));
}
_googleReply->deleteLater();
_googleReply = nullptr;
}
void TiGoogleMapProvider::_replyDestroyed()
{
_googleReply = nullptr;
}
void TiGoogleMapProvider::getSecGoogleWords(const int x, const int y, QString& sec1, QString& sec2) const
{
sec1 = QStringLiteral(""); // after &x=...
sec2 = QStringLiteral(""); // after &zoom=...
int seclen = ((x * 3) + y) % 8;
sec2 = _secGoogleWord.left(seclen);
if (y >= 10000 && y < 100000) {
sec1 = QStringLiteral("&s=");
}
}
void TiGoogleMapProvider::tryCorrectGoogleVersions(QNetworkAccessManager* networkManager)
{
QMutexLocker locker(&_googleVersionMutex);
if (_googleVersionRetrieved) {
return;
}
_googleVersionRetrieved = 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);
const QString url = QStringLiteral("http://maps.google.com/maps/api/js?v=3.2&sensor=false");
qheader.setUrl(QUrl(url));
QByteArray ua;
ua.append("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0");
qheader.setRawHeader("User-Agent", ua);
_googleReply = networkManager->get(qheader);
connect(_googleReply, &QNetworkReply::finished, this,
&TiGoogleMapProvider::_googleVersionCompleted);
connect(_googleReply, &QNetworkReply::destroyed, this, &TiGoogleMapProvider::_replyDestroyed);
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
connect(_googleReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &GoogleMapProvider::_networkReplyError);
#else
connect(_googleReply, &QNetworkReply::errorOccurred, this,
&TiGoogleMapProvider::_networkReplyError);
#endif
networkManager->setProxy(proxy);
}
}
QString TiGoogleStreetMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
// http://mt1.google.com/vt/lyrs=m
QString server = QStringLiteral("mt");
QString request = QStringLiteral("vt");
QString sec1; // after &x=...
QString sec2; // after &zoom=...
getSecGoogleWords(x, y, sec1, sec2);
tryCorrectGoogleVersions(networkManager);
return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
.arg(server)
.arg(getServerNum(x, y, 4))
.arg(request)
.arg(_versionGoogleMap)
.arg(m_language)
.arg(x)
.arg(sec1)
.arg(y)
.arg(zoom)
.arg(sec2);
}
QString TiGoogleSatelliteMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
// http://mt1.google.com/vt/lyrs=s
QString server = QStringLiteral("khm");
QString request = QStringLiteral("kh");
QString sec1; // after &x=...
QString sec2; // after &zoom=...
getSecGoogleWords(x, y, sec1, sec2);
tryCorrectGoogleVersions(networkManager);
return QString(QStringLiteral("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
.arg(server)
.arg(getServerNum(x, y, 4))
.arg(request)
.arg(_versionGoogleSatellite)
.arg(m_language)
.arg(x)
.arg(sec1)
.arg(y)
.arg(zoom)
.arg(sec2);
}
QString TiGoogleLabelsMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
QString server = "mts";
QString request = "vt";
QString sec1; // after &x=...
QString sec2; // after &zoom=...
getSecGoogleWords(x, y, sec1, sec2);
tryCorrectGoogleVersions(networkManager);
return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
.arg(server)
.arg(getServerNum(x, y, 4))
.arg(request)
.arg(_versionGoogleLabels)
.arg(m_language)
.arg(x)
.arg(sec1)
.arg(y)
.arg(zoom)
.arg(sec2);
}
QString TiGoogleTerrainMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
QString server = QStringLiteral("mt");
QString request = QStringLiteral("vt");
QString sec1; // after &x=...
QString sec2; // after &zoom=...
getSecGoogleWords(x, y, sec1, sec2);
tryCorrectGoogleVersions(networkManager);
return QString(QStringLiteral("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
.arg(server)
.arg(getServerNum(x, y, 4))
.arg(request)
.arg(_versionGoogleTerrain)
.arg(m_language)
.arg(x)
.arg(sec1)
.arg(y)
.arg(zoom)
.arg(sec2);
}
QString TiGoogleHybridMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
QString server = QStringLiteral("mt");
QString request = QStringLiteral("vt");
QString sec1; // after &x=...
QString sec2; // after &zoom=...
getSecGoogleWords(x, y, sec1, sec2);
tryCorrectGoogleVersions(networkManager);
return QString(QStringLiteral("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10"))
.arg(server)
.arg(getServerNum(x, y, 4))
.arg(request)
.arg(_versionGoogleHybrid)
.arg(m_language)
.arg(x)
.arg(sec1)
.arg(y)
.arg(zoom)
.arg(sec2);
}

@ -0,0 +1,133 @@
#pragma once
#include "timapprovider.h"
#include <QMutex>
#include <QNetworkReply>
class TiGoogleMapProvider : public TiMapProvider
{
Q_OBJECT
public:
TiGoogleMapProvider(const QString& format, const quint32 averageSize,
const QGeoMapType::MapStyle mapType = QGeoMapType::CustomMap,
QObject* parent = nullptr);
// Google Specific private slots
private slots:
void _networkReplyError(QNetworkReply::NetworkError error);
void _googleVersionCompleted();
void _replyDestroyed();
protected:
// Google Specific private methods
void getSecGoogleWords(const int x, const int y, QString& sec1, QString& sec2) const;
void tryCorrectGoogleVersions(QNetworkAccessManager* networkManager);
// Google Specific attributes
bool _googleVersionRetrieved;
QNetworkReply* _googleReply;
QMutex _googleVersionMutex;
QString _versionGoogleMap;
QString _versionGoogleSatellite;
QString _versionGoogleLabels;
QString _versionGoogleTerrain;
QString _versionGoogleHybrid;
QString _secGoogleWord;
};
static const quint32 AVERAGE_GOOGLE_STREET_MAP = 4913;
static const quint32 AVERAGE_GOOGLE_SAT_MAP = 56887;
static const quint32 AVERAGE_GOOGLE_TERRAIN_MAP = 19391;
// -----------------------------------------------------------
// Google Street Map
class TiGoogleStreetMapProvider : public TiGoogleMapProvider
{
Q_OBJECT
public:
TiGoogleStreetMapProvider(QObject* parent = nullptr) :
TiGoogleMapProvider(QStringLiteral("png"), AVERAGE_GOOGLE_STREET_MAP,
QGeoMapType::StreetMap, parent)
{
}
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Google Street Map
class TiGoogleSatelliteMapProvider : public TiGoogleMapProvider
{
Q_OBJECT
public:
TiGoogleSatelliteMapProvider(QObject* parent = nullptr) :
TiGoogleMapProvider(QStringLiteral("jpg"), AVERAGE_GOOGLE_SAT_MAP,
QGeoMapType::SatelliteMapDay, parent)
{
}
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Google Labels Map
class TiGoogleLabelsMapProvider : public TiGoogleMapProvider
{
Q_OBJECT
public:
TiGoogleLabelsMapProvider(QObject* parent = nullptr) :
TiGoogleMapProvider(QStringLiteral("png"), AVERAGE_TILE_SIZE, QGeoMapType::CustomMap, parent)
{
}
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Google Terrain Map
class TiGoogleTerrainMapProvider : public TiGoogleMapProvider
{
Q_OBJECT
public:
TiGoogleTerrainMapProvider(QObject* parent = nullptr) :
TiGoogleMapProvider(QStringLiteral("png"), AVERAGE_GOOGLE_TERRAIN_MAP,
QGeoMapType::TerrainMap, parent)
{
}
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
// -----------------------------------------------------------
// Google Hybrid Map
class TiGoogleHybridMapProvider : public TiGoogleMapProvider
{
Q_OBJECT
public:
TiGoogleHybridMapProvider(QObject* parent = nullptr) :
TiGoogleMapProvider(QStringLiteral("png"), AVERAGE_GOOGLE_SAT_MAP, QGeoMapType::HybridMap, parent)
{
}
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};

@ -0,0 +1,9 @@
{
"Keys": ["TiMap-maps"],
"Provider": "TiMap",
"Version": 100,
"Experimental": false,
"Features": [
"OnlineMappingFeature"
]
}

@ -0,0 +1,311 @@
#include "timapcacheworker.h"
#include <QSqlError>
#include <QSqlQuery>
#include "tilogger.h"
#include "timapengine.h"
#include "timapenginedata.h"
TiMapCacheWorker::TiMapCacheWorker() : m_db(nullptr), m_valid(false), m_isInit(false) { }
void TiMapCacheWorker::quit()
{
//线程退出也清理,防止未启用线程前添加的任务不能被释放的问题
QMutexLocker locker(&m_taskQueueMutex);
clear();
locker.unlock();
if (this->isRunning())
m_waitCond.wakeAll();
}
/**
* @brief TiMapCacheWorker::enqueueTask
* @param task
* @return
*/
bool TiMapCacheWorker::enqueueTask(TiMapTask* task)
{
//加锁,放入队列
QMutexLocker locker(&m_taskQueueMutex);
m_taskQueue.enqueue(task);
//线程已运行,唤醒任务
if (this->isRunning()) {
m_waitCond.wakeAll();
} else {
locker.unlock();
this->start(QThread::HighPriority);
}
return true;
}
void TiMapCacheWorker::setDBName(const QString& path)
{
if (m_dbPath != path)
m_dbPath = path;
}
void TiMapCacheWorker::run()
{
//如果数据库为无效的,初始化数据库
if (!m_isInit) {
init();
}
if (m_isInit) {
//打开数据库
openDB();
while (true) {
QMutexLocker locker(&m_taskQueueMutex);
if (!m_taskQueue.empty()) {
auto task = m_taskQueue.dequeue();
runTask(task);
task->deleteLater();
} else {
//队列为空,等待5s,5s后解除阻塞,如果还为空则退出线程
unsigned long timeoutMilliseconds = 5000;
m_waitCond.wait(locker.mutex(), timeoutMilliseconds);
if (m_taskQueue.empty())
break;
}
}
//关闭数据库
closeDB();
} else {
// init失败时,无法执行任务,需将队列中的任务删除
QMutexLocker locker(&m_taskQueueMutex);
clear();
}
}
void TiMapCacheWorker::runTask(TiMapTask* task)
{
switch (task->type()) {
case TiMapTask::taskInit:
break;
case TiMapTask::taskTestInternet:
break;
case TiMapTask::taskCacheTile:
saveTile(task);
break;
case TiMapTask::taskFetchTile:
getTile(task);
break;
}
}
/**
* @brief TiMapCacheWorker::clear
*/
void TiMapCacheWorker::clear()
{
while (!m_taskQueue.empty()) {
auto task = m_taskQueue.dequeue();
delete task;
}
}
/**
* @brief TiMapCacheWorker::init ,,,
* @return
*/
bool TiMapCacheWorker::init()
{
m_isInit = false;
if (!m_dbPath.isEmpty()) {
if (openDB()) {
m_isInit = createDB(*m_db);
} else {
LOG_WARN() << "can not open sql:" << m_db->lastError();
m_valid = false;
}
//创建完后,关闭数据库
closeDB();
} else {
LOG_CRIT() << "can not find sqlite path:" << m_dbPath;
m_valid = false;
}
if (!m_isInit)
m_valid = false;
return m_valid;
}
static const QString kSession = QStringLiteral("QGeoTileWorkerSession");
/**
* @brief TiMapCacheWorker::openDB
* @return false
*/
bool TiMapCacheWorker::openDB()
{
if (!m_valid) {
m_db.reset(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession)));
m_db->setDatabaseName(m_dbPath);
m_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
m_valid = m_db->open();
LOG_DEBUG() << "open DB:" << m_valid << m_dbPath;
}
return m_valid;
}
/**
* @brief TiMapCacheWorker::createDB ,
* @param db
* @param createDefault
* @return
*/
bool TiMapCacheWorker::createDB(QSqlDatabase& db, bool createDefault)
{
bool re = false;
QSqlQuery query(db);
re = query.exec("CREATE TABLE IF NOT EXISTS Tiles ("
"hash INTEGER PRIMARY KEY NOT NULL, "
"format TEXT NOT NULL, "
"tile BLOB NULL, "
"size INTEGER, "
"x INTEGER, "
"y INTEGER, "
"zoom INTEGER, "
"type INTEGER, "
"date INTEGER DEFAULT 0)");
if (!re) {
LOG_WARN() << "TiMap createDB Table error:" << query.lastError();
}
if (re) {
re = query.exec("CREATE INDEX IF NOT EXISTS Tiles_index ON Tiles (hash)");
if (!re) {
LOG_WARN() << "TiMap createDB Index error:" << query.lastError();
}
}
return re;
}
/**
* @brief TiMapCacheWorker::closeDB
*/
void TiMapCacheWorker::closeDB()
{
if (m_db && m_db->isOpen()) {
//关闭数据库
m_db->close();
m_db.reset();
//移除数据库时需释放
auto db = QSqlDatabase();
if (db.contains(kSession)) {
QSqlDatabase::removeDatabase(kSession);
}
m_valid = false;
}
}
/**
* @brief TiMapCacheWorker::testInternet internet
* ,TiMapEngine
*/
void TiMapCacheWorker::testInternet(TiMapTask* task)
{
if (!m_hostLookupID) {
m_hostLookupID = QHostInfo::lookupHost("www.baidu.com", this, [&](QHostInfo info) {
m_hostLookupID = 0;
auto _task = static_cast<TiMapTestInternetTask*>(task);
if (_task) {
if (info.error() == QHostInfo::NoError) {
// emit sigInternetState(true);
} else {
// emit sigInternetState(false);
}
}
});
}
}
/**
* @brief TiMapCacheWorker::testTask
* @param task
* @return
*/
bool TiMapCacheWorker::testTask(TiMapTask* task)
{
if (!m_valid) {
task->setError("Database Error!");
return false;
}
return true;
}
/**
* @brief TiMapCacheWorker::getTile tile
* @param task
*/
void TiMapCacheWorker::getTile(TiMapTask* task)
{
if (!testTask(task))
return;
auto _task = static_cast<TiMapFetchTileTask*>(task);
bool found = false;
if (_task) {
QSqlQuery query(*m_db);
QString sql
= QString("SELECT tile, format, size, x, y, zoom, type FROM Tiles WHERE hash = %1")
.arg(_task->hash());
if (query.exec(sql)) {
if (query.next()) {
auto img = query.value(0).toByteArray();
auto format = query.value(1).toString();
auto size = query.value(2).toUInt();
auto x = query.value(3).toInt();
auto y = query.value(4).toInt();
auto zoom = query.value(5).toUInt();
auto type = query.value(6).toString();
TiMapTile* tile = new TiMapTile(_task->hash());
tile->setFormat(format);
tile->setImg(img);
tile->setSize(size);
tile->setX(x);
tile->setY(y);
tile->setZoom(zoom);
tile->setType(type);
_task->setTileFetched(tile);
found = true;
}
}
if (!found) {
// LOG_WARN() << "not find tile hash:" << _task->hash();
_task->setError("tile not in cache database!");
}
}
}
void TiMapCacheWorker::saveTile(TiMapTask* task)
{
if (!testTask(task))
return;
auto _task = static_cast<TiMapSaveTileTask*>(task);
if (_task) {
QSqlQuery query(*m_db);
query.prepare(
"INSERT INTO Tiles(hash, format, tile, size, x, y, zoom, type, date) VALUES(?, "
"?, ?, ?, ?, ?, ?, ?, ?)");
query.addBindValue(_task->tile()->hash());
query.addBindValue(_task->tile()->format());
query.addBindValue(_task->tile()->img());
query.addBindValue(_task->tile()->img().size());
query.addBindValue(_task->tile()->x());
query.addBindValue(_task->tile()->y());
query.addBindValue(_task->tile()->zoom());
query.addBindValue(_task->tile()->type());
query.addBindValue(QDateTime::currentDateTime().toMSecsSinceEpoch());
if (query.exec()) {
//新的数据已存入
} else {
// Map数据已存在于数据库
}
}
}

@ -0,0 +1,49 @@
#pragma once
#include <QHostInfo>
#include <QMutex>
#include <QQueue>
#include <QSqlDatabase>
#include <QThread>
#include <QWaitCondition>
class TiMapTask;
/**
* @brief The TiMapCacheWorker class
* /\ 线
*/
class TiMapCacheWorker : public QThread
{
Q_OBJECT
public:
TiMapCacheWorker();
void quit();
bool enqueueTask(TiMapTask* task);
void setDBName(const QString& path);
// QThread interface
protected:
void run() override;
private:
void runTask(TiMapTask* task);
void clear();
bool init();
bool openDB();
bool createDB(QSqlDatabase& db, bool createDefault = true);
void closeDB();
void testInternet(TiMapTask* task);
bool testTask(TiMapTask* task);
void getTile(TiMapTask* task);
void saveTile(TiMapTask* task);
private:
QString m_dbPath;
QMutex m_taskQueueMutex;
QWaitCondition m_waitCond;
QQueue<TiMapTask*> m_taskQueue;
QScopedPointer<QSqlDatabase> m_db;
std::atomic_bool m_valid; // 数据库是否有效,有效指数据库打开并已初始化化
std::atomic_bool m_isInit;
int m_hostLookupID = 0;
};

@ -0,0 +1,133 @@
#include "timapengine.h"
#include "tilogger.h"
#include <QDir>
#include <QStandardPaths>
static const char* dbName = "TiMapCache.db";
TiMapEngine::TiMapEngine(QObject* parent) : QObject(parent)
{
m_internetState = false;
cacheCount = 0;
LOG_DEBUG() << "instance !";
qRegisterMetaType<TiMapTask::TaskType>();
init();
connect(&m_timer, &QTimer::timeout, this, &TiMapEngine::onTimeout);
testInternet();
m_mapUrlEngine = new TiMapUrlEngine(this);
}
TiMapEngine::~TiMapEngine()
{
m_worker.quit();
m_worker.wait();
}
/**
* @brief TiMapEngine::createFetchTileTask tile
* @param mapId
* @param x
* @param y
* @param zoom
* @return
*/
TiMapFetchTileTask* TiMapEngine::createFetchTileTask(int mapId, int x, int y, int zoom)
{
auto hash = getTileHash(mapId, x, y, zoom);
auto task = new TiMapFetchTileTask(hash);
return task;
}
/**
* @brief TiMapEngine::testInternet ,5s
*/
void TiMapEngine::testInternet()
{
if (m_timer.isActive())
return;
onTimeout();
}
void TiMapEngine::addTask(TiMapTask* task)
{
m_worker.enqueueTask(task);
}
void TiMapEngine::cacheTile(const QString& type, int x, int y, int zoom, const QByteArray& img,
const QString& format)
{
if (isCache()) {
auto mapid = getUrlEngine()->getIdFromType(type);
addTile(type, mapid, x, y, zoom, img, format);
}
}
void TiMapEngine::cacheTile(int mapId, int x, int y, int zoom, const QByteArray& img,
const QString& format)
{
if (isCache()) {
auto type = getUrlEngine()->getTypeFromId(mapId);
addTile(type, mapId, x, y, zoom, img, format);
}
}
/**
* @brief TiMapEngine::getTileHash tilehash
* @param mapId
* @param x
* @param y
* @param zoom
* @return
*/
quint32 TiMapEngine::getTileHash(int mapId, int x, int y, int zoom)
{
auto str = QString::asprintf("%010d%08d%08d%03d", mapId, x, y, zoom);
return qHash(str);
}
void TiMapEngine::init()
{
//初始化设置worker数据库路径
m_dbPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
+ QStringLiteral("/TiMap");
QDir di;
if (!di.exists(m_dbPath))
di.mkpath(m_dbPath);
m_dbName = dbName;
if (!m_dbPath.isEmpty() && !m_dbName.isEmpty()) {
m_worker.setDBName(m_dbPath + "/" + m_dbName);
}
}
void TiMapEngine::addTile(const QString& type, int mapid, int x, int y, int zoom,
const QByteArray& img, const QString& format)
{
auto tile = new TiMapTile(getTileHash(mapid, x, y, zoom));
tile->setFormat(format);
tile->setImg(img);
tile->setMapId(mapid);
tile->setType(type);
tile->setX(x);
tile->setY(y);
tile->setZoom(zoom);
auto task = new TiMapSaveTileTask(tile);
m_worker.enqueueTask(task);
}
void TiMapEngine::onTimeout()
{
m_timer.start(5000);
QHostInfo::lookupHost("www.baidu.com", this, [&](QHostInfo info) {
if (info.error() == QHostInfo::NoError) {
m_internetState = true;
LOG_INFO() << "internet online";
m_timer.stop();
} else {
m_internetState = false;
LOG_INFO() << "internet offline";
}
});
}

@ -0,0 +1,66 @@
#pragma once
#include <QObject>
#include <QTimer>
#include "timapcacheworker.h"
#include "timapenginedata.h"
#include "timapurlengine.h"
/**
* @brief The TiMapEngine class ,
*/
class TiMapEngine : public QObject
{
private:
TiMapEngine(QObject* parent = nullptr);
~TiMapEngine();
public:
static TiMapEngine* instance()
{
static TiMapEngine engine;
return &engine;
}
/**
* @brief getUrlEngine url,null
* @return
*/
TiMapUrlEngine* getUrlEngine() const { return m_mapUrlEngine; }
TiMapFetchTileTask* createFetchTileTask(int mapId, int x, int y, int zoom);
bool internetActive() const { return m_internetState; }
void testInternet();
QString getDBPath() const { return m_dbPath; }
QString getDBName() const { return m_dbName; }
void addTask(TiMapTask* task);
void cacheTile(const QString& type, int x, int y, int zoom, const QByteArray& img,
const QString& format);
void cacheTile(int mapId, int x, int y, int zoom, const QByteArray& img, const QString& format);
bool isCache() const { return m_isCache; }
void setCache(bool cache) { m_isCache = cache; }
static quint32 getTileHash(int mapId, int x, int y, int zoom);
std::atomic_int cacheCount;
private:
void init();
void addTile(const QString& type, int mapid, int x, int y, int zoom, const QByteArray& img,
const QString& format);
private slots:
void onTimeout();
private:
TiMapUrlEngine* m_mapUrlEngine = nullptr;
TiMapCacheWorker m_worker;
std::atomic_bool m_internetState;
QString m_dbPath;
QString m_dbName;
bool m_isCache = true;
QTimer m_timer;
};

@ -0,0 +1,119 @@
#pragma once
#include <QObject>
/**
* @brief The TiMapCacheTile class
*/
class TiMapTile : public QObject
{
Q_OBJECT
public:
explicit TiMapTile(uint hash) : m_hash(hash) { }
uint hash() const { return m_hash; }
QByteArray img() const { return m_img; }
int size() const { return m_size; }
QString format() const { return m_format; }
int x() const { return m_x; }
int y() const { return m_y; }
int zoom() const { return m_zoom; }
QString type() const { return m_type; }
int mapId() const { return m_mapId; }
void setImg(const QByteArray& img) { m_img = img; }
void setSize(int size) { m_size = size; }
void setFormat(const QString& format) { m_format = format; }
void setX(int x) { m_x = x; }
void setY(int y) { m_y = y; }
void setZoom(int z) { m_zoom = z; }
void setType(const QString& type) { m_type = type; }
void setMapId(int id) { m_mapId = id; }
private:
uint m_hash = 0; //由 x,y,zoom,type,计算得到的哈希值,具有tile的唯一性
QByteArray m_img; //瓦片具体数据
int m_size = 0; //瓦片数据大小
QString m_format; //瓦片格式
int m_x = 0; //瓦片x
int m_y = 0; //瓦片y
int m_zoom = 0; //瓦片zoom
QString m_type; //地图类型
int m_mapId = 0; //地图类型ID
};
/**
* @brief The TiMapTask class
*/
class TiMapTask : public QObject
{
Q_OBJECT
public:
enum TaskType { taskInit, taskTestInternet, taskCacheTile, taskFetchTile };
Q_ENUM(TaskType)
TiMapTask(TaskType type) : m_type(type) { }
virtual ~TiMapTask() { }
virtual TaskType type() { return m_type; }
void setError(QString errorString = QString()) { emit error(type(), errorString); }
signals:
void error(TiMapTask::TaskType type, QString errorString);
private:
TaskType m_type;
};
/**
* @brief The TiMapTestInternetTask class
*
*/
class TiMapTestInternetTask : public TiMapTask
{
Q_OBJECT
public:
TiMapTestInternetTask() : TiMapTask(TiMapTask::taskTestInternet) { }
};
/**
* @brief The TiMapFetchTileTask class tile()
*/
class TiMapFetchTileTask : public TiMapTask
{
Q_OBJECT
public:
TiMapFetchTileTask(uint hash) : TiMapTask(TiMapTask::taskFetchTile), m_hash(hash) { }
//设置已经获取到的tile
void setTileFetched(TiMapTile* tile) { emit tileFetched(tile); }
uint hash() const { return m_hash; }
signals:
void tileFetched(TiMapTile* tile);
private:
uint m_hash;
};
/**
* @brief The TiMapSaveTileTask class tile
*/
class TiMapSaveTileTask : public TiMapTask
{
Q_OBJECT
public:
TiMapSaveTileTask(TiMapTile* tile) : TiMapTask(TiMapTask::taskCacheTile), m_tile(tile) { }
~TiMapSaveTileTask()
{
if (m_tile) {
delete m_tile;
m_tile = nullptr;
}
}
TiMapTile* tile() const { return m_tile; }
private:
TiMapTile* m_tile = nullptr;
};

@ -0,0 +1,42 @@
#include "timapjsonengine.h"
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include "tilogger.h"
TiMapJsonEngine::TiMapJsonEngine(const QString& path, QObject* parent) : QObject(parent)
{
QDir dir("qrc:/");
LOG_DEBUG() << dir.absolutePath();
QFile loadFile(path);
if (!loadFile.open(QIODevice::ReadOnly)) {
LOG_DEBUG() << "json read error" << path;
return;
}
QByteArray saveData = loadFile.readAll();
loadFile.close();
QJsonParseError jsonError;
QJsonDocument loadDoc(QJsonDocument::fromJson(saveData, &jsonError));
if (jsonError.error != QJsonParseError::NoError)
return;
m_jsonObj = loadDoc.object();
LOG_DEBUG() << "json read success";
}
QString TiMapJsonEngine::getToken(const QString& provide)
{
QString re;
if (m_jsonObj.isEmpty())
return re;
if (m_jsonObj.contains(provide)) {
auto sub = m_jsonObj.value(provide).toObject();
re = sub.value("token").toString();
}
return re;
}

@ -0,0 +1,18 @@
#pragma once
#include <QJsonObject>
#include <QObject>
/**
* @brief The TiMapJsonEngine class
*/
class TiMapJsonEngine : public QObject
{
Q_OBJECT
public:
TiMapJsonEngine(const QString& path, QObject* parent = nullptr);
QString getToken(const QString& provide);
private:
QJsonObject m_jsonObj;
};

@ -0,0 +1,68 @@
#include "timapprovider.h"
// png,jpg,gif识别
static const unsigned char pngSignature[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00 };
static const unsigned char jpegSignature[] = { 0xFF, 0xD8, 0xFF, 0x00 };
static const unsigned char gifSignature[] = { 0x47, 0x49, 0x46, 0x38, 0x00 };
TiMapProvider::TiMapProvider(const QString& imageFormat, const quint32 averageSize,
const QGeoMapType::MapStyle mapType, QObject* parent) :
QObject(parent), m_mapType(mapType), m_imageFormat(imageFormat), m_averageSize(averageSize)
{
m_language = QStringLiteral("zh-CN");
}
QNetworkRequest TiMapProvider::getTileURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
QNetworkRequest request;
auto url = getURL(x, y, zoom, networkManager);
if (url.isEmpty())
return request;
request.setRawHeader(QByteArrayLiteral("Accept"), QByteArrayLiteral("text/html,image/*"));
request.setRawHeader(QByteArrayLiteral("User-Agent"),
QByteArrayLiteral("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"));
request.setUrl(QUrl(url));
return request;
}
QString TiMapProvider::getImageFormat(const QByteArray& image) const
{
QString format;
if (image.size() > 2) {
if (image.startsWith(reinterpret_cast<const char*>(pngSignature)))
format = QStringLiteral("png");
else if (image.startsWith(reinterpret_cast<const char*>(jpegSignature)))
format = QStringLiteral("jpg");
else if (image.startsWith(reinterpret_cast<const char*>(gifSignature)))
format = QStringLiteral("gif");
else {
return m_imageFormat;
}
}
return format;
}
QString TiMapProvider::tileXYToQuadKey(const int tileX, const int tileY, const int levelOfDetail) const
{
QString quadKey;
for (int i = levelOfDetail; i > 0; i--) {
char digit = '0';
const int mask = 1 << (i - 1);
if ((tileX & mask) != 0) {
digit++;
}
if ((tileY & mask) != 0) {
digit++;
digit++;
}
quadKey.append(digit);
}
return quadKey;
}
int TiMapProvider::getServerNum(const int x, const int y, const int max) const
{
return (x + 2 * y) % max;
}

@ -0,0 +1,45 @@
#pragma once
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QObject>
#include <private/qgeomaptype_p.h>
class TiMapProvider : public QObject
{
Q_OBJECT
public:
TiMapProvider(const QString& imageFormat, const quint32 averageSize,
const QGeoMapType::MapStyle mapType = QGeoMapType::CustomMap,
QObject* parent = nullptr);
/**
* @brief getTileURL
* @return ,使
*/
virtual QNetworkRequest getTileURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager);
virtual void setToken(const QString& token) { Q_UNUSED(token) }
virtual bool isElevationProvider() const { return false; }
virtual bool isBingProvider() const { return false; }
QGeoMapType::MapStyle getMapStyle() const { return m_mapType; }
QString getImageFormat(const QByteArray& image) const;
enum { AVERAGE_TILE_SIZE = 13652 };
protected:
virtual QString getURL(const int x, const int y, const int zoom, QNetworkAccessManager* networkManager)
= 0;
QString tileXYToQuadKey(const int tileX, const int tileY, const int levelOfDetail) const;
int getServerNum(const int x, const int y, const int max) const;
protected:
QGeoMapType::MapStyle m_mapType;
QString m_referrer;
QString m_imageFormat;
quint32 m_averageSize;
QByteArray m_userAgent;
QString m_language;
};

@ -0,0 +1,136 @@
#include "timapurlengine.h"
#include "titianditumapprovider.h"
#include "tigooglemapprovider.h"
#include "tiesrimapprovider.h"
#include "tibingmapprovider.h"
#include "tilogger.h"
TiMapUrlEngine::TiMapUrlEngine(QObject* parent) : QObject(parent)
{
m_providerNameList["Bing Road"] = "";
m_providerNameList["Bing Satellite"] = "";
m_providerNameList["Bing Hybrid"] = "";
m_providerNameList["Google Street Map"] = "";
m_providerNameList["Google Satellite"] = "";
m_providerNameList["Google Terrain"] = "";
m_providerNameList["Google Hybrid"] = "";
m_providerNameList["Google Labels"] = "";
m_providerNameList["Tianditu Satellite"] = "Tianditu Satellite Road";
m_providerNameList["Tianditu Street"] = "Tianditu Street Road";
m_providerList.append(
ProviderPair("Tianditu Satellite", new TiTiandituImgMapProvider(this))); //天地图卫星图
m_providerList.append(ProviderPair("Tianditu Satellite Road",
new TiTiandituCiaMapProvider(this))); //天地图路网标注信息图
m_providerList.append(
ProviderPair("Tianditu Street", new TiTiandituVecMapProvider(this))); //失量图
m_providerList.append(
ProviderPair("Tianditu Street Road", new TiTiandituCvaMapProvider(this))); //失量图标注
m_providerList.append(ProviderPair("Google Street Map", new TiGoogleStreetMapProvider(this)));
m_providerList.append(ProviderPair("Google Satellite", new TiGoogleSatelliteMapProvider(this)));
m_providerList.append(ProviderPair("Google Terrain", new TiGoogleTerrainMapProvider(this)));
m_providerList.append(ProviderPair("Google Hybrid", new TiGoogleHybridMapProvider(this)));
m_providerList.append(ProviderPair("Google Labels", new TiGoogleTerrainMapProvider(this)));
m_providerList.append(ProviderPair("Bing Road", new TiBingRoadMapProvider(this)));
m_providerList.append(ProviderPair("Bing Satellite", new TiBingSatelliteMapProvider(this)));
m_providerList.append(ProviderPair("Bing Hybrid", new TiBingHybridMapProvider(this)));
}
QMap<QString, QString> TiMapUrlEngine::getProviderNameList() const
{
return m_providerNameList;
}
QString TiMapUrlEngine::getTypeFromId(const int id) const
{
if (id >= 1 && id <= m_providerList.size()) {
return m_providerList.at(id - 1).first;
} else {
return m_providerList.at(0).first;
}
}
int TiMapUrlEngine::getIdFromType(const QString& type) const
{
for (int i = 0; i < m_providerList.size(); i++) {
if (m_providerList.at(i).first == type) {
return i + 1;
}
}
return 1;
}
TiMapProvider* TiMapUrlEngine::getMapProviderFromId(int id) const
{
if (id >= 1 && id <= m_providerList.count()) {
return m_providerList.at(id - 1).second;
} else {
return nullptr;
}
}
TiMapProvider* TiMapUrlEngine::getMapProviderFromType(const QString& type) const
{
for (int i = 0; i < m_providerList.size(); i++) {
if (m_providerList.at(i).first == type) {
return m_providerList.at(i).second;
}
}
return nullptr;
}
QNetworkRequest TiMapUrlEngine::getTileUrl(int id, int x, int y, int zoom,
QNetworkAccessManager* networkManager) const
{
auto _provide = getMapProviderFromId(id);
if (_provide)
return _provide->getTileURL(x, y, zoom, networkManager);
LOG_WARN() << "map not registered:" << getTypeFromId(id);
return QNetworkRequest(QUrl());
}
QNetworkRequest TiMapUrlEngine::getTileUrl(const QString& type, int x, int y, int zoom,
QNetworkAccessManager* networkManager) const
{
auto _provide = getMapProviderFromType(type);
if (_provide)
return _provide->getTileURL(x, y, zoom, networkManager);
LOG_WARN() << "map not registered:" << type;
return QNetworkRequest(QUrl());
}
QString TiMapUrlEngine::getImageFormat(QString type, const QByteArray& image)
{
auto _provide = getMapProviderFromType(type);
if (_provide) {
return _provide->getImageFormat(image);
}
LOG_WARN() << "map not find ByteArray format";
return "";
}
QString TiMapUrlEngine::getImageFormat(int id, const QByteArray& image)
{
auto _provide = getMapProviderFromId(id);
if (_provide) {
return _provide->getImageFormat(image);
}
LOG_WARN() << "map not find ByteArray format";
return "";
}
/**
* @brief TiMapUrlEngine::isElevation
* @param mapId
* @return ,false
*/
bool TiMapUrlEngine::isElevation(int mapId)
{
auto _provide = getMapProviderFromId(mapId);
if (_provide)
return _provide->isElevationProvider();
return false;
}

@ -0,0 +1,36 @@
#pragma once
#include <QHash>
#include <QNetworkAccessManager>
#include <QObject>
class TiMapProvider;
/**
* @brief The TiMapUrlEngine class
* hash map
*/
class TiMapUrlEngine : public QObject
{
Q_OBJECT
public:
TiMapUrlEngine(QObject* parent = nullptr);
typedef QPair<QString, TiMapProvider*> ProviderPair;
QMap<QString, QString> getProviderNameList() const;
QString getTypeFromId(const int id) const;
int getIdFromType(const QString& type) const;
TiMapProvider* getMapProviderFromId(int id) const;
TiMapProvider* getMapProviderFromType(const QString& type) const;
QNetworkRequest getTileUrl(int id, int x, int y, int zoom,
QNetworkAccessManager* networkManager) const;
QNetworkRequest getTileUrl(const QString& type, int x, int y, int zoom,
QNetworkAccessManager* networkManager) const;
QString getImageFormat(QString type, const QByteArray& image);
QString getImageFormat(int id, const QByteArray& image);
bool isElevation(int mapId);
private:
QList<ProviderPair> m_providerList;
QMap<QString, QString> m_providerNameList;
};

@ -0,0 +1,49 @@
#include "tiqgeocodereply.h"
#include "tilogger.h"
#include <QJsonDocument>
#include <QJsonObject>
TiQGeoCodeReply::TiQGeoCodeReply(QNetworkReply* reply, QObject* parent) :
QGeoCodeReply(parent), m_reply(reply)
{
connect(m_reply, &QNetworkReply::finished, this, &TiQGeoCodeReply::networkReplyFinish);
connect(m_reply, &QNetworkReply::errorOccurred, this, &TiQGeoCodeReply::networkReplyError);
//将来自每个数据源的响应数量的限制设置为限制。
setLimit(1);
//设置整个结果集中的偏移量,从该偏移量开始将结果取到偏移量。
setOffset(0);
}
TiQGeoCodeReply::~TiQGeoCodeReply()
{
if (m_reply)
m_reply->deleteLater();
}
void TiQGeoCodeReply::networkReplyFinish()
{
if (!m_reply)
return;
if (m_reply->error() != QNetworkReply::NoError)
return;
QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll());
QJsonObject object = document.object();
const QString sta = QStringLiteral("status");
if (object.value(sta) != QStringLiteral("OK")) {
QString error = object.value(sta).toString();
LOG_DEBUG() << m_reply->url() << "returned :" << error;
setError(QGeoCodeReply::CommunicationError, error);
m_reply->deleteLater();
m_reply = nullptr;
return;
}
}
void TiQGeoCodeReply::networkReplyError(QNetworkReply::NetworkError error) { }

@ -0,0 +1,19 @@
#pragma once
#include <QGeoCodeReply>
#include <QNetworkReply>
class TiQGeoCodeReply : public QGeoCodeReply
{
Q_OBJECT
public:
explicit TiQGeoCodeReply(QNetworkReply* reply, QObject* parent = nullptr);
~TiQGeoCodeReply();
private slots:
void networkReplyFinish();
void networkReplyError(QNetworkReply::NetworkError error);
private:
QNetworkReply* m_reply;
};

@ -0,0 +1,183 @@
#include "tiqgeofiletilecache.h"
#include "tilogger.h"
#include "timapengine.h"
#include <QSqlQuery>
#include <QSqlError>
TiQGeoFileTileCache::TiQGeoFileTileCache(const QString& directory, QObject* parent) :
QGeoFileTileCache(directory, parent)
{
}
TiQGeoFileTileCache::~TiQGeoFileTileCache()
{
if (m_db) {
if (m_db->isOpen())
m_db->close();
delete m_db;
m_db = nullptr;
}
}
QSharedPointer<QGeoTileTexture> TiQGeoFileTileCache::get(const QGeoTileSpec& spec)
{
QSharedPointer<QGeoTileTexture> tt = getFromMemory(spec);
if (tt)
return tt;
// return getFromSqlite(spec);
return getFromDisk(spec);
}
void TiQGeoFileTileCache::insert(const QGeoTileSpec& spec, const QByteArray& bytes,
const QString& format, CacheAreas areas)
{
if (bytes.isEmpty())
return;
if (areas & QAbstractGeoTileCache::DiskCache) {
// QString filename = tileSpecToFilename(spec, format, directory_);
// addToSqlite(spec, format, bytes);
}
if (areas & QAbstractGeoTileCache::MemoryCache) {
addToMemoryCache(spec, bytes, format);
}
/* inserts do not hit the texture cache -- this actually reduces overall
* cache hit rates because many tiles come too late to be useful
* and act as a poison */
}
void TiQGeoFileTileCache::addToSqlite(const QGeoTileSpec& spec, const QString& format,
const QByteArray& bytes)
{
if (!m_valid) {
auto _connectId = TiMapEngine::instance()->getUrlEngine()->getTypeFromId(spec.mapId());
m_valid = openSqlite(_connectId);
}
if (!m_valid)
return;
QSqlQuery query(*m_db);
query.prepare("INSERT INTO Tiles(hash, format, tile, size, x, y, zoom, type, date) VALUES(?, "
"?, ?, ?, ?, ?, ?, ?, ?)");
// 参见QAbstractGeoTileCache类的头文件中 "qgeotilespec_p.h" 中包含 qHash
// unsigned int qHash(const QGeoTileSpec& spec)
// {
// unsigned int result = (qHash(spec.plugin()) * 13) % 31;
// result += ((spec.mapId() * 17) % 31) << 5;
// result += ((spec.zoom() * 19) % 31) << 10;
// result += ((spec.x() * 23) % 31) << 15;
// result += ((spec.y() * 29) % 31) << 20;
// result += (spec.version() % 3) << 25;
// return result;
// }
query.addBindValue(getTileHash(spec.mapId(), spec.x(), spec.y(), spec.zoom()));
query.addBindValue(format);
query.addBindValue(bytes);
query.addBindValue(bytes.size());
query.addBindValue(spec.x());
query.addBindValue(spec.y());
query.addBindValue(spec.zoom());
query.addBindValue(spec.mapId());
query.addBindValue(QDateTime::currentDateTime().toMSecsSinceEpoch());
if (query.exec()) {
//新的数据已存入
} else {
// Map数据已存在于数据库
}
}
QSharedPointer<QGeoTileTexture> TiQGeoFileTileCache::getFromSqlite(const QGeoTileSpec& spec)
{
if (!m_valid) {
auto _connectId = TiMapEngine::instance()->getUrlEngine()->getTypeFromId(spec.mapId());
m_valid = openSqlite(_connectId);
}
if (!m_valid)
return QSharedPointer<QGeoTileTexture>();
bool found = false;
QByteArray byte;
QString format;
QSqlQuery query(*m_db);
QString sql = QString("SELECT tile, format, type FROM Tiles WHERE hash = \"%1\"")
.arg(getTileHash(spec.mapId(), spec.x(), spec.y(), spec.zoom()));
if (query.exec(sql)) {
if (query.next()) {
byte = query.value(0).toByteArray();
format = query.value(1).toString();
found = true;
}
}
if (found) {
QImage image;
// Some tiles from the servers could be valid images but the tile fetcher
// might be able to recognize them as tiles that should not be shown.
// If that's the case, the tile fetcher should write "NoRetry" inside the file.
if (isTileBogus(byte)) {
QSharedPointer<QGeoTileTexture> tt(new QGeoTileTexture);
tt->spec = spec;
tt->image = image;
return tt;
}
// This is a truly invalid image. The fetcher should try again.
if (!image.loadFromData(byte)) {
handleError(spec, QLatin1String("Problem with tile image"));
return QSharedPointer<QGeoTileTexture>(0);
}
// Converting it here, instead of in each QSGTexture::bind()
if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied)
image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
addToMemoryCache(spec, byte, format);
QSharedPointer<QGeoTileTexture> tt = addToTextureCache(spec, image);
if (tt) {
return tt;
}
}
return QSharedPointer<QGeoTileTexture>();
}
quint64 TiQGeoFileTileCache::getTileHash(int type, int x, int y, int z)
{
QString str = QString().asprintf("%03d%08d%08d%03d", type, x, y, z);
quint64 value = qHash(str);
return value;
}
bool TiQGeoFileTileCache::openSqlite(const QString& connectId)
{
if (m_db)
return false;
m_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", connectId));
QString dbname = directory() + "/" + m_dbName;
m_db->setDatabaseName(dbname);
m_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
bool re = m_db->open();
if (!re) {
LOG_DEBUG() << "sqlite can not open!";
delete m_db;
m_db = nullptr;
return false;
}
LOG_INFO() << "open db:" << dbname;
QSqlQuery query(*m_db);
if (!query.exec("CREATE TABLE IF NOT EXISTS Tiles ("
"hash INTEGER PRIMARY KEY NOT NULL, "
"format TEXT NOT NULL, "
"tile BLOB NULL, "
"size INTEGER, "
"x INTEGER, "
"y INTEGER, "
"zoom INTEGER, "
"type INTEGER, "
"date INTEGER DEFAULT 0)")) {
LOG_WARN() << "Map Cache Sql error(createDB Tiles):" << query.lastError().text();
}
return true;
}

@ -0,0 +1,32 @@
#pragma once
#include <private/qgeofiletilecache_p.h>
#include <QSqlDatabase>
class TiQGeoFileTileCache : public QGeoFileTileCache
{
public:
TiQGeoFileTileCache(const QString& directory = QString(), QObject* parent = nullptr);
~TiQGeoFileTileCache();
QSharedPointer<QGeoTileTexture> get(const QGeoTileSpec& spec) override;
void insert(const QGeoTileSpec& spec, const QByteArray& bytes, const QString& format,
QAbstractGeoTileCache::CacheAreas areas = QAbstractGeoTileCache::AllCaches) override;
private:
void addToSqlite(const QGeoTileSpec& spec, const QString& format, const QByteArray& bytes);
QSharedPointer<QGeoTileTexture> getFromSqlite(const QGeoTileSpec& spec);
//由于qtlocation提供的qhash计算出现错误的机率较大,因此我们自已计算hash
static quint64 getTileHash(int type, int x, int y, int z);
bool openSqlite(const QString& connectId);
private:
QSqlDatabase* m_db = nullptr;
bool m_valid = false;
QString m_dbName = "TiMapCache.db";
};

@ -0,0 +1,18 @@
#include "tiqgeoserviceproviderfactory.h"
#include "tiqgeotiledmappingmanagerengine.h"
QT_BEGIN_NAMESPACE
TiQGeoServiceProviderFactory::TiQGeoServiceProviderFactory()
{
}
QGeoMappingManagerEngine* TiQGeoServiceProviderFactory::createMappingManagerEngine(
const QVariantMap& parameters, QGeoServiceProvider::Error* error, QString* errorString) const
{
return new TiQGeoTiledMappingManagerEngine(parameters, error, errorString);
}
QT_END_NAMESPACE

@ -0,0 +1,22 @@
#pragma once
#include <QGeoServiceProviderFactory>
#include <QObject>
#include <QtPlugin>
QT_BEGIN_NAMESPACE
class TiQGeoServiceProviderFactory : public QObject, public QGeoServiceProviderFactory
{
Q_OBJECT
Q_INTERFACES(QGeoServiceProviderFactory)
Q_PLUGIN_METADATA(IID "org.qt-project.qt.geoservice.serviceproviderfactory/6.0" FILE
"timap_plugin.json")
public:
TiQGeoServiceProviderFactory();
// QGeoServiceProviderFactory interface
public:
QGeoMappingManagerEngine* createMappingManagerEngine(const QVariantMap& parameters,
QGeoServiceProvider::Error* error,
QString* errorString) const override;
};
QT_END_NAMESPACE

@ -0,0 +1,105 @@
#include "tiqgeotiledmappingmanagerengine.h"
#include "tigeotilefetcher.h"
#include "tilogger.h"
#include "tiqgeofiletilecache.h"
#include <private/qgeocameracapabilities_p.h>
#include <private/qgeofiletilecache_p.h>
#include "timapengine.h"
#include "timapprovider.h"
TiQGeoTiledMappingManagerEngine::TiQGeoTiledMappingManagerEngine(const QVariantMap& parameters,
QGeoServiceProvider::Error* error,
QString* errorString)
{
TiMapEngine::instance();
QGeoCameraCapabilities cameraCaps;
cameraCaps.setMinimumZoomLevel(2.0);
cameraCaps.setMaximumZoomLevel(20.0);
cameraCaps.setSupportsBearing(true);
cameraCaps.setSupportsTilting(true);
cameraCaps.setMinimumTilt(0);
cameraCaps.setMaximumTilt(80);
cameraCaps.setMinimumFieldOfView(20.0);
cameraCaps.setMaximumFieldOfView(120.0);
cameraCaps.setOverzoomEnabled(true);
setCameraCapabilities(cameraCaps);
setTileSize(QSize(256, 256));
QByteArray mapName = "TiMap";
// qt6 中qtlocation 的mapid必须从1开始,有序是因为我们这里使用的是list
int mapid = 1;
auto urlFactory = TiMapEngine::instance()->getUrlEngine();
auto provider = urlFactory->getMapProviderFromId(mapid);
QList<QGeoMapType> _mapList;
while (provider) {
QString providerType = urlFactory->getTypeFromId(mapid);
_mapList.append(QGeoMapType(provider->getMapStyle(),
providerType,
providerType,
false,
false,
mapid++,
mapName,
cameraCaps));
provider = urlFactory->getMapProviderFromId(mapid);
LOG_DEBUG() << providerType;
}
setSupportedMapTypes(_mapList);
//从网络中加载瓦片
auto tileFetcher = new TiGeoTileFetcher(parameters, this);
setTileFetcher(tileFetcher);
//瓦片缓存-这部分参考QtLocation的esri部分源码
//没有用QGeoFileTileCache默认加载地缓存不会释放还没找到原因估计要分析它的源码
QString cacheDirectory;
QString _cache = "cachePath";
if (parameters.contains(_cache)) {
cacheDirectory = TiMapEngine::instance()->getDBPath();
} else {
cacheDirectory = QAbstractGeoTileCache::baseLocationCacheDirectory() + QString("MapCache");
}
LOG_DEBUG() << cacheDirectory;
//设置地图缓冲,如果不需要缓存,可设置setMaxDiskUsage 大小,限制到小内存,,
//无法 注释setTileCache(); 注释后会默认缓冲图片
// QGeoFileTileCache* tileCache = new QGeoFileTileCache(cacheDirectory, this);
auto tileCache = new TiQGeoFileTileCache(cacheDirectory, this);
tileCache->setMaxDiskUsage(1024 * 1024);
tileCache->setMaxMemoryUsage(1024 * 1024 * 100);
setTileCache(tileCache);
/*
* Disk cache setup -- defaults to ByteSize (old behavior)
*/
// tileCache->setCostStrategyDisk(QGeoFileTileCache::ByteSize);
/*
* Memory cache setup -- defaults to ByteSize (old behavior)
*/
// tileCache->setCostStrategyMemory(QGeoFileTileCache::ByteSize);
/*
* Texture cache setup -- defaults to ByteSize (old behavior)
*/
// tileCache->setCostStrategyTexture(QGeoFileTileCache::ByteSize);
m_prefetchStyle = QGeoTiledMap::NoPrefetching;
*error = QGeoServiceProvider::NoError;
errorString->clear();
}
TiQGeoTiledMappingManagerEngine::~TiQGeoTiledMappingManagerEngine() { }
QGeoMap* TiQGeoTiledMappingManagerEngine::createMap()
{
auto map = new QGeoTiledMap(this, nullptr);
map->setPrefetchStyle(m_prefetchStyle);
return map;
}
void TiQGeoTiledMappingManagerEngine::setCache(const QVariant& parameters) { }

@ -0,0 +1,16 @@
#pragma once
#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/private/qgeotiledmappingmanagerengine_p.h>
class TiQGeoTiledMappingManagerEngine : public QGeoTiledMappingManagerEngine
{
public:
TiQGeoTiledMappingManagerEngine(const QVariantMap& parameters,
QGeoServiceProvider::Error* error, QString* errorString);
~TiQGeoTiledMappingManagerEngine();
QGeoMap* createMap() override;
private:
void setCache(const QVariant& parameters);
};

@ -0,0 +1,186 @@
#include "tiqgeotiledmapreply.h"
#include "tilogger.h"
#include "timapengine.h"
#include "timapprovider.h"
#include <private/qgeotilespec_p.h>
TiQGeoTiledMapReply::TiQGeoTiledMapReply(QNetworkAccessManager* networkManger,
const QNetworkRequest& request, const QGeoTileSpec& spec,
QObject* parent) :
QGeoTiledMapReply(spec, parent), m_reply(nullptr), m_request(request), m_networkManager(networkManger)
{
//如果请求地址为空,显示空白tile
if (m_request.url().isEmpty()) {
if (!m_noTitle.size()) {
QFile fi(":/resources/TiMapImage/notile.png");
if (fi.open(QFile::ReadOnly))
m_noTitle = fi.readAll();
}
setMapImageData(m_noTitle);
setMapImageFormat("png");
setFinished(true);
setCached(false);
} else {
//如果地址不为空,从本地数据库获取tile
auto task = TiMapEngine::instance()->createFetchTileTask(spec.mapId(), spec.x(), spec.y(),
spec.zoom());
connect(task, &TiMapFetchTileTask::tileFetched, this, &TiQGeoTiledMapReply::onCacheReply);
connect(task, &TiMapFetchTileTask::error, this, &TiQGeoTiledMapReply::onCacheError);
TiMapEngine::instance()->addTask(task);
}
}
TiQGeoTiledMapReply::~TiQGeoTiledMapReply()
{
closeReply();
}
void TiQGeoTiledMapReply::abort()
{
m_timer.stop();
if (m_reply)
m_reply->abort();
emit aborted();
}
/**
* @brief TiQGeoTiledMapReply::networkReplyFinished tile
*/
void TiQGeoTiledMapReply::networkReplyFinished()
{
//定时器还在运行,停止
m_timer.stop();
//可能已是获取超时
if (!m_reply) {
LOG_DEBUG() << "reply null:" << hash();
emit aborted();
return;
}
//获取错误
if (m_reply->error() != QNetworkReply::NoError) {
LOG_DEBUG() << "reply error:" << hash();
emit aborted();
return;
}
//获取到tile
auto img = m_reply->readAll();
QString format = TiMapEngine::instance()->getUrlEngine()->getImageFormat(tileSpec().mapId(), img);
//判断是否是高程服务
auto isElv = TiMapEngine::instance()->getUrlEngine()->isElevation(tileSpec().mapId());
if (isElv) {
LOG_DEBUG() << "isElv:" << hash();
} else {
//非高程数据
auto mapProvider
= TiMapEngine::instance()->getUrlEngine()->getMapProviderFromId(tileSpec().mapId());
//可放大的图层
if (mapProvider && mapProvider->isBingProvider() && img.size()) {
setError(QGeoTiledMapReply::CommunicationError, "Bing tile above zoom level");
LOG_DEBUG() << "bing :" << hash();
} else {
//正常图层
setMapImageData(img);
if (!format.isEmpty()) {
setMapImageFormat(format);
// LOG_DEBUG() << "write database:" << hash() << (TiMapEngine::instance()->cacheCount);
//缓冲到数据库
TiMapEngine::instance()->cacheTile(tileSpec().mapId(), tileSpec().x(),
tileSpec().y(), tileSpec().zoom(), img, format);
} else {
LOG_DEBUG() << "format null:" << hash();
}
}
setFinished(true);
}
closeReply();
}
void TiQGeoTiledMapReply::networkReplyError(QNetworkReply::NetworkError error)
{
m_timer.stop();
LOG_DEBUG() << "reply error:" << hash();
if (!m_reply) {
return;
}
LOG_DEBUG() << "reply error:" << error << hash();
setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
TiMapEngine::instance()->testInternet();
setFinished(true);
closeReply();
}
/**
* @brief TiQGeoTiledMapReply::onCacheReply tile
* @param tile
*/
void TiQGeoTiledMapReply::onCacheReply(TiMapTile *tile)
{
if (tile->x() == tileSpec().x() && tile->y() == tileSpec().y()
&& tile->zoom() == tileSpec().zoom()) {
setMapImageFormat(tile->format());
setMapImageData(tile->img());
setFinished(true);
setCached(true);
}
tile->deleteLater();
}
/**
* @brief TiQGeoTiledMapReply::onCacheError tile error
* @param type
* @param errorString
*/
void TiQGeoTiledMapReply::onCacheError(TiMapTask::TaskType type, QString errorString)
{
//无网络
if (!TiMapEngine::instance()->internetActive()) {
TiMapEngine::instance()->testInternet();
LOG_DEBUG() << "no internet:" << hash();
setFinished(true);
} else { //网络正常
m_reply = m_networkManager->get(m_request);
m_reply->setParent(nullptr);
//接收结束后,读取接收到的数据
connect(m_reply, &QNetworkReply::finished, this, &TiQGeoTiledMapReply::networkReplyFinished);
//发生错误时,释放reply
connect(m_reply, &QNetworkReply::errorOccurred, this, &TiQGeoTiledMapReply::networkReplyError);
//防止m_reply不会释放造成内存泄露,改为由析构函数释放
// connect(this, &TiQGeoTiledMapReply::destroyed, m_reply, &QNetworkReply::deleteLater);
//等待10秒的时间获取tile,超时后结束获取
connect(&m_timer, &QTimer::timeout, this, &TiQGeoTiledMapReply::onTimeout);
m_timer.setSingleShot(true);
m_timer.start(10000);
}
}
void TiQGeoTiledMapReply::onTimeout()
{
closeReply();
emit aborted();
LOG_DEBUG() << "timeout:" << hash();
}
void TiQGeoTiledMapReply::closeReply()
{
m_timer.stop();
if (m_reply) {
m_reply->deleteLater();
m_reply = nullptr;
}
}
quint32 TiQGeoTiledMapReply::hash()
{
return TiMapEngine::instance()->getTileHash(tileSpec().mapId(), tileSpec().x(), tileSpec().y(),
tileSpec().zoom());
}

@ -0,0 +1,37 @@
#pragma once
#include <private/qgeotiledmapreply_p.h>
#include <QNetworkReply>
#include <QTimer>
#include "timapengine.h"
class TiQGeoTiledMapReply : public QGeoTiledMapReply
{
Q_OBJECT
public:
TiQGeoTiledMapReply(QNetworkAccessManager* networkManger, const QNetworkRequest& reply,
const QGeoTileSpec& spec, QObject* parent = nullptr);
~TiQGeoTiledMapReply();
void abort() override;
private slots:
void networkReplyFinished();
void networkReplyError(QNetworkReply::NetworkError error);
void onCacheReply(TiMapTile* tile);
void onCacheError(TiMapTask::TaskType type, QString errorString);
void onTimeout();
private:
void closeReply();
quint32 hash();
private:
QNetworkReply* m_reply;
QNetworkRequest m_request;
QNetworkAccessManager* m_networkManager;
QByteArray m_noTitle;
QTimer m_timer;
};

@ -0,0 +1,117 @@
#include "titianditumapprovider.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include "timapengine.h"
#include "tilogger.h"
//天地图密钥
static const char* token = "1c5b7cbf9da7d33b221f68c32b6a1791";
TiTiandituMapProvider::TiTiandituMapProvider(const QString& format, const quint32 averageSize,
const QGeoMapType::MapStyle mapType, QObject* parent) :
TiMapProvider(format, averageSize, mapType, parent)
{
}
void TiTiandituMapProvider::setToken(const QString& token)
{
if (token.isEmpty() && token == m_token)
return;
m_token = token;
}
static const QString tiandituImg
= QStringLiteral("http://t6.tianditu.gov.cn/img_w/"
"wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&"
"TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=%1&TILEROW=%2&TILECOL=%3&tk=%4");
TiTiandituImgMapProvider::TiTiandituImgMapProvider(QObject* parent) :
TiTiandituMapProvider("png", AVERAGE_TILE_SIZE, QGeoMapType::SatelliteMapDay, parent)
{
setToken(token);
}
TiTiandituImgMapProvider::~TiTiandituImgMapProvider() { }
QString TiTiandituImgMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString xx = QString("%1").arg(x);
const QString yy = QString("%1").arg(y);
const QString zz = QString("%1").arg(zoom);
return tiandituImg.arg(zz, yy, xx, m_token);
}
static const QString tiandituCia
= QStringLiteral("http://t6.tianditu.gov.cn/cia_w/"
"wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&"
"TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=%1&TILEROW=%2&TILECOL=%3&tk=%4");
TiTiandituCiaMapProvider::TiTiandituCiaMapProvider(QObject* parent) :
TiTiandituMapProvider("png", AVERAGE_TILE_SIZE, QGeoMapType::StreetMap, parent)
{
setToken(token);
}
TiTiandituCiaMapProvider::~TiTiandituCiaMapProvider() { }
QString TiTiandituCiaMapProvider::getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString xx = QString("%1").arg(x);
const QString yy = QString("%1").arg(y);
const QString zz = QString("%1").arg(zoom);
return tiandituCia.arg(zz, yy, xx, m_token);
}
static const QString tiandituVec = QStringLiteral(
"http://t6.tianditu.gov.cn/vec_w/"
"wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&"
"TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=%1&TILEROW=%2&TILECOL=%3&tk=%4");
TiTiandituVecMapProvider::TiTiandituVecMapProvider(QObject* parent)
: TiTiandituMapProvider("png", AVERAGE_TILE_SIZE, QGeoMapType::StreetMap, parent)
{
setToken(token);
}
TiTiandituVecMapProvider::~TiTiandituVecMapProvider() {}
QString TiTiandituVecMapProvider::getURL(const int x,
const int y,
const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString xx = QString("%1").arg(x);
const QString yy = QString("%1").arg(y);
const QString zz = QString("%1").arg(zoom);
return tiandituVec.arg(zz, yy, xx, m_token);
}
static const QString tiandituCva = QStringLiteral(
"http://t6.tianditu.gov.cn/cva_w/"
"wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&"
"TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=%1&TILEROW=%2&TILECOL=%3&tk=%4");
TiTiandituCvaMapProvider::TiTiandituCvaMapProvider(QObject* parent)
: TiTiandituMapProvider("png", AVERAGE_TILE_SIZE, QGeoMapType::StreetMap, parent)
{
setToken(token);
}
TiTiandituCvaMapProvider::~TiTiandituCvaMapProvider() {}
QString TiTiandituCvaMapProvider::getURL(const int x,
const int y,
const int zoom,
QNetworkAccessManager* networkManager)
{
Q_UNUSED(networkManager)
const QString xx = QString("%1").arg(x);
const QString yy = QString("%1").arg(y);
const QString zz = QString("%1").arg(zoom);
return tiandituCva.arg(zz, yy, xx, m_token);
}

@ -0,0 +1,73 @@
#pragma once
#include "timapprovider.h"
class TiTiandituMapProvider : public TiMapProvider
{
public:
TiTiandituMapProvider(const QString& format, const quint32 averageSize,
const QGeoMapType::MapStyle mapType = QGeoMapType::CustomMap,
QObject* parent = nullptr);
// TiMapProvider interface
public:
void setToken(const QString& token) override;
protected:
QString m_token;
};
/**
* @brief The TiTiandituImgMapProvider class
*/
class TiTiandituImgMapProvider : public TiTiandituMapProvider
{
public:
TiTiandituImgMapProvider(QObject* parent = nullptr);
~TiTiandituImgMapProvider();
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
/**
* @brief The TiTiandituCiaMapProvider class
*/
class TiTiandituCiaMapProvider : public TiTiandituMapProvider
{
public:
TiTiandituCiaMapProvider(QObject* parent = nullptr);
~TiTiandituCiaMapProvider();
protected:
QString getURL(const int x, const int y, const int zoom,
QNetworkAccessManager* networkManager) override;
};
///
/// \brief The TiTiandituVecMapProvider class 天地图失量底图
///
class TiTiandituVecMapProvider : public TiTiandituMapProvider
{
public:
TiTiandituVecMapProvider(QObject* parent = nullptr);
~TiTiandituVecMapProvider();
protected:
QString getURL(const int x,
const int y,
const int zoom,
QNetworkAccessManager* networkManager) override;
};
class TiTiandituCvaMapProvider : public TiTiandituMapProvider
{
public:
TiTiandituCvaMapProvider(QObject* parent = nullptr);
~TiTiandituCvaMapProvider();
protected:
QString getURL(const int x,
const int y,
const int zoom,
QNetworkAccessManager* networkManager) override;
};
Loading…
Cancel
Save