mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 11:45:53 +01:00
Fixed/improved label rendering
This commit is contained in:
parent
f1396b6eff
commit
b65682a828
@ -545,7 +545,7 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
|
||||
quint32 blocks, unused, val, cnt = 0;
|
||||
quint16 bitmap;
|
||||
quint8 sb, flags;
|
||||
QByteArray label, houseNumber, reference;
|
||||
QByteArray name, houseNumber, reference;
|
||||
|
||||
|
||||
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))
|
||||
return false;
|
||||
if (flags & 0x80) {
|
||||
if (!subfile.readString(label))
|
||||
if (!subfile.readString(name))
|
||||
return false;
|
||||
p.label = label.split('\r').first();
|
||||
name = name.split('\r').first();
|
||||
p.tags.append(Tag("name", name));
|
||||
}
|
||||
if (flags & 0x40) {
|
||||
if (!subfile.readString(houseNumber))
|
||||
return false;
|
||||
p.tags.append(Tag("addr:housenumber", houseNumber));
|
||||
}
|
||||
if (flags & 0x20) {
|
||||
if (!subfile.readString(reference))
|
||||
return false;
|
||||
p.reference = reference;
|
||||
p.tags.append(Tag("ref", reference));
|
||||
}
|
||||
if (flags & 0x10) {
|
||||
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);
|
||||
quint32 val, unused, cnt = 0;
|
||||
quint8 sb, flags;
|
||||
QByteArray label, houseNumber;
|
||||
QByteArray name, houseNumber;
|
||||
|
||||
|
||||
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))
|
||||
return false;
|
||||
if (flags & 0x80) {
|
||||
if (!subfile.readString(label))
|
||||
if (!subfile.readString(name))
|
||||
return false;
|
||||
p.label = label.split('\r').first();
|
||||
name = name.split('\r').first();
|
||||
p.tags.append(Tag("name", name));
|
||||
}
|
||||
if (flags & 0x40) {
|
||||
if (!subfile.readString(houseNumber))
|
||||
return false;
|
||||
p.tags.append(Tag("addr:housenumber", houseNumber));
|
||||
}
|
||||
if (flags & 0x20) {
|
||||
qint32 unused;
|
||||
if (!subfile.readVInt32(unused))
|
||||
qint32 elevation;
|
||||
if (!subfile.readVInt32(elevation))
|
||||
return false;
|
||||
p.tags.append(Tag("ele", QByteArray::number(elevation)));
|
||||
}
|
||||
|
||||
setPointId(p);
|
||||
|
@ -43,24 +43,24 @@ public:
|
||||
Point(const Coordinates &c) : coordinates(c) {}
|
||||
|
||||
Coordinates coordinates;
|
||||
QString label;
|
||||
QVector<Tag> tags;
|
||||
int layer;
|
||||
quint64 id;
|
||||
|
||||
QString label;
|
||||
|
||||
bool operator<(const Point &other) const
|
||||
{return id > other.id;}
|
||||
};
|
||||
|
||||
struct Path {
|
||||
Polygon poly;
|
||||
QString label;
|
||||
QString reference;
|
||||
QVector<Tag> tags;
|
||||
Coordinates labelPos;
|
||||
int layer;
|
||||
bool closed;
|
||||
|
||||
QString label;
|
||||
QPainterPath path;
|
||||
|
||||
bool operator<(const Path &other) const
|
||||
|
@ -44,6 +44,41 @@ static QPointF centroid(const QPainterPath &polygon)
|
||||
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)
|
||||
{
|
||||
const Style &s = style();
|
||||
@ -51,23 +86,23 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
|
||||
QList<const Style::Symbol*> symbols(s.symbols(_zoom));
|
||||
|
||||
for (int i = 0; i < _points.size(); i++) {
|
||||
const MapData::Point &point = _points.at(i);
|
||||
const QString *label = point.label.isEmpty() ? 0 : &(point.label);
|
||||
MapData::Point &point = _points[i];
|
||||
QString *label = 0;
|
||||
const Style::TextRender *ti = 0;
|
||||
const Style::Symbol *si = 0;
|
||||
|
||||
if (label) {
|
||||
for (int i = 0; i < labels.size(); i++) {
|
||||
const Style::TextRender *ri = labels.at(i);
|
||||
if (ri->rule().match(point.tags)) {
|
||||
for (int j = 0; j < labels.size(); j++) {
|
||||
const Style::TextRender *ri = labels.at(j);
|
||||
if (ri->rule().match(point.tags)) {
|
||||
if ((label = pointLabel(ri, point))) {
|
||||
ti = ri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < symbols.size(); i++) {
|
||||
const Style::Symbol *ri = symbols.at(i);
|
||||
for (int j = 0; j < symbols.size(); j++) {
|
||||
const Style::Symbol *ri = symbols.at(j);
|
||||
if (ri->rule().match(point.tags)) {
|
||||
si = ri;
|
||||
break;
|
||||
@ -102,21 +137,22 @@ void RasterTile::processAreaNames(const QRect &tileRect,
|
||||
const Style::TextRender *ri = instructions.at(i);
|
||||
|
||||
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())
|
||||
continue;
|
||||
if (!path.path.elementCount())
|
||||
continue;
|
||||
if (set.contains(path.label))
|
||||
if (!path.closed || !path.path.elementCount())
|
||||
continue;
|
||||
if (!ri->rule().match(path.closed, path.tags))
|
||||
continue;
|
||||
if (!(label = pathLabel(ri, path)))
|
||||
continue;
|
||||
if (set.contains(path.label))
|
||||
continue;
|
||||
|
||||
QPointF pos = path.labelPos.isNull()
|
||||
? 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);
|
||||
if (item->isValid() && tileRect.contains(item->boundingRect().toRect())
|
||||
&& !item->collides(textItems)) {
|
||||
@ -133,26 +169,32 @@ void RasterTile::processStreetNames(const QRect &tileRect,
|
||||
{
|
||||
const Style &s = style();
|
||||
QList<const Style::TextRender*> instructions(s.pathLabels(_zoom));
|
||||
QSet<QString> set;
|
||||
|
||||
for (int i = 0; i < instructions.size(); i++) {
|
||||
const Style::TextRender *ri = instructions.at(i);
|
||||
|
||||
for (int j = 0; j < _paths.size(); j++) {
|
||||
MapData::Path &path = _paths[j];
|
||||
QString *label = 0;
|
||||
bool limit = false;
|
||||
|
||||
if (path.label.isEmpty())
|
||||
continue;
|
||||
if (!path.path.elementCount())
|
||||
continue;
|
||||
if (!ri->rule().match(path.closed, path.tags))
|
||||
continue;
|
||||
if (!(label = pathLabel(ri, path, &limit)))
|
||||
continue;
|
||||
if (limit && set.contains(path.label))
|
||||
continue;
|
||||
|
||||
TextPathItem *item = new TextPathItem(path.path,
|
||||
&path.label, tileRect, &ri->font(), &ri->fillColor(),
|
||||
&ri->strokeColor());
|
||||
if (item->isValid() && !item->collides(textItems))
|
||||
TextPathItem *item = new TextPathItem(path.path, label, tileRect,
|
||||
&ri->font(), &ri->fillColor(), &ri->strokeColor());
|
||||
if (item->isValid() && !item->collides(textItems)) {
|
||||
textItems.append(item);
|
||||
else
|
||||
if (limit)
|
||||
set.insert(path.label);
|
||||
} else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
@ -185,6 +227,7 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
|
||||
QCache<Key, QVector<const Style::PathRender *> > cache(1024);
|
||||
QVector<PathInstruction> instructions;
|
||||
const Style &s = style();
|
||||
QVector<const Style::PathRender*> *ri;
|
||||
|
||||
for (int i = 0 ; i < _paths.size(); i++) {
|
||||
MapData::Path &path = _paths[i];
|
||||
@ -192,9 +235,8 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
|
||||
Key key(_zoom, path.closed, path.tags);
|
||||
QVector<const Style::PathRender*> *cached = cache.object(key);
|
||||
if (!cached) {
|
||||
QVector<const Style::PathRender*> *ri
|
||||
= new QVector<const Style::PathRender*>();
|
||||
s.match(_zoom, path.closed, path.tags, ri);
|
||||
ri = new QVector<const Style::PathRender*>(s.paths(_zoom,
|
||||
path.closed, path.tags));
|
||||
for (int j = 0; j < ri->size(); j++)
|
||||
instructions.append(PathInstruction(ri->at(j), &path));
|
||||
cache.insert(key, ri);
|
||||
@ -212,7 +254,9 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions()
|
||||
void RasterTile::drawPaths(QPainter *painter)
|
||||
{
|
||||
QVector<PathInstruction> instructions(pathInstructions());
|
||||
const Style::PathRender *lri = 0;
|
||||
if (instructions.isEmpty())
|
||||
return;
|
||||
const Style::PathRender *lri = instructions.first().render();
|
||||
|
||||
QPixmap layer(_pixmap.size());
|
||||
layer.fill(Qt::transparent);
|
||||
@ -226,11 +270,11 @@ void RasterTile::drawPaths(QPainter *painter)
|
||||
PathInstruction &is = instructions[i];
|
||||
const Style::PathRender *ri = is.render();
|
||||
|
||||
if (lri && ri != lri) {
|
||||
if (ri != lri) {
|
||||
painter->drawPixmap(_xy, layer);
|
||||
lp.fillRect(QRect(_xy, _pixmap.size()), Qt::transparent);
|
||||
lri = ri;
|
||||
}
|
||||
lri = ri;
|
||||
|
||||
if (!is.path()->path.elementCount())
|
||||
is.path()->path = painterPath(is.path()->poly);
|
||||
|
@ -152,6 +152,8 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule,
|
||||
int fontSize = 9;
|
||||
bool bold = false, italic = false;
|
||||
|
||||
if (attr.hasAttribute("k"))
|
||||
ri._key = attr.value("k").toLatin1();
|
||||
if (attr.hasAttribute("fill"))
|
||||
ri._fillColor = QColor(attr.value("fill").toString());
|
||||
if (attr.hasAttribute("stroke"))
|
||||
@ -169,7 +171,6 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule,
|
||||
italic = true;
|
||||
}
|
||||
}
|
||||
|
||||
ri._font.setPixelSize(fontSize);
|
||||
ri._font.setBold(bold);
|
||||
ri._font.setItalic(italic);
|
||||
@ -337,12 +338,16 @@ Style::Style(const QString &path)
|
||||
loadXml(":/mapsforge/default.xml");
|
||||
}
|
||||
|
||||
void Style::match(int zoom, bool closed, const QVector<MapData::Tag> &tags,
|
||||
QVector<const Style::PathRender*> *ri) const
|
||||
QVector<const Style::PathRender *> Style::paths(int zoom, bool closed,
|
||||
const QVector<MapData::Tag> &tags) const
|
||||
{
|
||||
QVector<const Style::PathRender*> ri;
|
||||
|
||||
for (int i = 0; i < _paths.size(); i++)
|
||||
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
|
||||
|
@ -192,12 +192,14 @@ public:
|
||||
const QFont &font() const {return _font;}
|
||||
const QColor &fillColor() const {return _fillColor;}
|
||||
const QColor &strokeColor() const {return _strokeColor;}
|
||||
const QByteArray &key() const {return _key;}
|
||||
|
||||
private:
|
||||
friend class Style;
|
||||
|
||||
QColor _fillColor, _strokeColor;
|
||||
QFont _font;
|
||||
QByteArray _key;
|
||||
};
|
||||
|
||||
class Symbol : public Render
|
||||
@ -215,8 +217,8 @@ public:
|
||||
|
||||
Style(const QString &path);
|
||||
|
||||
void match(int zoom, bool closed, const QVector<MapData::Tag> &tags,
|
||||
QVector<const PathRender *> *ri) const;
|
||||
QVector<const PathRender *> paths(int zoom, bool closed,
|
||||
const QVector<MapData::Tag> &tags) const;
|
||||
QList<const TextRender*> pathLabels(int zoom) const;
|
||||
QList<const TextRender*> pointLabels(int zoom) const;
|
||||
QList<const TextRender*> areaLabels(int zoom) const;
|
||||
|
Loading…
Reference in New Issue
Block a user