1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-12-03 16:09:08 +01:00

Compare commits

...

3 Commits

Author SHA1 Message Date
c1c8f6303c Code cleanup 2023-12-11 21:13:11 +01:00
5fcc27c176 Fixed broken TMS maps rendering 2023-12-11 20:31:13 +01:00
77e9fae19d Asynchronous rendering of online vector maps 2023-12-11 20:11:16 +01:00
2 changed files with 155 additions and 46 deletions

View File

@ -1,7 +1,6 @@
#include <QPainter> #include <QPainter>
#include <QDir> #include <QDir>
#include <QPixmapCache> #include <QPixmapCache>
#include <QtConcurrent>
#include "common/rectc.h" #include "common/rectc.h"
#include "common/programpaths.h" #include "common/programpaths.h"
#include "common/downloader.h" #include "common/downloader.h"
@ -11,18 +10,13 @@
#define MAX_OVERZOOM 3 #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, OnlineMap::OnlineMap(const QString &fileName, const QString &name,
const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio, const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio,
const QList<HTTPHeader> &headers, int tileSize, bool scalable, bool invertY, const QList<HTTPHeader> &headers, int tileSize, bool scalable, bool invertY,
bool quadTiles, QObject *parent) bool quadTiles, QObject *parent)
: Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds), : Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds),
_zoom(_zooms.max()), _tileSize(tileSize), _base(0), _mapRatio(1.0), _zoom(_zooms.max()), _tileSize(tileSize), _baseZoom(0), _mapRatio(1.0),
_tileRatio(tileRatio), _scalable(scalable), _invertY(invertY) _tileRatio(tileRatio), _scalable(scalable), _scaledSize(0), _invertY(invertY)
{ {
_tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name), _tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name),
this); this);
@ -31,7 +25,7 @@ OnlineMap::OnlineMap(const QString &fileName, const QString &name,
connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded);
if (_scalable) { if (_scalable) {
_base = _zooms.max(); _baseZoom = _zooms.max();
_zooms.setMax(qMin(_zooms.max() + MAX_OVERZOOM, OSM::ZOOMS.max())); _zooms.setMax(qMin(_zooms.max() + MAX_OVERZOOM, OSM::ZOOMS.max()));
} }
} }
@ -72,12 +66,16 @@ qreal OnlineMap::resolution(const QRectF &rect)
int OnlineMap::zoomIn() int OnlineMap::zoomIn()
{ {
cancelJobs(false);
_zoom = qMin(_zoom + 1, _zooms.max()); _zoom = qMin(_zoom + 1, _zooms.max());
return _zoom; return _zoom;
} }
int OnlineMap::zoomOut() int OnlineMap::zoomOut()
{ {
cancelJobs(false);
_zoom = qMax(_zoom - 1, _zooms.min()); _zoom = qMax(_zoom - 1, _zooms.min());
return _zoom; return _zoom;
} }
@ -96,6 +94,11 @@ void OnlineMap::load(const Projection &in, const Projection &out,
} }
} }
void OnlineMap::unload()
{
cancelJobs(true);
}
qreal OnlineMap::coordinatesRatio() const qreal OnlineMap::coordinatesRatio() const
{ {
return _mapRatio > 1.0 ? _mapRatio / _tileRatio : 1.0; return _mapRatio > 1.0 ? _mapRatio / _tileRatio : 1.0;
@ -116,16 +119,63 @@ QPoint OnlineMap::tileCoordinates(int x, int y, int zoom)
return QPoint(x, _invertY ? (1<<zoom) - y - 1 : y); return QPoint(x, _invertY ? (1<<zoom) - y - 1 : y);
} }
bool OnlineMap::isRunning(const QString &key) const
{
for (int i = 0; i < _jobs.size(); i++) {
const QList<OnlineMapTile> &tiles = _jobs.at(i)->tiles();
for (int j = 0; j < tiles.size(); j++)
if (tiles.at(j).key() == key)
return true;
}
return false;
}
void OnlineMap::runJob(OnlineMapJob *job)
{
_jobs.append(job);
connect(job, &OnlineMapJob::finished, this, &OnlineMap::jobFinished);
job->run();
}
void OnlineMap::removeJob(OnlineMapJob *job)
{
_jobs.removeOne(job);
job->deleteLater();
}
void OnlineMap::jobFinished(OnlineMapJob *job)
{
const QList<OnlineMapTile> &tiles = job->tiles();
for (int i = 0; i < tiles.size(); i++) {
const OnlineMapTile &mt = tiles.at(i);
if (!mt.pixmap().isNull())
QPixmapCache::insert(mt.key(), mt.pixmap());
}
removeJob(job);
emit tilesLoaded();
}
void OnlineMap::cancelJobs(bool wait)
{
for (int i = 0; i < _jobs.size(); i++)
_jobs.at(i)->cancel(wait);
}
void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags) void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{ {
int base = _scalable ? qMin(_base, _zoom) : _zoom; int baseZoom = _scalable ? qMin(_baseZoom, _zoom) : _zoom;
unsigned overzoom = _zoom - base; unsigned overzoom = _zoom - baseZoom;
unsigned f = 1U<<overzoom; unsigned f = 1U<<overzoom;
qreal scale = OSM::zoom2scale(base, _tileSize * f); qreal scale = OSM::zoom2scale(baseZoom, _tileSize * f);
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale, QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
-rect.topLeft().y() * scale) * coordinatesRatio(), base); -rect.topLeft().y() * scale) * coordinatesRatio(), baseZoom);
Coordinates ctl(OSM::tile2ll(tile, base)); Coordinates ctl(OSM::tile2ll(tile, baseZoom));
QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat()))); QPointF tl(ll2xy(Coordinates(ctl.lon(), -ctl.lat())));
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y()); QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
int width = ceil(s.width() / (tileSize() * f)); int width = ceil(s.width() / (tileSize() * f));
@ -135,8 +185,8 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
fetchTiles.reserve(width * height); fetchTiles.reserve(width * height);
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) { for (int j = 0; j < height; j++) {
QPoint tc(tileCoordinates(tile.x() + i, tile.y() + j, base)); QPoint tc(tileCoordinates(tile.x() + i, tile.y() + j, baseZoom));
fetchTiles.append(TileLoader::Tile(tc, base)); fetchTiles.append(TileLoader::Tile(tc, baseZoom));
} }
} }
@ -145,36 +195,49 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
else else
_tileLoader->loadTilesAsync(fetchTiles); _tileLoader->loadTilesAsync(fetchTiles);
QList<OnlineTile> renderTiles; QList<OnlineMapTile> renderTiles;
for (int i = 0; i < fetchTiles.count(); i++) { for (int i = 0; i < fetchTiles.count(); i++) {
const TileLoader::Tile &t = fetchTiles.at(i); const TileLoader::Tile &t = fetchTiles.at(i);
if (t.file().isNull()) if (t.file().isNull())
continue; continue;
QPixmap pm; QString key(overzoom
if (QPixmapCache::find(cacheName(t.file(), overzoom), &pm)) { ? t.file() + ":" + QString::number(overzoom) : t.file());
QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize() * f, if (isRunning(key))
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<void> 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; continue;
QPixmapCache::insert(cacheName(mt.file(), overzoom), pm); QPixmap pm;
if (QPixmapCache::find(key, &pm)) {
QPoint tc(tileCoordinates(t.xy().x(), t.xy().y(), baseZoom));
QPointF tp(tl.x() + (tc.x() - tile.x()) * tileSize() * f,
tl.y() + (tc.y() - tile.y()) * tileSize() * f);
drawTile(painter, pm, tp);
} else
renderTiles.append(OnlineMapTile(t.xy(), t.file(), _zoom, overzoom,
_scaledSize, key));
}
QPointF tp(tl.x() + (mt.xy().x() - tile.x()) * tileSize() * f, if (!renderTiles.isEmpty()) {
tl.y() + (mt.xy().y() - tile.y()) * tileSize() * f); if (flags & Map::Block || !_scalable) {
drawTile(painter, pm, tp); QFuture<void> future = QtConcurrent::map(renderTiles,
&OnlineMapTile::load);
future.waitForFinished();
for (int i = 0; i < renderTiles.size(); i++) {
const OnlineMapTile &mt = renderTiles.at(i);
QPixmap pm(mt.pixmap());
if (pm.isNull())
continue;
QPixmapCache::insert(mt.key(), pm);
QPoint tc(tileCoordinates(mt.xy().x(), mt.xy().y(), baseZoom));
QPointF tp(tl.x() + (tc.x() - tile.x()) * tileSize() * f,
tl.y() + (tc.y() - tile.y()) * tileSize() * f);
drawTile(painter, pm, tp);
}
} else
runJob(new OnlineMapJob(renderTiles));
} }
} }

View File

@ -3,17 +3,18 @@
#include <QImageReader> #include <QImageReader>
#include <QPixmap> #include <QPixmap>
#include <QtConcurrent>
#include "common/range.h" #include "common/range.h"
#include "common/rectc.h" #include "common/rectc.h"
#include "map.h" #include "map.h"
#include "tileloader.h" #include "tileloader.h"
class OnlineTile class OnlineMapTile
{ {
public: public:
OnlineTile(const QPoint &xy, const QString &file, int zoom, int overzoom, OnlineMapTile(const QPoint &xy, const QString &file, int zoom, int overzoom,
int scaledSize) : _xy(xy), _file(file), _zoom(zoom), _overzoom(overzoom), int scaledSize, const QString &key) : _zoom(zoom), _overzoom(overzoom),
_scaledSize(scaledSize) {} _scaledSize(scaledSize), _xy(xy), _file(file), _key(key) {}
void load() void load()
{ {
@ -27,18 +28,53 @@ public:
} }
const QPoint &xy() const {return _xy;} const QPoint &xy() const {return _xy;}
const QString &file() const {return _file;}
const QPixmap &pixmap() const {return _pixmap;} const QPixmap &pixmap() const {return _pixmap;}
const QString &key() const {return _key;}
private: private:
QPoint _xy;
QString _file;
int _zoom; int _zoom;
int _overzoom; int _overzoom;
int _scaledSize; int _scaledSize;
QPoint _xy;
QString _file;
QString _key;
QPixmap _pixmap; QPixmap _pixmap;
}; };
class OnlineMapJob : public QObject
{
Q_OBJECT
public:
OnlineMapJob(const QList<OnlineMapTile> &tiles) : _tiles(tiles) {}
void run()
{
connect(&_watcher, &QFutureWatcher<void>::finished, this,
&OnlineMapJob::handleFinished);
_future = QtConcurrent::map(_tiles, &OnlineMapTile::load);
_watcher.setFuture(_future);
}
void cancel(bool wait)
{
_future.cancel();
if (wait)
_future.waitForFinished();
}
const QList<OnlineMapTile> &tiles() const {return _tiles;}
signals:
void finished(OnlineMapJob *job);
private slots:
void handleFinished() {emit finished(this);}
private:
QFutureWatcher<void> _watcher;
QFuture<void> _future;
QList<OnlineMapTile> _tiles;
};
class OnlineMap : public Map class OnlineMap : public Map
{ {
Q_OBJECT Q_OBJECT
@ -68,8 +104,12 @@ public:
void load(const Projection &in, const Projection &out, qreal deviceRatio, void load(const Projection &in, const Projection &out, qreal deviceRatio,
bool hidpi); bool hidpi);
void unload();
void clearCache(); void clearCache();
private slots:
void jobFinished(OnlineMapJob *job);
private: private:
int limitZoom(int zoom) const; int limitZoom(int zoom) const;
qreal tileSize() const; qreal tileSize() const;
@ -77,6 +117,10 @@ private:
qreal imageRatio() const; qreal imageRatio() const;
QPoint tileCoordinates(int x, int y, int zoom); QPoint tileCoordinates(int x, int y, int zoom);
void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp); void drawTile(QPainter *painter, QPixmap &pixmap, QPointF &tp);
bool isRunning(const QString &key) const;
void runJob(OnlineMapJob *job);
void removeJob(OnlineMapJob *job);
void cancelJobs(bool wait);
TileLoader *_tileLoader; TileLoader *_tileLoader;
QString _name; QString _name;
@ -84,11 +128,13 @@ private:
RectC _bounds; RectC _bounds;
int _zoom; int _zoom;
int _tileSize; int _tileSize;
int _base; int _baseZoom;
qreal _mapRatio, _tileRatio; qreal _mapRatio, _tileRatio;
bool _scalable; bool _scalable;
int _scaledSize; int _scaledSize;
bool _invertY; bool _invertY;
QList<OnlineMapJob*> _jobs;
}; };
#endif // ONLINEMAP_H #endif // ONLINEMAP_H