1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Fixed/improved label rendering

This commit is contained in:
Martin Tůma 2021-04-15 23:11:47 +02:00
parent f1396b6eff
commit b65682a828
5 changed files with 102 additions and 46 deletions

View File

@ -545,7 +545,7 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
quint32 blocks, unused, val, cnt = 0; quint32 blocks, unused, val, cnt = 0;
quint16 bitmap; quint16 bitmap;
quint8 sb, flags; quint8 sb, flags;
QByteArray label, houseNumber, reference; QByteArray name, houseNumber, reference;
if (!subfile.seek(tile->offset & OFFSET_MASK)) if (!subfile.seek(tile->offset & OFFSET_MASK))
@ -579,18 +579,20 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
if (!subfile.readByte(flags)) if (!subfile.readByte(flags))
return false; return false;
if (flags & 0x80) { if (flags & 0x80) {
if (!subfile.readString(label)) if (!subfile.readString(name))
return false; return false;
p.label = label.split('\r').first(); name = name.split('\r').first();
p.tags.append(Tag("name", name));
} }
if (flags & 0x40) { if (flags & 0x40) {
if (!subfile.readString(houseNumber)) if (!subfile.readString(houseNumber))
return false; return false;
p.tags.append(Tag("addr:housenumber", houseNumber));
} }
if (flags & 0x20) { if (flags & 0x20) {
if (!subfile.readString(reference)) if (!subfile.readString(reference))
return false; return false;
p.reference = reference; p.tags.append(Tag("ref", reference));
} }
if (flags & 0x10) { if (flags & 0x10) {
if (!(subfile.readVInt32(lat) && subfile.readVInt32(lon))) if (!(subfile.readVInt32(lat) && subfile.readVInt32(lon)))
@ -626,7 +628,7 @@ bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
QVector<unsigned> points(rows); QVector<unsigned> points(rows);
quint32 val, unused, cnt = 0; quint32 val, unused, cnt = 0;
quint8 sb, flags; quint8 sb, flags;
QByteArray label, houseNumber; QByteArray name, houseNumber;
if (!subfile.seek(tile->offset & OFFSET_MASK)) if (!subfile.seek(tile->offset & OFFSET_MASK))
@ -660,18 +662,21 @@ bool MapData::readPoints(const VectorTile *tile, int zoom, QList<Point> *list)
if (!subfile.readByte(flags)) if (!subfile.readByte(flags))
return false; return false;
if (flags & 0x80) { if (flags & 0x80) {
if (!subfile.readString(label)) if (!subfile.readString(name))
return false; return false;
p.label = label.split('\r').first(); name = name.split('\r').first();
p.tags.append(Tag("name", name));
} }
if (flags & 0x40) { if (flags & 0x40) {
if (!subfile.readString(houseNumber)) if (!subfile.readString(houseNumber))
return false; return false;
p.tags.append(Tag("addr:housenumber", houseNumber));
} }
if (flags & 0x20) { if (flags & 0x20) {
qint32 unused; qint32 elevation;
if (!subfile.readVInt32(unused)) if (!subfile.readVInt32(elevation))
return false; return false;
p.tags.append(Tag("ele", QByteArray::number(elevation)));
} }
setPointId(p); setPointId(p);

View File

@ -43,24 +43,24 @@ public:
Point(const Coordinates &c) : coordinates(c) {} Point(const Coordinates &c) : coordinates(c) {}
Coordinates coordinates; Coordinates coordinates;
QString label;
QVector<Tag> tags; QVector<Tag> tags;
int layer; int layer;
quint64 id; quint64 id;
QString label;
bool operator<(const Point &other) const bool operator<(const Point &other) const
{return id > other.id;} {return id > other.id;}
}; };
struct Path { struct Path {
Polygon poly; Polygon poly;
QString label;
QString reference;
QVector<Tag> tags; QVector<Tag> tags;
Coordinates labelPos; Coordinates labelPos;
int layer; int layer;
bool closed; bool closed;
QString label;
QPainterPath path; QPainterPath path;
bool operator<(const Path &other) const bool operator<(const Path &other) const

View File

@ -44,6 +44,41 @@ static QPointF centroid(const QPainterPath &polygon)
return QPointF(cx * factor, cy * factor); return QPointF(cx * factor, cy * factor);
} }
static QString *pointLabel(const Style::TextRender *ri, MapData::Point &point)
{
for (int i = 0; i < point.tags.size(); i++) {
if (point.tags.at(i).key == ri->key()) {
if (point.tags.at(i).value.isEmpty())
return 0;
else {
point.label = point.tags.at(i).value;
return &point.label;
}
}
}
return 0;
}
static QString *pathLabel(const Style::TextRender *ri, MapData::Path &path,
bool *limit = 0)
{
for (int i = 0; i < path.tags.size(); i++) {
if (path.tags.at(i).key == ri->key()) {
if (path.tags.at(i).value.isEmpty())
return 0;
else {
path.label = path.tags.at(i).value;
if (limit)
*limit = (path.tags.at(i).key == "ref");
return &path.label;
}
}
}
return 0;
}
void RasterTile::processPoints(QList<TextItem*> &textItems) void RasterTile::processPoints(QList<TextItem*> &textItems)
{ {
const Style &s = style(); const Style &s = style();
@ -51,23 +86,23 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
QList<const Style::Symbol*> symbols(s.symbols(_zoom)); QList<const Style::Symbol*> symbols(s.symbols(_zoom));
for (int i = 0; i < _points.size(); i++) { for (int i = 0; i < _points.size(); i++) {
const MapData::Point &point = _points.at(i); MapData::Point &point = _points[i];
const QString *label = point.label.isEmpty() ? 0 : &(point.label); QString *label = 0;
const Style::TextRender *ti = 0; const Style::TextRender *ti = 0;
const Style::Symbol *si = 0; const Style::Symbol *si = 0;
if (label) { for (int j = 0; j < labels.size(); j++) {
for (int i = 0; i < labels.size(); i++) { const Style::TextRender *ri = labels.at(j);
const Style::TextRender *ri = labels.at(i); if (ri->rule().match(point.tags)) {
if (ri->rule().match(point.tags)) { if ((label = pointLabel(ri, point))) {
ti = ri; ti = ri;
break; break;
} }
} }
} }
for (int i = 0; i < symbols.size(); i++) { for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(i); const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.tags)) { if (ri->rule().match(point.tags)) {
si = ri; si = ri;
break; break;
@ -102,21 +137,22 @@ void RasterTile::processAreaNames(const QRect &tileRect,
const Style::TextRender *ri = instructions.at(i); const Style::TextRender *ri = instructions.at(i);
for (int j = 0; j < _paths.size(); j++) { for (int j = 0; j < _paths.size(); j++) {
const MapData::Path &path = _paths.at(j); MapData::Path &path = _paths[j];
QString *label = 0;
if (!path.closed || path.label.isEmpty()) if (!path.closed || !path.path.elementCount())
continue;
if (!path.path.elementCount())
continue;
if (set.contains(path.label))
continue; continue;
if (!ri->rule().match(path.closed, path.tags)) if (!ri->rule().match(path.closed, path.tags))
continue; continue;
if (!(label = pathLabel(ri, path)))
continue;
if (set.contains(path.label))
continue;
QPointF pos = path.labelPos.isNull() QPointF pos = path.labelPos.isNull()
? centroid(path.path) : ll2xy(path.labelPos); ? centroid(path.path) : ll2xy(path.labelPos);
TextPointItem *item = new TextPointItem(pos.toPoint(), &path.label, TextPointItem *item = new TextPointItem(pos.toPoint(), label,
&ri->font(), 0, &ri->fillColor(), 0, false); &ri->font(), 0, &ri->fillColor(), 0, false);
if (item->isValid() && tileRect.contains(item->boundingRect().toRect()) if (item->isValid() && tileRect.contains(item->boundingRect().toRect())
&& !item->collides(textItems)) { && !item->collides(textItems)) {
@ -133,26 +169,32 @@ void RasterTile::processStreetNames(const QRect &tileRect,
{ {
const Style &s = style(); const Style &s = style();
QList<const Style::TextRender*> instructions(s.pathLabels(_zoom)); QList<const Style::TextRender*> instructions(s.pathLabels(_zoom));
QSet<QString> set;
for (int i = 0; i < instructions.size(); i++) { for (int i = 0; i < instructions.size(); i++) {
const Style::TextRender *ri = instructions.at(i); const Style::TextRender *ri = instructions.at(i);
for (int j = 0; j < _paths.size(); j++) { for (int j = 0; j < _paths.size(); j++) {
MapData::Path &path = _paths[j]; MapData::Path &path = _paths[j];
QString *label = 0;
bool limit = false;
if (path.label.isEmpty())
continue;
if (!path.path.elementCount()) if (!path.path.elementCount())
continue; continue;
if (!ri->rule().match(path.closed, path.tags)) if (!ri->rule().match(path.closed, path.tags))
continue; continue;
if (!(label = pathLabel(ri, path, &limit)))
continue;
if (limit && set.contains(path.label))
continue;
TextPathItem *item = new TextPathItem(path.path, TextPathItem *item = new TextPathItem(path.path, label, tileRect,
&path.label, tileRect, &ri->font(), &ri->fillColor(), &ri->font(), &ri->fillColor(), &ri->strokeColor());
&ri->strokeColor()); if (item->isValid() && !item->collides(textItems)) {
if (item->isValid() && !item->collides(textItems))
textItems.append(item); textItems.append(item);
else if (limit)
set.insert(path.label);
} else
delete item; delete item;
} }
} }
@ -185,6 +227,7 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
QCache<Key, QVector<const Style::PathRender *> > cache(1024); QCache<Key, QVector<const Style::PathRender *> > cache(1024);
QVector<PathInstruction> instructions; QVector<PathInstruction> instructions;
const Style &s = style(); const Style &s = style();
QVector<const Style::PathRender*> *ri;
for (int i = 0 ; i < _paths.size(); i++) { for (int i = 0 ; i < _paths.size(); i++) {
MapData::Path &path = _paths[i]; MapData::Path &path = _paths[i];
@ -192,9 +235,8 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
Key key(_zoom, path.closed, path.tags); Key key(_zoom, path.closed, path.tags);
QVector<const Style::PathRender*> *cached = cache.object(key); QVector<const Style::PathRender*> *cached = cache.object(key);
if (!cached) { if (!cached) {
QVector<const Style::PathRender*> *ri ri = new QVector<const Style::PathRender*>(s.paths(_zoom,
= new QVector<const Style::PathRender*>(); path.closed, path.tags));
s.match(_zoom, path.closed, path.tags, ri);
for (int j = 0; j < ri->size(); j++) for (int j = 0; j < ri->size(); j++)
instructions.append(PathInstruction(ri->at(j), &path)); instructions.append(PathInstruction(ri->at(j), &path));
cache.insert(key, ri); cache.insert(key, ri);
@ -212,7 +254,9 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
void RasterTile::drawPaths(QPainter *painter) void RasterTile::drawPaths(QPainter *painter)
{ {
QVector<PathInstruction> instructions(pathInstructions()); QVector<PathInstruction> instructions(pathInstructions());
const Style::PathRender *lri = 0; if (instructions.isEmpty())
return;
const Style::PathRender *lri = instructions.first().render();
QPixmap layer(_pixmap.size()); QPixmap layer(_pixmap.size());
layer.fill(Qt::transparent); layer.fill(Qt::transparent);
@ -226,11 +270,11 @@ void RasterTile::drawPaths(QPainter *painter)
PathInstruction &is = instructions[i]; PathInstruction &is = instructions[i];
const Style::PathRender *ri = is.render(); const Style::PathRender *ri = is.render();
if (lri && ri != lri) { if (ri != lri) {
painter->drawPixmap(_xy, layer); painter->drawPixmap(_xy, layer);
lp.fillRect(QRect(_xy, _pixmap.size()), Qt::transparent); lp.fillRect(QRect(_xy, _pixmap.size()), Qt::transparent);
lri = ri;
} }
lri = ri;
if (!is.path()->path.elementCount()) if (!is.path()->path.elementCount())
is.path()->path = painterPath(is.path()->poly); is.path()->path = painterPath(is.path()->poly);

View File

@ -152,6 +152,8 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule,
int fontSize = 9; int fontSize = 9;
bool bold = false, italic = false; bool bold = false, italic = false;
if (attr.hasAttribute("k"))
ri._key = attr.value("k").toLatin1();
if (attr.hasAttribute("fill")) if (attr.hasAttribute("fill"))
ri._fillColor = QColor(attr.value("fill").toString()); ri._fillColor = QColor(attr.value("fill").toString());
if (attr.hasAttribute("stroke")) if (attr.hasAttribute("stroke"))
@ -169,7 +171,6 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule,
italic = true; italic = true;
} }
} }
ri._font.setPixelSize(fontSize); ri._font.setPixelSize(fontSize);
ri._font.setBold(bold); ri._font.setBold(bold);
ri._font.setItalic(italic); ri._font.setItalic(italic);
@ -337,12 +338,16 @@ Style::Style(const QString &path)
loadXml(":/mapsforge/default.xml"); loadXml(":/mapsforge/default.xml");
} }
void Style::match(int zoom, bool closed, const QVector<MapData::Tag> &tags, QVector<const Style::PathRender *> Style::paths(int zoom, bool closed,
QVector<const Style::PathRender*> *ri) const const QVector<MapData::Tag> &tags) const
{ {
QVector<const Style::PathRender*> ri;
for (int i = 0; i < _paths.size(); i++) for (int i = 0; i < _paths.size(); i++)
if (_paths.at(i).rule().match(zoom, closed, tags)) if (_paths.at(i).rule().match(zoom, closed, tags))
ri->append(&_paths.at(i)); ri.append(&_paths.at(i));
return ri;
} }
QList<const Style::TextRender*> Style::pathLabels(int zoom) const QList<const Style::TextRender*> Style::pathLabels(int zoom) const

View File

@ -192,12 +192,14 @@ public:
const QFont &font() const {return _font;} const QFont &font() const {return _font;}
const QColor &fillColor() const {return _fillColor;} const QColor &fillColor() const {return _fillColor;}
const QColor &strokeColor() const {return _strokeColor;} const QColor &strokeColor() const {return _strokeColor;}
const QByteArray &key() const {return _key;}
private: private:
friend class Style; friend class Style;
QColor _fillColor, _strokeColor; QColor _fillColor, _strokeColor;
QFont _font; QFont _font;
QByteArray _key;
}; };
class Symbol : public Render class Symbol : public Render
@ -215,8 +217,8 @@ public:
Style(const QString &path); Style(const QString &path);
void match(int zoom, bool closed, const QVector<MapData::Tag> &tags, QVector<const PathRender *> paths(int zoom, bool closed,
QVector<const PathRender *> *ri) const; const QVector<MapData::Tag> &tags) const;
QList<const TextRender*> pathLabels(int zoom) const; QList<const TextRender*> pathLabels(int zoom) const;
QList<const TextRender*> pointLabels(int zoom) const; QList<const TextRender*> pointLabels(int zoom) const;
QList<const TextRender*> areaLabels(int zoom) const; QList<const TextRender*> areaLabels(int zoom) const;