mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-01-31 17:15: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;
|
||||
}
|
||||
|
||||
QVector<RasterTile::PathInstruction> RasterTile::pathInstructions(
|
||||
QVector<PainterPath> &paths)
|
||||
void RasterTile::pathInstructions(QVector<PainterPath> &paths,
|
||||
QVector<RasterTile::RenderInstruction> &instructions)
|
||||
{
|
||||
QCache<Key, QList<const Style::PathRender *> > cache(8192);
|
||||
QVector<PathInstruction> instructions;
|
||||
QCache<PathKey, QList<const Style::PathRender *> > cache(8192);
|
||||
const Style &s = style(_ratio);
|
||||
QList<const Style::PathRender*> *ri;
|
||||
|
||||
for (int i = 0; i < _paths.size(); i++) {
|
||||
const MapData::Path &path = _paths.at(i);
|
||||
PainterPath &rp = paths[i];
|
||||
Key key(_zoom, path.closed, path.tags);
|
||||
PathKey key(_zoom, path.closed, path.tags);
|
||||
|
||||
rp.path = &path;
|
||||
|
||||
@ -257,34 +256,66 @@ QVector<RasterTile::PathInstruction> RasterTile::pathInstructions(
|
||||
ri = new QList<const Style::PathRender*>(s.paths(_zoom, path.closed,
|
||||
path.tags));
|
||||
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);
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
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++) {
|
||||
const PathInstruction &is = instructions.at(i);
|
||||
const Style::PathRender *ri = is.render();
|
||||
const RenderInstruction &is = instructions.at(i);
|
||||
PainterPath *path = is.path();
|
||||
|
||||
if (path) {
|
||||
const Style::PathRender *ri = is.pathRender();
|
||||
|
||||
if (!path->pp.elementCount())
|
||||
path->pp = painterPath(path->path->poly, ri->curve());
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class PathInstruction
|
||||
class RenderInstruction
|
||||
{
|
||||
public:
|
||||
PathInstruction() : _render(0), _path(0) {}
|
||||
PathInstruction(const Style::PathRender *render, PainterPath *path)
|
||||
: _render(render), _path(path) {}
|
||||
RenderInstruction() : _pathRender(0), _circleRender(0), _path(0),
|
||||
_point(0) {}
|
||||
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)
|
||||
return _render->zOrder() < other._render->zOrder();
|
||||
if (layer() == other.layer())
|
||||
return zOrder() < other.zOrder();
|
||||
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;}
|
||||
const MapData::Point *point() const {return _point;}
|
||||
|
||||
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;
|
||||
const MapData::Point *_point;
|
||||
};
|
||||
|
||||
struct Key {
|
||||
Key(int zoom, bool closed, const QVector<MapData::Tag> &tags)
|
||||
struct PathKey {
|
||||
PathKey(int zoom, bool closed, const QVector<MapData::Tag> &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
|
||||
&& tags == other.tags;
|
||||
@ -96,6 +110,18 @@ private:
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -116,9 +142,12 @@ private:
|
||||
~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
|
||||
{return _transform.proj2img(_proj.ll2xy(c));}
|
||||
void processPointLabels(QList<TextItem*> &textItems);
|
||||
@ -142,7 +171,12 @@ private:
|
||||
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);
|
||||
}
|
||||
|
@ -79,10 +79,24 @@ bool Style::Rule::match(int zoom, bool closed,
|
||||
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,
|
||||
const Rule &rule)
|
||||
{
|
||||
PathRender ri(rule, _paths.size());
|
||||
PathRender ri(rule, _paths.size() + _circles.size());
|
||||
const QXmlStreamAttributes &attr = reader.attributes();
|
||||
QString file;
|
||||
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)
|
||||
{
|
||||
PathRender ri(rule, _paths.size());
|
||||
PathRender ri(rule, _paths.size() + _circles.size());
|
||||
const QXmlStreamAttributes &attr = reader.attributes();
|
||||
bool ok;
|
||||
|
||||
@ -180,6 +194,49 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule)
|
||||
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,
|
||||
QList<QList<TextRender>*> &lists)
|
||||
{
|
||||
@ -351,6 +408,8 @@ void Style::rule(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||
area(reader, dir, ratio, r);
|
||||
else if (reader.name() == QLatin1String("line"))
|
||||
line(reader, r);
|
||||
else if (reader.name() == QLatin1String("circle"))
|
||||
circle(reader, r);
|
||||
else if (reader.name() == QLatin1String("pathText")) {
|
||||
QList<QList<TextRender>*> list;
|
||||
list.append(&_pathLabels);
|
||||
@ -458,6 +517,18 @@ QList<const Style::PathRender *> Style::paths(int zoom, bool closed,
|
||||
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 TextRender*> list;
|
||||
@ -549,3 +620,8 @@ QBrush Style::PathRender::brush() const
|
||||
else
|
||||
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(int zoom, bool closed,
|
||||
const QVector<MapData::Tag> &tags) const;
|
||||
bool match(int zoom, const QVector<MapData::Tag> &tags) const;
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
@ -184,6 +185,28 @@ public:
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -227,6 +250,8 @@ public:
|
||||
|
||||
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;
|
||||
@ -235,6 +260,7 @@ public:
|
||||
|
||||
private:
|
||||
QList<PathRender> _paths;
|
||||
QList<CircleRender> _circles;
|
||||
QList<TextRender> _pathLabels, _pointLabels, _areaLabels;
|
||||
QList<Symbol> _symbols;
|
||||
|
||||
@ -248,6 +274,7 @@ private:
|
||||
void area(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||
const Rule &rule);
|
||||
void line(QXmlStreamReader &reader, const Rule &rule);
|
||||
void circle(QXmlStreamReader &reader, const Rule &rule);
|
||||
void text(QXmlStreamReader &reader, const Rule &rule,
|
||||
QList<QList<TextRender> *> &lists);
|
||||
void symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio,
|
||||
|
Loading…
x
Reference in New Issue
Block a user