From 148fc76d5a32a299f345409fb0f411a9b7b078f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 11 Dec 2023 18:54:46 +0100 Subject: [PATCH] Added support for online vector maps overzoom --- src/map/aqmmap.cpp | 8 +-- src/map/gemfmap.cpp | 8 +-- src/map/onlinemap.cpp | 112 ++++++++++++++++++++++++++++++---------- src/map/onlinemap.h | 39 +++++++++++++- src/map/osmdroidmap.cpp | 8 +-- src/map/sqlitemap.cpp | 8 +-- src/map/tile.h | 32 ++++-------- src/map/tileloader.cpp | 101 ++++++------------------------------ src/map/tileloader.h | 40 +++++++++++--- src/map/wmsmap.cpp | 56 +++++++++++++++----- src/map/wmsmap.h | 1 + src/map/wmtsmap.cpp | 56 +++++++++++++++----- src/map/wmtsmap.h | 1 + 13 files changed, 285 insertions(+), 185 deletions(-) diff --git a/src/map/aqmmap.cpp b/src/map/aqmmap.cpp index 068e51e4..d4def250 100644 --- a/src/map/aqmmap.cpp +++ b/src/map/aqmmap.cpp @@ -355,7 +355,7 @@ void AQMMap::draw(QPainter *painter, const QRectF &rect, Flags flags) int width = ceil(s.width() / tileSize()); int height = ceil(s.height() / tileSize()); - QList tiles; + QList tiles; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { @@ -369,15 +369,15 @@ void AQMMap::draw(QPainter *painter, const QRectF &rect, Flags flags) tl.y() + (t.y() - tile.y()) * tileSize()); drawTile(painter, pm, tp); } else - tiles.append(RenderTile(t, tileData(t), key)); + tiles.append(DataTile(t, tileData(t), key)); } } - QFuture future = QtConcurrent::map(tiles, &RenderTile::load); + QFuture future = QtConcurrent::map(tiles, &DataTile::load); future.waitForFinished(); for (int i = 0; i < tiles.size(); i++) { - const RenderTile &mt = tiles.at(i); + const DataTile &mt = tiles.at(i); QPixmap pm(mt.pixmap()); if (pm.isNull()) continue; diff --git a/src/map/gemfmap.cpp b/src/map/gemfmap.cpp index 435693c9..2edbe90b 100644 --- a/src/map/gemfmap.cpp +++ b/src/map/gemfmap.cpp @@ -251,7 +251,7 @@ void GEMFMap::draw(QPainter *painter, const QRectF &rect, Flags flags) int width = ceil(s.width() / tileSize()); int height = ceil(s.height() / tileSize()); - QList tiles; + QList tiles; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { @@ -265,15 +265,15 @@ void GEMFMap::draw(QPainter *painter, const QRectF &rect, Flags flags) tl.y() + (t.y() - tile.y()) * tileSize()); drawTile(painter, pm, tp); } else - tiles.append(RenderTile(t, tileData(t), key)); + tiles.append(DataTile(t, tileData(t), key)); } } - QFuture future = QtConcurrent::map(tiles, &RenderTile::load); + QFuture future = QtConcurrent::map(tiles, &DataTile::load); future.waitForFinished(); for (int i = 0; i < tiles.size(); i++) { - const RenderTile &mt = tiles.at(i); + const DataTile &mt = tiles.at(i); QPixmap pm(mt.pixmap()); if (pm.isNull()) continue; diff --git a/src/map/onlinemap.cpp b/src/map/onlinemap.cpp index 7b5dce7e..eacdd322 100644 --- a/src/map/onlinemap.cpp +++ b/src/map/onlinemap.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "common/rectc.h" #include "common/programpaths.h" #include "common/downloader.h" @@ -7,12 +9,19 @@ #include "onlinemap.h" +#define MAX_OVERZOOM 3 + +static QString cacheName(const QString &file, unsigned overzoom) +{ + return overzoom ? file + ":" + QString::number(overzoom) : file; +} + OnlineMap::OnlineMap(const QString &fileName, const QString &name, const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio, const QList &headers, int tileSize, bool scalable, bool invertY, bool quadTiles, QObject *parent) : Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds), - _zoom(_zooms.max()), _tileSize(tileSize), _mapRatio(1.0), + _zoom(_zooms.max()), _tileSize(tileSize), _base(0), _mapRatio(1.0), _tileRatio(tileRatio), _scalable(scalable), _invertY(invertY) { _tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name), @@ -20,6 +29,11 @@ OnlineMap::OnlineMap(const QString &fileName, const QString &name, _tileLoader->setUrl(url, quadTiles ? TileLoader::QuadTiles : TileLoader::XYZ); _tileLoader->setHeaders(headers); connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded); + + if (_scalable) { + _base = _zooms.max(); + _zooms.setMax(qMin(_zooms.max() + MAX_OVERZOOM, OSM::ZOOMS.max())); + } } QRectF OnlineMap::bounds() @@ -77,7 +91,7 @@ void OnlineMap::load(const Projection &in, const Projection &out, _mapRatio = hidpi ? deviceRatio : 1.0; if (_scalable) { - _tileLoader->setScaledSize(_tileSize * deviceRatio); + _scaledSize = _tileSize * deviceRatio; _tileRatio = deviceRatio; } } @@ -97,43 +111,79 @@ qreal OnlineMap::tileSize() const return (_tileSize / coordinatesRatio()); } +QPoint OnlineMap::tileCoordinates(int x, int y, int zoom) +{ + return QPoint(x, _invertY ? (1< tiles; - tiles.reserve(width * height); - for (int i = 0; i < width; i++) - for (int j = 0; j < height; j++) - tiles.append(FetchTile(QPoint(tile.x() + i, _invertY ? (1<<_zoom) - - (tile.y() + j) - 1 : tile.y() + j), _zoom)); + int width = ceil(s.width() / (tileSize() * f)); + int height = ceil(s.height() / (tileSize() * f)); + + QVector fetchTiles; + fetchTiles.reserve(width * height); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + QPoint tc(tileCoordinates(tile.x() + i, tile.y() + j, base)); + fetchTiles.append(TileLoader::Tile(tc, base)); + } + } if (flags & Map::Block) - _tileLoader->loadTilesSync(tiles); + _tileLoader->loadTilesSync(fetchTiles); else - _tileLoader->loadTilesAsync(tiles); - - for (int i = 0; i < tiles.count(); i++) { - FetchTile &t = tiles[i]; - QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize(), - tl.y() + ((_invertY - ? (1<<_zoom) - t.xy().y() - 1 - : t.xy().y()) - tile.y()) * tileSize()); - - if (!t.pixmap().isNull()) { - t.pixmap().setDevicePixelRatio(imageRatio()); - painter->drawPixmap(tp, t.pixmap()); - } + _tileLoader->loadTilesAsync(fetchTiles); + + QList renderTiles; + for (int i = 0; i < fetchTiles.count(); i++) { + const TileLoader::Tile &t = fetchTiles.at(i); + if (t.file().isNull()) + continue; + + QPixmap pm; + if (QPixmapCache::find(cacheName(t.file(), overzoom), &pm)) { + QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize() * f, + tl.y() + (t.xy().y() - tile.y()) * tileSize() * f); + drawTile(painter, pm, tp); + } else + renderTiles.append(OnlineTile(t.xy(), t.file(), _zoom, overzoom, + _scaledSize)); + } + + QFuture future = QtConcurrent::map(renderTiles, &OnlineTile::load); + future.waitForFinished(); + + for (int i = 0; i < renderTiles.size(); i++) { + const OnlineTile &mt = renderTiles.at(i); + QPixmap pm(mt.pixmap()); + if (pm.isNull()) + continue; + + QPixmapCache::insert(cacheName(mt.file(), overzoom), pm); + + QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize() * f, + tl.y() + (mt.xy().y() - tile.y()) * tileSize() * f); + drawTile(painter, pm, tp); } } +void OnlineMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp) +{ + pixmap.setDevicePixelRatio(imageRatio()); + painter->drawPixmap(tp, pixmap); +} + QPointF OnlineMap::ll2xy(const Coordinates &c) { qreal scale = OSM::zoom2scale(_zoom, _tileSize); @@ -147,3 +197,9 @@ Coordinates OnlineMap::xy2ll(const QPointF &p) return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale) * coordinatesRatio()); } + +void OnlineMap::clearCache() +{ + _tileLoader->clearCache(); + QPixmapCache::clear(); +} diff --git a/src/map/onlinemap.h b/src/map/onlinemap.h index dc9553b4..9821bec0 100644 --- a/src/map/onlinemap.h +++ b/src/map/onlinemap.h @@ -1,11 +1,44 @@ #ifndef ONLINEMAP_H #define ONLINEMAP_H +#include +#include #include "common/range.h" #include "common/rectc.h" #include "map.h" #include "tileloader.h" +class OnlineTile +{ +public: + OnlineTile(const QPoint &xy, const QString &file, int zoom, int overzoom, + int scaledSize) : _xy(xy), _file(file), _zoom(zoom), _overzoom(overzoom), + _scaledSize(scaledSize) {} + + void load() + { + QByteArray format(_overzoom + ? QByteArray::number(_zoom) + ';' + QByteArray::number(_overzoom) + : QByteArray::number(_zoom)); + QImageReader reader(_file, format); + if (_scaledSize) + reader.setScaledSize(QSize(_scaledSize, _scaledSize)); + _pixmap = QPixmap::fromImage(reader.read()); + } + + const QPoint &xy() const {return _xy;} + const QString &file() const {return _file;} + const QPixmap &pixmap() const {return _pixmap;} + +private: + QPoint _xy; + QString _file; + int _zoom; + int _overzoom; + int _scaledSize; + QPixmap _pixmap; +}; + class OnlineMap : public Map { Q_OBJECT @@ -35,13 +68,15 @@ class OnlineMap : public Map void load(const Projection &in, const Projection &out, qreal deviceRatio, bool hidpi); - void clearCache() {_tileLoader->clearCache();} + void clearCache(); private: int limitZoom(int zoom) const; qreal tileSize() const; qreal coordinatesRatio() const; qreal imageRatio() const; + QPoint tileCoordinates(int x, int y, int zoom); + void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp); TileLoader *_tileLoader; QString _name; @@ -49,8 +84,10 @@ class OnlineMap : public Map RectC _bounds; int _zoom; int _tileSize; + int _base; qreal _mapRatio, _tileRatio; bool _scalable; + int _scaledSize; bool _invertY; }; diff --git a/src/map/osmdroidmap.cpp b/src/map/osmdroidmap.cpp index 6d7de953..99834535 100644 --- a/src/map/osmdroidmap.cpp +++ b/src/map/osmdroidmap.cpp @@ -246,7 +246,7 @@ void OsmdroidMap::draw(QPainter *painter, const QRectF &rect, Flags flags) int width = ceil(s.width() / tileSize()); int height = ceil(s.height() / tileSize()); - QList tiles; + QList tiles; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { @@ -260,15 +260,15 @@ void OsmdroidMap::draw(QPainter *painter, const QRectF &rect, Flags flags) tl.y() + (t.y() - tile.y()) * tileSize()); drawTile(painter, pm, tp); } else - tiles.append(RenderTile(t, tileData(_zoom, t), key)); + tiles.append(DataTile(t, tileData(_zoom, t), key)); } } - QFuture future = QtConcurrent::map(tiles, &RenderTile::load); + QFuture future = QtConcurrent::map(tiles, &DataTile::load); future.waitForFinished(); for (int i = 0; i < tiles.size(); i++) { - const RenderTile &mt = tiles.at(i); + const DataTile &mt = tiles.at(i); QPixmap pm(mt.pixmap()); if (pm.isNull()) continue; diff --git a/src/map/sqlitemap.cpp b/src/map/sqlitemap.cpp index 0d5aa122..46250167 100644 --- a/src/map/sqlitemap.cpp +++ b/src/map/sqlitemap.cpp @@ -193,7 +193,7 @@ void SqliteMap::draw(QPainter *painter, const QRectF &rect, Flags flags) int width = ceil(s.width() / tileSize()); int height = ceil(s.height() / tileSize()); - QList tiles; + QList tiles; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { @@ -207,15 +207,15 @@ void SqliteMap::draw(QPainter *painter, const QRectF &rect, Flags flags) tl.y() + (t.y() - tile.y()) * tileSize()); drawTile(painter, pm, tp); } else - tiles.append(RenderTile(t, tileData(_zoom, t), key)); + tiles.append(DataTile(t, tileData(_zoom, t), key)); } } - QFuture future = QtConcurrent::map(tiles, &RenderTile::load); + QFuture future = QtConcurrent::map(tiles, &DataTile::load); future.waitForFinished(); for (int i = 0; i < tiles.size(); i++) { - const RenderTile &mt = tiles.at(i); + const DataTile &mt = tiles.at(i); QPixmap pm(mt.pixmap()); if (pm.isNull()) continue; diff --git a/src/map/tile.h b/src/map/tile.h index 05efa058..f4956a79 100644 --- a/src/map/tile.h +++ b/src/map/tile.h @@ -4,32 +4,29 @@ #include #include #include -#include -#include "rectd.h" -class FetchTile +class FileTile { public: - FetchTile() {} - FetchTile(const QPoint &xy, const QVariant &zoom, const RectD &bbox = RectD()) - : _xy(xy), _zoom(zoom), _bbox(bbox) {} + FileTile(const QPoint &xy, const QString &file) + : _xy(xy), _file(file) {} - const QVariant &zoom() const {return _zoom;} const QPoint &xy() const {return _xy;} - const RectD &bbox() const {return _bbox;} - QPixmap &pixmap() {return _pixmap;} + const QString &file() const {return _file;} + const QPixmap &pixmap() const {return _pixmap;} + + void load() {_pixmap.load(_file);} private: QPoint _xy; - QVariant _zoom; - RectD _bbox; + QString _file; QPixmap _pixmap; }; -class RenderTile +class DataTile { public: - RenderTile(const QPoint &xy, const QByteArray &data, const QString &key) + DataTile(const QPoint &xy, const QByteArray &data, const QString &key) : _xy(xy), _data(data), _key(key) {} const QPoint &xy() const {return _xy;} @@ -45,13 +42,4 @@ class RenderTile QPixmap _pixmap; }; -#ifndef QT_NO_DEBUG -inline QDebug operator<<(QDebug dbg, const FetchTile &tile) -{ - dbg.nospace() << "Tile(" << tile.zoom() << ", " << tile.xy() << ", " - << tile.bbox() << ")"; - return dbg.space(); -} -#endif // QT_NO_DEBUG - #endif // TILE_H diff --git a/src/map/tileloader.cpp b/src/map/tileloader.cpp index 48aa3b08..036ae439 100644 --- a/src/map/tileloader.cpp +++ b/src/map/tileloader.cpp @@ -1,42 +1,12 @@ #include #include #include -#include -#include -#include #include "tileloader.h" #define SUBSTITUTE_CHAR '$' #define IS_INT(zoom) \ ((QMetaType::Type)((zoom).type()) == QMetaType::Int) -class TileImage -{ -public: - TileImage() : _tile(0), _scaledSize(0) {} - TileImage(const QString &file, FetchTile *tile, int scaledSize) - : _file(file), _tile(tile), _scaledSize(scaledSize) {} - - void load() - { - QImage img; - QByteArray z(IS_INT(_tile->zoom()) - ? QByteArray::number(_tile->zoom().toInt()) : QByteArray()); - QImageReader reader(_file, z); - if (_scaledSize) - reader.setScaledSize(QSize(_scaledSize, _scaledSize)); - reader.read(&img); - _tile->pixmap().convertFromImage(img); - } - - const QString &file() const {return _file;} - FetchTile *tile() {return _tile;} - -private: - QString _file; - FetchTile *_tile; - int _scaledSize; -}; static QString fsSafeStr(const QString &str) { @@ -77,7 +47,7 @@ static QString quadKey(const QPoint &xy, int zoom) } TileLoader::TileLoader(const QString &dir, QObject *parent) - : QObject(parent), _urlType(XYZ), _dir(dir), _scaledSize(0) + : QObject(parent), _urlType(XYZ), _dir(dir) { if (!QDir().mkpath(_dir)) qWarning("%s: %s", qPrintable(_dir), "Error creating tiles directory"); @@ -87,26 +57,20 @@ TileLoader::TileLoader(const QString &dir, QObject *parent) } -void TileLoader::loadTilesAsync(QVector &list) +void TileLoader::loadTilesAsync(QVector &list) { QList dl; - QList imgs; for (int i = 0; i < list.size(); i++) { - FetchTile &t = list[i]; + Tile &t = list[i]; QString file(tileFile(t)); - if (QPixmapCache::find(file, &t.pixmap())) - continue; - - QFileInfo fi(file); - - if (fi.exists()) - imgs.append(TileImage(file, &t, _scaledSize)); + if (QFileInfo::exists(file)) + t.setFile(file); else { QUrl url(tileUrl(t)); if (url.isLocalFile()) - imgs.append(TileImage(url.toLocalFile(), &t, _scaledSize)); + t.setFile(url.toLocalFile()); else dl.append(Download(url, file)); } @@ -114,37 +78,23 @@ void TileLoader::loadTilesAsync(QVector &list) if (!dl.empty()) _downloader->get(dl, _headers); - - QFuture future = QtConcurrent::map(imgs, &TileImage::load); - future.waitForFinished(); - - for (int i = 0; i < imgs.size(); i++) { - TileImage &ti = imgs[i]; - QPixmapCache::insert(ti.file(), ti.tile()->pixmap()); - } } -void TileLoader::loadTilesSync(QVector &list) +void TileLoader::loadTilesSync(QVector &list) { QList dl; - QList tl; - QList imgs; + QList tl; for (int i = 0; i < list.size(); i++) { - FetchTile &t = list[i]; + Tile &t = list[i]; QString file(tileFile(t)); - if (QPixmapCache::find(file, &t.pixmap())) - continue; - - QFileInfo fi(file); - - if (fi.exists()) - imgs.append(TileImage(file, &t, _scaledSize)); + if (QFileInfo::exists(file)) + t.setFile(file); else { QUrl url(tileUrl(t)); if (url.isLocalFile()) - imgs.append(TileImage(url.toLocalFile(), &t, _scaledSize)); + t.setFile(url.toLocalFile()); else { dl.append(Download(url, file)); tl.append(&t); @@ -159,20 +109,12 @@ void TileLoader::loadTilesSync(QVector &list) wait.exec(); for (int i = 0; i < tl.size(); i++) { - FetchTile *t = tl[i]; + Tile *t = tl[i]; QString file = tileFile(*t); if (QFileInfo(file).exists()) - imgs.append(TileImage(file, t, _scaledSize)); + t->setFile(file); } } - - QFuture future = QtConcurrent::map(imgs, &TileImage::load); - future.waitForFinished(); - - for (int i = 0; i < imgs.size(); i++) { - TileImage &ti = imgs[i]; - QPixmapCache::insert(ti.file(), ti.tile()->pixmap()); - } } void TileLoader::clearCache() @@ -184,20 +126,9 @@ void TileLoader::clearCache() dir.remove(list.at(i)); _downloader->clearErrors(); - - QPixmapCache::clear(); -} - -void TileLoader::setScaledSize(int size) -{ - if (_scaledSize == size) - return; - - _scaledSize = size; - QPixmapCache::clear(); } -QUrl TileLoader::tileUrl(const FetchTile &tile) const +QUrl TileLoader::tileUrl(const Tile &tile) const { QString url(_url); @@ -221,7 +152,7 @@ QUrl TileLoader::tileUrl(const FetchTile &tile) const return QUrl(url); } -QString TileLoader::tileFile(const FetchTile &tile) const +QString TileLoader::tileFile(const Tile &tile) const { QString zoom(IS_INT(tile.zoom()) ? tile.zoom().toString() : fsSafeStr(tile.zoom().toString())); diff --git a/src/map/tileloader.h b/src/map/tileloader.h index dbcb2db8..c384eefa 100644 --- a/src/map/tileloader.h +++ b/src/map/tileloader.h @@ -4,7 +4,7 @@ #include #include #include "common/downloader.h" -#include "tile.h" +#include "rectd.h" class TileLoader : public QObject { @@ -17,29 +17,55 @@ class TileLoader : public QObject BoundingBox }; + class Tile + { + public: + Tile() {} + Tile(const QPoint &xy, int zoom) + : _xy(xy), _zoom(zoom) {} + Tile(const QPoint &xy, const QString &zoom) + : _xy(xy), _zoom(zoom) {} + Tile(const QPoint &xy, int zoom, const RectD &bbox) + : _xy(xy), _zoom(zoom), _bbox(bbox) {} + + const QVariant &zoom() const {return _zoom;} + const QPoint &xy() const {return _xy;} + const RectD &bbox() const {return _bbox;} + const QString &file() const {return _file;} + + private: + friend class TileLoader; + + void setFile(const QString &file) {_file = file;} + + QPoint _xy; + QVariant _zoom; + RectD _bbox; + QString _file; + }; + + TileLoader(const QString &dir, QObject *parent = 0); void setUrl(const QString &url, UrlType type) {_url = url; _urlType = type;} void setHeaders(const QList &headers) {_headers = headers;} - void setScaledSize(int size); - void loadTilesAsync(QVector &list); - void loadTilesSync(QVector &list); + void loadTilesAsync(QVector &list); + void loadTilesSync(QVector &list); void clearCache(); signals: void finished(); private: - QUrl tileUrl(const FetchTile &tile) const; - QString tileFile(const FetchTile &tile) const; + QUrl tileUrl(const Tile &tile) const; + QString tileFile(const Tile &tile) const; Downloader *_downloader; QString _url; UrlType _urlType; QString _dir; QList _headers; - int _scaledSize; }; #endif // TILELOADER_H diff --git a/src/map/wmsmap.cpp b/src/map/wmsmap.cpp index decfc615..392b5a2a 100644 --- a/src/map/wmsmap.cpp +++ b/src/map/wmsmap.cpp @@ -1,9 +1,12 @@ #include #include #include +#include +#include #include "common/wgs84.h" #include "common/rectc.h" #include "common/programpaths.h" +#include "tile.h" #include "tileloader.h" #include "wmsmap.h" @@ -111,6 +114,7 @@ void WMSMap::load(const Projection &in, const Projection &out, void WMSMap::clearCache() { _tileLoader->clearCache(); + QPixmapCache::clear(); } QRectF WMSMap::bounds() @@ -183,8 +187,8 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) QPoint br = QPoint(qCeil(rect.right() / tileSize()), qCeil(rect.bottom() / tileSize())); - QVector tiles; - tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y())); + QVector fetchTiles; + fetchTiles.reserve((br.x() - tl.x()) * (br.y() - tl.y())); for (int i = tl.x(); i < br.x(); i++) { for (int j = tl.y(); j < br.y(); j++) { PointD ttl(_transform.img2proj(QPointF(i * _tileSize, @@ -195,21 +199,47 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) ? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x())) : RectD(ttl, tbr); - tiles.append(FetchTile(QPoint(i, j), _zoom, bbox)); + fetchTiles.append(TileLoader::Tile(QPoint(i, j), _zoom, bbox)); } } if (flags & Map::Block) - _tileLoader->loadTilesSync(tiles); + _tileLoader->loadTilesSync(fetchTiles); else - _tileLoader->loadTilesAsync(tiles); - - for (int i = 0; i < tiles.count(); i++) { - FetchTile &t = tiles[i]; - QPointF tp(t.xy().x() * tileSize(), t.xy().y() * tileSize()); - if (!t.pixmap().isNull()) { - t.pixmap().setDevicePixelRatio(_mapRatio); - painter->drawPixmap(tp, t.pixmap()); - } + _tileLoader->loadTilesAsync(fetchTiles); + + QList renderTiles; + for (int i = 0; i < fetchTiles.count(); i++) { + const TileLoader::Tile &t = fetchTiles.at(i); + if (t.file().isNull()) + continue; + + QPixmap pm; + if (QPixmapCache::find(t.file(), &pm)) { + QPointF tp(t.xy().x() * tileSize(), t.xy().y() * tileSize()); + drawTile(painter, pm, tp); + } else + renderTiles.append(FileTile(t.xy(), t.file())); } + + QFuture future = QtConcurrent::map(renderTiles, &FileTile::load); + future.waitForFinished(); + + for (int i = 0; i < renderTiles.size(); i++) { + const FileTile &mt = renderTiles.at(i); + QPixmap pm(mt.pixmap()); + if (pm.isNull()) + continue; + + QPixmapCache::insert(mt.file(), pm); + + QPointF tp(mt.xy().x() * tileSize(), mt.xy().y() * tileSize()); + drawTile(painter, pm, tp); + } +} + +void WMSMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp) +{ + pixmap.setDevicePixelRatio(_mapRatio); + painter->drawPixmap(tp, pixmap); } diff --git a/src/map/wmsmap.h b/src/map/wmsmap.h index dd60ffe2..3ae0979a 100644 --- a/src/map/wmsmap.h +++ b/src/map/wmsmap.h @@ -51,6 +51,7 @@ private slots: void updateTransform(); qreal tileSize() const; void init(); + void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp); QString _name; WMS *_wms; diff --git a/src/map/wmtsmap.cpp b/src/map/wmtsmap.cpp index d2dcb770..180e104d 100644 --- a/src/map/wmtsmap.cpp +++ b/src/map/wmtsmap.cpp @@ -1,11 +1,14 @@ #include #include #include +#include +#include #include "common/rectc.h" #include "common/wgs84.h" #include "common/programpaths.h" #include "transform.h" #include "tileloader.h" +#include "tile.h" #include "wmts.h" #include "wmtsmap.h" @@ -56,6 +59,7 @@ void WMTSMap::load(const Projection &in, const Projection &out, void WMTSMap::clearCache() { _tileLoader->clearCache(); + QPixmapCache::clear(); } double WMTSMap::sd2res(double scaleDenominator) const @@ -189,25 +193,51 @@ void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) QPoint br = QPoint(qCeil(rect.right() / ts.width()), qCeil(rect.bottom() / ts.height())); - QVector tiles; - tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y())); + QVector fetchTiles; + fetchTiles.reserve((br.x() - tl.x()) * (br.y() - tl.y())); for (int i = tl.x(); i < br.x(); i++) for (int j = tl.y(); j < br.y(); j++) - tiles.append(FetchTile(QPoint(i, j), z.id())); + fetchTiles.append(TileLoader::Tile(QPoint(i, j), z.id())); if (flags & Map::Block) - _tileLoader->loadTilesSync(tiles); + _tileLoader->loadTilesSync(fetchTiles); else - _tileLoader->loadTilesAsync(tiles); - - for (int i = 0; i < tiles.count(); i++) { - FetchTile &t = tiles[i]; - QPointF tp(t.xy().x() * ts.width(), t.xy().y() * ts.height()); - if (!t.pixmap().isNull()) { - t.pixmap().setDevicePixelRatio(imageRatio()); - painter->drawPixmap(tp, t.pixmap()); - } + _tileLoader->loadTilesAsync(fetchTiles); + + QList renderTiles; + for (int i = 0; i < fetchTiles.count(); i++) { + const TileLoader::Tile &t = fetchTiles.at(i); + if (t.file().isNull()) + continue; + + QPixmap pm; + if (QPixmapCache::find(t.file(), &pm)) { + QPointF tp(t.xy().x() * ts.width(), t.xy().y() * ts.height()); + drawTile(painter, pm, tp); + } else + renderTiles.append(FileTile(t.xy(), t.file())); } + + QFuture future = QtConcurrent::map(renderTiles, &FileTile::load); + future.waitForFinished(); + + for (int i = 0; i < renderTiles.size(); i++) { + const FileTile &mt = renderTiles.at(i); + QPixmap pm(mt.pixmap()); + if (pm.isNull()) + continue; + + QPixmapCache::insert(mt.file(), pm); + + QPointF tp(mt.xy().x() * ts.width(), mt.xy().y() * ts.height()); + drawTile(painter, pm, tp); + } +} + +void WMTSMap::drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp) +{ + pixmap.setDevicePixelRatio(imageRatio()); + painter->drawPixmap(tp, pixmap); } QPointF WMTSMap::ll2xy(const Coordinates &c) diff --git a/src/map/wmtsmap.h b/src/map/wmtsmap.h index 10489d71..0d75d459 100644 --- a/src/map/wmtsmap.h +++ b/src/map/wmtsmap.h @@ -53,6 +53,7 @@ private slots: qreal coordinatesRatio() const; qreal imageRatio() const; void init(); + void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp); QString _name; WMTS *_wmts;