diff --git a/src/map/IMG/rastertile.cpp b/src/map/IMG/rastertile.cpp index 81c0608b..01986d52 100644 --- a/src/map/IMG/rastertile.cpp +++ b/src/map/IMG/rastertile.cpp @@ -174,6 +174,8 @@ void RasterTile::render() qDeleteAll(textItems); + _valid = true; + //painter.setPen(Qt::red); //painter.setRenderHint(QPainter::Antialiasing, false); //painter.drawRect(QRect(_xy, _pixmap.size())); @@ -185,7 +187,7 @@ void RasterTile::ll2xy(QList &polys) MapData::Poly &poly = polys[i]; for (int j = 0; j < poly.points.size(); j++) { QPointF &p = poly.points[j]; - p = _map->ll2xy(Coordinates(p.x(), p.y())); + p = ll2xy(Coordinates(p.x(), p.y())); } } } @@ -193,7 +195,7 @@ void RasterTile::ll2xy(QList &polys) void RasterTile::ll2xy(QList &points) { for (int i = 0; i < points.size(); i++) { - QPointF p(_map->ll2xy(points.at(i).coordinates)); + QPointF p(ll2xy(points.at(i).coordinates)); points[i].coordinates = Coordinates(p.x(), p.y()); } } @@ -210,8 +212,8 @@ void RasterTile::drawPolygons(QPainter *painter) if (poly.raster.isValid()) { RectC r(poly.raster.rect()); - QPointF tl(_map->ll2xy(r.topLeft())); - QPointF br(_map->ll2xy(r.bottomRight())); + QPointF tl(ll2xy(r.topLeft())); + QPointF br(ll2xy(r.bottomRight())); QSizeF size(QRectF(tl, br).size()); bool insert = false; diff --git a/src/map/IMG/rastertile.h b/src/map/IMG/rastertile.h index 5aa169f8..5dc4fbfe 100644 --- a/src/map/IMG/rastertile.h +++ b/src/map/IMG/rastertile.h @@ -3,6 +3,8 @@ #include #include "mapdata.h" +#include "map/projection.h" +#include "map/transform.h" class QPainter; class IMGMap; @@ -15,20 +17,25 @@ class Style; class RasterTile { public: - RasterTile(IMGMap *map, const Style *style, int zoom, const QRect &rect, - qreal ratio, const QString &key, const QList &polygons, + RasterTile(const Projection &proj, const Transform &transform, + const Style *style, int zoom, const QRect &rect, qreal ratio, + const QString &key, const QList &polygons, const QList &lines, QList &points) - : _map(map), _style(style), _zoom(zoom), _rect(rect), _ratio(ratio), - _key(key), _pixmap(rect.width() * ratio, rect.height() * ratio), - _polygons(polygons), _lines(lines), _points(points) {} + : _proj(proj), _transform(transform), _style(style), _zoom(zoom), + _rect(rect), _ratio(ratio), _key(key), + _pixmap(rect.width() * ratio, rect.height() * ratio), _polygons(polygons), + _lines(lines), _points(points), _valid(false) {} const QString &key() const {return _key;} QPoint xy() const {return _rect.topLeft();} const QPixmap &pixmap() const {return _pixmap;} + bool isValid() const {return _valid;} void render(); private: + QPointF ll2xy(const Coordinates &c) const + {return _transform.proj2img(_proj.ll2xy(c));} void ll2xy(QList &polys); void ll2xy(QList &points); @@ -42,7 +49,8 @@ private: void processShields(QList &textItems); void processStreetNames(QList &textItems); - IMGMap *_map; + Projection _proj; + Transform _transform; const Style *_style; int _zoom; QRect _rect; @@ -52,6 +60,7 @@ private: QList _polygons; QList _lines; QList _points; + bool _valid; }; } diff --git a/src/map/imgmap.cpp b/src/map/imgmap.cpp index 667d66c0..dc5064f1 100644 --- a/src/map/imgmap.cpp +++ b/src/map/imgmap.cpp @@ -100,6 +100,8 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect) int IMGMap::zoomIn() { + cancelJobs(); + _zoom = qMin(_zoom + 1, _data.first()->zooms().max()); updateTransform(); return _zoom; @@ -107,6 +109,8 @@ int IMGMap::zoomIn() int IMGMap::zoomOut() { + cancelJobs(); + _zoom = qMax(_zoom - 1, _data.first()->zooms().min()); updateTransform(); return _zoom; @@ -139,6 +143,53 @@ void IMGMap::updateTransform() _bounds.adjust(0.5, 0, -0.5, 0); } +bool IMGMap::isRunning(const QString &key) const +{ + for (int i = 0; i < _jobs.size(); i++) { + const QList &tiles = _jobs.at(i)->tiles(); + for (int j = 0; j < tiles.size(); j++) + if (tiles.at(j).key() == key) + return true; + } + + return false; +} + +void IMGMap::runJob(IMGMapJob *job) +{ + _jobs.append(job); + + connect(job, &IMGMapJob::finished, this, &IMGMap::jobFinished); + job->run(); +} + +void IMGMap::removeJob(IMGMapJob *job) +{ + _jobs.removeOne(job); + job->deleteLater(); +} + +void IMGMap::jobFinished(IMGMapJob *job) +{ + const QList &tiles = job->tiles(); + + for (int i = 0; i < tiles.size(); i++) { + const IMG::RasterTile &mt = tiles.at(i); + if (mt.isValid()) + QPixmapCache::insert(mt.key(), mt.pixmap()); + } + + removeJob(job); + + emit tilesLoaded(); +} + +void IMGMap::cancelJobs() +{ + for (int i = 0; i < _jobs.size(); i++) + _jobs.at(i)->cancel(); +} + void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags) { Q_UNUSED(flags); @@ -159,6 +210,9 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags) QString key(_data.at(n)->fileName() + "-" + QString::number(_zoom) + "_" + QString::number(ttl.x()) + "_" + QString::number(ttl.y())); + if (isRunning(key)) + continue; + if (QPixmapCache::find(key, &pm)) painter->drawPixmap(ttl, pm); else { @@ -182,7 +236,8 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags) _data.at(n)->points(pointRectD.toRectC(_projection, 20), _zoom, &points); - tiles.append(RasterTile(this, _data.at(n)->style(), _zoom, + tiles.append(RasterTile(_projection, _transform, + _data.at(n)->style(), _zoom, QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), _tileRatio, key, polygons, lines, points)); } @@ -190,14 +245,19 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags) } } - QFuture future = QtConcurrent::map(tiles, &RasterTile::render); - future.waitForFinished(); + if (!tiles.isEmpty()) { + if (flags & Map::Block) { + QFuture future = QtConcurrent::map(tiles, &RasterTile::render); + future.waitForFinished(); - for (int i = 0; i < tiles.size(); i++) { - const RasterTile &mt = tiles.at(i); - const QPixmap &pm = mt.pixmap(); - painter->drawPixmap(mt.xy(), pm); - QPixmapCache::insert(mt.key(), pm); + for (int i = 0; i < tiles.size(); i++) { + const RasterTile &mt = tiles.at(i); + const QPixmap &pm = mt.pixmap(); + painter->drawPixmap(mt.xy(), pm); + QPixmapCache::insert(mt.key(), pm); + } + } else + runJob(new IMGMapJob(tiles)); } } diff --git a/src/map/imgmap.h b/src/map/imgmap.h index c1573580..b5e1b5f7 100644 --- a/src/map/imgmap.h +++ b/src/map/imgmap.h @@ -1,12 +1,44 @@ #ifndef IMGMAP_H #define IMGMAP_H +#include #include "map.h" #include "projection.h" #include "transform.h" #include "IMG/mapdata.h" +#include "IMG/rastertile.h" +class IMGMapJob : public QObject +{ + Q_OBJECT + +public: + IMGMapJob(const QList &tiles) + : _tiles(tiles) {} + + void run() + { + connect(&_watcher, &QFutureWatcher::finished, this, + &IMGMapJob::handleFinished); + _future = QtConcurrent::map(_tiles, &IMG::RasterTile::render); + _watcher.setFuture(_future); + } + void cancel() {_future.cancel();} + const QList &tiles() const {return _tiles;} + +signals: + void finished(IMGMapJob *job); + +private slots: + void handleFinished() {emit finished(this);} + +private: + QFutureWatcher _watcher; + QFuture _future; + QList _tiles; +}; + class IMGMap : public Map { Q_OBJECT @@ -44,9 +76,16 @@ public: static Map* create(const QString &path, const Projection &, bool *isDir); +private slots: + void jobFinished(IMGMapJob *job); + private: Transform transform(int zoom) const; void updateTransform(); + bool isRunning(const QString &key) const; + void runJob(IMGMapJob *job); + void removeJob(IMGMapJob *job); + void cancelJobs(); QList _data; int _zoom; @@ -56,6 +95,8 @@ private: RectC _dataBounds; qreal _tileRatio; + QList _jobs; + bool _valid; QString _errorString; };