QAD::Map:

* add MapViewTileProviderBase - base class for tile server provider
 * migrate OSM to new class
 * add MapTiler provider
 * add offlineMode for MapView
This commit is contained in:
2025-03-18 12:16:10 +03:00
parent bf11ca21c0
commit 347104d512
14 changed files with 494 additions and 150 deletions

View File

@@ -4,7 +4,7 @@ cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default
project(QAD) project(QAD)
set(QAD_MAJOR 2) set(QAD_MAJOR 2)
set(QAD_MINOR 32) set(QAD_MINOR 32)
set(QAD_REVISION 0) set(QAD_REVISION 1)
set(QAD_SUFFIX ) set(QAD_SUFFIX )
set(QAD_COMPANY SHS) set(QAD_COMPANY SHS)
set(QAD_DOMAIN org.SHS) set(QAD_DOMAIN org.SHS)

View File

@@ -1,8 +1,8 @@
#include "mapview.h" #include "mapview.h"
#include "osm_downloader_p.h" #include "mapview_tile_cache_p.h"
#include "mapview_tile_downloader_p.h"
#include "osm_math_p.h" #include "osm_math_p.h"
#include "osm_tile_cache_p.h"
#include "qad_types.h" #include "qad_types.h"
#include <QGraphicsPixmapItem> #include <QGraphicsPixmapItem>
@@ -18,10 +18,10 @@ const int tileSize = 256;
MapView::MapView(QWidget * parent): QWidget(parent) { MapView::MapView(QWidget * parent): QWidget(parent) {
downloader = new OSMDownloader(this); downloader = new MapViewTileDownloader(this);
cache = new OSMTileCache(this); cache = new MapViewTileCache(this);
setMouseTracking(true); setMouseTracking(true);
connect(cache, &OSMTileCache::tileReady, this, [this]() { connect(cache, &MapViewTileCache::tileReady, this, [this]() {
if (!is_downloading) drawBackground(); if (!is_downloading) drawBackground();
}); });
int size = 16; int size = 16;
@@ -92,16 +92,34 @@ void MapView::setCachePath(const QString & p) {
} }
void MapView::setOfflineMode(bool yes) {
is_offline = yes;
cache->setOfflineMode(yes);
}
void MapView::setTileObsoleteTime(int secs) { void MapView::setTileObsoleteTime(int secs) {
cache->setTileObsoleteTime(secs); cache->setTileObsoleteTime(secs);
} }
void collectDownloadIndeces(OSMTileCache * cache, void MapView::setTileProvider(MapViewTileProviderBase * p) {
QQueue<OSM::TileIndex> & indeces, cache->clearCache();
OSM::TileIndex index, downloader->setTileProvider(p);
int target_zoom_level, drawBackground();
bool only_new) { }
MapViewTileProviderBase * MapView::tileProvider() const {
return downloader->tileProvider();
}
void collectDownloadIndeces(MapViewTileCache * cache,
QQueue<OSM::TileIndex> & indeces,
OSM::TileIndex index,
int target_zoom_level,
bool only_new) {
if (only_new) { if (only_new) {
if (!cache->isTileFileExists(index)) indeces << index; if (!cache->isTileFileExists(index)) indeces << index;
} else } else
@@ -118,7 +136,7 @@ void collectDownloadIndeces(OSMTileCache * cache,
} }
void MapView::downloadCurrentView(int target_zoom_level, bool only_new) { void MapView::downloadCurrentView(int target_zoom_level, bool only_new, int parallel) {
int sx = qMax(0, (int)floor(view_rect.left() * tiles_side)); int sx = qMax(0, (int)floor(view_rect.left() * tiles_side));
int sy = qMax(0, (int)floor(view_rect.top() * tiles_side)); int sy = qMax(0, (int)floor(view_rect.top() * tiles_side));
int ex = qMin(tiles_side, (int)ceil(view_rect.right() * tiles_side)); int ex = qMin(tiles_side, (int)ceil(view_rect.right() * tiles_side));
@@ -141,7 +159,7 @@ void MapView::downloadCurrentView(int target_zoom_level, bool only_new) {
std::atomic_int value(0); std::atomic_int value(0);
auto conn = connect( auto conn = connect(
downloader, downloader,
&OSMDownloader::tileDone, &MapViewTileDownloader::tileDone,
this, this,
[this, &dialog, &indeces, &value]() { [this, &dialog, &indeces, &value]() {
// qDebug() << "done"; // qDebug() << "done";
@@ -160,8 +178,10 @@ void MapView::downloadCurrentView(int target_zoom_level, bool only_new) {
downloader->clearQueue(); downloader->clearQueue();
}); });
is_downloading = true; is_downloading = true;
for (int i = 0; i < 1; ++i) for (int i = 0; i < parallel; ++i) {
if (indeces.isEmpty()) break;
downloader->queueTile(indeces.dequeue()); downloader->queueTile(indeces.dequeue());
}
// dialog.exec(); // dialog.exec();
dialog.setModal(true); dialog.setModal(true);
dialog.show(); dialog.show();
@@ -264,11 +284,13 @@ void MapView::drawBackground() {
QPointF offset = view_rect.topLeft() * mins * scale_; QPointF offset = view_rect.topLeft() * mins * scale_;
p.setRenderHint(QPainter::SmoothPixmapTransform); p.setRenderHint(QPainter::SmoothPixmapTransform);
p.setPen(Qt::white); p.setPen(Qt::white);
QSizeF tile_size(tileSize, tileSize);
if (downloader->tileProvider()) tile_size = downloader->tileProvider()->tileSize();
for (int ix = sx; ix < ex; ++ix) { for (int ix = sx; ix < ex; ++ix) {
for (int iy = sy; iy < ey; ++iy) { for (int iy = sy; iy < ey; ++iy) {
QRectF r((ix)*ts, (iy)*ts, ts, ts); QRectF r((ix)*ts, (iy)*ts, ts, ts);
r.translate(-offset); r.translate(-offset);
QRectF px_rct(QPointF(), QSizeF(tileSize, tileSize)); QRectF px_rct(QPointF(), tile_size /*QSizeF(tileSize, tileSize)*/);
auto tile = cache->getTile((OSM::TileIndex){zoom_level, ix, iy}, px_rct); auto tile = cache->getTile((OSM::TileIndex){zoom_level, ix, iy}, px_rct);
if (!tile.isEmpty()) { if (!tile.isEmpty()) {
p.drawPixmap(r, tile.pixmap, px_rct); p.drawPixmap(r, tile.pixmap, px_rct);

View File

@@ -1,7 +1,7 @@
/* /*
QAD - Qt ADvanced QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
@@ -28,16 +28,18 @@
#include <QWidget> #include <QWidget>
class OSMDownloader; class MapViewTileDownloader;
class OSMTileCache; class MapViewTileProviderBase;
class MapViewTileCache;
class QAD_MAP_EXPORT MapView: public QWidget { class QAD_MAP_EXPORT MapView: public QWidget {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QPointF center READ center WRITE setCenter) Q_PROPERTY(QPointF center READ center WRITE setCenter)
Q_PROPERTY(double zoom READ getZoom WRITE setZoom) Q_PROPERTY(double zoom READ getZoom WRITE setZoom)
Q_PROPERTY(bool offlineMode READ isOfflineMode WRITE setOfflineMode)
friend class OSMDownloader; friend class MapViewTileDownloader;
friend class OSMTileCache; friend class MapViewTileCache;
friend class MapItemBase; friend class MapItemBase;
public: public:
@@ -61,9 +63,14 @@ public:
QString cachePath() const; QString cachePath() const;
void setCachePath(const QString & p); void setCachePath(const QString & p);
void setTileObsoleteTime(int secs); bool isOfflineMode() const { return is_offline; }
void setOfflineMode(bool yes);
void downloadCurrentView(int target_zoom_level = 17, bool only_new = true); void setTileObsoleteTime(int secs);
void setTileProvider(MapViewTileProviderBase * p);
MapViewTileProviderBase * tileProvider() const;
void downloadCurrentView(int target_zoom_level = 17, bool only_new = true, int parallel = 1);
protected: protected:
QSize sizeHint() const override { return QSize(200, 200); } QSize sizeHint() const override { return QSize(200, 200); }
@@ -89,17 +96,17 @@ private:
QPointF mapToNorm(QPoint screen) const; QPointF mapToNorm(QPoint screen) const;
QPoint mapFromNorm(QPointF norm) const; QPoint mapFromNorm(QPointF norm) const;
OSMDownloader * downloader = nullptr; MapViewTileDownloader * downloader = nullptr;
OSMTileCache * cache = nullptr; MapViewTileCache * cache = nullptr;
MapItemBase * hover = nullptr; MapItemBase * hover = nullptr;
QPointF center_ = QPointF(0.5, 0.5); QPointF center_ = QPointF(0.5, 0.5);
QPointF last_click_coord = center_; QPointF last_click_coord = center_;
QPoint press_point, zoom_anchor; QPoint press_point, zoom_anchor;
QPixmap background; QPixmap background;
QRectF view_rect; QRectF view_rect;
QVector<MapItemBase *> items_; QVector<MapItemBase *> items_;
QBrush brush_tr; QBrush brush_tr;
bool is_pan = false, is_downloading = false; bool is_pan = false, is_downloading = false, is_offline = false;
double zoom_ = 1., scale_ = 1., px2m = 1.; double zoom_ = 1., scale_ = 1., px2m = 1.;
int zoom_level = 0, tiles_side = 1, max_level = 19; int zoom_level = 0, tiles_side = 1, max_level = 19;

View File

@@ -1,27 +1,27 @@
#include "mapview.h" #include "mapview.h"
#include "osm_downloader_p.h" #include "mapview_tile_cache_p.h"
#include "osm_tile_cache_p.h" #include "mapview_tile_downloader_p.h"
#include "qad_locations.h" #include "qad_locations.h"
OSMTileCache::OSMTileCache(MapView * p): QThread() { MapViewTileCache::MapViewTileCache(MapView * p): QThread() {
qRegisterMetaType<OSM::TileIndex>(); qRegisterMetaType<OSM::TileIndex>();
qRegisterMetaType<OSM::TilePixmap>(); qRegisterMetaType<OSM::TilePixmap>();
parent = p; parent = p;
setCacheRoot(QAD::userPath(QAD::ltCache, "map_osm") + "/"); setCacheRoot(QAD::userPath(QAD::ltCache, "mapview") + "/");
setAdditionalCacheSize(64); setAdditionalCacheSize(64);
start(); start();
} }
OSMTileCache::~OSMTileCache() { MapViewTileCache::~MapViewTileCache() {
requestInterruption(); requestInterruption();
cond.wakeAll(); cond.wakeAll();
wait(); wait();
} }
void OSMTileCache::tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap) { void MapViewTileCache::tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap) {
auto * tile = new OSM::TilePixmap(); auto * tile = new OSM::TilePixmap();
tile->index = index; tile->index = index;
tile->pixmap = pixmap; tile->pixmap = pixmap;
@@ -29,10 +29,10 @@ void OSMTileCache::tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap)
} }
OSM::TilePixmap OSMTileCache::getTile(OSM::TileIndex index, QRectF & rect_src) { OSM::TilePixmap MapViewTileCache::getTile(OSM::TileIndex index, QRectF & rect_src) {
OSM::TilePixmap ret = getTileFromCache(index); OSM::TilePixmap ret = getTileFromCache(index);
if (ret.isEmpty() || ret.obsolete) { if (ret.isEmpty() || ret.obsolete) {
parent->downloader->queueTile(index); if (!is_offline) parent->downloader->queueTile(index);
} }
if (ret.isEmpty()) { if (ret.isEmpty()) {
QVector<QPointF> offsets; QVector<QPointF> offsets;
@@ -56,7 +56,12 @@ OSM::TilePixmap OSMTileCache::getTile(OSM::TileIndex index, QRectF & rect_src) {
} }
bool OSMTileCache::isTileFileExists(OSM::TileIndex index) const { void MapViewTileCache::clearCache() {
tile_cache.clear();
}
bool MapViewTileCache::isTileFileExists(OSM::TileIndex index) const {
QString hashdir = index.cacheDir(); QString hashdir = index.cacheDir();
if (!cache_dir.exists(hashdir)) return false; if (!cache_dir.exists(hashdir)) return false;
QString hashname = hashdir + "/" + index.hashName(); QString hashname = hashdir + "/" + index.hashName();
@@ -64,15 +69,29 @@ bool OSMTileCache::isTileFileExists(OSM::TileIndex index) const {
} }
void OSMTileCache::setCacheRoot(const QString & p) { void MapViewTileCache::setCacheRoot(const QString & p) {
cache_root = p; cache_root = p;
tileProviderChanged();
}
void MapViewTileCache::tileProviderChanged() {
cache_dir.setPath(cache_root); cache_dir.setPath(cache_root);
qDebug() << "[OSMTileCache] Cache dir" << cache_root; auto * provider = parent->downloader->provider;
if (provider) {
cache_dir.setPath(cache_root + "/" + provider->name());
}
qDebug() << "[MapViewTileCache] Cache dir" << cache_dir.absolutePath();
if (!cache_dir.exists()) cache_dir.mkpath("."); if (!cache_dir.exists()) cache_dir.mkpath(".");
} }
OSM::TilePixmap OSMTileCache::getTileFromCache(OSM::TileIndex index) { void MapViewTileCache::setOfflineMode(bool yes) {
is_offline = yes;
}
OSM::TilePixmap MapViewTileCache::getTileFromCache(OSM::TileIndex index) {
OSM::TilePixmap ret; OSM::TilePixmap ret;
ret.index = index; ret.index = index;
auto * tile = tile_cache[index.hash()]; auto * tile = tile_cache[index.hash()];
@@ -101,12 +120,12 @@ OSM::TilePixmap OSMTileCache::getTileFromCache(OSM::TileIndex index) {
} }
void OSMTileCache::updateCacheSize() { void MapViewTileCache::updateCacheSize() {
tile_cache.setMaxCost(fixed_size_b + add_size_b); tile_cache.setMaxCost(fixed_size_b + add_size_b);
} }
void OSMTileCache::saveTile(OSM::TilePixmap * tile) { void MapViewTileCache::saveTile(OSM::TilePixmap * tile) {
tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes()); tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes());
emit tileReady(*tile); emit tileReady(*tile);
cond_mutex.lock(); cond_mutex.lock();
@@ -118,7 +137,7 @@ void OSMTileCache::saveTile(OSM::TilePixmap * tile) {
} }
void OSMTileCache::writeToDisk(const OSM::TilePixmap & tile) { void MapViewTileCache::writeToDisk(const OSM::TilePixmap & tile) {
QString hashdir = tile.index.cacheDir(); QString hashdir = tile.index.cacheDir();
if (!cache_dir.exists(hashdir)) cache_dir.mkdir(hashdir); if (!cache_dir.exists(hashdir)) cache_dir.mkdir(hashdir);
QFile f(cache_dir.absoluteFilePath(hashdir + "/" + tile.index.hashName())); QFile f(cache_dir.absoluteFilePath(hashdir + "/" + tile.index.hashName()));
@@ -128,7 +147,7 @@ void OSMTileCache::writeToDisk(const OSM::TilePixmap & tile) {
} }
void OSMTileCache::run() { void MapViewTileCache::run() {
while (!isInterruptionRequested()) { while (!isInterruptionRequested()) {
OSM::TilePixmap tile; OSM::TilePixmap tile;
cond_mutex.lock(); cond_mutex.lock();

View File

@@ -1,7 +1,7 @@
/* /*
QAD - Qt ADvanced QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
@@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef osm_tile_cache_h #ifndef mapview_tile_cache_h
#define osm_tile_cache_h #define mapview_tile_cache_h
#include "osm_types_p.h" #include "osm_types_p.h"
@@ -31,12 +31,12 @@
class MapView; class MapView;
class OSMTileCache: public QThread { class MapViewTileCache: public QThread {
Q_OBJECT Q_OBJECT
public: public:
explicit OSMTileCache(MapView * p); explicit MapViewTileCache(MapView * p);
~OSMTileCache(); ~MapViewTileCache();
void setMinimumCacheSize(int bytes) { void setMinimumCacheSize(int bytes) {
fixed_size_b = bytes; fixed_size_b = bytes;
@@ -50,12 +50,16 @@ public:
void tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap); void tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap);
OSM::TilePixmap getTile(OSM::TileIndex index, QRectF & rect_src); OSM::TilePixmap getTile(OSM::TileIndex index, QRectF & rect_src);
void clearCache();
bool isTileFileExists(OSM::TileIndex index) const; bool isTileFileExists(OSM::TileIndex index) const;
QString cacheRoot() const { return cache_root; } QString cacheRoot() const { return cache_root; }
void setCacheRoot(const QString & p); void setCacheRoot(const QString & p);
void tileProviderChanged();
void setOfflineMode(bool yes);
private: private:
OSM::TilePixmap getTileFromCache(OSM::TileIndex index); OSM::TilePixmap getTileFromCache(OSM::TileIndex index);
void updateCacheSize(); void updateCacheSize();
@@ -70,6 +74,7 @@ private:
QMutex cond_mutex; QMutex cond_mutex;
int secs_obsolete = -1; int secs_obsolete = -1;
int fixed_size_b = 0, add_size_b = 0; int fixed_size_b = 0, add_size_b = 0;
bool is_offline = false;
QQueue<OSM::TilePixmap> queue; QQueue<OSM::TilePixmap> queue;
QCache<quint64, OSM::TilePixmap> tile_cache; QCache<quint64, OSM::TilePixmap> tile_cache;

View File

@@ -0,0 +1,90 @@
#include "mapview.h"
#include "mapview_tile_cache_p.h"
#include "mapview_tile_downloader_p.h"
MapViewTileDownloader::MapViewTileDownloader(MapView * p): QThread() {
qRegisterMetaType<OSM::TileIndex>();
parent = p;
start();
}
MapViewTileDownloader::~MapViewTileDownloader() {
requestInterruption();
cond.wakeAll();
wait();
if (provider) provider->deleteLater();
}
bool MapViewTileDownloader::queueTile(OSM::TileIndex index, bool force) {
// auto hash = tile.hash();
bool ret = false;
cond_mutex.lock();
if ((!queue.contains(index) && !in_progress.contains(index.hash())) || force) {
queue.enqueue(index);
cond.wakeOne();
ret = true;
}
cond_mutex.unlock();
return ret;
}
void MapViewTileDownloader::queueTiles(QList<OSM::TileIndex> indeces) {
cond_mutex.lock();
queue << indeces;
cond.wakeOne();
cond_mutex.unlock();
}
void MapViewTileDownloader::clearQueue() {
cond_mutex.lock();
queue.clear();
cond_mutex.unlock();
}
void MapViewTileDownloader::setTileProvider(MapViewTileProviderBase * p) {
if (provider) {
disconnect(provider, &MapViewTileProviderBase::tileReady, this, &MapViewTileDownloader::tileReady);
provider->deleteLater();
}
provider = p;
if (provider) {
connect(provider, &MapViewTileProviderBase::tileReady, this, &MapViewTileDownloader::tileReady);
}
parent->cache->tileProviderChanged();
}
void MapViewTileDownloader::requestTile(OSM::TileIndex index) {
if (!provider) return;
provider->requestTile(index);
}
void MapViewTileDownloader::tileReady(OSM::TileIndex index, QPixmap pm) {
if (!pm.isNull()) parent->cache->tileDownloaded(index, pm);
cond_mutex.lock();
in_progress.remove(index.hash());
cond_mutex.unlock();
emit tileDone();
}
void MapViewTileDownloader::run() {
while (!isInterruptionRequested()) {
cond_mutex.lock();
if (queue.isEmpty())
cond.wait(&cond_mutex);
else {
auto t = queue.dequeue();
in_progress.insert(t.hash());
QMetaObject::invokeMethod(parent, [this, t]() { requestTile(t); }, Qt::QueuedConnection);
}
cond_mutex.unlock();
}
}

View File

@@ -1,7 +1,7 @@
/* /*
QAD - Qt ADvanced QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
@@ -17,9 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef osm_downloader_h #ifndef mapview_tile_downloader_h
#define osm_downloader_h #define mapview_tile_downloader_h
#include "mapview_tile_provider_base.h"
#include "osm_types_p.h" #include "osm_types_p.h"
#include <QMutex> #include <QMutex>
@@ -33,24 +34,28 @@
class MapView; class MapView;
class OSMDownloader: public QThread { class MapViewTileDownloader: public QThread {
Q_OBJECT Q_OBJECT
friend class MapViewTileCache;
public: public:
explicit OSMDownloader(MapView * p); explicit MapViewTileDownloader(MapView * p);
~OSMDownloader(); ~MapViewTileDownloader();
bool queueTile(OSM::TileIndex index, bool force = false); bool queueTile(OSM::TileIndex index, bool force = false);
void queueTiles(QList<OSM::TileIndex> indeces); void queueTiles(QList<OSM::TileIndex> indeces);
void clearQueue(); void clearQueue();
void setTileProvider(MapViewTileProviderBase * p);
MapViewTileProviderBase * tileProvider() const { return provider; }
private: private:
void run() override; void run() override;
void requestTile(OSM::TileIndex index); void requestTile(OSM::TileIndex index);
MapView * parent; MapView * parent;
QNetworkAccessManager * nam = nullptr; MapViewTileProviderBase * provider = nullptr;
QString provider;
QWaitCondition cond; QWaitCondition cond;
QMutex cond_mutex; QMutex cond_mutex;
QQueue<OSM::TileIndex> queue; QQueue<OSM::TileIndex> queue;
@@ -59,6 +64,7 @@ private:
public slots: public slots:
private slots: private slots:
void tileReady(OSM::TileIndex index, QPixmap pm);
signals: signals:
void tileDone(); void tileDone();

View File

@@ -0,0 +1,13 @@
#include "mapview_tile_provider_base.h"
void MapViewTileProviderBase::setParameters(const PIValueTree & vt) {
parameters.applyValues(vt);
applyParameters();
}
void MapViewTileProviderBase::initParameters(const PIValueTree & vt) {
parameters = vt;
applyParameters();
}

View File

@@ -0,0 +1,57 @@
/*
QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef mapview_tile_provider_base_h
#define mapview_tile_provider_base_h
#include "osm_types_p.h"
#include "qad_map_export.h"
#include <QPixmap>
#include <pivaluetree.h>
class QAD_MAP_EXPORT MapViewTileProviderBase: public QObject {
Q_OBJECT
public:
MapViewTileProviderBase() {}
virtual ~MapViewTileProviderBase() {}
const PIValueTree & getParameters() const { return parameters; }
void setParameters(const PIValueTree & vt);
virtual QString name() const = 0;
virtual bool requestTile(OSM::TileIndex index) = 0;
virtual QSize tileSize() = 0;
protected:
void initParameters(const PIValueTree & vt);
virtual void applyParameters() {}
private:
PIValueTree parameters;
signals:
void tileReady(OSM::TileIndex index, QPixmap pm);
};
#endif

View File

@@ -0,0 +1,65 @@
#include "mapview_tile_provider_maptiler.h"
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QTimer>
#include <piqt.h>
MapViewTileProvider_MapTiler::MapViewTileProvider_MapTiler() {
nam = new QNetworkAccessManager();
PIValueTree p;
p.addChild(PIValueTree("url", "https://api.maptiler.com/maps"));
p.addChild(PIValueTree("key", ""));
p.addChild(PIValueTree("tileset", ""));
initParameters(p);
}
MapViewTileProvider_MapTiler::~MapViewTileProvider_MapTiler() {
piDeleteSafety(nam);
}
QString MapViewTileProvider_MapTiler::name() const {
static QString ret = "MapTiler";
return ret;
}
bool MapViewTileProvider_MapTiler::requestTile(OSM::TileIndex index) {
QNetworkRequest req(url + QString("/%1/%2/%3/%4.jpg?key=%5").arg(tileset).arg(index.z).arg(index.x).arg(index.y).arg(key));
req.setHeader(QNetworkRequest::UserAgentHeader, "Qt/5");
auto * r = nam->get(req);
if (!r) return false;
// qDebug() << "Reqst:" << index.z << index.x << index.y;
connect(r, &QNetworkReply::finished, this, [this, r, index]() {
r->deleteLater();
QPixmap tim;
if (r->error() != QNetworkReply::NoError) {
qDebug() << "Retry:" << index.z << index.x << index.y << r->error();
QTimer::singleShot(500, this, [this, index] { requestTile(index); });
return;
} else {
QByteArray data = r->readAll();
if (!data.isEmpty()) {
tim.loadFromData(data, "jpg");
// qDebug() << "Ready:" << index.z << index.x << index.y;
}
}
tileReady(index, tim);
});
return true;
}
QSize MapViewTileProvider_MapTiler::tileSize() {
return {512, 512};
}
void MapViewTileProvider_MapTiler::applyParameters() {
url = PI2QString(getParameters().childValue("url").toString());
key = PI2QString(getParameters().childValue("key").toString());
tileset = PI2QString(getParameters().childValue("tileset").toString());
}

View File

@@ -0,0 +1,48 @@
/*
QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef mapview_tile_provider_maptiler_h
#define mapview_tile_provider_maptiler_h
#include "mapview_tile_provider_base.h"
#include <QNetworkAccessManager>
class QAD_MAP_EXPORT MapViewTileProvider_MapTiler: public MapViewTileProviderBase {
Q_OBJECT
public:
MapViewTileProvider_MapTiler();
~MapViewTileProvider_MapTiler();
QString name() const override;
bool requestTile(OSM::TileIndex index) override;
QSize tileSize() override;
protected:
void applyParameters() override;
private:
QNetworkAccessManager * nam = nullptr;
QString url, key, tileset;
};
#endif

View File

@@ -0,0 +1,56 @@
#include "mapview_tile_provider_osm.h"
#include <QNetworkReply>
#include <QNetworkRequest>
#include <piqt.h>
MapViewTileProvider_OSM::MapViewTileProvider_OSM() {
nam = new QNetworkAccessManager();
PIValueTree p;
p.addChild(PIValueTree("url", "http://tile.openstreetmap.org"));
initParameters(p);
}
MapViewTileProvider_OSM::~MapViewTileProvider_OSM() {
piDeleteSafety(nam);
}
QString MapViewTileProvider_OSM::name() const {
static QString ret = "OSM";
return ret;
}
bool MapViewTileProvider_OSM::requestTile(OSM::TileIndex index) {
QNetworkRequest req(url + QString("/%1/%2/%3.png").arg(index.z).arg(index.x).arg(index.y));
req.setHeader(QNetworkRequest::UserAgentHeader, "Qt/5");
auto * r = nam->get(req);
if (!r) return false;
connect(r, &QNetworkReply::finished, this, [this, r, index]() {
r->deleteLater();
QPixmap tim;
if (r->error() != QNetworkReply::NoError) {
qDebug() << "Error:" << r->error();
} else {
QByteArray data = r->readAll();
if (!data.isEmpty()) {
tim.loadFromData(data, "png");
}
}
emit tileReady(index, tim);
});
return true;
}
QSize MapViewTileProvider_OSM::tileSize() {
return {256, 256};
}
void MapViewTileProvider_OSM::applyParameters() {
url = PI2QString(getParameters().childValue("url").toString());
}

View File

@@ -0,0 +1,48 @@
/*
QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef mapview_tile_provider_osm_h
#define mapview_tile_provider_osm_h
#include "mapview_tile_provider_base.h"
#include <QNetworkAccessManager>
class QAD_MAP_EXPORT MapViewTileProvider_OSM: public MapViewTileProviderBase {
Q_OBJECT
public:
MapViewTileProvider_OSM();
~MapViewTileProvider_OSM();
QString name() const override;
bool requestTile(OSM::TileIndex index) override;
QSize tileSize() override;
protected:
void applyParameters() override;
private:
QNetworkAccessManager * nam = nullptr;
QString url;
};
#endif

View File

@@ -1,92 +0,0 @@
#include "mapview.h"
#include "osm_downloader_p.h"
#include "osm_tile_cache_p.h"
OSMDownloader::OSMDownloader(MapView * p): QThread() {
qRegisterMetaType<OSM::TileIndex>();
nam = new QNetworkAccessManager();
parent = p;
provider = "http://tile.openstreetmap.org";
start();
}
OSMDownloader::~OSMDownloader() {
requestInterruption();
cond.wakeAll();
wait();
delete nam;
}
bool OSMDownloader::queueTile(OSM::TileIndex index, bool force) {
// auto hash = tile.hash();
bool ret = false;
cond_mutex.lock();
if ((!queue.contains(index) && !in_progress.contains(index.hash())) || force) {
queue.enqueue(index);
cond.wakeOne();
ret = true;
}
cond_mutex.unlock();
return ret;
}
void OSMDownloader::queueTiles(QList<OSM::TileIndex> indeces) {
cond_mutex.lock();
queue << indeces;
cond.wakeOne();
cond_mutex.unlock();
}
void OSMDownloader::clearQueue() {
cond_mutex.lock();
queue.clear();
cond_mutex.unlock();
}
void OSMDownloader::requestTile(OSM::TileIndex index) {
QNetworkRequest req(provider + QString("/%1/%2/%3.png").arg(index.z).arg(index.x).arg(index.y));
req.setHeader(QNetworkRequest::UserAgentHeader, "Qt/5");
auto * r = nam->get(req);
if (!r) return;
connect(r, &QNetworkReply::finished, this, [this, r, index]() {
r->deleteLater();
if (r->error() != QNetworkReply::NoError) {
qDebug() << "Error:" << r->error();
} else {
QByteArray data = r->readAll();
if (!data.isEmpty()) {
QPixmap tim;
tim.loadFromData(data, "png");
if (!tim.isNull()) parent->cache->tileDownloaded(index, tim);
}
}
cond_mutex.lock();
in_progress.remove(index.hash());
cond_mutex.unlock();
emit tileDone();
});
}
void OSMDownloader::run() {
while (!isInterruptionRequested()) {
cond_mutex.lock();
if (queue.isEmpty())
cond.wait(&cond_mutex);
else {
auto t = queue.dequeue();
in_progress.insert(t.hash());
QMetaObject::invokeMethod(
parent,
[this, t]() { requestTile(t); },
Qt::QueuedConnection);
}
cond_mutex.unlock();
}
}