1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-30 22:51:16 +01:00

Some more Mapsforge maps rendering improvements

This commit is contained in:
Martin Tůma 2023-06-06 07:18:31 +02:00
parent 1233d20a21
commit 88fa1ed786
9 changed files with 113 additions and 64 deletions

View File

@ -23,17 +23,21 @@ using namespace Mapsforge;
static void copyPaths(const RectC &rect, const QList<MapData::Path> *src, static void copyPaths(const RectC &rect, const QList<MapData::Path> *src,
QList<MapData::Path> *dst) QList<MapData::Path> *dst)
{ {
for (int i = 0; i < src->size(); i++) for (int i = 0; i < src->size(); i++) {
if (rect.intersects(src->at(i).poly.boundingRect())) const MapData::Path &path = src->at(i);
dst->append(src->at(i)); if (rect.intersects(path.poly.boundingRect()))
dst->append(path);
}
} }
static void copyPoints(const RectC &rect, const QList<MapData::Point> *src, static void copyPoints(const RectC &rect, const QList<MapData::Point> *src,
QList<MapData::Point> *dst) QList<MapData::Point> *dst)
{ {
for (int i = 0; i < src->size(); i++) for (int i = 0; i < src->size(); i++) {
if (rect.contains(src->at(i).coordinates)) const MapData::Point &point = src->at(i);
dst->append(src->at(i)); if (rect.contains(point.coordinates))
dst->append(point);
}
} }
static double distance(const Coordinates &c1, const Coordinates &c2) static double distance(const Coordinates &c1, const Coordinates &c2)
@ -540,19 +544,20 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
_pointLock.unlock(); _pointLock.unlock();
} }
void MapData::paths(const RectC &rect, int zoom, QList<Path> *list) void MapData::paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
QList<Path> *list)
{ {
if (!rect.isValid()) if (!searchRect.isValid())
return; return;
int l(level(zoom)); int l(level(zoom));
PathCTX ctx(this, rect, zoom, list); PathCTX ctx(this, boundsRect, zoom, list);
double min[2], max[2]; double min[2], max[2];
min[0] = rect.left(); min[0] = searchRect.left();
min[1] = rect.bottom(); min[1] = searchRect.bottom();
max[0] = rect.right(); max[0] = searchRect.right();
max[1] = rect.top(); max[1] = searchRect.top();
_tiles.at(l)->Search(min, max, pathCb, &ctx); _tiles.at(l)->Search(min, max, pathCb, &ctx);
} }

View File

@ -62,7 +62,8 @@ public:
int tileSize() const {return _tileSize;} int tileSize() const {return _tileSize;}
void points(const RectC &rect, int zoom, QList<Point> *list); void points(const RectC &rect, int zoom, QList<Point> *list);
void paths(const RectC &rect, int zoom, QList<Path> *set); void paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
QList<Path> *set);
unsigned tagId(const QByteArray &name) const {return _keys.value(name);} unsigned tagId(const QByteArray &name) const {return _keys.value(name);}
void load(); void load();

View File

@ -8,6 +8,8 @@
using namespace Mapsforge; using namespace Mapsforge;
#define TEXT_EXTENT 160 #define TEXT_EXTENT 160
#define PATHS_EXTENT 20
#define SEARCH_EXTENT -0.5
static double limit = cos(deg2rad(170)); static double limit = cos(deg2rad(170));
@ -250,15 +252,28 @@ void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
const QFont *font = ti ? &ti->font() : 0; const QFont *font = ti ? &ti->font() : 0;
const QColor *color = ti ? &ti->fillColor() : 0; const QColor *color = ti ? &ti->fillColor() : 0;
const QColor *hColor = ti ? haloColor(ti) : 0; const QColor *hColor = ti ? haloColor(ti) : 0;
bool rotate = si ? si->rotate() : false;
PathItem *item = new PathItem(path.pp, lbl, img, _rect, font, color, PathItem *item = new PathItem(path.pp, lbl, img, _rect, font, color,
hColor); hColor, rotate);
if (item->isValid() && !item->collides(textItems)) { if (item->isValid() && !item->collides(textItems)) {
textItems.append(item); textItems.append(item);
if (limit) if (limit)
set.insert(*lbl); set.insert(*lbl);
} else } else {
delete item; delete item;
if (img && lbl) {
PathItem *item = new PathItem(path.pp, 0, img, _rect, 0, 0, 0,
rotate);
if (item->isValid() && !item->collides(textItems)) {
textItems.append(item);
if (limit)
set.insert(*lbl);
} else
delete item;
}
}
} }
} }
@ -382,6 +397,7 @@ void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
painter->setPen(ri->pen(_zoom)); painter->setPen(ri->pen(_zoom));
painter->setBrush(ri->brush()); painter->setBrush(ri->brush());
if (dy != 0) if (dy != 0)
painter->drawPath(parallelPath(path->pp, dy)); painter->drawPath(parallelPath(path->pp, dy));
else else
@ -402,14 +418,18 @@ void RasterTile::fetchData(QList<MapData::Path> &paths,
{ {
QPoint ttl(_rect.topLeft()); QPoint ttl(_rect.topLeft());
/* Add a "sub-pixel" margin to assure the tile areas do not QRectF pathRect(QPointF(ttl.x() - PATHS_EXTENT, ttl.y() - PATHS_EXTENT),
overlap on the border lines. This prevents areas overlap QPointF(ttl.x() + _rect.width() + PATHS_EXTENT, ttl.y() + _rect.height()
artifacts at least when using the EPSG:3857 projection. */ + PATHS_EXTENT));
QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5), QRectF searchRect(QPointF(ttl.x() - SEARCH_EXTENT, ttl.y() - SEARCH_EXTENT),
QPointF(ttl.x() + _rect.width() - 0.5, ttl.y() + _rect.height() - 0.5)); QPointF(ttl.x() + _rect.width() + SEARCH_EXTENT, ttl.y() + _rect.height()
+ SEARCH_EXTENT));
RectD pathRectD(_transform.img2proj(pathRect.topLeft()), RectD pathRectD(_transform.img2proj(pathRect.topLeft()),
_transform.img2proj(pathRect.bottomRight())); _transform.img2proj(pathRect.bottomRight()));
_data->paths(pathRectD.toRectC(_proj, 20), _zoom, &paths); RectD searchRectD(_transform.img2proj(searchRect.topLeft()),
_transform.img2proj(searchRect.bottomRight()));
_data->paths(searchRectD.toRectC(_proj, 20), pathRectD.toRectC(_proj, 20),
_zoom, &paths);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT), QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT),
QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height() QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height()

View File

@ -138,9 +138,9 @@ private:
public: public:
PathItem(const QPainterPath &line, const QByteArray *label, PathItem(const QPainterPath &line, const QByteArray *label,
const QImage *img, const QRect &tileRect, const QFont *font, const QImage *img, const QRect &tileRect, const QFont *font,
const QColor *color, const QColor *haloColor) : TextPathItem(line, const QColor *color, const QColor *haloColor, bool rotate)
label ? new QString(*label) : 0, tileRect, font, color, haloColor, : TextPathItem(line, label ? new QString(*label) : 0, tileRect, font,
img) {} color, haloColor, img, rotate) {}
~PathItem() {delete _text;} ~PathItem() {delete _text;}
}; };

View File

@ -17,18 +17,26 @@ static QString resourcePath(const QString &src, const QString &dir)
return dir + "/" + url.toLocalFile(); return dir + "/" + url.toLocalFile();
} }
static QImage image(const QString &path, int width, int height, qreal ratio) static QImage image(const QString &path, int width, int height, int percent,
qreal ratio)
{ {
QImageReader ir(path, "svg"); QImageReader ir(path, "svg");
if (ir.canRead()) { if (ir.canRead()) {
QSize s(ir.size());
if (!height && !width) { if (!height && !width) {
height = 20; height = 20;
width = 20; width = 20;
} else if (!width) { } else if (!width) {
width = ir.size().height() / (ir.size().height() / (double)height); width = s.height() / (s.height() / (double)height);
} else if (!height) } else if (!height)
height = ir.size().width() / (ir.size().width() / (double)width); height = s.width() / (s.width() / (double)width);
if (percent != 100) {
width *= percent / 100.0;
height *= percent / 100.0;
}
ir.setScaledSize(QSize(width * ratio, height * ratio)); ir.setScaledSize(QSize(width * ratio, height * ratio));
QImage img(ir.read()); QImage img(ir.read());
@ -175,7 +183,7 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const QXmlStreamAttributes &attr = reader.attributes(); const QXmlStreamAttributes &attr = reader.attributes();
QString file; QString file;
QColor fillColor; QColor fillColor;
int height = 0, width = 0; int height = 0, width = 0, percent = 100;
bool ok; bool ok;
ri._area = true; ri._area = true;
@ -213,9 +221,16 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return; return;
} }
} }
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (!file.isNull()) if (!file.isNull())
ri._brush = QBrush(image(file, width, height, ratio)); ri._brush = QBrush(image(file, width, height, percent, ratio));
else if (fillColor.isValid()) else if (fillColor.isValid())
ri._brush = QBrush(fillColor); ri._brush = QBrush(fillColor);
@ -231,6 +246,8 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
const QXmlStreamAttributes &attr = reader.attributes(); const QXmlStreamAttributes &attr = reader.attributes();
bool ok; bool ok;
ri._brush = Qt::NoBrush;
if (attr.hasAttribute("stroke")) if (attr.hasAttribute("stroke"))
ri._strokeColor = QColor(attr.value("stroke").toString()); ri._strokeColor = QColor(attr.value("stroke").toString());
if (attr.hasAttribute("stroke-width")) { if (attr.hasAttribute("stroke-width")) {
@ -424,7 +441,7 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
Symbol ri(rule); Symbol ri(rule);
const QXmlStreamAttributes &attr = reader.attributes(); const QXmlStreamAttributes &attr = reader.attributes();
QString file; QString file;
int height = 0, width = 0; int height = 0, width = 0, percent = 100;
bool ok; bool ok;
if (attr.hasAttribute("src")) if (attr.hasAttribute("src"))
@ -447,6 +464,13 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return; return;
} }
} }
if (attr.hasAttribute("symbol-percent")) {
percent = attr.value("symbol-percent").toInt(&ok);
if (!ok || percent < 0) {
reader.raiseError("invalid symbol-percent value");
return;
}
}
if (attr.hasAttribute("priority")) { if (attr.hasAttribute("priority")) {
ri._priority = attr.value("priority").toInt(&ok); ri._priority = attr.value("priority").toInt(&ok);
if (!ok) { if (!ok) {
@ -454,8 +478,12 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return; return;
} }
} }
if (attr.hasAttribute("rotate")) {
if (attr.value("rotate").toString() == "false")
ri._rotate = false;
}
ri._img = image(file, width, height, ratio); ri._img = image(file, width, height, percent, ratio);
list.append(ri); list.append(ri);

View File

@ -212,15 +212,17 @@ public:
class Symbol : public Render class Symbol : public Render
{ {
public: public:
Symbol(const Rule &rule) : Render(rule), _priority(0) {} Symbol(const Rule &rule) : Render(rule), _priority(0), _rotate(true) {}
const QImage &img() const {return _img;} const QImage &img() const {return _img;}
int priority() const {return _priority;} int priority() const {return _priority;}
bool rotate() const {return _rotate;}
private: private:
friend class Style; friend class Style;
int _priority; int _priority;
bool _rotate;
QImage _img; QImage _img;
}; };
@ -282,8 +284,7 @@ private:
QList<PathRender> _paths; QList<PathRender> _paths;
QList<CircleRender> _circles; QList<CircleRender> _circles;
QList<TextRender> _pathLabels, _pointLabels, _areaLabels; QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
QList<Symbol> _symbols; QList<Symbol> _symbols, _lineSymbols;
QList<Symbol> _lineSymbols;
bool loadXml(const QString &path, const MapData &data, qreal ratio); bool loadXml(const QString &path, const MapData &data, qreal ratio);
void rendertheme(QXmlStreamReader &reader, const QString &dir, void rendertheme(QXmlStreamReader &reader, const QString &dir,

View File

@ -266,15 +266,15 @@ void TextPathItem::init(const T &line, const QRect &tileRect)
if (_text && _img) { if (_text && _img) {
cw = _font->pixelSize() * CHAR_RATIO; cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2; mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw + _img->width() + PADDING; textWidth = _text->size() * cw + _img->width() + PADDING;
} else if (_text) { } else if (_text) {
cw = _font->pixelSize() * CHAR_RATIO; cw = _font->pixelSize() * CHAR_RATIO;
mw = _font->pixelSize() / 2; mw = _font->pixelSize() / 2.0;
textWidth = _text->size() * cw; textWidth = _text->size() * cw;
} else { } else {
cw = _img->width(); cw = _img->width();
mw = _img->height() / 2; mw = _img->height() / 2.0;
textWidth = _img->width(); textWidth = _img->width();
} }
@ -296,16 +296,18 @@ void TextPathItem::init(const T &line, const QRect &tileRect)
TextPathItem::TextPathItem(const QPolygonF &line, const QString *label, TextPathItem::TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color, const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor, const QImage *img) : TextItem(label), _font(font), const QColor *haloColor, const QImage *img, bool rotate)
_color(color), _haloColor(haloColor), _img(img), _reverse(false) : TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{ {
init(line, tileRect); init(line, tileRect);
} }
TextPathItem::TextPathItem(const QPainterPath &line, const QString *label, TextPathItem::TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color, const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor, const QImage *img) : TextItem(label), _font(font), const QColor *haloColor, const QImage *img, bool rotate)
_color(color), _haloColor(haloColor), _img(img), _reverse(false) : TextItem(label), _font(font), _color(color), _haloColor(haloColor),
_img(img), _rotate(rotate), _reverse(false)
{ {
init(line, tileRect); init(line, tileRect);
} }
@ -318,13 +320,11 @@ void TextPathItem::paint(QPainter *painter) const
painter->save(); painter->save();
painter->translate(QPointF(_path.elementAt(0).x, _path.elementAt(0).y)); painter->translate(QPointF(_path.elementAt(0).x, _path.elementAt(0).y));
painter->rotate(360 - _path.angleAtPercent(0)); painter->rotate(360 - _path.angleAtPercent(0));
if (_reverse && _rotate) {
if (_reverse) painter->rotate(180);
painter->drawImage(QPointF(0, -s.height()/2), painter->translate(-s.width(), 0);
_img->transformed(QTransform().rotate(180.0))); }
else painter->drawImage(QPointF(0, -s.height()/2), *_img);
painter->drawImage(QPointF(0, -s.height()/2), *_img);
painter->restore(); painter->restore();
} }

View File

@ -1,20 +1,21 @@
#ifndef TEXTPATHITEM_H #ifndef TEXTPATHITEM_H
#define TEXTPATHITEM_H #define TEXTPATHITEM_H
#include <QVector>
#include <QPainterPath>
#include "textitem.h" #include "textitem.h"
class QFont;
class QImage;
class QColor;
class TextPathItem : public TextItem class TextPathItem : public TextItem
{ {
public: public:
TextPathItem() : TextItem(0), _font(0), _color(0) {}
TextPathItem(const QPolygonF &line, const QString *label, TextPathItem(const QPolygonF &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color, const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor, const QImage *img = 0); const QColor *haloColor, const QImage *img = 0, bool rotate = true);
TextPathItem(const QPainterPath &line, const QString *label, TextPathItem(const QPainterPath &line, const QString *label,
const QRect &tileRect, const QFont *font, const QColor *color, const QRect &tileRect, const QFont *font, const QColor *color,
const QColor *haloColor, const QImage *img = 0); const QColor *haloColor, const QImage *img = 0, bool rotate = true);
bool isValid() const {return !_path.isEmpty();} bool isValid() const {return !_path.isEmpty();}
@ -26,13 +27,11 @@ private:
template<class T> void init(const T &line, const QRect &tileRect); template<class T> void init(const T &line, const QRect &tileRect);
const QFont *_font; const QFont *_font;
const QColor *_color; const QColor *_color, *_haloColor;
const QColor *_haloColor;
const QImage *_img; const QImage *_img;
QPainterPath _path;
QRectF _rect; QRectF _rect;
QPainterPath _shape; QPainterPath _path, _shape;
bool _reverse; bool _rotate, _reverse;
}; };
#endif // TEXTPATHITEM_H #endif // TEXTPATHITEM_H

View File

@ -1,12 +1,8 @@
#ifndef TEXTPOINTITEM_H #ifndef TEXTPOINTITEM_H
#define TEXTPOINTITEM_H #define TEXTPOINTITEM_H
#include <QRect>
#include <QString>
#include <QVector>
#include "textitem.h" #include "textitem.h"
class QPainter;
class QFont; class QFont;
class QImage; class QImage;
class QColor; class QColor;
@ -14,7 +10,6 @@ class QColor;
class TextPointItem : public TextItem class TextPointItem : public TextItem
{ {
public: public:
TextPointItem() : TextItem(0), _font(0), _img(0) {}
TextPointItem(const QPoint &point, const QString *text, const QFont *font, TextPointItem(const QPoint &point, const QString *text, const QFont *font,
const QImage *img, const QColor *color, const QColor *haloColor, const QImage *img, const QColor *color, const QColor *haloColor,
const QColor *bgColor = 0, int padding = 0, double rotate = NAN); const QColor *bgColor = 0, int padding = 0, double rotate = NAN);