#include "mapview.h" #include "mapview_tile_cache_p.h" #include "mapview_tile_downloader_p.h" #include "qad_locations.h" MapViewTileCache::MapViewTileCache(MapView * p): QThread() { qRegisterMetaType(); qRegisterMetaType(); parent = p; setCacheRoot(QAD::userPath(QAD::ltCache, "mapview") + "/"); setAdditionalCacheSize(64); start(); } MapViewTileCache::~MapViewTileCache() { requestInterruption(); cond.wakeAll(); wait(); } void MapViewTileCache::tileDownloaded(MapViewTypes::TileIndex index, const QPixmap & pixmap) { auto * tile = new MapViewTypes::TilePixmap(); tile->index = index; tile->pixmap = pixmap; saveTile(tile); } MapViewTypes::TilePixmap MapViewTileCache::getTile(MapViewTypes::TileIndex index, QRectF & rect_src) { MapViewTypes::TilePixmap ret = getTileFromCache(index); if (ret.isEmpty() || ret.obsolete) { if (!is_offline) parent->downloader->queueTile(index); } if (ret.isEmpty()) { QVector offsets; while (index.z >= 0) { index.z--; offsets << QPointF(index.x % 2, index.y % 2); index.x /= 2; index.y /= 2; ret = getTileFromCache(index); if (!ret.isEmpty()) { for (int i = offsets.size() - 1; i >= 0; --i) { rect_src.setSize(rect_src.size() / 2.); rect_src.translate(offsets[i].x() * rect_src.width(), offsets[i].y() * rect_src.height()); } return ret; } } } else rect_src = ret.pixmap.rect(); return ret; } void MapViewTileCache::clearCache() { tile_cache.clear(); } bool MapViewTileCache::isTileFileExists(MapViewTypes::TileIndex index) const { QString hashdir = index.cacheDir(); if (!cache_dir.exists(hashdir)) return false; QString hashname = hashdir + "/" + index.hashName(); return cache_dir.exists(hashname); } void MapViewTileCache::setCacheRoot(const QString & p) { cache_root = p; tileProviderChanged(); } void MapViewTileCache::tileProviderChanged() { cache_dir.setPath(cache_root); auto * provider = parent->downloader->provider; if (provider) { cache_dir.setPath(cache_root + "/" + provider->cacheDir()); } qDebug() << "[MapViewTileCache] Cache dir" << cache_dir.absolutePath(); if (!cache_dir.exists()) cache_dir.mkpath("."); } void MapViewTileCache::setOfflineMode(bool yes) { is_offline = yes; } MapViewTypes::TilePixmap MapViewTileCache::getTileFromCache(MapViewTypes::TileIndex index) { MapViewTypes::TilePixmap ret; ret.index = index; auto * tile = tile_cache[index.hash()]; if (tile) { ret.pixmap = tile->pixmap; } else { QString hashdir = index.cacheDir(); if (cache_dir.exists(hashdir)) { QString hashname = hashdir + "/" + index.hashName(); if (cache_dir.exists(hashname)) { QString fname = cache_dir.absoluteFilePath(hashname); ret.pixmap.load(fname, "png"); tile = new MapViewTypes::TilePixmap(); tile->index = index; tile->pixmap = ret.pixmap; if (secs_obsolete > 0) { int secs_old = QFileInfo(fname).lastModified().secsTo(QDateTime::currentDateTime()); ret.obsolete = secs_old >= secs_obsolete; } tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes()); return ret; } } } return ret; } void MapViewTileCache::updateCacheSize() { tile_cache.setMaxCost(fixed_size_b + add_size_b); } void MapViewTileCache::saveTile(MapViewTypes::TilePixmap * tile) { tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes()); emit tileReady(*tile); cond_mutex.lock(); if (!queue.contains(*tile)) { queue.enqueue(*tile); cond.wakeOne(); } cond_mutex.unlock(); } void MapViewTileCache::writeToDisk(const MapViewTypes::TilePixmap & tile) { QString hashdir = tile.index.cacheDir(); if (!cache_dir.exists(hashdir)) cache_dir.mkdir(hashdir); QFile f(cache_dir.absoluteFilePath(hashdir + "/" + tile.index.hashName())); if (!f.open(QIODevice::ReadWrite)) return; f.resize(0); tile.pixmap.save(&f, "png"); } void MapViewTileCache::run() { while (!isInterruptionRequested()) { MapViewTypes::TilePixmap tile; cond_mutex.lock(); if (queue.isEmpty()) { cond.wait(&cond_mutex); cond_mutex.unlock(); } else { tile = queue.dequeue(); cond_mutex.unlock(); writeToDisk(tile); } } }