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:
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;
|
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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user