1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 23:03:22 +02:00
GPXSee/src/map/tileloader.cpp

213 lines
4.5 KiB
C++

#include <QDir>
#include <QFileInfo>
#include <QEventLoop>
#include <QPixmapCache>
#include <QImageReader>
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QtCore>
#else // QT_VERSION < 5
#include <QtConcurrent>
#endif // QT_VERSION < 5
#include "tileloader.h"
class TileImage
{
public:
TileImage() : _tile(0), _scaledSize(0) {}
TileImage(const QString &file, Tile *tile, int scaledSize)
: _file(file), _tile(tile), _scaledSize(scaledSize) {}
void createPixmap()
{
_tile->pixmap().convertFromImage(_image);
}
void load()
{
QByteArray z(_tile->zoom().toString().toLatin1());
QImageReader reader(_file, z);
if (_scaledSize)
reader.setScaledSize(QSize(_scaledSize, _scaledSize));
reader.read(&_image);
}
const QString &file() const {return _file;}
Tile *tile() {return _tile;}
private:
QString _file;
Tile *_tile;
int _scaledSize;
QImage _image;
};
static void render(TileImage &ti)
{
ti.load();
}
static QString quadKey(const QPoint &xy, int zoom)
{
QString qk;
for (int i = zoom; i > 0; i--) {
char digit = '0';
unsigned mask = 1 << (i - 1);
if (xy.x() & mask)
digit++;
if (xy.y() & mask)
digit += 2;
qk.append(digit);
}
return qk;
}
TileLoader::TileLoader(const QString &dir, QObject *parent)
: QObject(parent), _dir(dir), _scaledSize(0), _quadTiles(false)
{
if (!QDir().mkpath(_dir))
qWarning("%s: %s", qPrintable(_dir), "Error creating tiles directory");
_downloader = new Downloader(this);
connect(_downloader, SIGNAL(finished()), this, SIGNAL(finished()));
}
void TileLoader::loadTilesAsync(QVector<Tile> &list)
{
QList<Download> dl;
QList<TileImage> imgs;
for (int i = 0; i < list.size(); 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));
else {
QUrl url(tileUrl(t));
if (url.isLocalFile())
imgs.append(TileImage(url.toLocalFile(), &t, _scaledSize));
else
dl.append(Download(url, file));
}
}
if (!dl.empty())
_downloader->get(dl, _authorization);
QFuture<void> future = QtConcurrent::map(imgs, render);
future.waitForFinished();
for (int i = 0; i < imgs.size(); i++) {
TileImage &ti = imgs[i];
ti.createPixmap();
QPixmapCache::insert(ti.file(), ti.tile()->pixmap());
}
}
void TileLoader::loadTilesSync(QVector<Tile> &list)
{
QList<Download> dl;
QList<Tile *> tl;
QList<TileImage> imgs;
for (int i = 0; i < list.size(); 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));
else {
QUrl url(tileUrl(t));
if (url.isLocalFile())
imgs.append(TileImage(url.toLocalFile(), &t, _scaledSize));
else {
dl.append(Download(url, file));
tl.append(&t);
}
}
}
if (!dl.empty()) {
QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl, _authorization))
wait.exec();
for (int i = 0; i < tl.size(); i++) {
Tile *t = tl[i];
QString file = tileFile(*t);
if (QFileInfo(file).exists())
imgs.append(TileImage(file, t, _scaledSize));
}
}
QFuture<void> future = QtConcurrent::map(imgs, render);
future.waitForFinished();
for (int i = 0; i < imgs.size(); i++)
imgs[i].createPixmap();
}
void TileLoader::clearCache()
{
QDir dir = QDir(_dir);
QStringList list = dir.entryList();
for (int i = 0; i < list.count(); i++)
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 Tile &tile) const
{
QString url(_url);
if (!tile.bbox().isNull()) {
QString bbox = QString("%1,%2,%3,%4").arg(
QString::number(tile.bbox().left(), 'f', 6),
QString::number(tile.bbox().bottom(), 'f', 6),
QString::number(tile.bbox().right(), 'f', 6),
QString::number(tile.bbox().top(), 'f', 6));
url.replace("$bbox", bbox);
} else if (_quadTiles) {
url.replace("$quadkey", quadKey(tile.xy(), tile.zoom().toInt()));
} else {
url.replace("$z", tile.zoom().toString());
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
}
return QUrl(url);
}
QString TileLoader::tileFile(const Tile &tile) const
{
return _dir + QLatin1Char('/') + tile.zoom().toString() + QLatin1Char('-')
+ QString::number(tile.xy().x()) + QLatin1Char('-')
+ QString::number(tile.xy().y());
}