1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-23 19:25:54 +01:00

Compare commits

...

2 Commits

Author SHA1 Message Date
2c1d340a44 Millitary areas zoom levels 2024-11-20 09:24:40 +01:00
848bde0f80 Properly mix the way and node POIs 2024-11-20 09:13:59 +01:00
7 changed files with 135 additions and 177 deletions

View File

@ -82,7 +82,7 @@
<!-- Water -->
<rule e="way" closed="yes" k="natural" v="water">
<area fill="#9fc4e1"/>
<rule e="way" k="*" v="*" zoom-min="10">
<rule e="way" k="*" v="*" zoom-min="14">
<caption fill="#ffffff" font-size="12" font-family="serif" font-style="italic" k="name" stroke="#9fc4e1" stroke-width="2"/>
</rule>
</rule>
@ -187,12 +187,14 @@
<!-- Area overlays -->
<rule e="way" k="landuse" v="military" zoom-min="10">
<area src=":/patterns/military-area.svg" symbol-height="4"/>
<caption fill="#ff4040" font-size="10" font-style="italic" text-transform="uppercase" k="name" stroke="#ffffff" stroke-width="2"/>
<rule e="way" k="*" v="*" zoom-min="16">
<caption fill="#ff4040" font-size="10" font-style="italic" text-transform="uppercase" k="name" stroke="#ffffff" stroke-width="2"/>
</rule>
</rule>
<rule e="way" k="boundary" v="protected_area|national_park" zoom-min="10" zoom-max="14">
<rule e="way" k="protect_class" v="pr_2">
<area src=":/patterns/nature-reserve.svg" symbol-height="4"/>
<rule e="way" k="*" v="*" zoom-max="12">
<rule e="way" k="*" v="*" zoom-max="11">
<caption fill="#9ac269" font-size="10" font-style="italic" text-transform="uppercase" k="name" stroke="#ffffff" stroke-width="2"/>
</rule>
</rule>

View File

@ -19,6 +19,26 @@ using namespace Mapsforge;
#define KEY_REF "ref"
#define KEY_ELE "ele"
static Coordinates centroid(const Polygon &polygon)
{
double area = 0;
double cx = 0, cy = 0;
const QVector<Coordinates> &v = polygon.first();
for (int i = 0; i < v.count(); i++) {
int j = (i == v.count() - 1) ? 0 : i + 1;
double f = (v.at(i).lon() * v.at(j).lat() - v.at(j).lon() * v.at(i).lat());
area += f;
cx += (v.at(i).lon() + v.at(j).lon()) * f;
cy += (v.at(i).lat() + v.at(j).lat()) * f;
}
double factor = 1.0 / (3.0 * area);
return Coordinates(cx * factor, cy * factor);
}
static void copyPaths(const RectC &rect, const QList<MapData::Path> *src,
QList<MapData::Path> *dst)
{
@ -39,6 +59,16 @@ static void copyPoints(const RectC &rect, const QList<MapData::Point> *src,
}
}
static void copyPoints(const RectC &rect, const QList<MapData::Path> *src,
QList<MapData::Point> *dst)
{
for (int i = 0; i < src->size(); i++) {
const MapData::Path &path = src->at(i);
if (path.closed && rect.contains(path.point.coordinates))
dst->append(path.point);
}
}
static double distance(const Coordinates &c1, const Coordinates &c2)
{
return hypot(c1.lon() - c2.lon(), c1.lat() - c2.lat());
@ -425,7 +455,7 @@ MapData::MapData(const QString &fileName)
if (!readHeader(file))
return;
_pathCache.setMaxCost(256);
_pathCache.setMaxCost(512);
_pointCache.setMaxCost(256);
_valid = true;
@ -528,9 +558,9 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
_pointLock.lock();
QList<Point> *cached = _pointCache.object(key);
QList<Point> *tilePoints = _pointCache.object(key);
if (!cached) {
if (!tilePoints) {
QList<Point> *p = new QList<Point>();
if (readPoints(tile, zoom, p)) {
copyPoints(rect, p, list);
@ -538,9 +568,26 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom,
} else
delete p;
} else
copyPoints(rect, cached, list);
copyPoints(rect, tilePoints, list);
_pointLock.unlock();
_pathLock.lock();
QList<Path> *tilePaths = _pathCache.object(key);
if (!tilePaths) {
QList<Path> *p = new QList<Path>();
if (readPaths(tile, zoom, p)) {
copyPoints(rect, p, list);
_pathCache.insert(key, p);
} else
delete p;
} else
copyPoints(rect, tilePaths, list);
_pathLock.unlock();
}
void MapData::paths(const RectC &searchRect, const RectC &boundsRect, int zoom,
@ -620,9 +667,9 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
&& subfile.readByte(sb)))
return false;
p.layer = sb >> 4;
p.point.layer = sb >> 4;
int tags = sb & 0x0F;
if (!readTags(subfile, tags, _pathTags, p.tags))
if (!readTags(subfile, tags, _pathTags, p.point.tags))
return false;
if (!subfile.readByte(flags))
@ -631,17 +678,17 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
if (!subfile.readString(name))
return false;
name = name.split('\r').first();
p.tags.append(Tag(ID_NAME, name));
p.point.tags.append(Tag(ID_NAME, name));
}
if (flags & 0x40) {
if (!subfile.readString(houseNumber))
return false;
p.tags.append(Tag(ID_HOUSE, houseNumber));
p.point.tags.append(Tag(ID_HOUSE, houseNumber));
}
if (flags & 0x20) {
if (!subfile.readString(reference))
return false;
p.tags.append(Tag(ID_REF, reference));
p.point.tags.append(Tag(ID_REF, reference));
}
if (flags & 0x10) {
if (!(subfile.readVInt32(lat) && subfile.readVInt32(lon)))
@ -660,8 +707,10 @@ bool MapData::readPaths(const VectorTile *tile, int zoom, QList<Path> *list)
const QVector<Coordinates> &outline = p.poly.first();
p.closed = isClosed(outline);
if (flags & 0x10)
p.labelPos = Coordinates(outline.first().lon() + MD(lon),
p.point.coordinates = Coordinates(outline.first().lon() + MD(lon),
outline.first().lat() + MD(lat));
else if (p.closed)
p.point.coordinates = centroid(p.poly);
list->append(p);
}

View File

@ -39,6 +39,8 @@ public:
struct Point {
Point(quint64 id) : id(id) {}
bool center() const {return (id & 1ULL<<63) != 0;}
quint64 id;
Coordinates coordinates;
QVector<Tag> tags;
@ -46,17 +48,14 @@ public:
};
struct Path {
Path(quint64 id) : id(id) {}
Path(quint64 id) : point(id | 1ULL<<63) {}
quint64 id;
Point point;
Polygon poly;
QVector<Tag> tags;
Coordinates labelPos;
int layer;
bool closed;
bool operator<(const Path &other) const
{return layer < other.layer;}
{return point.layer < other.point.layer;}
};
RectC bounds() const;

View File

@ -16,33 +16,6 @@ using namespace Mapsforge;
static double LIMIT = cos(deg2rad(170));
static bool rectNearPolygon(const QRectF &tileRect, const QPainterPath &path,
const QRectF &rect)
{
return ((tileRect.contains(rect) || path.boundingRect().contains(rect))
&& (path.contains(rect.topLeft()) || path.contains(rect.topRight())
|| path.contains(rect.bottomLeft()) || path.contains(rect.bottomRight())));
}
static QPointF centroid(const QPainterPath &polygon)
{
qreal area = 0;
qreal cx = 0, cy = 0;
for (int i = 0; i < polygon.elementCount(); i++) {
int j = (i == polygon.elementCount() - 1) ? 0 : i + 1;
qreal f = (polygon.elementAt(i).x * polygon.elementAt(j).y
- polygon.elementAt(j).x * polygon.elementAt(i).y);
area += f;
cx += (polygon.elementAt(i).x + polygon.elementAt(j).x) * f;
cy += (polygon.elementAt(i).y + polygon.elementAt(j).y) * f;
}
qreal factor = 1.0 / (3.0 * area);
return QPointF(cx * factor, cy * factor);
}
static const QByteArray *label(unsigned key, const QVector<MapData::Tag> &tags)
{
for (int i = 0; i < tags.size(); i++) {
@ -102,13 +75,11 @@ static QPainterPath parallelPath(const QPainterPath &p, double dy)
}
void RasterTile::processLabels(const QList<MapData::Point> &points,
const QVector<PainterPath> &paths, QList<TextItem*> &textItems) const
QList<TextItem*> &textItems) const
{
QList<Label> items;
QList<const Style::TextRender*> pointLabels(_style->pointLabels(_zoom));
QList<const Style::Symbol*> pointSymbols(_style->pointSymbols(_zoom));
QList<const Style::TextRender*> areaLabels(_style->areaLabels(_zoom));
QList<const Style::Symbol*> areaSymbols(_style->areaSymbols(_zoom));
QList<const Style::TextRender*> labels(_style->labels(_zoom));
QList<const Style::Symbol*> symbols(_style->symbols(_zoom));
for (int i = 0; i < points.size(); i++) {
const MapData::Point &point = points.at(i);
@ -116,17 +87,17 @@ void RasterTile::processLabels(const QList<MapData::Point> &points,
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
for (int j = 0; j < pointSymbols.size(); j++) {
const Style::Symbol *ri = pointSymbols.at(j);
if (ri->rule().match(point.tags)) {
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(point.center(), point.tags)) {
si = ri;
break;
}
}
for (int j = 0; j < pointLabels.size(); j++) {
const Style::TextRender *ri = pointLabels.at(j);
if (ri->rule().match(point.tags)) {
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(point.center(), point.tags)) {
if ((lbl = label(ri->key(), point.tags))) {
if (!si || si->id() == ri->symbolId()) {
ti = ri;
@ -140,39 +111,6 @@ void RasterTile::processLabels(const QList<MapData::Point> &points,
items.append(Label(&point, lbl, si, ti));
}
for (int i = 0; i < paths.size(); i++) {
const PainterPath &path = paths.at(i);
const Style::TextRender *ti = 0;
const Style::Symbol *si = 0;
const QByteArray *lbl = 0;
if (!path.path->closed)
continue;
for (int j = 0; j < areaSymbols.size(); j++) {
const Style::Symbol *ri = areaSymbols.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
si = ri;
break;
}
}
for (int j = 0; j < areaLabels.size(); j++) {
const Style::TextRender *ri = areaLabels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
if ((lbl = label(ri->key(), path.path->tags))) {
if (!si || si->id() == ri->symbolId()) {
ti = ri;
break;
}
}
}
}
if (ti || si)
items.append(Label(&path, lbl, si, ti));
}
std::sort(items.begin(), items.end());
for (int i = 0; i < items.size(); i++) {
@ -182,24 +120,12 @@ void RasterTile::processLabels(const QList<MapData::Point> &points,
const QColor *color = l.ti ? &l.ti->fillColor() : 0;
const QColor *hColor = l.ti ? haloColor(l.ti) : 0;
if (l.point) {
PointItem *item = new PointItem(ll2xy(l.point->coordinates).toPoint(),
l.lbl, font, img, color, hColor);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
} else {
QPointF pos = l.path->path->labelPos.isNull()
? centroid(l.path->pp) : ll2xy(l.path->path->labelPos);
PointItem *item = new PointItem(pos.toPoint(), l.lbl, font, img,
color, hColor);
if (item->isValid() && rectNearPolygon(_rect, l.path->pp,
item->boundingRect()) && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
PointItem *item = new PointItem(ll2xy(l.point->coordinates).toPoint(),
l.lbl, font, img, color, hColor);
if (item->isValid() && !item->collides(textItems))
textItems.append(item);
else
delete item;
}
}
@ -208,7 +134,7 @@ void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
{
QList<const Style::TextRender*> labels(_style->pathLabels(_zoom));
QList<const Style::Symbol*> symbols(_style->lineSymbols(_zoom));
QList<Label> items;
QList<LineLabel> items;
QSet<QByteArray> set;
for (int i = 0; i < paths.size(); i++) {
@ -222,7 +148,7 @@ void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
for (int j = 0; j < symbols.size(); j++) {
const Style::Symbol *ri = symbols.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
if (ri->rule().matchPath(path.path->closed, path.path->point.tags)) {
si = ri;
break;
}
@ -230,8 +156,8 @@ void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
for (int j = 0; j < labels.size(); j++) {
const Style::TextRender *ri = labels.at(j);
if (ri->rule().match(path.path->closed, path.path->tags)) {
if ((lbl = label(ri->key(), path.path->tags))) {
if (ri->rule().matchPath(path.path->closed, path.path->point.tags)) {
if ((lbl = label(ri->key(), path.path->point.tags))) {
if (!si || si->id() == ri->symbolId()) {
ti = ri;
break;
@ -241,13 +167,13 @@ void RasterTile::processLineLabels(const QVector<PainterPath> &paths,
}
if (ti || si)
items.append(Label(&path, lbl, si, ti));
items.append(LineLabel(&path, lbl, si, ti));
}
std::sort(items.begin(), items.end());
for (int i = 0; i < items.size(); i++) {
const Label &l = items.at(i);
const LineLabel &l = items.at(i);
const QImage *img = l.si ? &l.si->img() : 0;
const QFont *font = l.ti ? &l.ti->font() : 0;
const QColor *color = l.ti ? &l.ti->fillColor() : 0;
@ -361,13 +287,13 @@ void RasterTile::pathInstructions(const QList<MapData::Path> &paths,
for (int i = 0; i < paths.size(); i++) {
const MapData::Path &path = paths.at(i);
PainterPath &rp = painterPaths[i];
PathKey key(_zoom, path.closed, path.tags);
PathKey key(_zoom, path.closed, path.point.tags);
rp.path = &path;
if (!(ri = cache.object(key))) {
ri = new QList<const Style::PathRender*>(_style->paths(_zoom,
path.closed, path.tags));
path.closed, path.point.tags));
for (int j = 0; j < ri->size(); j++)
instructions.append(RenderInstruction(ri->at(j), &rp));
cache.insert(key, ri);
@ -530,7 +456,7 @@ void RasterTile::render()
drawPaths(&painter, paths, points, renderPaths);
processLabels(points, renderPaths, textItems);
processLabels(points, textItems);
processLineLabels(renderPaths, textItems);
drawTextItems(&painter, textItems);

View File

@ -46,30 +46,40 @@ private:
struct Label {
Label(const MapData::Point *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: point(p), path(0), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
Label(const PainterPath *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: point(0), path(p), lbl(lbl), ti(ti), si(si)
: point(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const Label &other) const
{
quint64 id = point ? point->id : path->path->id;
quint64 oid = other.point ? other.point->id : other.path->path->id;
if (priority() == other.priority())
return id < oid;
return point->id < other.point->id;
else
return (priority() > other.priority());
}
int priority() const {return si ? si->priority() : ti->priority();}
const MapData::Point *point;
const QByteArray *lbl;
const Style::TextRender *ti;
const Style::Symbol *si;
};
struct LineLabel {
LineLabel(const PainterPath *p, const QByteArray *lbl,
const Style::Symbol *si, const Style::TextRender *ti)
: path(p), lbl(lbl), ti(ti), si(si)
{
Q_ASSERT(si || ti);
}
bool operator<(const LineLabel &other) const
{
return (priority() > other.priority());
}
int priority() const {return si ? si->priority() : ti->priority();}
const PainterPath *path;
const QByteArray *lbl;
const Style::TextRender *ti;
@ -110,7 +120,7 @@ private:
int layer() const
{
if (_path)
return _path->path->layer;
return _path->path->point.layer;
else if (_point)
return _point->layer;
else
@ -199,7 +209,7 @@ private:
Coordinates xy2ll(const QPointF &p) const
{return _proj.xy2ll(_transform.img2proj(p));}
void processLabels(const QList<MapData::Point> &points,
const QVector<PainterPath> &paths, QList<TextItem*> &textItems) const;
QList<TextItem*> &textItems) const;
void processLineLabels(const QVector<PainterPath> &paths,
QList<TextItem*> &textItems) const;
QPainterPath painterPath(const Polygon &polygon, bool curve) const;

View File

@ -126,8 +126,13 @@ Style::Rule::Filter::Filter(const MapData &data, const QList<QByteArray> &keys,
_vals = valList(vc);
}
bool Style::Rule::match(const QVector<MapData::Tag> &tags) const
bool Style::Rule::match(bool path, const QVector<MapData::Tag> &tags) const
{
Type type = path ? WayType : NodeType;
if (!(_type == Rule::AnyType || _type == type))
return false;
for (int i = 0; i < _filters.size(); i++)
if (!_filters.at(i).match(tags))
return false;
@ -135,7 +140,7 @@ bool Style::Rule::match(const QVector<MapData::Tag> &tags) const
return true;
}
bool Style::Rule::match(bool closed, const QVector<MapData::Tag> &tags) const
bool Style::Rule::matchPath(bool closed, const QVector<MapData::Tag> &tags) const
{
Closed cl = closed ? YesClosed : NoClosed;
@ -858,30 +863,13 @@ QList<const Style::TextRender*> Style::pathLabels(int zoom) const
return list;
}
QList<const Style::TextRender*> Style::pointLabels(int zoom) const
QList<const Style::TextRender*> Style::labels(int zoom) const
{
QList<const TextRender*> list;
for (int i = 0; i < _labels.size(); i++) {
const TextRender &label= _labels.at(i);
const Rule &rule = label.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::NodeType))
list.append(&label);
}
return list;
}
QList<const Style::TextRender*> Style::areaLabels(int zoom) const
{
QList<const TextRender*> list;
for (int i = 0; i < _labels.size(); i++) {
const TextRender &label= _labels.at(i);
const Rule &rule = label.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::WayType))
if (label.rule()._zooms.contains(zoom))
list.append(&label);
}
@ -901,30 +889,13 @@ QList<const Style::Symbol*> Style::lineSymbols(int zoom) const
return list;
}
QList<const Style::Symbol*> Style::pointSymbols(int zoom) const
QList<const Style::Symbol*> Style::symbols(int zoom) const
{
QList<const Symbol*> list;
for (int i = 0; i < _symbols.size(); i++) {
const Symbol &symbol = _symbols.at(i);
const Rule &rule = symbol.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::NodeType))
list.append(&symbol);
}
return list;
}
QList<const Style::Symbol*> Style::areaSymbols(int zoom) const
{
QList<const Symbol*> list;
for (int i = 0; i < _symbols.size(); i++) {
const Symbol &symbol = _symbols.at(i);
const Rule &rule = symbol.rule();
if (rule._zooms.contains(zoom) && (rule._type == Rule::AnyType
|| rule._type == Rule::WayType))
if (symbol.rule()._zooms.contains(zoom))
list.append(&symbol);
}

View File

@ -18,11 +18,8 @@ public:
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;
bool match(bool path, const QVector<MapData::Tag> &tags) const;
bool matchPath(bool closed, const QVector<MapData::Tag> &tags) const;
private:
enum Type {
@ -109,8 +106,12 @@ public:
if (!filter.isTautology())
_filters.append(filter);
}
bool match(int zoom, Type type, Closed 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;
friend class Style;
@ -266,9 +267,9 @@ public:
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*> labels(int zoom) const;
QList<const TextRender*> areaLabels(int zoom) const;
QList<const Symbol*> pointSymbols(int zoom) const;
QList<const Symbol*> symbols(int zoom) const;
QList<const Symbol*> areaSymbols(int zoom) const;
QList<const Symbol*> lineSymbols(int zoom) const;
const HillShadingRender *hillShading(int zoom) const;