1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-06-28 03:59:15 +02:00

Do not do any time consuming actions in the mapview redraw callback

On all vector maps (ENC, IMG and Mapsforge), do the data loading
asynchronous like the tile rendering.
This commit is contained in:
2023-05-19 19:33:22 +02:00
parent 4615709b99
commit a92d6efec6
17 changed files with 340 additions and 282 deletions

View File

@ -208,13 +208,15 @@ bool MapData::readTags(SubFile &subfile, int count,
bool MapData::readSubFiles()
{
QDataStream stream(&_file);
/* both _pointFile and _pathFile can be used here */
QDataStream stream(&_pointFile);
for (int i = 0; i < _subFiles.size(); i++) {
const SubFileInfo &f = _subFiles.at(i);
quint64 offset, nextOffset;
stream.device()->seek(f.offset);
if (!stream.device()->seek(f.offset))
return false;
QPoint tl(OSM::ll2tile(_bounds.topLeft(), f.base));
QPoint br(OSM::ll2tile(_bounds.bottomRight(), f.base));
@ -359,7 +361,7 @@ bool MapData::readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap)
return true;
}
bool MapData::readHeader()
bool MapData::readHeader(QFile &file)
{
char magic[MAGIC_SIZE];
quint32 hdrSize;
@ -367,18 +369,18 @@ bool MapData::readHeader()
bool debugMap;
if (_file.read(magic, MAGIC_SIZE) < (qint64)MAGIC_SIZE
if (file.read(magic, MAGIC_SIZE) < (qint64)MAGIC_SIZE
|| memcmp(magic, MAGIC, MAGIC_SIZE)) {
_errorString = "Not a Mapsforge map";
return false;
}
if (_file.read((char*)&hdrSize, sizeof(hdrSize)) < (qint64)sizeof(hdrSize)) {
if (file.read((char*)&hdrSize, sizeof(hdrSize)) < (qint64)sizeof(hdrSize)) {
_errorString = "Unexpected EOF";
return false;
}
SubFile hdr(_file, MAGIC_SIZE, qFromBigEndian(hdrSize));
SubFile hdr(file, MAGIC_SIZE, qFromBigEndian(hdrSize));
if (!readMapInfo(hdr, projection, debugMap)) {
_errorString = "Error reading map info";
@ -407,18 +409,19 @@ bool MapData::readHeader()
return true;
}
MapData::MapData(const QString &fileName) : _file(fileName), _valid(false)
MapData::MapData(const QString &fileName)
: _pointFile(fileName), _pathFile(fileName), _valid(false)
{
if (!_file.open(QFile::ReadOnly | QIODevice::Unbuffered)) {
_errorString = _file.errorString();
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QIODevice::Unbuffered)) {
_errorString = file.errorString();
return;
}
if (!readHeader())
if (!readHeader(file))
return;
_file.close();
_pathCache.setMaxCost(256);
_pointCache.setMaxCost(256);
@ -444,13 +447,16 @@ RectC MapData::bounds() const
void MapData::load()
{
if (_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered))
readSubFiles();
_pointFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
_pathFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
readSubFiles();
}
void MapData::clear()
{
_file.close();
_pointFile.close();
_pathFile.close();
_pathCache.clear();
_pointCache.clear();
@ -516,6 +522,9 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
QList<Point> *list)
{
Key key(tile, zoom);
_pointLock.lock();
QList<Point> *cached = _pointCache.object(key);
if (!cached) {
@ -527,6 +536,8 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
delete p;
} else
copyPoints(rect, cached, list);
_pointLock.unlock();
}
void MapData::paths(const RectC &rect, int zoom, QList<Path> *list)
@ -550,6 +561,9 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
QList<Path> *list)
{
Key key(tile, zoom);
_pathLock.lock();
QList<Path> *cached = _pathCache.object(key);
if (!cached) {
@ -561,12 +575,14 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom,
delete p;
} else
copyPaths(rect, cached, list);
_pathLock.unlock();
}
bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
{
const SubFileInfo &info = _subFiles.at(level(zoom));
SubFile subfile(_file, info.offset, info.size);
SubFile subfile(_pathFile, info.offset, info.size);
int rows = info.max - info.min + 1;
QVector<unsigned> paths(rows);
quint32 blocks, unused, val, cnt = 0;
@ -652,7 +668,7 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
{
const SubFileInfo &info = _subFiles.at(level(zoom));
SubFile subfile(_file, info.offset, info.size);
SubFile subfile(_pointFile, info.offset, info.size);
int rows = info.max - info.min + 1;
QVector<unsigned> points(rows);
quint32 val, unused, cnt = 0;

View File

@ -3,6 +3,7 @@
#include <QFile>
#include <QCache>
#include <QMutex>
#include "common/hash.h"
#include "common/rectc.h"
#include "common/rtree.h"
@ -138,7 +139,7 @@ private:
bool readTagInfo(SubFile &hdr);
bool readTagInfo(SubFile &hdr, QVector<TagSource> &tags);
bool readMapInfo(SubFile &hdr, QByteArray &projection, bool &debugMap);
bool readHeader();
bool readHeader(QFile &file);
bool readSubFiles();
void clearTiles();
@ -157,7 +158,7 @@ private:
friend HASH_T qHash(const MapData::Key &key);
QFile _file;
QFile _pointFile, _pathFile;
RectC _bounds;
quint16 _tileSize;
QVector<SubFileInfo> _subFiles;
@ -167,6 +168,7 @@ private:
QCache<Key, QList<Path> > _pathCache;
QCache<Key, QList<Point> > _pointCache;
QMutex _pathLock, _pointLock;
bool _valid;
QString _errorString;

View File

@ -1,10 +1,13 @@
#include <QPainter>
#include <QCache>
#include "common/programpaths.h"
#include "map/rectd.h"
#include "rastertile.h"
using namespace Mapsforge;
#define TEXT_EXTENT 160
static qreal area(const QPainterPath &polygon)
{
qreal area = 0;
@ -52,14 +55,15 @@ static const QColor *haloColor(const Style::TextRender *ti)
? &ti->strokeColor() : 0;
}
void RasterTile::processPointLabels(QList<TextItem*> &textItems)
void RasterTile::processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems)
{
QList<const Style::TextRender*> labels(_style->pointLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->pointSymbols(_zoom));
QList<PainterPoint> points;
QList<PainterPoint> painterPoints;
for (int i = 0; i < _points.size(); i++) {
const MapData::Point &point = _points.at(i);
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
const QByteArray *lbl = 0;
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
@ -83,13 +87,13 @@ void RasterTile::processPointLabels(QList<TextItem*> &textItems)
}
if (ti || si)
points.append(PainterPoint(&point, lbl, si, ti));
painterPoints.append(PainterPoint(&point, lbl, si, ti));
}
std::sort(points.begin(), points.end());
std::sort(painterPoints.begin(), painterPoints.end());
for (int i = 0; i < points.size(); i++) {
const PainterPoint &p = points.at(i);
for (int i = 0; i < painterPoints.size(); i++) {
const PainterPoint &p = painterPoints.at(i);
const QImage *img = p.si ? &p.si->img() : 0;
const QFont *font = p.ti ? &p.ti->font() : 0;
const QColor *color = p.ti ? &p.ti->fillColor() : 0;
@ -238,15 +242,16 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
return path;
}
void RasterTile::pathInstructions(QVector<PainterPath> &paths,
void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions)
{
QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
QList<const Style::PathRender*> *ri;
for (int i = 0; i < _paths.size(); i++) {
const MapData::Path &path = _paths.at(i);
PainterPath &rp = paths[i];
for (int i = 0; i < paths.size(); i++) {
const MapData::Path &path = paths.at(i);
PainterPath &rp = painterPaths[i];
PathKey key(_zoom, path.closed, path.tags);
rp.path = &path;
@ -264,14 +269,14 @@ void RasterTile::pathInstructions(QVector<PainterPath> &paths,
}
}
void RasterTile::circleInstructions(
void RasterTile::circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions)
{
QCache<PointKey, QList<const Style::CircleRender *> > cache(8192);
QList<const Style::CircleRender*> *ri;
for (int i = 0; i < _points.size(); i++) {
const MapData::Point &point = _points.at(i);
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
PointKey key(_zoom, point.tags);
if (!(ri = cache.object(key))) {
@ -287,11 +292,12 @@ void RasterTile::circleInstructions(
}
}
void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
const QList<MapData::Point> &points, QVector<PainterPath> &painterPaths)
{
QVector<RenderInstruction> instructions;
pathInstructions(paths, instructions);
circleInstructions(instructions);
pathInstructions(paths, painterPaths, instructions);
circleInstructions(points, instructions);
std::sort(instructions.begin(), instructions.end());
for (int i = 0; i < instructions.size(); i++) {
@ -318,10 +324,37 @@ void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
}
}
void RasterTile::fetchData(QList<MapData::Path> &paths,
QList<MapData::Point> &points)
{
QPoint ttl(_rect.topLeft());
/* Add a "sub-pixel" margin to assure the tile areas do not
overlap on the border lines. This prevents areas overlap
artifacts at least when using the EPSG:3857 projection. */
QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5),
QPointF(ttl.x() + _rect.width() - 0.5, ttl.y() + _rect.height() - 0.5));
RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight()));
_data->paths(pathRectD.toRectC(_proj, 20), _zoom, &paths);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()
+ TEXT_EXTENT));
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data->points(pointRectD.toRectC(_proj, 20), _zoom, &points);
}
void RasterTile::render()
{
QList<MapData::Path> paths;
QList<MapData::Point> points;
fetchData(paths, points);
QList<TextItem*> textItems;
QVector<PainterPath> renderPaths(_paths.size());
QVector<PainterPath> renderPaths(paths.size());
_pixmap.setDevicePixelRatio(_ratio);
_pixmap.fill(Qt::transparent);
@ -330,9 +363,9 @@ void RasterTile::render()
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_rect.x(), -_rect.y());
drawPaths(&painter, renderPaths);
drawPaths(&painter, paths, points, renderPaths);
processPointLabels(textItems);
processPointLabels(points, textItems);
processAreaLabels(textItems, renderPaths);
processLineLabels(textItems, renderPaths);
drawTextItems(&painter, textItems);

View File

@ -15,11 +15,10 @@ class RasterTile
{
public:
RasterTile(const Projection &proj, const Transform &transform,
const Style *style, int zoom, const QRect &rect, qreal ratio,
const QList<MapData::Path> &paths, const QList<MapData::Point> &points)
: _proj(proj), _transform(transform), _style(style),
_zoom(zoom), _rect(rect), _ratio(ratio), _pixmap(rect.width() * ratio,
rect.height() * ratio), _paths(paths), _points(points), _valid(false) {}
const Style *style, MapData *data, int zoom, const QRect &rect,
qreal ratio) : _proj(proj), _transform(transform), _style(style),
_data(data), _zoom(zoom), _rect(rect), _ratio(ratio),
_pixmap(rect.width() * ratio, rect.height() * ratio), _valid(false) {}
int zoom() const {return _zoom;}
QPoint xy() const {return _rect.topLeft();}
@ -147,31 +146,33 @@ private:
friend HASH_T qHash(const RasterTile::PathKey &key);
friend HASH_T qHash(const RasterTile::PointKey &key);
void pathInstructions(QVector<PainterPath> &paths,
void fetchData(QList<MapData::Path> &paths, QList<MapData::Point> &points);
void pathInstructions(const QList<MapData::Path> &paths,
QVector<PainterPath> &painterPaths,
QVector<RasterTile::RenderInstruction> &instructions);
void circleInstructions(const QList<MapData::Point> &points,
QVector<RasterTile::RenderInstruction> &instructions);
void circleInstructions(QVector<RasterTile::RenderInstruction> &instructions);
QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));}
void processPointLabels(QList<TextItem*> &textItems);
void processPointLabels(const QList<MapData::Point> &points,
QList<TextItem*> &textItems);
void processAreaLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
void processLineLabels(QList<TextItem*> &textItems,
QVector<PainterPath> &paths);
QPainterPath painterPath(const Polygon &polygon, bool curve) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void drawPaths(QPainter *painter, QVector<PainterPath> &paths);
void drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
const QList<MapData::Point> &points, QVector<PainterPath> &painterPaths);
Projection _proj;
Transform _transform;
const Style *_style;
MapData *_data;
int _zoom;
QRect _rect;
qreal _ratio;
QPixmap _pixmap;
QList<MapData::Path> _paths;
QList<MapData::Point> _points;
bool _valid;
};