mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-02-07 12:05:14 +01:00
Render circles
This commit is contained in:
parent
648627b17f
commit
b6ca28e159
@ -238,18 +238,17 @@ QPainterPath RasterTile::painterPath(const Polygon &polygon, bool curve) const
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<RasterTile::PathInstruction> RasterTile::pathInstructions(
|
void RasterTile::pathInstructions(QVector<PainterPath> &paths,
|
||||||
QVector<PainterPath> &paths)
|
QVector<RasterTile::RenderInstruction> &instructions)
|
||||||
{
|
{
|
||||||
QCache<Key, QList<const Style::PathRender *> > cache(8192);
|
QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
|
||||||
QVector<PathInstruction> instructions;
|
|
||||||
const Style &s = style(_ratio);
|
const Style &s = style(_ratio);
|
||||||
QList<const Style::PathRender*> *ri;
|
QList<const Style::PathRender*> *ri;
|
||||||
|
|
||||||
for (int i = 0; i < _paths.size(); i++) {
|
for (int i = 0; i < _paths.size(); i++) {
|
||||||
const MapData::Path &path = _paths.at(i);
|
const MapData::Path &path = _paths.at(i);
|
||||||
PainterPath &rp = paths[i];
|
PainterPath &rp = paths[i];
|
||||||
Key key(_zoom, path.closed, path.tags);
|
PathKey key(_zoom, path.closed, path.tags);
|
||||||
|
|
||||||
rp.path = &path;
|
rp.path = &path;
|
||||||
|
|
||||||
@ -257,34 +256,66 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions(
|
|||||||
ri = new QList<const Style::PathRender*>(s.paths(_zoom, path.closed,
|
ri = new QList<const Style::PathRender*>(s.paths(_zoom, path.closed,
|
||||||
path.tags));
|
path.tags));
|
||||||
for (int j = 0; j < ri->size(); j++)
|
for (int j = 0; j < ri->size(); j++)
|
||||||
instructions.append(PathInstruction(ri->at(j), &rp));
|
instructions.append(RenderInstruction(ri->at(j), &rp));
|
||||||
cache.insert(key, ri);
|
cache.insert(key, ri);
|
||||||
} else {
|
} else {
|
||||||
for (int j = 0; j < ri->size(); j++)
|
for (int j = 0; j < ri->size(); j++)
|
||||||
instructions.append(PathInstruction(ri->at(j), &rp));
|
instructions.append(RenderInstruction(ri->at(j), &rp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::sort(instructions.begin(), instructions.end());
|
void RasterTile::circleInstructions(
|
||||||
|
QVector<RasterTile::RenderInstruction> &instructions)
|
||||||
|
{
|
||||||
|
QCache<PointKey, QList<const Style::CircleRender *> > cache(8192);
|
||||||
|
const Style &s = style(_ratio);
|
||||||
|
QList<const Style::CircleRender*> *ri;
|
||||||
|
|
||||||
return instructions;
|
for (int i = 0; i < _points.size(); i++) {
|
||||||
|
const MapData::Point &point = _points.at(i);
|
||||||
|
PointKey key(_zoom, point.tags);
|
||||||
|
|
||||||
|
if (!(ri = cache.object(key))) {
|
||||||
|
ri = new QList<const Style::CircleRender*>(s.circles(_zoom, point.tags));
|
||||||
|
for (int j = 0; j < ri->size(); j++)
|
||||||
|
instructions.append(RenderInstruction(ri->at(j), &point));
|
||||||
|
cache.insert(key, ri);
|
||||||
|
} else {
|
||||||
|
for (int j = 0; j < ri->size(); j++)
|
||||||
|
instructions.append(RenderInstruction(ri->at(j), &point));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
|
void RasterTile::drawPaths(QPainter *painter, QVector<PainterPath> &paths)
|
||||||
{
|
{
|
||||||
QVector<PathInstruction> instructions(pathInstructions(paths));
|
QVector<RenderInstruction> instructions;
|
||||||
|
pathInstructions(paths, instructions);
|
||||||
|
circleInstructions(instructions);
|
||||||
|
std::sort(instructions.begin(), instructions.end());
|
||||||
|
|
||||||
for (int i = 0; i < instructions.size(); i++) {
|
for (int i = 0; i < instructions.size(); i++) {
|
||||||
const PathInstruction &is = instructions.at(i);
|
const RenderInstruction &is = instructions.at(i);
|
||||||
const Style::PathRender *ri = is.render();
|
|
||||||
PainterPath *path = is.path();
|
PainterPath *path = is.path();
|
||||||
|
|
||||||
if (!path->pp.elementCount())
|
if (path) {
|
||||||
path->pp = painterPath(path->path->poly, ri->curve());
|
const Style::PathRender *ri = is.pathRender();
|
||||||
|
|
||||||
painter->setPen(ri->pen(_zoom));
|
if (!path->pp.elementCount())
|
||||||
painter->setBrush(ri->brush());
|
path->pp = painterPath(path->path->poly, ri->curve());
|
||||||
painter->drawPath(path->pp);
|
|
||||||
|
painter->setPen(ri->pen(_zoom));
|
||||||
|
painter->setBrush(ri->brush());
|
||||||
|
painter->drawPath(path->pp);
|
||||||
|
} else {
|
||||||
|
const Style::CircleRender *ri = is.circleRender();
|
||||||
|
qreal radius = ri->radius(_zoom);
|
||||||
|
|
||||||
|
painter->setPen(ri->pen());
|
||||||
|
painter->setBrush(ri->brush());
|
||||||
|
painter->drawEllipse(ll2xy(is.point()->coordinates), radius, radius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,33 +59,47 @@ private:
|
|||||||
const Style::Symbol *si;
|
const Style::Symbol *si;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PathInstruction
|
class RenderInstruction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PathInstruction() : _render(0), _path(0) {}
|
RenderInstruction() : _pathRender(0), _circleRender(0), _path(0),
|
||||||
PathInstruction(const Style::PathRender *render, PainterPath *path)
|
_point(0) {}
|
||||||
: _render(render), _path(path) {}
|
RenderInstruction(const Style::PathRender *render, PainterPath *path)
|
||||||
|
: _pathRender(render), _circleRender(0), _path(path), _point(0) {}
|
||||||
|
RenderInstruction(const Style::CircleRender *render,
|
||||||
|
const MapData::Point *point) : _pathRender(0), _circleRender(render),
|
||||||
|
_path(0), _point(point) {}
|
||||||
|
|
||||||
bool operator<(const PathInstruction &other) const
|
bool operator<(const RenderInstruction &other) const
|
||||||
{
|
{
|
||||||
if (_path->path->layer == other._path->path->layer)
|
if (layer() == other.layer())
|
||||||
return _render->zOrder() < other._render->zOrder();
|
return zOrder() < other.zOrder();
|
||||||
else
|
else
|
||||||
return (_path->path->layer < other._path->path->layer);
|
return (layer() < other.layer());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Style::PathRender *render() const {return _render;}
|
const Style::PathRender *pathRender() const {return _pathRender;}
|
||||||
|
const Style::CircleRender *circleRender() const {return _circleRender;}
|
||||||
PainterPath *path() const {return _path;}
|
PainterPath *path() const {return _path;}
|
||||||
|
const MapData::Point *point() const {return _point;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Style::PathRender *_render;
|
int layer() const {return _path ? _path->path->layer : _point->layer;}
|
||||||
|
int zOrder() const
|
||||||
|
{
|
||||||
|
return _pathRender ? _pathRender->zOrder() : _circleRender->zOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Style::PathRender *_pathRender;
|
||||||
|
const Style::CircleRender *_circleRender;
|
||||||
PainterPath *_path;
|
PainterPath *_path;
|
||||||
|
const MapData::Point *_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Key {
|
struct PathKey {
|
||||||
Key(int zoom, bool closed, const QVector<MapData::Tag> &tags)
|
PathKey(int zoom, bool closed, const QVector<MapData::Tag> &tags)
|
||||||
: zoom(zoom), closed(closed), tags(tags) {}
|
: zoom(zoom), closed(closed), tags(tags) {}
|
||||||
bool operator==(const Key &other) const
|
bool operator==(const PathKey &other) const
|
||||||
{
|
{
|
||||||
return zoom == other.zoom && closed == other.closed
|
return zoom == other.zoom && closed == other.closed
|
||||||
&& tags == other.tags;
|
&& tags == other.tags;
|
||||||
@ -96,6 +110,18 @@ private:
|
|||||||
const QVector<MapData::Tag> &tags;
|
const QVector<MapData::Tag> &tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PointKey {
|
||||||
|
PointKey(int zoom, const QVector<MapData::Tag> &tags)
|
||||||
|
: zoom(zoom), tags(tags) {}
|
||||||
|
bool operator==(const PointKey &other) const
|
||||||
|
{
|
||||||
|
return zoom == other.zoom && tags == other.tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zoom;
|
||||||
|
const QVector<MapData::Tag> &tags;
|
||||||
|
};
|
||||||
|
|
||||||
class PointItem : public TextPointItem
|
class PointItem : public TextPointItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -116,9 +142,12 @@ private:
|
|||||||
~PathItem() {delete _text;}
|
~PathItem() {delete _text;}
|
||||||
};
|
};
|
||||||
|
|
||||||
friend HASH_T qHash(const RasterTile::Key &key);
|
friend HASH_T qHash(const RasterTile::PathKey &key);
|
||||||
|
friend HASH_T qHash(const RasterTile::PointKey &key);
|
||||||
|
|
||||||
QVector<PathInstruction> pathInstructions(QVector<PainterPath> &paths);
|
void pathInstructions(QVector<PainterPath> &paths,
|
||||||
|
QVector<RasterTile::RenderInstruction> &instructions);
|
||||||
|
void circleInstructions(QVector<RasterTile::RenderInstruction> &instructions);
|
||||||
QPointF ll2xy(const Coordinates &c) const
|
QPointF ll2xy(const Coordinates &c) const
|
||||||
{return _transform.proj2img(_proj.ll2xy(c));}
|
{return _transform.proj2img(_proj.ll2xy(c));}
|
||||||
void processPointLabels(QList<TextItem*> &textItems);
|
void processPointLabels(QList<TextItem*> &textItems);
|
||||||
@ -142,7 +171,12 @@ private:
|
|||||||
bool _valid;
|
bool _valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline HASH_T qHash(const RasterTile::Key &key)
|
inline HASH_T qHash(const RasterTile::PathKey &key)
|
||||||
|
{
|
||||||
|
return ::qHash(key.zoom) ^ ::qHash(key.tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline HASH_T qHash(const RasterTile::PointKey &key)
|
||||||
{
|
{
|
||||||
return ::qHash(key.zoom) ^ ::qHash(key.tags);
|
return ::qHash(key.zoom) ^ ::qHash(key.tags);
|
||||||
}
|
}
|
||||||
|
@ -79,10 +79,24 @@ bool Style::Rule::match(int zoom, bool closed,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Style::Rule::match(int zoom, const QVector<MapData::Tag> &tags) const
|
||||||
|
{
|
||||||
|
if (_type && NodeType != _type)
|
||||||
|
return false;
|
||||||
|
if (!_zooms.contains(zoom))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < _filters.size(); i++)
|
||||||
|
if (!_filters.at(i).match(tags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||||
const Rule &rule)
|
const Rule &rule)
|
||||||
{
|
{
|
||||||
PathRender ri(rule, _paths.size());
|
PathRender ri(rule, _paths.size() + _circles.size());
|
||||||
const QXmlStreamAttributes &attr = reader.attributes();
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
QString file;
|
QString file;
|
||||||
int height = 0, width = 0;
|
int height = 0, width = 0;
|
||||||
@ -127,7 +141,7 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
|||||||
|
|
||||||
void Style::line(QXmlStreamReader &reader, const Rule &rule)
|
void Style::line(QXmlStreamReader &reader, const Rule &rule)
|
||||||
{
|
{
|
||||||
PathRender ri(rule, _paths.size());
|
PathRender ri(rule, _paths.size() + _circles.size());
|
||||||
const QXmlStreamAttributes &attr = reader.attributes();
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
@ -180,6 +194,49 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
|
|||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Style::circle(QXmlStreamReader &reader, const Rule &rule)
|
||||||
|
{
|
||||||
|
CircleRender ri(rule, _paths.size() + _circles.size());
|
||||||
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
|
bool ok;
|
||||||
|
QColor fillColor, strokeColor;
|
||||||
|
qreal strokeWidth = 0;
|
||||||
|
|
||||||
|
if (attr.hasAttribute("fill"))
|
||||||
|
fillColor = QColor(attr.value("fill").toString());
|
||||||
|
if (attr.hasAttribute("stroke"))
|
||||||
|
strokeColor = QColor(attr.value("stroke").toString());
|
||||||
|
if (attr.hasAttribute("stroke-width")) {
|
||||||
|
strokeWidth = attr.value("stroke-width").toFloat(&ok);
|
||||||
|
if (!ok || strokeWidth < 0) {
|
||||||
|
reader.raiseError("invalid stroke-width value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attr.hasAttribute("radius")) {
|
||||||
|
ri._radius = attr.value("radius").toDouble(&ok);
|
||||||
|
if (!ok || ri._radius <= 0) {
|
||||||
|
reader.raiseError("invalid radius value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reader.raiseError("missing radius");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attr.hasAttribute("scale-radius")) {
|
||||||
|
if (attr.value("scale-radius").toString() == "true")
|
||||||
|
ri._scale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ri._pen = (strokeColor.isValid() && strokeWidth > 0)
|
||||||
|
? QPen(QBrush(strokeColor), strokeWidth) : Qt::NoPen;
|
||||||
|
ri._brush = fillColor.isValid() ? QBrush(fillColor) : Qt::NoBrush;
|
||||||
|
|
||||||
|
_circles.append(ri);
|
||||||
|
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
|
||||||
void Style::text(QXmlStreamReader &reader, const Rule &rule,
|
void Style::text(QXmlStreamReader &reader, const Rule &rule,
|
||||||
QList<QList<TextRender>*> &lists)
|
QList<QList<TextRender>*> &lists)
|
||||||
{
|
{
|
||||||
@ -351,6 +408,8 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
|||||||
area(reader, dir, ratio, r);
|
area(reader, dir, ratio, r);
|
||||||
else if (reader.name() == QLatin1String("line"))
|
else if (reader.name() == QLatin1String("line"))
|
||||||
line(reader, r);
|
line(reader, r);
|
||||||
|
else if (reader.name() == QLatin1String("circle"))
|
||||||
|
circle(reader, r);
|
||||||
else if (reader.name() == QLatin1String("pathText")) {
|
else if (reader.name() == QLatin1String("pathText")) {
|
||||||
QList<QList<TextRender>*> list;
|
QList<QList<TextRender>*> list;
|
||||||
list.append(&_pathLabels);
|
list.append(&_pathLabels);
|
||||||
@ -458,6 +517,18 @@ QList<const Style::PathRender *> Style::paths(int zoom, bool closed,
|
|||||||
return ri;
|
return ri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<const Style::CircleRender *> Style::circles(int zoom,
|
||||||
|
const QVector<MapData::Tag> &tags) const
|
||||||
|
{
|
||||||
|
QList<const CircleRender*> ri;
|
||||||
|
|
||||||
|
for (int i = 0; i < _circles.size(); i++)
|
||||||
|
if (_circles.at(i).rule().match(zoom, tags))
|
||||||
|
ri.append(&_circles.at(i));
|
||||||
|
|
||||||
|
return ri;
|
||||||
|
}
|
||||||
|
|
||||||
QList<const Style::TextRender*> Style::pathLabels(int zoom) const
|
QList<const Style::TextRender*> Style::pathLabels(int zoom) const
|
||||||
{
|
{
|
||||||
QList<const TextRender*> list;
|
QList<const TextRender*> list;
|
||||||
@ -549,3 +620,8 @@ QBrush Style::PathRender::brush() const
|
|||||||
else
|
else
|
||||||
return Qt::NoBrush;
|
return Qt::NoBrush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal Style::CircleRender::radius(int zoom) const
|
||||||
|
{
|
||||||
|
return (_scale && zoom >= 12) ? pow(1.5, zoom - 12) * _radius : _radius;
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
bool match(bool closed, const QVector<MapData::Tag> &tags) const;
|
bool match(bool closed, const QVector<MapData::Tag> &tags) const;
|
||||||
bool match(int zoom, bool closed,
|
bool match(int zoom, bool closed,
|
||||||
const QVector<MapData::Tag> &tags) const;
|
const QVector<MapData::Tag> &tags) const;
|
||||||
|
bool match(int zoom, const QVector<MapData::Tag> &tags) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {
|
enum Type {
|
||||||
@ -184,6 +185,28 @@ public:
|
|||||||
bool _area, _curve;
|
bool _area, _curve;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
class TextRender : public Render
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -227,6 +250,8 @@ public:
|
|||||||
|
|
||||||
QList<const PathRender *> paths(int zoom, bool closed,
|
QList<const PathRender *> paths(int zoom, bool closed,
|
||||||
const QVector<MapData::Tag> &tags) const;
|
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*> pathLabels(int zoom) const;
|
||||||
QList<const TextRender*> pointLabels(int zoom) const;
|
QList<const TextRender*> pointLabels(int zoom) const;
|
||||||
QList<const TextRender*> areaLabels(int zoom) const;
|
QList<const TextRender*> areaLabels(int zoom) const;
|
||||||
@ -235,6 +260,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QList<PathRender> _paths;
|
QList<PathRender> _paths;
|
||||||
|
QList<CircleRender> _circles;
|
||||||
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
|
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
|
||||||
QList<Symbol> _symbols;
|
QList<Symbol> _symbols;
|
||||||
|
|
||||||
@ -248,6 +274,7 @@ private:
|
|||||||
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||||
const Rule &rule);
|
const Rule &rule);
|
||||||
void line(QXmlStreamReader &reader, const Rule &rule);
|
void line(QXmlStreamReader &reader, const Rule &rule);
|
||||||
|
void circle(QXmlStreamReader &reader, const Rule &rule);
|
||||||
void text(QXmlStreamReader &reader, const Rule &rule,
|
void text(QXmlStreamReader &reader, const Rule &rule,
|
||||||
QList<QList<TextRender> *> &lists);
|
QList<QList<TextRender> *> &lists);
|
||||||
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user