From 648627b17fcd55ae4ed24c940b9f0e6529ff66ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 6 Apr 2023 23:29:05 +0200 Subject: [PATCH] Use style-defined priorities + code cleanup --- src/map/mapsforge/mapdata.cpp | 48 ++++--------------- src/map/mapsforge/mapdata.h | 18 +++---- src/map/mapsforge/rastertile.cpp | 81 +++++++++++++++----------------- src/map/mapsforge/rastertile.h | 71 +++++++++++++++++++--------- src/map/mapsforge/style.cpp | 14 ++++++ src/map/mapsforge/style.h | 10 ++-- src/map/mapsforgemap.cpp | 2 +- 7 files changed, 125 insertions(+), 119 deletions(-) diff --git a/src/map/mapsforge/mapdata.cpp b/src/map/mapsforge/mapdata.cpp index c4cbe35b..bc90e795 100644 --- a/src/map/mapsforge/mapdata.cpp +++ b/src/map/mapsforge/mapdata.cpp @@ -15,42 +15,12 @@ using namespace Mapsforge; #define MD(val) ((val) / 1e6) #define OFFSET_MASK 0x7FFFFFFFFFL -static quint8 pointType(const QVector &tags) -{ - for (int i = 0; i < tags.size(); i++) { - const MapData::Tag &tag = tags.at(i); - if (tag.key == "place") { - if (tag.value == "country") - return 4; - else if (tag.value == "city") - return 3; - else if (tag.value == "town") - return 2; - else if (tag.value == "village") - return 1; - else - return 0; - } - } - - return 0; -} - -static void setPointId(MapData::Point &p) -{ - HASH_T hash = qHash(QPair(p.coordinates.lon(), - p.coordinates.lat())); - quint8 type = pointType(p.tags); - - p.id = ((quint64)type)<<56 | (quint64)hash; -} - static void copyPaths(const RectC &rect, const QList *src, - QSet *dst) + QList *dst) { for (int i = 0; i < src->size(); i++) if (rect.intersects(src->at(i).poly.boundingRect())) - dst->insert(src->at(i)); + dst->append(src->at(i)); } static void copyPoints(const RectC &rect, const QList *src, @@ -494,7 +464,7 @@ void MapData::clearTiles() bool MapData::pathCb(VectorTile *tile, void *context) { PathCTX *ctx = (PathCTX*)context; - ctx->data->paths(tile, ctx->rect, ctx->zoom, ctx->set); + ctx->data->paths(tile, ctx->rect, ctx->zoom, ctx->list); return true; } @@ -545,10 +515,10 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom, copyPoints(rect, cached, list); } -void MapData::paths(const RectC &rect, int zoom, QSet *set) +void MapData::paths(const RectC &rect, int zoom, QList *list) { int l(level(zoom)); - PathCTX ctx(this, rect, zoom, set); + PathCTX ctx(this, rect, zoom, list); double min[2], max[2]; min[0] = rect.left(); @@ -560,7 +530,7 @@ void MapData::paths(const RectC &rect, int zoom, QSet *set) } void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom, - QSet *set) + QList *list) { Key key(tile, zoom); QList *cached = _pathCache.object(key); @@ -568,12 +538,12 @@ void MapData::paths(const VectorTile *tile, const RectC &rect, int zoom, if (!cached) { QList *p = new QList(); if (readPaths(tile, zoom, p)) { - copyPaths(rect, p, set); + copyPaths(rect, p, list); _pathCache.insert(key, p); } else delete p; } else - copyPaths(rect, cached, set); + copyPaths(rect, cached, list); } bool MapData::readPaths(const VectorTile *tile, int zoom, QList *list) @@ -719,8 +689,6 @@ bool MapData::readPoints(const VectorTile *tile, int zoom, QList *list) p.tags.append(Tag("ele", QByteArray::number(elevation))); } - setPointId(p); - list->append(p); } diff --git a/src/map/mapsforge/mapdata.h b/src/map/mapsforge/mapdata.h index 727d2c1d..d1ab62ea 100644 --- a/src/map/mapsforge/mapdata.h +++ b/src/map/mapsforge/mapdata.h @@ -41,15 +41,15 @@ public: }; struct Point { - Point(const Coordinates &c) : coordinates(c) {} + Point(const Coordinates &c) : coordinates(c) + { + id = (quint64)qHash(QPair(c.lon(), c.lat())); + } quint64 id; Coordinates coordinates; QVector tags; int layer; - - bool operator<(const Point &other) const - {return id > other.id;} }; struct Path { @@ -74,7 +74,7 @@ public: int tileSize() const {return _tileSize;} void points(const RectC &rect, int zoom, QList *list); - void paths(const RectC &rect, int zoom, QSet *set); + void paths(const RectC &rect, int zoom, QList *set); void load(); void clear(); @@ -100,13 +100,13 @@ private: }; struct PathCTX { - PathCTX(MapData *data, const RectC &rect, int zoom, QSet *set) - : data(data), rect(rect), zoom(zoom), set(set) {} + PathCTX(MapData *data, const RectC &rect, int zoom, QList *list) + : data(data), rect(rect), zoom(zoom), list(list) {} MapData *data; const RectC ▭ int zoom; - QSet *set; + QList *list; }; struct PointCTX { @@ -139,7 +139,7 @@ private: int level(int zoom) const; void paths(const VectorTile *tile, const RectC &rect, int zoom, - QSet *set); + QList *list); void points(const VectorTile *tile, const RectC &rect, int zoom, QList *list); bool readPaths(const VectorTile *tile, int zoom, QList *list); diff --git a/src/map/mapsforge/rastertile.cpp b/src/map/mapsforge/rastertile.cpp index a8f95a8c..85d2919f 100644 --- a/src/map/mapsforge/rastertile.cpp +++ b/src/map/mapsforge/rastertile.cpp @@ -1,8 +1,6 @@ #include #include #include "common/programpaths.h" -#include "map/mapsforgemap.h" -#include "map/textpathitem.h" #include "rastertile.h" using namespace Mapsforge; @@ -61,15 +59,15 @@ static const QColor *haloColor(const Style::TextRender *ti) ? &ti->strokeColor() : 0; } - void RasterTile::processPointLabels(QList &textItems) { const Style &s = style(_ratio); QList labels(s.pointLabels(_zoom)); QList symbols(s.pointSymbols(_zoom)); + QList points; for (int i = 0; i < _points.size(); i++) { - MapData::Point &point = _points[i]; + const MapData::Point &point = _points.at(i); const QByteArray *lbl = 0; const Style::TextRender *ti = 0; const Style::Symbol *si = 0; @@ -92,16 +90,21 @@ void RasterTile::processPointLabels(QList &textItems) } } - if (!ti && !si) - continue; + if (ti || si) + points.append(PainterPoint(&point, lbl, si, ti)); + } - const QImage *img = si ? &si->img() : 0; - const QFont *font = ti ? &ti->font() : 0; - const QColor *color = ti ? &ti->fillColor() : 0; - const QColor *hColor = ti ? haloColor(ti) : 0; + std::sort(points.begin(), points.end()); - PointItem *item = new PointItem(ll2xy(point.coordinates).toPoint(), - lbl ? new QString(*lbl) : 0, font, img, color, hColor); + for (int i = 0; i < points.size(); i++) { + const PainterPoint &p = points.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; + const QColor *hColor = p.ti ? haloColor(p.ti) : 0; + + PointItem *item = new PointItem(ll2xy(p.p->coordinates).toPoint(), + p.lbl, font, img, color, hColor); if (item->isValid() && !item->collides(textItems)) textItems.append(item); else @@ -110,16 +113,17 @@ void RasterTile::processPointLabels(QList &textItems) } void RasterTile::processAreaLabels(QList &textItems, - QVector &renderPaths) + QVector &paths) { const Style &s = style(_ratio); QList labels(s.areaLabels(_zoom)); QList symbols(s.areaSymbols(_zoom)); - for (int i = 0; i < renderPaths.size(); i++) { - RenderPath &path = renderPaths[i]; + for (int i = 0; i < paths.size(); i++) { + PainterPath &path = paths[i]; const Style::TextRender *ti = 0; const Style::Symbol *si = 0; + const QByteArray *lbl = 0; if (!path.path->closed) continue; @@ -127,11 +131,8 @@ void RasterTile::processAreaLabels(QList &textItems, for (int j = 0; j < labels.size(); j++) { const Style::TextRender *ri = labels.at(j); if (ri->rule().match(path.path->closed, path.path->tags)) { - const QByteArray *lbl; - if ((lbl = label(ri->key(), path.path->tags))) { - path.label = *lbl; + if ((lbl = label(ri->key(), path.path->tags))) ti = ri; - } break; } } @@ -154,8 +155,8 @@ void RasterTile::processAreaLabels(QList &textItems, QPointF pos = path.path->labelPos.isNull() ? centroid(path.pp) : ll2xy(path.path->labelPos); - TextPointItem *item = new TextPointItem(pos.toPoint(), &path.label, - font, img, color, hColor, 0); + PointItem *item = new PointItem(pos.toPoint(), lbl, font, img, color, + hColor); if (item->isValid() && _rect.contains(item->boundingRect().toRect()) && !item->collides(textItems)) textItems.append(item); @@ -165,7 +166,7 @@ void RasterTile::processAreaLabels(QList &textItems, } void RasterTile::processLineLabels(QList &textItems, - QVector &renderPaths) + QVector &paths) { const Style &s = style(_ratio); QList instructions(s.pathLabels(_zoom)); @@ -174,8 +175,8 @@ void RasterTile::processLineLabels(QList &textItems, for (int i = 0; i < instructions.size(); i++) { const Style::TextRender *ri = instructions.at(i); - for (int i = 0; i < renderPaths.size(); i++) { - RenderPath &path = renderPaths[i]; + for (int i = 0; i < paths.size(); i++) { + PainterPath &path = paths[i]; const QByteArray *lbl = label(ri->key(), path.path->tags); if (!lbl) @@ -188,10 +189,8 @@ void RasterTile::processLineLabels(QList &textItems, if (limit && set.contains(*lbl)) continue; - path.label = *lbl; - - TextPathItem *item = new TextPathItem(path.pp, &path.label, _rect, - &ri->font(), &ri->fillColor(), haloColor(ri)); + PathItem *item = new PathItem(path.pp, lbl, _rect, &ri->font(), + &ri->fillColor(), haloColor(ri)); if (item->isValid() && !item->collides(textItems)) { textItems.append(item); if (limit) @@ -240,25 +239,23 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const } QVector RasterTile::pathInstructions( - QVector &renderPaths) + QVector &paths) { QCache > cache(8192); QVector instructions; const Style &s = style(_ratio); QList *ri; - int i = 0; - for (QSet::const_iterator it = _paths.cbegin(); - it != _paths.cend(); ++it) { - const MapData::Path &path = *it; - RenderPath &rp = renderPaths[i]; + for (int i = 0; i < _paths.size(); i++) { + const MapData::Path &path = _paths.at(i); + PainterPath &rp = paths[i]; Key key(_zoom, path.closed, path.tags); rp.path = &path; if (!(ri = cache.object(key))) { - ri = new QList(s.paths(_zoom, - path.closed, path.tags)); + ri = new QList(s.paths(_zoom, path.closed, + path.tags)); for (int j = 0; j < ri->size(); j++) instructions.append(PathInstruction(ri->at(j), &rp)); cache.insert(key, ri); @@ -266,8 +263,6 @@ QVector RasterTile::pathInstructions( for (int j = 0; j < ri->size(); j++) instructions.append(PathInstruction(ri->at(j), &rp)); } - - i++; } std::sort(instructions.begin(), instructions.end()); @@ -275,14 +270,14 @@ QVector RasterTile::pathInstructions( return instructions; } -void RasterTile::drawPaths(QPainter *painter, QVector &renderPaths) +void RasterTile::drawPaths(QPainter *painter, QVector &paths) { - QVector instructions(pathInstructions(renderPaths)); + QVector instructions(pathInstructions(paths)); for (int i = 0; i < instructions.size(); i++) { const PathInstruction &is = instructions.at(i); const Style::PathRender *ri = is.render(); - RenderPath *path = is.path(); + PainterPath *path = is.path(); if (!path->pp.elementCount()) path->pp = painterPath(path->path->poly, ri->curve()); @@ -295,10 +290,8 @@ void RasterTile::drawPaths(QPainter *painter, QVector &renderPaths) void RasterTile::render() { - std::sort(_points.begin(), _points.end()); - QList textItems; - QVector renderPaths(_paths.size()); + QVector renderPaths(_paths.size()); _pixmap.setDevicePixelRatio(_ratio); _pixmap.fill(Qt::transparent); diff --git a/src/map/mapsforge/rastertile.h b/src/map/mapsforge/rastertile.h index cdbe4de8..d831dc71 100644 --- a/src/map/mapsforge/rastertile.h +++ b/src/map/mapsforge/rastertile.h @@ -5,19 +5,17 @@ #include "map/projection.h" #include "map/transform.h" #include "map/textpointitem.h" +#include "map/textpathitem.h" #include "style.h" #include "mapdata.h" -class MapsforgeMap; -class TextItem; - namespace Mapsforge { class RasterTile { public: RasterTile(const Projection &proj, const Transform &transform, int zoom, - const QRect &rect, qreal ratio, const QSet &paths, + const QRect &rect, qreal ratio, const QList &paths, const QList &points) : _proj(proj), _transform(transform), _zoom(zoom), _rect(rect), _ratio(ratio), _pixmap(rect.width() * ratio, rect.height() * ratio), _paths(paths), @@ -31,19 +29,41 @@ public: void render(); private: - struct RenderPath { - RenderPath() : path(0) {} + struct PainterPath { + PainterPath() : path(0) {} QPainterPath pp; - QString label; const MapData::Path *path; }; + struct PainterPoint { + PainterPoint(const MapData::Point *p, const QByteArray *lbl, + const Style::Symbol *si, const Style::TextRender *ti) + : p(p), lbl(lbl), ti(ti), si(si) + { + Q_ASSERT(si || ti); + } + + bool operator<(const PainterPoint &other) const + { + if (priority() == other.priority()) + return p->id < other.p->id; + else + return (priority() > other.priority()); + } + int priority() const {return si ? si->priority() : ti->priority();} + + const MapData::Point *p; + const QByteArray *lbl; + const Style::TextRender *ti; + const Style::Symbol *si; + }; + class PathInstruction { public: PathInstruction() : _render(0), _path(0) {} - PathInstruction(const Style::PathRender *render, RenderPath *path) + PathInstruction(const Style::PathRender *render, PainterPath *path) : _render(render), _path(path) {} bool operator<(const PathInstruction &other) const @@ -55,11 +75,11 @@ private: } const Style::PathRender *render() const {return _render;} - RenderPath *path() const {return _path;} + PainterPath *path() const {return _path;} private: const Style::PathRender *_render; - RenderPath *_path; + PainterPath *_path; }; struct Key { @@ -79,29 +99,36 @@ private: class PointItem : public TextPointItem { public: - PointItem(const QPoint &point, QString *text, const QFont *font, - const QImage *img, const QColor *color, const QColor *haloColor) - : TextPointItem(point, text, font, img, color, haloColor, 0), - _label(text) {} - ~PointItem() {delete _label;} + PointItem(const QPoint &point, const QByteArray *label, + const QFont *font, const QImage *img, const QColor *color, + const QColor *haloColor) : TextPointItem(point, + label ? new QString(*label) : 0, font, img, color, haloColor, 0) {} + ~PointItem() {delete _text;} + }; - private: - QString *_label; + class PathItem : public TextPathItem + { + public: + PathItem(const QPainterPath &line, const QByteArray *label, + const QRect &tileRect, const QFont *font, const QColor *color, + const QColor *haloColor) : TextPathItem(line, + label ? new QString(*label) : 0, tileRect, font, color, haloColor) {} + ~PathItem() {delete _text;} }; friend HASH_T qHash(const RasterTile::Key &key); - QVector pathInstructions(QVector &renderPaths); + QVector pathInstructions(QVector &paths); QPointF ll2xy(const Coordinates &c) const {return _transform.proj2img(_proj.ll2xy(c));} void processPointLabels(QList &textItems); void processAreaLabels(QList &textItems, - QVector &renderPaths); + QVector &paths); void processLineLabels(QList &textItems, - QVector &renderPaths); + QVector &paths); QPainterPath painterPath(const Polygon &polygon, bool curve) const; void drawTextItems(QPainter *painter, const QList &textItems); - void drawPaths(QPainter *painter, QVector &renderPaths); + void drawPaths(QPainter *painter, QVector &paths); Projection _proj; Transform _transform; @@ -109,7 +136,7 @@ private: QRect _rect; qreal _ratio; QPixmap _pixmap; - QSet _paths; + QList _paths; QList _points; bool _valid; diff --git a/src/map/mapsforge/style.cpp b/src/map/mapsforge/style.cpp index 559a4f6c..800f97d0 100644 --- a/src/map/mapsforge/style.cpp +++ b/src/map/mapsforge/style.cpp @@ -238,6 +238,13 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule, else if (transform == "capitalize") capitalization = QFont::Capitalize; } + if (attr.hasAttribute("priority")) { + ri._priority = attr.value("priority").toInt(&ok); + if (!ok) { + reader.raiseError("invalid priority value"); + return; + } + } ri._font.setFamily(fontFamily); ri._font.setPixelSize(fontSize); @@ -277,6 +284,13 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio, return; } } + if (attr.hasAttribute("priority")) { + ri._priority = attr.value("priority").toInt(&ok); + if (!ok) { + reader.raiseError("invalid priority value"); + return; + } + } if (!file.isNull()) ri._img = image(file, width, height, ratio); diff --git a/src/map/mapsforge/style.h b/src/map/mapsforge/style.h index 92f59d7c..1f856373 100644 --- a/src/map/mapsforge/style.h +++ b/src/map/mapsforge/style.h @@ -188,18 +188,20 @@ public: { public: TextRender(const Rule &rule) - : Render(rule), _fillColor(Qt::black), _strokeColor(Qt::black), - _strokeWidth(0) {} + : Render(rule), _priority(0), _fillColor(Qt::black), + _strokeColor(Qt::black), _strokeWidth(0) {} const QFont &font() const {return _font;} const QColor &fillColor() const {return _fillColor;} const QColor &strokeColor() const {return _strokeColor;} qreal strokeWidth() const {return _strokeWidth;} const QByteArray &key() const {return _key;} + int priority() const {return _priority;} private: friend class Style; + int _priority; QColor _fillColor, _strokeColor; qreal _strokeWidth; QFont _font; @@ -209,13 +211,15 @@ public: class Symbol : public Render { public: - Symbol(const Rule &rule) : Render(rule) {} + Symbol(const Rule &rule) : Render(rule), _priority(0) {} const QImage &img() const {return _img;} + int priority() const {return _priority;} private: friend class Style; + int _priority; QImage _img; }; diff --git a/src/map/mapsforgemap.cpp b/src/map/mapsforgemap.cpp index 1c98b197..463b2e8e 100644 --- a/src/map/mapsforgemap.cpp +++ b/src/map/mapsforgemap.cpp @@ -175,7 +175,7 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags) if (QPixmapCache::find(key(_zoom, ttl), &pm)) painter->drawPixmap(ttl, pm); else { - QSet paths; + QList paths; QList points; /* Add a "sub-pixel" margin to assure the tile areas do not