mirror of
https://github.com/tumic0/GPXSee.git
synced 2024-11-24 03:35:53 +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 <QPainter>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
#include <QPainterPath>
|
||||||
#include "bitmapline.h"
|
#include "bitmapline.h"
|
||||||
|
|
||||||
|
|
||||||
@ -58,3 +59,23 @@ void BitmapLine::draw(QPainter *painter, const QVector<QPolygonF> &lines,
|
|||||||
for (int i = 0; i < lines.size(); i++)
|
for (int i = 0; i < lines.size(); i++)
|
||||||
draw(painter, lines.at(i), img);
|
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 QPainter;
|
||||||
class QImage;
|
class QImage;
|
||||||
class QPolygonF;
|
class QPolygonF;
|
||||||
|
class QPainterPath;
|
||||||
|
|
||||||
namespace BitmapLine
|
namespace BitmapLine
|
||||||
{
|
{
|
||||||
void draw(QPainter *painter, const QPolygonF &line, const QImage &img);
|
void draw(QPainter *painter, const QPolygonF &line, const QImage &img);
|
||||||
void draw(QPainter *painter, const QVector<QPolygonF> &lines,
|
void draw(QPainter *painter, const QVector<QPolygonF> &lines,
|
||||||
const QImage &img);
|
const QImage &img);
|
||||||
|
void draw(QPainter *painter, const QPainterPath &line, const QImage &img);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BITMAPLINE_H
|
#endif // BITMAPLINE_H
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "map/rectd.h"
|
#include "map/rectd.h"
|
||||||
#include "map/hillshading.h"
|
#include "map/hillshading.h"
|
||||||
#include "map/filter.h"
|
#include "map/filter.h"
|
||||||
|
#include "map/bitmapline.h"
|
||||||
#include "rastertile.h"
|
#include "rastertile.h"
|
||||||
|
|
||||||
using namespace Mapsforge;
|
using namespace Mapsforge;
|
||||||
@ -421,13 +422,21 @@ void RasterTile::drawPaths(QPainter *painter, const QList<MapData::Path> &paths,
|
|||||||
if (!path->pp.elementCount())
|
if (!path->pp.elementCount())
|
||||||
path->pp = painterPath(path->path->poly, ri->curve());
|
path->pp = painterPath(path->path->poly, ri->curve());
|
||||||
|
|
||||||
painter->setPen(ri->pen(_zoom));
|
if (ri->bitmapLine()) {
|
||||||
painter->setBrush(ri->brush());
|
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)
|
if (dy != 0)
|
||||||
painter->drawPath(parallelPath(path->pp, dy));
|
painter->drawPath(parallelPath(path->pp, dy));
|
||||||
else
|
else
|
||||||
painter->drawPath(path->pp);
|
painter->drawPath(path->pp);
|
||||||
|
}
|
||||||
} else if (point) {
|
} else if (point) {
|
||||||
const Style::CircleRender *ri = is.circleRender();
|
const Style::CircleRender *ri = is.circleRender();
|
||||||
qreal radius = ri->radius(_zoom);
|
qreal radius = ri->radius(_zoom);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <QPainter>
|
||||||
#include "common/programpaths.h"
|
#include "common/programpaths.h"
|
||||||
#include "style.h"
|
#include "style.h"
|
||||||
|
|
||||||
@ -388,8 +389,8 @@ void Style::circle(QXmlStreamReader &reader, qreal baseStrokeWidth,
|
|||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Style::text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
|
void Style::text(QXmlStreamReader &reader, const MapData &data,
|
||||||
QList<QList<TextRender>*> &lists)
|
const Rule &rule, bool line)
|
||||||
{
|
{
|
||||||
TextRender ri(rule);
|
TextRender ri(rule);
|
||||||
const QXmlStreamAttributes &attr = reader.attributes();
|
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.setItalic(italic);
|
||||||
ri._font.setCapitalization(capitalization);
|
ri._font.setCapitalization(capitalization);
|
||||||
|
|
||||||
if (fontSize)
|
if (fontSize) {
|
||||||
for (int i = 0; i < lists.size(); i++)
|
if (line)
|
||||||
lists[i]->append(ri);
|
_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();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||||
const Rule &rule, QList<Symbol> &list)
|
const Rule &rule, bool line)
|
||||||
{
|
{
|
||||||
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, percent = 100;
|
int height = 0, width = 0, percent = 100;
|
||||||
bool ok;
|
bool ok, bitmapLine = false;
|
||||||
|
|
||||||
if (attr.hasAttribute("src"))
|
if (attr.hasAttribute("src"))
|
||||||
file = resourcePath(attr.value("src").toString(), dir);
|
file = resourcePath(attr.value("src").toString(), dir);
|
||||||
@ -505,23 +513,62 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attr.hasAttribute("priority")) {
|
|
||||||
ri._priority = attr.value("priority").toInt(&ok);
|
// Convert repeating "always-display" lineSymbols to bitmap lines
|
||||||
if (!ok) {
|
if (line && (rule._type == Rule::AnyType || rule._type == Rule::WayType)) {
|
||||||
reader.raiseError("invalid priority value");
|
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;
|
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();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -580,22 +627,14 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir,
|
|||||||
line(reader, dir, ratio, baseStrokeWidth, r);
|
line(reader, dir, ratio, baseStrokeWidth, r);
|
||||||
else if (reader.name() == QLatin1String("circle"))
|
else if (reader.name() == QLatin1String("circle"))
|
||||||
circle(reader, baseStrokeWidth, r);
|
circle(reader, baseStrokeWidth, r);
|
||||||
else if (reader.name() == QLatin1String("pathText")) {
|
else if (reader.name() == QLatin1String("pathText"))
|
||||||
QList<QList<TextRender>*> list;
|
text(reader, data, r, true);
|
||||||
list.append(&_pathLabels);
|
else if (reader.name() == QLatin1String("caption"))
|
||||||
text(reader, data, r, list);
|
text(reader, data, r, false);
|
||||||
} 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("symbol"))
|
else if (reader.name() == QLatin1String("symbol"))
|
||||||
symbol(reader, dir, ratio, r, _symbols);
|
symbol(reader, dir, ratio, r, false);
|
||||||
else if (reader.name() == QLatin1String("lineSymbol"))
|
else if (reader.name() == QLatin1String("lineSymbol"))
|
||||||
symbol(reader, dir, ratio, r, _lineSymbols);
|
symbol(reader, dir, ratio, r, true);
|
||||||
else
|
else
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,8 @@ public:
|
|||||||
bool area() const {return _area;}
|
bool area() const {return _area;}
|
||||||
bool curve() const {return _curve;}
|
bool curve() const {return _curve;}
|
||||||
qreal dy(int zoom) const;
|
qreal dy(int zoom) const;
|
||||||
|
const QImage &img() const {return _img;}
|
||||||
|
bool bitmapLine() const {return !_img.isNull() && _strokeWidth == 0;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Style;
|
friend class Style;
|
||||||
@ -333,9 +335,9 @@ private:
|
|||||||
const Rule &rule);
|
const Rule &rule);
|
||||||
void hillshading(QXmlStreamReader &reader, const QSet<QString> &cats);
|
void hillshading(QXmlStreamReader &reader, const QSet<QString> &cats);
|
||||||
void text(QXmlStreamReader &reader, const MapData &data, const Rule &rule,
|
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,
|
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