mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-23 19:25:54 +01:00
Render repeating "always-display" lineSymbols as bitmap lines
This commit is contained in:
parent
70ddd83154
commit
01fba7b742
@ -1,6 +1,7 @@
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <QtMath>
|
||||
#include <QPainterPath>
|
||||
#include "bitmapline.h"
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QUrl>
|
||||
#include <QFileInfo>
|
||||
#include <QImageReader>
|
||||
#include <QPainter>
|
||||
#include "common/programpaths.h"
|
||||
#include "style.h"
|
||||
|
||||
@ -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();
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
list.append(ri);
|
||||
pr._brush = Qt::NoBrush;
|
||||
|
||||
_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();
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
@ -161,6 +161,8 @@ public:
|
||||
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;
|
||||
@ -333,9 +335,9 @@ private:
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user