1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-04-11 08:09:10 +02:00

336 lines
8.3 KiB
C++

#ifndef MAPSFORGE_STYLE_H
#define MAPSFORGE_STYLE_H
#include <QString>
#include <QList>
#include <QPen>
#include <QFont>
#include "mapdata.h"
class QXmlStreamReader;
namespace Mapsforge {
class Style
{
public:
class Rule {
public:
Rule() : _type(AnyType), _closed(AnyClosed), _zooms(0, 127) {}
bool match(const QVector<MapData::Tag> &tags) const;
bool match(bool closed, const QVector<MapData::Tag> &tags) const;
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:
Filter() : _neg(false) {}
Filter(const MapData &data, const QList<QByteArray> &keys,
const QList<QByteArray> &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(0u) && _vals.contains(QByteArray()));
}
private:
bool keyMatches(const QVector<MapData::Tag> &tags) const
{
for (int i = 0; i < _keys.size(); i++) {
for (int j = 0; j < tags.size(); j++) {
unsigned key = _keys.at(i);
if (!key || key == tags.at(j).key)
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++) {
const QByteArray &ba = _vals.at(i);
if (!ba.size() || ba == tags.at(j).value)
return true;
}
}
return false;
}
QList<unsigned> _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 HillShadingRender : public Render
{
public:
HillShadingRender() : Render(Rule()), _zOrder(-1), _layer(-1) {}
HillShadingRender(const Rule &rule, int zOrder, int layer)
: Render(rule), _zOrder(zOrder), _layer(layer) {}
bool isValid() const {return _zOrder >= 0;}
int zOrder() const {return _zOrder;}
int layer() const {return _layer;}
private:
int _zOrder;
int _layer;
};
class PathRender : public Render
{
public:
PathRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _strokeWidth(0), _strokeCap(Qt::RoundCap),
_strokeJoin(Qt::RoundJoin), _area(false), _curve(false),
_scale(Stroke), _dy(0) {}
int zOrder() const {return _zOrder;}
QPen pen(int zoom) const;
const QBrush &brush() const {return _brush;}
bool area() const {return _area;}
bool curve() const {return _curve;}
qreal dy(int zoom) const;
private:
friend class Style;
enum Scale {None, Stroke, All};
int _zOrder;
QColor _strokeColor;
qreal _strokeWidth;
QVector<qreal> _strokeDasharray;
Qt::PenCapStyle _strokeCap;
Qt::PenJoinStyle _strokeJoin;
QBrush _brush;
bool _area, _curve;
Scale _scale;
qreal _dy;
};
class CircleRender : public Render
{
public:
CircleRender(const Rule &rule, int zOrder) : Render(rule),
_zOrder(zOrder), _pen(Qt::NoPen), _brush(Qt::NoBrush),
_scale(false) {}
int zOrder() const {return _zOrder;}
const QPen &pen() const {return _pen;}
const QBrush &brush() const {return _brush;}
qreal radius(int zoom) const;
private:
friend class Style;
int _zOrder;
QPen _pen;
QBrush _brush;
qreal _radius;
bool _scale;
};
class TextRender : public Render
{
public:
TextRender(const Rule &rule)
: Render(rule), _priority(0), _fillColor(Qt::black),
_strokeColor(Qt::black), _strokeWidth(0) {}
const QString &symbolId() const {return _symbolId;}
const QFont &font() const {return _font;}
const QColor &fillColor() const {return _fillColor;}
const QColor &strokeColor() const {return _strokeColor;}
qreal strokeWidth() const {return _strokeWidth;}
unsigned key() const {return _key;}
int priority() const {return _priority;}
private:
friend class Style;
QString _symbolId;
int _priority;
QColor _fillColor, _strokeColor;
qreal _strokeWidth;
QFont _font;
unsigned _key;
};
class Symbol : public Render
{
public:
Symbol(const Rule &rule)
: Render(rule), _priority(0), _rotate(true) {}
const QString &id() const {return _id;}
const QImage &img() const {return _img;}
bool rotate() const {return _rotate;}
int priority() const {return _priority;}
private:
friend class Style;
QString _id;
int _priority;
bool _rotate;
QImage _img;
};
void load(const MapData &data, qreal ratio);
void clear();
QList<const PathRender *> paths(int zoom, bool closed,
const QVector<MapData::Tag> &tags) const;
QList<const CircleRender *> circles(int zoom,
const QVector<MapData::Tag> &tags) const;
QList<const TextRender*> pathLabels(int zoom) const;
QList<const TextRender*> pointLabels(int zoom) const;
QList<const TextRender*> areaLabels(int zoom) const;
QList<const Symbol*> pointSymbols(int zoom) const;
QList<const Symbol*> areaSymbols(int zoom) const;
QList<const Symbol*> lineSymbols(int zoom) const;
const HillShadingRender *hillShading(int zoom) const;
private:
class Menu {
public:
class Layer {
public:
Layer() : _enabled(false) {}
Layer(const QString &id, bool enabled)
: _id(id), _enabled(enabled) {}
const QStringList &cats() const {return _cats;}
const QStringList &overlays() const {return _overlays;}
const QString &id() const {return _id;}
const QString &parent() const {return _parent;}
bool enabled() const {return _enabled;}
void setParent(const QString &parent) {_parent = parent;}
void addCat(const QString &cat) {_cats.append(cat);}
void addOverlay(const QString &overlay) {_overlays.append(overlay);}
private:
QStringList _cats;
QStringList _overlays;
QString _id;
QString _parent;
bool _enabled;
};
Menu() {}
Menu(const QString &defaultValue) : _defaultvalue(defaultValue) {}
void addLayer(const Layer &layer) {_layers.append(layer);}
QSet<QString> cats() const;
private:
const Layer *findLayer(const QString &id) const;
void addCats(const Layer *layer, QSet<QString> &cats) const;
QString _defaultvalue;
QList<Layer> _layers;
};
HillShadingRender _hillShading;
QList<PathRender> _paths;
QList<CircleRender> _circles;
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
QList<Symbol> _symbols, _lineSymbols;
bool loadXml(const QString &path, const MapData &data, qreal ratio);
void rendertheme(QXmlStreamReader &reader, const QString &dir,
const MapData &data, qreal ratio);
Menu::Layer layer(QXmlStreamReader &reader);
Menu stylemenu(QXmlStreamReader &reader);
QString cat(QXmlStreamReader &reader);
void rule(QXmlStreamReader &reader, const QString &dir, const MapData &data,
qreal ratio, qreal baseStrokeWidth, const QSet<QString> &cats,
const Rule &parent);
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
qreal baseStrokeWidth, const Rule &rule);
void line(QXmlStreamReader &reader, qreal baseStrokeWidth, const Rule &rule);
void circle(QXmlStreamReader &reader, qreal baseStrokeWidth,
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);
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
const Rule &rule, QList<Symbol> &list);
};
}
#endif // MAPSFORGE_STYLE_H