1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-25 12:15:54 +01:00
GPXSee/src/map/mapsforge/style.h

243 lines
5.3 KiB
C
Raw Normal View History

2021-04-10 15:27:40 +02:00
#ifndef MAPSFORGE_STYLE_H
#define MAPSFORGE_STYLE_H
#include <QString>
#include <QList>
#include <QPen>
#include <QFont>
#include "mapdata.h"
class QXmlStreamReader;
namespace Mapsforge {
inline bool wcmp(const QByteArray &b1, const QByteArray &b2)
{
int len = b1.length();
if (!len)
return true;
if (len != b2.length())
return false;
return !memcmp(b1.constData(), b2.constData(), len);
}
2021-04-10 15:27:40 +02:00
class Style
{
public:
class Rule {
public:
Rule() : _type(AnyType), _closed(AnyClosed), _zooms(0, 127) {}
bool match(int zoom, bool closed,
const QVector<MapData::Tag> &tags) const;
bool match(int zoom, const QVector<MapData::Tag> &tags) const;
private:
enum Type {
AnyType = 0,
NodeType = 1,
WayType = 2,
InvalidType = 3
};
enum Closed {
AnyClosed = 0,
YesClosed = 1,
NoClosed = 2,
InvalidClosed = 3
};
class Filter {
public:
2021-04-13 22:23:27 +02:00
Filter() : _neg(false) {}
2021-04-10 15:27:40 +02:00
Filter(const QList<QByteArray> &keys, const QList<QByteArray> &vals)
: _neg(false)
{
_keys = list(keys);
QList<QByteArray> vc(vals);
if (vc.removeAll("~"))
_neg = true;
_vals = list(vals);
}
bool match(const QVector<MapData::Tag> &tags) const
{
if (_neg) {
if (!keyMatches(tags))
return true;
return valueMatches(tags);
} else
return (keyMatches(tags) && valueMatches(tags));
}
bool isTautology() const
{
return (!_neg && _keys.contains(QByteArray())
&& _vals.contains(QByteArray()));
}
private:
static QList<QByteArray> list(const QList<QByteArray> &in)
{
QList<QByteArray> out;
for (int i = 0; i < in.size(); i++) {
if (in.at(i) == "*")
out.append(QByteArray());
else
out.append(in.at(i));
}
return out;
}
bool keyMatches(const QVector<MapData::Tag> &tags) const
{
for (int i = 0; i < _keys.size(); i++)
for (int j = 0; j < tags.size(); j++)
if (wcmp(_keys.at(i), tags.at(j).key))
2021-04-10 15:27:40 +02:00
return true;
return false;
}
bool valueMatches(const QVector<MapData::Tag> &tags) const
{
for (int i = 0; i < _vals.size(); i++)
for (int j = 0; j < tags.size(); j++)
if (wcmp(_vals.at(i), tags.at(j).value))
2021-04-10 15:27:40 +02:00
return true;
return false;
}
QList<QByteArray> _keys;
QList<QByteArray> _vals;
bool _neg;
};
void setType(Type type)
{
_type = static_cast<Type>(static_cast<int>(type)
| static_cast<int>(_type));
}
void setMinZoom(int zoom) {_zooms.setMin(qMax(zoom, _zooms.min()));}
void setMaxZoom(int zoom) {_zooms.setMax(qMin(zoom, _zooms.max()));}
void setClosed(Closed closed)
{
_closed = static_cast<Closed>(static_cast<int>(closed)
| static_cast<int>(_closed));
}
void addFilter(const Filter &filter)
{
if (!filter.isTautology())
_filters.append(filter);
}
bool match(int zoom, Type type, Closed closed,
const QVector<MapData::Tag> &tags) const;
friend class Style;
Type _type;
Closed _closed;
Range _zooms;
QVector<Filter> _filters;
};
class Render
{
public:
Render(const Rule &rule) : _rule(rule) {}
const Rule &rule() const {return _rule;}
private:
Rule _rule;
};
class PathRender : public Render
{
public:
PathRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap),
_strokeJoin(Qt::RoundJoin) {}
int zOrder() const {return _zOrder;}
QPen pen(int zoom) const;
QBrush brush() const;
private:
friend class Style;
int _zOrder;
QColor _fillColor, _strokeColor;
qreal _strokeWidth;
QVector<qreal> _strokeDasharray;
Qt::PenCapStyle _strokeCap;
Qt::PenJoinStyle _strokeJoin;
QImage _fillImage;
};
class TextRender : public Render
{
public:
TextRender(const Rule &rule)
: Render(rule), _fillColor(Qt::black), _strokeColor(Qt::white) {}
const QFont &font() const {return _font;}
const QColor &fillColor() const {return _fillColor;}
const QColor &strokeColor() const {return _strokeColor;}
private:
friend class Style;
QColor _fillColor, _strokeColor;
QFont _font;
};
class Symbol : public Render
{
public:
Symbol(const Rule &rule) : Render(rule) {}
const QImage &img() const {return _img;}
private:
friend class Style;
QImage _img;
};
Style(const QString &path);
void match(int zoom, bool closed, const QVector<MapData::Tag> &tags,
QVector<const PathRender *> *ri) const;
const QList<TextRender> &pathLabels() const {return _pathLabels;}
const QList<TextRender> &pointLabels() const {return _pointLabels;}
const QList<Symbol> &symbols() const {return _symbols;}
private:
QList<PathRender> _paths;
QList<TextRender> _pathLabels, _pointLabels;
QList<Symbol> _symbols;
bool loadXml(const QString &path);
void rendertheme(QXmlStreamReader &reader, const QString &dir);
void layer(QXmlStreamReader &reader, QSet<QString> &cats);
void stylemenu(QXmlStreamReader &reader, QSet<QString> &cats);
void cat(QXmlStreamReader &reader, QSet<QString> &cats);
void rule(QXmlStreamReader &reader, const QString &dir,
const QSet<QString> &cats, const Rule &parent);
void area(QXmlStreamReader &reader, const QString &dir, const Rule &rule);
void line(QXmlStreamReader &reader, const Rule &rule);
void text(QXmlStreamReader &reader, const Rule &rule,
QList<TextRender> &list);
void symbol(QXmlStreamReader &reader, const QString &dir, const Rule &rule);
};
}
#endif // MAPSFORGE_STYLE_H