Skip to content

Commit

Permalink
Render repeating "always-display" lineSymbols as bitmap lines
Browse files Browse the repository at this point in the history
  • Loading branch information
tumic0 committed Nov 8, 2024
1 parent 70ddd83 commit 01fba7b
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 42 deletions.
21 changes: 21 additions & 0 deletions src/map/bitmapline.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <QPainter>
#include <QImage>
#include <QtMath>
#include <QPainterPath>
#include "bitmapline.h"


Expand Down Expand Up @@ -58,3 +59,23 @@ void BitmapLine::draw(QPainter *painter, const QVector<QPolygonF> &lines,
for (int i = 0; i < lines.size(); i++)
draw(painter, lines.at(i), img);
}

void BitmapLine::draw(QPainter *painter, const QPainterPath &line,
const QImage &img)
{
int offset = 0;

for (int i = 1; i < line.elementCount(); i++) {
QLineF segment(line.elementAt(i-1).x, line.elementAt(i-1).y,
line.elementAt(i).x, line.elementAt(i).y);
int len = qCeil(segment.length() * img.devicePixelRatio());

painter->save();
painter->translate(segment.p1());
painter->rotate(-segment.angle());
painter->drawImage(0.0, -img.height()/2.0, img2line(img, len, offset));
painter->restore();

offset = (len + offset) % img.width();
}
}
2 changes: 2 additions & 0 deletions src/map/bitmapline.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
class QPainter;
class QImage;
class QPolygonF;
class QPainterPath;

namespace BitmapLine
{
void draw(QPainter *painter, const QPolygonF &line, const QImage &img);
void draw(QPainter *painter, const QVector<QPolygonF> &lines,
const QImage &img);
void draw(QPainter *painter, const QPainterPath &line, const QImage &img);
}

#endif // BITMAPLINE_H
21 changes: 15 additions & 6 deletions src/map/mapsforge/rastertile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "map/rectd.h"
#include "map/hillshading.h"
#include "map/filter.h"
#include "map/bitmapline.h"
#include "rastertile.h"

using namespace Mapsforge;
Expand Down Expand Up @@ -421,13 +422,21 @@ void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
if (!path->pp.elementCount())
path->pp = painterPath(path->path->poly, ri->curve());

painter->setPen(ri->pen(_zoom));
painter->setBrush(ri->brush());
if (ri->bitmapLine()) {
if (dy != 0)
BitmapLine::draw(painter, parallelPath(path->pp, dy),
ri->img());
else
BitmapLine::draw(painter, path->pp, ri->img());
} else {
painter->setPen(ri->pen(_zoom));
painter->setBrush(ri->brush());

if (dy != 0)
painter->drawPath(parallelPath(path->pp, dy));
else
painter->drawPath(path->pp);
if (dy != 0)
painter->drawPath(parallelPath(path->pp, dy));
else
painter->drawPath(path->pp);
}
} else if (point) {
const Style::CircleRender *ri = is.circleRender();
qreal radius = ri->radius(_zoom);
Expand Down
107 changes: 73 additions & 34 deletions src/map/mapsforge/style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <QUrl>
#include <QFileInfo>
#include <QImageReader>
#include <QPainter>
#include "common/programpaths.h"
#include "style.h"

Expand Down Expand Up @@ -388,8 +389,8 @@ void Style::circle(QXmlStreamReader &reader, qreal baseStrokeWidth,
reader.skipCurrentElement();
}

void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
QList<QList<TextRender>*> &lists)
void Style::text(QXmlStreamReader &reader, const MapData &data,
const Rule &rule, bool line)
{
TextRender ri(rule);
const QXmlStreamAttributes &attr = reader.attributes();
Expand Down Expand Up @@ -462,21 +463,28 @@ void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule
ri._font.setItalic(italic);
ri._font.setCapitalization(capitalization);

if (fontSize)
for (int i = 0; i < lists.size(); i++)
lists[i]->append(ri);
if (fontSize) {
if (line)
_pathLabels.append(ri);
else {
if (rule._type == Rule::WayType || rule._type == Rule::AnyType)
_areaLabels.append(ri);
if (rule._type == Rule::NodeType || rule._type == Rule::AnyType)
_pointLabels.append(ri);
}
}

reader.skipCurrentElement();
}

void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule, QList<Symbol> &list)
const Rule &rule, bool line)
{
Symbol ri(rule);
const QXmlStreamAttributes &attr = reader.attributes();
QString file;
int height = 0, width = 0, percent = 100;
bool ok;
bool ok, bitmapLine = false;

if (attr.hasAttribute("src"))
file = resourcePath(attr.value("src").toString(), dir);
Expand Down Expand Up @@ -505,23 +513,62 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
return;
}
}
if (attr.hasAttribute("priority")) {
ri._priority = attr.value("priority").toInt(&ok);
if (!ok) {
reader.raiseError("invalid priority value");

// Convert repeating "always-display" lineSymbols to bitmap lines
if (line && (rule._type == Rule::AnyType || rule._type == Rule::WayType)) {
bool repeat = (attr.value("repeat").toString() == "true");
bool always = (attr.value("display").toString() == "always");
double start = attr.hasAttribute("repeat-start")
? attr.value("repeat-start").toDouble(&ok) : 30;

if (always && repeat && ok && start == 0)
bitmapLine = true;
}

if (bitmapLine) {
PathRender pr(rule, _paths.size() + _circles.size()
+ _hillShading.isValid());

double gap = attr.hasAttribute("repeat-gap")
? attr.value("repeat-gap").toDouble(&ok) : 200;
if (!ok || gap < 0) {
reader.raiseError("invalid repeat-gap value");
return;
}
}
if (attr.hasAttribute("rotate")) {
if (attr.value("rotate").toString() == "false")
ri._rotate = false;
}
if (attr.hasAttribute("id"))
ri._id = attr.value("id").toString();

ri._img = image(file, width, height, percent, ratio);
QImage s(image(file, width, height, percent, ratio));
pr._img = QImage(qCeil(gap) + s.width(), s.height(),
QImage::Format_ARGB32_Premultiplied);
pr._img.setDevicePixelRatio(s.devicePixelRatio());
pr._img.fill(Qt::transparent);
QPainter painter(&pr._img);
painter.drawImage(QPoint(0, 0), s);

pr._brush = Qt::NoBrush;

list.append(ri);
_paths.append(pr);
} else {
ri._img = image(file, width, height, percent, ratio);

if (attr.hasAttribute("priority")) {
ri._priority = attr.value("priority").toInt(&ok);
if (!ok) {
reader.raiseError("invalid priority value");
return;
}
}
if (attr.hasAttribute("rotate")) {
if (attr.value("rotate").toString() == "false")
ri._rotate = false;
}
if (attr.hasAttribute("id"))
ri._id = attr.value("id").toString();

if (line)
_lineSymbols.append(ri);
else
_symbols.append(ri);
}

reader.skipCurrentElement();
}
Expand Down Expand Up @@ -580,22 +627,14 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir,
line(reader, dir, ratio, baseStrokeWidth, r);
else if (reader.name() == QLatin1String("circle"))
circle(reader, baseStrokeWidth, r);
else if (reader.name() == QLatin1String("pathText")) {
QList<QList<TextRender>*> list;
list.append(&_pathLabels);
text(reader, data, r, list);
} else if (reader.name() == QLatin1String("caption")) {
QList<QList<TextRender>*> list;
if (r._type == Rule::WayType || r._type == Rule::AnyType)
list.append(&_areaLabels);
if (r._type == Rule::NodeType || r._type == Rule::AnyType)
list.append(&_pointLabels);
text(reader, data, r, list);
}
else if (reader.name() == QLatin1String("pathText"))
text(reader, data, r, true);
else if (reader.name() == QLatin1String("caption"))
text(reader, data, r, false);
else if (reader.name() == QLatin1String("symbol"))
symbol(reader, dir, ratio, r, _symbols);
symbol(reader, dir, ratio, r, false);
else if (reader.name() == QLatin1String("lineSymbol"))
symbol(reader, dir, ratio, r, _lineSymbols);
symbol(reader, dir, ratio, r, true);
else
reader.skipCurrentElement();
}
Expand Down
6 changes: 4 additions & 2 deletions src/map/mapsforge/style.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ class Style
bool area() const {return _area;}
bool curve() const {return _curve;}
qreal dy(int zoom) const;
const QImage &img() const {return _img;}
bool bitmapLine() const {return !_img.isNull() && _strokeWidth == 0;}

private:
friend class Style;
Expand Down Expand Up @@ -333,9 +335,9 @@ class Style
const Rule &rule);
void hillshading(QXmlStreamReader &reader, const QSet<QString> &cats);
void text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
QList<QList<TextRender> *> &lists);
bool line);
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule, QList<Symbol> &list);
const Rule &rule, bool line);
};

}
Expand Down

0 comments on commit 01fba7b

Please sign in to comment.