1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +01:00

Improved mapsforge hi-dpi rendering

This commit is contained in:
Martin Tůma 2021-04-18 12:20:07 +02:00
parent b6add991d2
commit 663859ef1c
11 changed files with 114 additions and 81 deletions

View File

@ -13,6 +13,8 @@ using namespace IMG;
#define AREA(rect) \
(rect.size().width() * rect.size().height())
static const QColor textColor(Qt::black);
static const QColor haloColor(Qt::white);
static const QColor shieldColor(Qt::white);
static const QColor shieldBgColor1("#dd3e3e");
static const QColor shieldBgColor2("#379947");
@ -316,8 +318,8 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
|| Style::isNatureReserve(poly.type))) {
const Style::Polygon &style = _style->polygon(poly.type);
TextPointItem *item = new TextPointItem(
centroid(poly.points).toPoint(), &poly.label.text(),
poiFont(), 0, &style.brush().color());
centroid(poly.points).toPoint(), &poly.label.text(), poiFont(),
0, &style.brush().color(), &haloColor);
if (item->isValid() && !item->collides(textItems)
&& !item->collides(labels)
&& !(exists && tileRect.contains(item->boundingRect()))
@ -417,7 +419,7 @@ void RasterTile::processShields(const QRect &tileRect,
TextPointItem *item = new TextPointItem(
p.at(jt.value()).toPoint(), &(sp.value(it.key())->text()),
poiFont(), 0, &shieldColor, shieldBgColor(it.key().type()));
poiFont(), 0, &shieldColor, 0, shieldBgColor(it.key().type()));
bool valid = false;
while (true) {
@ -457,7 +459,7 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
const QFont *fnt = poi
? poiFont(style.textFontSize()) : font(style.textFontSize());
const QColor *color = style.textColor().isValid()
? &style.textColor() : 0;
? &style.textColor() : &textColor;
if ((!label || !fnt) && !img)
continue;
@ -471,7 +473,7 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
}
TextPointItem *item = new TextPointItem(QPoint(point.coordinates.lon(),
point.coordinates.lat()), label, fnt, img, color);
point.coordinates.lat()), label, fnt, img, color, &haloColor);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else

View File

@ -79,6 +79,13 @@ static QString *pathLabel(const Style::TextRender *ri, MapData::Path &path,
return 0;
}
static const QColor *haloColor(const Style::TextRender *ti)
{
return (ti->strokeColor() != ti->fillColor() && ti->strokeWidth() > 0)
? &ti->strokeColor() : 0;
}
void RasterTile::processPointLabels(QList<TextItem*> &textItems)
{
const Style &s = style();
@ -115,9 +122,11 @@ void RasterTile::processPointLabels(QList<TextItem*> &textItems)
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;
TextPointItem *item = new TextPointItem(
ll2xy(point.coordinates).toPoint(), label, font, img, color, 0, false);
ll2xy(point.coordinates).toPoint(), label, font, img, color,
hColor, 0, false);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
@ -125,8 +134,7 @@ void RasterTile::processPointLabels(QList<TextItem*> &textItems)
}
}
void RasterTile::processAreaLabels(const QRect &tileRect,
QList<TextItem*> &textItems)
void RasterTile::processAreaLabels(QList<TextItem*> &textItems)
{
const Style &s = style();
QList<const Style::TextRender*> labels(s.areaLabels(_zoom));
@ -165,12 +173,13 @@ void RasterTile::processAreaLabels(const QRect &tileRect,
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;
QPointF pos = path.labelPos.isNull()
? centroid(path.path) : ll2xy(path.labelPos);
TextPointItem *item = new TextPointItem(pos.toPoint(), label, font, img,
color, 0, false);
if (item->isValid() && tileRect.contains(item->boundingRect().toRect())
color, hColor, 0, false);
if (item->isValid() && _rect.contains(item->boundingRect().toRect())
&& !item->collides(textItems))
textItems.append(item);
else
@ -178,8 +187,7 @@ void RasterTile::processAreaLabels(const QRect &tileRect,
}
}
void RasterTile::processLineLabels(const QRect &tileRect,
QList<TextItem*> &textItems)
void RasterTile::processLineLabels(QList<TextItem*> &textItems)
{
const Style &s = style();
QList<const Style::TextRender*> instructions(s.pathLabels(_zoom));
@ -202,8 +210,8 @@ void RasterTile::processLineLabels(const QRect &tileRect,
if (limit && set.contains(path.label))
continue;
TextPathItem *item = new TextPathItem(path.path, label, tileRect,
&ri->font(), &ri->fillColor(), &ri->strokeColor());
TextPathItem *item = new TextPathItem(path.path, label, _rect,
&ri->font(), &ri->fillColor(), haloColor(ri));
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
@ -271,11 +279,12 @@ void RasterTile::drawPaths(QPainter *painter)
const Style::PathRender *lri = 0;
QPixmap layer(_pixmap.size());
layer.setDevicePixelRatio(_ratio);
layer.fill(Qt::transparent);
QPainter lp(&layer);
lp.setRenderHint(QPainter::Antialiasing);
lp.translate(-_xy.x(), -_xy.y());
lp.translate(-_rect.x(), -_rect.y());
lp.setCompositionMode(QPainter::CompositionMode_Source);
for (int i = 0; i < instructions.size(); i++) {
@ -283,8 +292,8 @@ void RasterTile::drawPaths(QPainter *painter)
const Style::PathRender *ri = is.render();
if (lri && lri != ri) {
painter->drawPixmap(_xy, layer);
lp.fillRect(QRect(_xy, _pixmap.size()), Qt::transparent);
painter->drawPixmap(_rect.topLeft(), layer);
lp.fillRect(QRect(_rect.topLeft(), _pixmap.size()), Qt::transparent);
}
if (!is.path()->path.elementCount())
@ -304,7 +313,7 @@ void RasterTile::drawPaths(QPainter *painter)
}
if (lri)
painter->drawPixmap(_xy, layer);
painter->drawPixmap(_rect.topLeft(), layer);
}
void RasterTile::render()
@ -312,24 +321,24 @@ void RasterTile::render()
std::sort(_points.begin(), _points.end());
QList<TextItem*> textItems;
QRect tileRect(_xy, _pixmap.size());
_pixmap.fill(Qt::transparent);
QPainter painter(&_pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(-_xy.x(), -_xy.y());
painter.scale(_ratio, _ratio);
painter.translate(-_rect.x(), -_rect.y());
drawPaths(&painter);
processPointLabels(textItems);
processAreaLabels(tileRect, textItems);
processLineLabels(tileRect, textItems);
processAreaLabels(textItems);
processLineLabels(textItems);
drawTextItems(&painter, textItems);
//painter.setPen(Qt::red);
//painter.setBrush(Qt::NoBrush);
//painter.drawRect(QRect(_xy, _pixmap.size()));
//painter.drawRect(QRect(_rect.topLeft(), _pixmap.size()));
qDeleteAll(textItems);
}

View File

@ -16,13 +16,14 @@ class RasterTile
{
public:
RasterTile(const Projection &proj, const Transform &transform, int zoom,
const QRect &rect, const QString &key, const QList<MapData::Path> &paths,
const QList<MapData::Point> &points)
: _proj(proj), _transform(transform), _zoom(zoom), _xy(rect.topLeft()),
_key(key), _pixmap(rect.size()), _paths(paths), _points(points) {}
const QRect &rect, qreal ratio, const QString &key,
const QList<MapData::Path> &paths, const QList<MapData::Point> &points)
: _proj(proj), _transform(transform), _zoom(zoom), _rect(rect),
_ratio(ratio), _key(key), _pixmap(rect.width() * ratio,
rect.height() * ratio), _paths(paths), _points(points) {}
const QString &key() const {return _key;}
const QPoint &xy() const {return _xy;}
QPoint xy() const {return _rect.topLeft();}
const QPixmap &pixmap() const {return _pixmap;}
void render();
@ -72,8 +73,8 @@ private:
QPointF ll2xy(const Coordinates &c) const
{return _transform.proj2img(_proj.ll2xy(c));}
void processPointLabels(QList<TextItem*> &textItems);
void processAreaLabels(const QRect &tileRect, QList<TextItem*> &textItems);
void processLineLabels(const QRect &tileRect, QList<TextItem*> &textItems);
void processAreaLabels(QList<TextItem*> &textItems);
void processLineLabels(QList<TextItem*> &textItems);
QPainterPath painterPath(const Polygon &polygon) const;
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void drawPaths(QPainter *painter);
@ -81,7 +82,8 @@ private:
Projection _proj;
Transform _transform;
int _zoom;
QPoint _xy;
QRect _rect;
qreal _ratio;
QString _key;
QPixmap _pixmap;
QList<MapData::Path> _paths;

View File

@ -159,6 +159,8 @@ void Style::text(QXmlStreamReader &reader, const Rule &rule,
ri._fillColor = QColor(attr.value("fill").toString());
if (attr.hasAttribute("stroke"))
ri._strokeColor = QColor(attr.value("stroke").toString());
if (attr.hasAttribute("stroke-width"))
ri._strokeWidth = attr.value("stroke-width").toFloat();
if (attr.hasAttribute("font-size"))
fontSize = attr.value("font-size").toInt();
if (attr.hasAttribute("font-style")) {

View File

@ -187,17 +187,20 @@ public:
{
public:
TextRender(const Rule &rule)
: Render(rule), _fillColor(Qt::black), _strokeColor(Qt::white) {}
: Render(rule), _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;}
private:
friend class Style;
QColor _fillColor, _strokeColor;
qreal _strokeWidth;
QFont _font;
QByteArray _key;
};

View File

@ -21,7 +21,8 @@ static int log2i(unsigned val)
}
MapsforgeMap::MapsforgeMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _data(fileName), _zoom(0), _projection(PCS::pcs(3857))
: Map(fileName, parent), _data(fileName), _zoom(0),
_projection(PCS::pcs(3857)), _tileRatio(1.0)
{
_zoom = _data.zooms().min();
updateTransform();
@ -147,9 +148,10 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
if (isRunning(key))
continue;
if (QPixmapCache::find(key, &pm))
if (QPixmapCache::find(key, &pm)) {
pm.setDevicePixelRatio(_tileRatio);
painter->drawPixmap(ttl, pm);
else {
} else {
QList<MapData::Path> paths;
QList<MapData::Point> points;
@ -170,11 +172,12 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
pointRect &= _bounds;
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.points(pointRectD.toRectC(_projection, 20), _zoom, &points);
_data.points(pointRectD.toRectC(_projection, 20), _zoom,
&points);
tiles.append(RasterTile(_projection, _transform, _zoom,
QRect(ttl, QSize(_data.tileSize(), _data.tileSize())), key,
paths, points));
QRect(ttl, QSize(_data.tileSize(), _data.tileSize())),
_tileRatio, key, paths, points));
}
}
}
@ -188,6 +191,13 @@ void MapsforgeMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
}
}
void MapsforgeMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
{
Q_UNUSED(mapRatio);
_tileRatio = deviceRatio;
}
void MapsforgeMap::setOutputProjection(const Projection &projection)
{
if (projection == _projection)

View File

@ -72,6 +72,7 @@ public:
void load();
void unload();
void setOutputProjection(const Projection &projection);
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
QPointF ll2xy(const Coordinates &c)
{return _transform.proj2img(_projection.ll2xy(c));}
@ -99,6 +100,7 @@ private:
Projection _projection;
Transform _transform;
QRectF _bounds;
qreal _tileRatio;
QSet<QString> _running;
};

View File

@ -238,7 +238,7 @@ static bool reverse(const QPainterPath &path)
TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color)
: TextItem(label), _font(font), _color(color), _outlineColor(0)
: TextItem(label), _font(font), _color(color), _haloColor(0)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
@ -259,8 +259,8 @@ TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
TextPathItem::TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *outlineColor) : TextItem(label), _font(font), _color(color),
_outlineColor(outlineColor)
const QColor *haloColor) : TextItem(label), _font(font), _color(color),
_haloColor(haloColor)
{
qreal cw = font->pixelSize() * 0.6;
qreal textWidth = _text->size() * cw;
@ -290,22 +290,23 @@ void TextPathItem::paint(QPainter *painter) const
QTransform t = painter->transform();
painter->setFont(*_font);
painter->setPen(_outlineColor ? *_outlineColor : Qt::white);
painter->setPen(_haloColor ? *_haloColor : Qt::white);
for (int i = 0; i < _text->size(); i++) {
QPointF point = _path.pointAtPercent(percent);
qreal angle = _path.angleAtPercent(percent);
QChar c = _text->at(i);
painter->translate(point);
painter->rotate(-angle);
painter->drawText(QPoint(-1, fm.descent() - 1), _text->at(i));
painter->drawText(QPoint(1, fm.descent() + 1), _text->at(i));
painter->drawText(QPoint(-1, fm.descent() + 1), _text->at(i));
painter->drawText(QPoint(1, fm.descent() -1), _text->at(i));
painter->drawText(QPoint(0, fm.descent() - 1), _text->at(i));
painter->drawText(QPoint(0, fm.descent() + 1), _text->at(i));
painter->drawText(QPoint(-1, fm.descent()), _text->at(i));
painter->drawText(QPoint(1, fm.descent()), _text->at(i));
painter->drawText(QPoint(-1, fm.descent() - 1), c);
painter->drawText(QPoint(1, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent() + 1), c);
painter->drawText(QPoint(1, fm.descent() -1), c);
painter->drawText(QPoint(0, fm.descent() - 1), c);
painter->drawText(QPoint(0, fm.descent() + 1), c);
painter->drawText(QPoint(-1, fm.descent()), c);
painter->drawText(QPoint(1, fm.descent()), c);
painter->setTransform(t);
int width = fm.horizontalAdvance(_text->at(i));

View File

@ -13,7 +13,7 @@ public:
const QRect &tileRect, const QFont *font, const QColor *color);
TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *outlineColor);
const QColor *haloColor);
bool isValid() const {return !_path.isEmpty();}
@ -24,7 +24,7 @@ public:
private:
const QFont *_font;
const QColor *_color;
const QColor *_outlineColor;
const QColor *_haloColor;
QPainterPath _path;
QRectF _rect;
QPainterPath _shape;

View File

@ -2,6 +2,7 @@
#include <QFontMetrics>
#include <QImage>
#include <QPainter>
#include <QStaticText>
#include "textpointitem.h"
@ -17,8 +18,9 @@ static void expand(QRect &rect, int width)
TextPointItem::TextPointItem(const QPoint &point, const QString *text,
const QFont *font, const QImage *img, const QColor *color,
const QColor *bgColor, bool padding) : TextItem(font ? text : 0),
_font(font), _img(img), _color(color), _bgColor(bgColor)
const QColor *haloColor, const QColor *bgColor, bool padding)
: TextItem(font ? text : 0), _font(font), _img(img), _color(color),
_haloColor(haloColor), _bgColor(bgColor)
{
if (_text) {
QFontMetrics fm(*_font);
@ -66,31 +68,31 @@ void TextPointItem::paint(QPainter *painter) const
painter->setBrush(Qt::NoBrush);
painter->setFont(*_font);
painter->drawText(_textRect, FLAGS, *_text);
} else if (_haloColor) {
QStaticText st(*_text);
st.setTextFormat(Qt::PlainText);
st.setTextWidth(_textRect.width());
st.setTextOption(QTextOption(Qt::AlignHCenter));
st.setPerformanceHint(QStaticText::AggressiveCaching);
painter->setPen(*_haloColor);
painter->setFont(*_font);
painter->drawStaticText(_textRect.topLeft() + QPointF(-1, -1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(+1, +1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(-1, +1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(+1, -1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(0, -1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(0, +1), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(-1, 0), st);
painter->drawStaticText(_textRect.topLeft() + QPointF(+1, 0), st);
painter->setPen(*_color);
painter->drawStaticText(_textRect.topLeft(), st);
} else {
QImage img(_textRect.size(), QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QPainter ip(&img);
ip.setPen(Qt::white);
ip.setFont(*_font);
ip.drawText(img.rect(), FLAGS, *_text);
painter->drawImage(_textRect.x() - 1, _textRect.y() - 1, img);
painter->drawImage(_textRect.x() + 1, _textRect.y() + 1, img);
painter->drawImage(_textRect.x() - 1, _textRect.y() + 1, img);
painter->drawImage(_textRect.x() + 1, _textRect.y() - 1, img);
painter->drawImage(_textRect.x(), _textRect.y() - 1, img);
painter->drawImage(_textRect.x(), _textRect.y() + 1, img);
painter->drawImage(_textRect.x() - 1, _textRect.y(), img);
painter->drawImage(_textRect.x() + 1, _textRect.y(), img);
if (_color) {
painter->setFont(*_font);
painter->setPen(*_color);
painter->drawText(_textRect, FLAGS, *_text);
} else {
img.invertPixels();
painter->drawImage(_textRect, img);
}
painter->setPen(*_color);
painter->setFont(*_font);
painter->drawText(_textRect, FLAGS, *_text);
}
}

View File

@ -16,8 +16,8 @@ class TextPointItem : public TextItem
public:
TextPointItem() : TextItem(0), _font(0), _img(0) {}
TextPointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QColor *color, const QColor *bgColor = 0,
bool padding = true);
const QImage *img, const QColor *color, const QColor *haloColor,
const QColor *bgColor = 0, bool padding = true);
bool isValid() const {return !_rect.isEmpty();}
@ -30,7 +30,7 @@ public:
private:
const QFont *_font;
const QImage *_img;
const QColor *_color, *_bgColor;
const QColor *_color, *_haloColor, *_bgColor;
QRect _rect, _textRect;
QPainterPath _shape;
};