3 #include <QPixmapCache>
4 #include "common/rectc.h"
5 #include "common/programpaths.h"
6 #include "common/downloader.h"
11 #define MAX_TILE_SIZE 4096
13 OnlineMap::OnlineMap(const QString
&fileName
, const QString
&name
,
14 const QString
&url
, const Range
&zooms
, const RectC
&bounds
, qreal tileRatio
,
15 const QList
<HTTPHeader
> &headers
, int tileSize
, bool scalable
, bool invertY
,
16 bool quadTiles
, QObject
*parent
)
17 : Map(fileName
, parent
), _name(name
), _zooms(zooms
), _bounds(bounds
),
18 _zoom(_zooms
.max()), _tileSize(tileSize
), _baseZoom(0), _mapRatio(1.0),
19 _tileRatio(tileRatio
), _scalable(scalable
), _scaledSize(0), _invertY(invertY
)
21 _tileLoader
= new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name
),
23 _tileLoader
->setUrl(url
, quadTiles
? TileLoader::QuadTiles
: TileLoader::XYZ
);
24 _tileLoader
->setHeaders(headers
);
25 connect(_tileLoader
, &TileLoader::finished
, this, &OnlineMap::tilesLoaded
);
27 _baseZoom
= _zooms
.max();
30 QRectF
OnlineMap::bounds()
32 return QRectF(ll2xy(_bounds
.topLeft()), ll2xy(_bounds
.bottomRight()));
35 int OnlineMap::limitZoom(int zoom
) const
37 if (zoom
< _zooms
.min())
39 if (zoom
> _zooms
.max())
45 int OnlineMap::zoomFit(const QSize
&size
, const RectC
&rect
)
50 QRectF
tbr(OSM::ll2m(rect
.topLeft()), OSM::ll2m(rect
.bottomRight()));
51 QPointF
sc(tbr
.width() / size
.width(), tbr
.height() / size
.height());
52 _zoom
= limitZoom(OSM::scale2zoom(qMax(sc
.x(), -sc
.y())
53 / coordinatesRatio(), _tileSize
));
59 qreal
OnlineMap::resolution(const QRectF
&rect
)
61 return OSM::resolution(rect
.center(), _zoom
, _tileSize
);
64 int OnlineMap::zoomIn()
68 _zoom
= qMin(_zoom
+ 1, _zooms
.max());
72 int OnlineMap::zoomOut()
76 _zoom
= qMax(_zoom
- 1, _zooms
.min());
80 void OnlineMap::load(const Projection
&in
, const Projection
&out
,
81 qreal deviceRatio
, bool hidpi
)
86 _mapRatio
= hidpi
? deviceRatio
: 1.0;
87 _zooms
.setMax(_baseZoom
);
90 _scaledSize
= _tileSize
* deviceRatio
;
91 _tileRatio
= deviceRatio
;
93 for (int i
= _baseZoom
+ 1; i
<= OSM::ZOOMS
.max(); i
++) {
94 if (_tileSize
* _tileRatio
* (1U<<(i
- _baseZoom
)) > MAX_TILE_SIZE
)
101 void OnlineMap::unload()
106 qreal
OnlineMap::coordinatesRatio() const
108 return _mapRatio
> 1.0 ? _mapRatio
/ _tileRatio
: 1.0;
111 qreal
OnlineMap::imageRatio() const
113 return _mapRatio
> 1.0 ? _mapRatio
: _tileRatio
;
116 qreal
OnlineMap::tileSize() const
118 return (_tileSize
/ coordinatesRatio());
121 QPoint
OnlineMap::tileCoordinates(int x
, int y
, int zoom
)
123 return QPoint(x
, _invertY
? (1<<zoom
) - y
- 1 : y
);
126 bool OnlineMap::isRunning(const QString
&key
) const
128 for (int i
= 0; i
< _jobs
.size(); i
++) {
129 const QList
<OnlineMapTile
> &tiles
= _jobs
.at(i
)->tiles();
130 for (int j
= 0; j
< tiles
.size(); j
++)
131 if (tiles
.at(j
).key() == key
)
138 void OnlineMap::runJob(OnlineMapJob
*job
)
142 connect(job
, &OnlineMapJob::finished
, this, &OnlineMap::jobFinished
);
146 void OnlineMap::removeJob(OnlineMapJob
*job
)
148 _jobs
.removeOne(job
);
152 void OnlineMap::jobFinished(OnlineMapJob
*job
)
154 const QList
<OnlineMapTile
> &tiles
= job
->tiles();
156 for (int i
= 0; i
< tiles
.size(); i
++) {
157 const OnlineMapTile
&mt
= tiles
.at(i
);
158 if (!mt
.pixmap().isNull())
159 QPixmapCache::insert(mt
.key(), mt
.pixmap());
167 void OnlineMap::cancelJobs(bool wait
)
169 for (int i
= 0; i
< _jobs
.size(); i
++)
170 _jobs
.at(i
)->cancel(wait
);
173 void OnlineMap::draw(QPainter
*painter
, const QRectF
&rect
, Flags flags
)
175 int baseZoom
= qMin(_baseZoom
, _zoom
);
176 unsigned overzoom
= _zoom
- baseZoom
;
177 unsigned f
= 1U<<overzoom
;
179 qreal scale
= OSM::zoom2scale(baseZoom
, _tileSize
* f
);
180 QPoint tile
= OSM::mercator2tile(QPointF(rect
.topLeft().x() * scale
,
181 -rect
.topLeft().y() * scale
) * coordinatesRatio(), baseZoom
);
182 Coordinates
ctl(OSM::tile2ll(tile
, baseZoom
));
183 QPointF
tl(ll2xy(Coordinates(ctl
.lon(), -ctl
.lat())));
184 QSizeF
s(rect
.right() - tl
.x(), rect
.bottom() - tl
.y());
185 int width
= ceil(s
.width() / (tileSize() * f
));
186 int height
= ceil(s
.height() / (tileSize() * f
));
188 QVector
<TileLoader::Tile
> fetchTiles
;
189 fetchTiles
.reserve(width
* height
);
190 for (int i
= 0; i
< width
; i
++) {
191 for (int j
= 0; j
< height
; j
++) {
192 QPoint
tc(tileCoordinates(tile
.x() + i
, tile
.y() + j
, baseZoom
));
193 fetchTiles
.append(TileLoader::Tile(tc
, baseZoom
));
197 if (flags
& Map::Block
)
198 _tileLoader
->loadTilesSync(fetchTiles
);
200 _tileLoader
->loadTilesAsync(fetchTiles
);
202 QList
<OnlineMapTile
> renderTiles
;
203 for (int i
= 0; i
< fetchTiles
.count(); i
++) {
204 const TileLoader::Tile
&t
= fetchTiles
.at(i
);
205 if (t
.file().isNull())
209 ? t
.file() + ":" + QString::number(overzoom
) : t
.file());
214 if (QPixmapCache::find(key
, &pm
)) {
215 QPoint
tc(tileCoordinates(t
.xy().x(), t
.xy().y(), baseZoom
));
216 QPointF
tp(tl
.x() + (tc
.x() - tile
.x()) * tileSize() * f
,
217 tl
.y() + (tc
.y() - tile
.y()) * tileSize() * f
);
218 drawTile(painter
, pm
, tp
);
220 renderTiles
.append(OnlineMapTile(t
.xy(), t
.file(), _zoom
, overzoom
,
224 if (!renderTiles
.isEmpty()) {
225 if (flags
& Map::Block
|| !_scalable
) {
226 QFuture
<void> future
= QtConcurrent::map(renderTiles
,
227 &OnlineMapTile::load
);
228 future
.waitForFinished();
230 for (int i
= 0; i
< renderTiles
.size(); i
++) {
231 const OnlineMapTile
&mt
= renderTiles
.at(i
);
232 QPixmap
pm(mt
.pixmap());
236 QPixmapCache::insert(mt
.key(), pm
);
238 QPoint
tc(tileCoordinates(mt
.xy().x(), mt
.xy().y(), baseZoom
));
239 QPointF
tp(tl
.x() + (tc
.x() - tile
.x()) * tileSize() * f
,
240 tl
.y() + (tc
.y() - tile
.y()) * tileSize() * f
);
241 drawTile(painter
, pm
, tp
);
244 runJob(new OnlineMapJob(renderTiles
));
248 void OnlineMap::drawTile(QPainter
*painter
, QPixmap
&pixmap
, QPointF
&tp
)
250 pixmap
.setDevicePixelRatio(imageRatio());
251 painter
->drawPixmap(tp
, pixmap
);
254 QPointF
OnlineMap::ll2xy(const Coordinates
&c
)
256 qreal scale
= OSM::zoom2scale(_zoom
, _tileSize
);
257 QPointF m
= OSM::ll2m(c
);
258 return QPointF(m
.x() / scale
, m
.y() / -scale
) / coordinatesRatio();
261 Coordinates
OnlineMap::xy2ll(const QPointF
&p
)
263 qreal scale
= OSM::zoom2scale(_zoom
, _tileSize
);
264 return OSM::m2ll(QPointF(p
.x() * scale
, -p
.y() * scale
)
265 * coordinatesRatio());
268 void OnlineMap::clearCache()
270 _tileLoader
->clearCache();
271 QPixmapCache::clear();