diff --git a/src/map/mapsforge/mapdata.cpp b/src/map/mapsforge/mapdata.cpp index 466be650..760a50d3 100644 --- a/src/map/mapsforge/mapdata.cpp +++ b/src/map/mapsforge/mapdata.cpp @@ -23,17 +23,21 @@ using namespace Mapsforge; static void copyPaths(const RectC &rect, const QList *src, QList *dst) { - for (int i = 0; i < src->size(); i++) - if (rect.intersects(src->at(i).poly.boundingRect())) - dst->append(src->at(i)); + for (int i = 0; i < src->size(); i++) { + const MapData::Path &path = src->at(i); + if (rect.intersects(path.poly.boundingRect())) + dst->append(path); + } } static void copyPoints(const RectC &rect, const QList *src, QList *dst) { - for (int i = 0; i < src->size(); i++) - if (rect.contains(src->at(i).coordinates)) - dst->append(src->at(i)); + for (int i = 0; i < src->size(); i++) { + const MapData::Point &point = src->at(i); + if (rect.contains(point.coordinates)) + dst->append(point); + } } static double distance(const Coordinates &c1, const Coordinates &c2) @@ -540,19 +544,20 @@ void MapData::points(const VectorTile *tile, const RectC &rect, int zoom, _pointLock.unlock(); } -void MapData::paths(const RectC &rect, int zoom, QList *list) +void MapData::paths(const RectC &searchRect, const RectC &boundsRect, int zoom, + QList *list) { - if (!rect.isValid()) + if (!searchRect.isValid()) return; int l(level(zoom)); - PathCTX ctx(this, rect, zoom, list); + PathCTX ctx(this, boundsRect, zoom, list); double min[2], max[2]; - min[0] = rect.left(); - min[1] = rect.bottom(); - max[0] = rect.right(); - max[1] = rect.top(); + min[0] = searchRect.left(); + min[1] = searchRect.bottom(); + max[0] = searchRect.right(); + max[1] = searchRect.top(); _tiles.at(l)->Search(min, max, pathCb, &ctx); } diff --git a/src/map/mapsforge/mapdata.h b/src/map/mapsforge/mapdata.h index cc1efb05..7ebf37ad 100644 --- a/src/map/mapsforge/mapdata.h +++ b/src/map/mapsforge/mapdata.h @@ -62,7 +62,8 @@ public: int tileSize() const {return _tileSize;} void points(const RectC &rect, int zoom, QList *list); - void paths(const RectC &rect, int zoom, QList *set); + void paths(const RectC &searchRect, const RectC &boundsRect, int zoom, + QList *set); unsigned tagId(const QByteArray &name) const {return _keys.value(name);} void load(); diff --git a/src/map/mapsforge/rastertile.cpp b/src/map/mapsforge/rastertile.cpp index 38d60803..a36ddffa 100644 --- a/src/map/mapsforge/rastertile.cpp +++ b/src/map/mapsforge/rastertile.cpp @@ -8,6 +8,8 @@ using namespace Mapsforge; #define TEXT_EXTENT 160 +#define PATHS_EXTENT 20 +#define SEARCH_EXTENT -0.5 static double limit = cos(deg2rad(170)); @@ -250,15 +252,28 @@ void RasterTile::processLineLabels(const QVector &paths, const QFont *font = ti ? &ti->font() : 0; const QColor *color = ti ? &ti->fillColor() : 0; const QColor *hColor = ti ? haloColor(ti) : 0; + bool rotate = si ? si->rotate() : false; PathItem *item = new PathItem(path.pp, lbl, img, _rect, font, color, - hColor); + hColor, rotate); if (item->isValid() && !item->collides(textItems)) { textItems.append(item); if (limit) set.insert(*lbl); - } else + } else { delete item; + + if (img && lbl) { + PathItem *item = new PathItem(path.pp, 0, img, _rect, 0, 0, 0, + rotate); + if (item->isValid() && !item->collides(textItems)) { + textItems.append(item); + if (limit) + set.insert(*lbl); + } else + delete item; + } + } } } @@ -382,6 +397,7 @@ void RasterTile::drawPaths(QPainter *painter, const QList &paths, painter->setPen(ri->pen(_zoom)); painter->setBrush(ri->brush()); + if (dy != 0) painter->drawPath(parallelPath(path->pp, dy)); else @@ -402,14 +418,18 @@ void RasterTile::fetchData(QList &paths, { QPoint ttl(_rect.topLeft()); - /* Add a "sub-pixel" margin to assure the tile areas do not - overlap on the border lines. This prevents areas overlap - artifacts at least when using the EPSG:3857 projection. */ - QRectF pathRect(QPointF(ttl.x() + 0.5, ttl.y() + 0.5), - QPointF(ttl.x() + _rect.width() - 0.5, ttl.y() + _rect.height() - 0.5)); + QRectF pathRect(QPointF(ttl.x() - PATHS_EXTENT, ttl.y() - PATHS_EXTENT), + QPointF(ttl.x() + _rect.width() + PATHS_EXTENT, ttl.y() + _rect.height() + + PATHS_EXTENT)); + QRectF searchRect(QPointF(ttl.x() - SEARCH_EXTENT, ttl.y() - SEARCH_EXTENT), + QPointF(ttl.x() + _rect.width() + SEARCH_EXTENT, ttl.y() + _rect.height() + + SEARCH_EXTENT)); RectD pathRectD(_transform.img2proj(pathRect.topLeft()), _transform.img2proj(pathRect.bottomRight())); - _data->paths(pathRectD.toRectC(_proj, 20), _zoom, &paths); + RectD searchRectD(_transform.img2proj(searchRect.topLeft()), + _transform.img2proj(searchRect.bottomRight())); + _data->paths(searchRectD.toRectC(_proj, 20), pathRectD.toRectC(_proj, 20), + _zoom, &paths); QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT, ttl.y() - TEXT_EXTENT), QPointF(ttl.x() + _rect.width() + TEXT_EXTENT, ttl.y() + _rect.height() diff --git a/src/map/mapsforge/rastertile.h b/src/map/mapsforge/rastertile.h index d8136731..8c7cc665 100644 --- a/src/map/mapsforge/rastertile.h +++ b/src/map/mapsforge/rastertile.h @@ -138,9 +138,9 @@ private: public: PathItem(const QPainterPath &line, const QByteArray *label, const QImage *img, const QRect &tileRect, const QFont *font, - const QColor *color, const QColor *haloColor) : TextPathItem(line, - label ? new QString(*label) : 0, tileRect, font, color, haloColor, - img) {} + const QColor *color, const QColor *haloColor, bool rotate) + : TextPathItem(line, label ? new QString(*label) : 0, tileRect, font, + color, haloColor, img, rotate) {} ~PathItem() {delete _text;} }; diff --git a/src/map/mapsforge/style.cpp b/src/map/mapsforge/style.cpp index a159ec2a..68418c3e 100644 --- a/src/map/mapsforge/style.cpp +++ b/src/map/mapsforge/style.cpp @@ -17,18 +17,26 @@ static QString resourcePath(const QString &src, const QString &dir) return dir + "/" + url.toLocalFile(); } -static QImage image(const QString &path, int width, int height, qreal ratio) +static QImage image(const QString &path, int width, int height, int percent, + qreal ratio) { QImageReader ir(path, "svg"); if (ir.canRead()) { + QSize s(ir.size()); + if (!height && !width) { height = 20; width = 20; } else if (!width) { - width = ir.size().height() / (ir.size().height() / (double)height); + width = s.height() / (s.height() / (double)height); } else if (!height) - height = ir.size().width() / (ir.size().width() / (double)width); + height = s.width() / (s.width() / (double)width); + + if (percent != 100) { + width *= percent / 100.0; + height *= percent / 100.0; + } ir.setScaledSize(QSize(width * ratio, height * ratio)); QImage img(ir.read()); @@ -175,7 +183,7 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio, const QXmlStreamAttributes &attr = reader.attributes(); QString file; QColor fillColor; - int height = 0, width = 0; + int height = 0, width = 0, percent = 100; bool ok; ri._area = true; @@ -213,9 +221,16 @@ void Style::area(QXmlStreamReader &reader, const QString &dir, qreal ratio, return; } } + if (attr.hasAttribute("symbol-percent")) { + percent = attr.value("symbol-percent").toInt(&ok); + if (!ok || percent < 0) { + reader.raiseError("invalid symbol-percent value"); + return; + } + } if (!file.isNull()) - ri._brush = QBrush(image(file, width, height, ratio)); + ri._brush = QBrush(image(file, width, height, percent, ratio)); else if (fillColor.isValid()) ri._brush = QBrush(fillColor); @@ -231,6 +246,8 @@ void Style::line(QXmlStreamReader &reader, const Rule &rule) const QXmlStreamAttributes &attr = reader.attributes(); bool ok; + ri._brush = Qt::NoBrush; + if (attr.hasAttribute("stroke")) ri._strokeColor = QColor(attr.value("stroke").toString()); if (attr.hasAttribute("stroke-width")) { @@ -424,7 +441,7 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio, Symbol ri(rule); const QXmlStreamAttributes &attr = reader.attributes(); QString file; - int height = 0, width = 0; + int height = 0, width = 0, percent = 100; bool ok; if (attr.hasAttribute("src")) @@ -447,6 +464,13 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio, return; } } + if (attr.hasAttribute("symbol-percent")) { + percent = attr.value("symbol-percent").toInt(&ok); + if (!ok || percent < 0) { + reader.raiseError("invalid symbol-percent value"); + return; + } + } if (attr.hasAttribute("priority")) { ri._priority = attr.value("priority").toInt(&ok); if (!ok) { @@ -454,8 +478,12 @@ void Style::symbol(QXmlStreamReader &reader, const QString &dir, qreal ratio, return; } } + if (attr.hasAttribute("rotate")) { + if (attr.value("rotate").toString() == "false") + ri._rotate = false; + } - ri._img = image(file, width, height, ratio); + ri._img = image(file, width, height, percent, ratio); list.append(ri); diff --git a/src/map/mapsforge/style.h b/src/map/mapsforge/style.h index e004fa49..a732f9d7 100644 --- a/src/map/mapsforge/style.h +++ b/src/map/mapsforge/style.h @@ -212,15 +212,17 @@ public: class Symbol : public Render { public: - Symbol(const Rule &rule) : Render(rule), _priority(0) {} + Symbol(const Rule &rule) : Render(rule), _priority(0), _rotate(true) {} const QImage &img() const {return _img;} int priority() const {return _priority;} + bool rotate() const {return _rotate;} private: friend class Style; int _priority; + bool _rotate; QImage _img; }; @@ -282,8 +284,7 @@ private: QList _paths; QList _circles; QList _pathLabels, _pointLabels, _areaLabels; - QList _symbols; - QList _lineSymbols; + QList _symbols, _lineSymbols; bool loadXml(const QString &path, const MapData &data, qreal ratio); void rendertheme(QXmlStreamReader &reader, const QString &dir, diff --git a/src/map/textpathitem.cpp b/src/map/textpathitem.cpp index f377bd4e..8c4783e1 100644 --- a/src/map/textpathitem.cpp +++ b/src/map/textpathitem.cpp @@ -266,15 +266,15 @@ void TextPathItem::init(const T &line, const QRect &tileRect) if (_text && _img) { cw = _font->pixelSize() * CHAR_RATIO; - mw = _font->pixelSize() / 2; + mw = _font->pixelSize() / 2.0; textWidth = _text->size() * cw + _img->width() + PADDING; } else if (_text) { cw = _font->pixelSize() * CHAR_RATIO; - mw = _font->pixelSize() / 2; + mw = _font->pixelSize() / 2.0; textWidth = _text->size() * cw; } else { cw = _img->width(); - mw = _img->height() / 2; + mw = _img->height() / 2.0; textWidth = _img->width(); } @@ -296,16 +296,18 @@ void TextPathItem::init(const T &line, const QRect &tileRect) TextPathItem::TextPathItem(const QPolygonF &line, const QString *label, const QRect &tileRect, const QFont *font, const QColor *color, - const QColor *haloColor, const QImage *img) : TextItem(label), _font(font), - _color(color), _haloColor(haloColor), _img(img), _reverse(false) + const QColor *haloColor, const QImage *img, bool rotate) + : TextItem(label), _font(font), _color(color), _haloColor(haloColor), + _img(img), _rotate(rotate), _reverse(false) { init(line, tileRect); } TextPathItem::TextPathItem(const QPainterPath &line, const QString *label, const QRect &tileRect, const QFont *font, const QColor *color, - const QColor *haloColor, const QImage *img) : TextItem(label), _font(font), - _color(color), _haloColor(haloColor), _img(img), _reverse(false) + const QColor *haloColor, const QImage *img, bool rotate) + : TextItem(label), _font(font), _color(color), _haloColor(haloColor), + _img(img), _rotate(rotate), _reverse(false) { init(line, tileRect); } @@ -318,13 +320,11 @@ void TextPathItem::paint(QPainter *painter) const painter->save(); painter->translate(QPointF(_path.elementAt(0).x, _path.elementAt(0).y)); painter->rotate(360 - _path.angleAtPercent(0)); - - if (_reverse) - painter->drawImage(QPointF(0, -s.height()/2), - _img->transformed(QTransform().rotate(180.0))); - else - painter->drawImage(QPointF(0, -s.height()/2), *_img); - + if (_reverse && _rotate) { + painter->rotate(180); + painter->translate(-s.width(), 0); + } + painter->drawImage(QPointF(0, -s.height()/2), *_img); painter->restore(); } diff --git a/src/map/textpathitem.h b/src/map/textpathitem.h index edf9b02b..3a66ca16 100644 --- a/src/map/textpathitem.h +++ b/src/map/textpathitem.h @@ -1,20 +1,21 @@ #ifndef TEXTPATHITEM_H #define TEXTPATHITEM_H -#include -#include #include "textitem.h" +class QFont; +class QImage; +class QColor; + class TextPathItem : public TextItem { public: - TextPathItem() : TextItem(0), _font(0), _color(0) {} TextPathItem(const QPolygonF &line, const QString *label, const QRect &tileRect, const QFont *font, const QColor *color, - const QColor *haloColor, const QImage *img = 0); + const QColor *haloColor, const QImage *img = 0, bool rotate = true); TextPathItem(const QPainterPath &line, const QString *label, const QRect &tileRect, const QFont *font, const QColor *color, - const QColor *haloColor, const QImage *img = 0); + const QColor *haloColor, const QImage *img = 0, bool rotate = true); bool isValid() const {return !_path.isEmpty();} @@ -26,13 +27,11 @@ private: template void init(const T &line, const QRect &tileRect); const QFont *_font; - const QColor *_color; - const QColor *_haloColor; + const QColor *_color, *_haloColor; const QImage *_img; - QPainterPath _path; QRectF _rect; - QPainterPath _shape; - bool _reverse; + QPainterPath _path, _shape; + bool _rotate, _reverse; }; #endif // TEXTPATHITEM_H diff --git a/src/map/textpointitem.h b/src/map/textpointitem.h index 929b2827..a42ffb03 100644 --- a/src/map/textpointitem.h +++ b/src/map/textpointitem.h @@ -1,12 +1,8 @@ #ifndef TEXTPOINTITEM_H #define TEXTPOINTITEM_H -#include -#include -#include #include "textitem.h" -class QPainter; class QFont; class QImage; class QColor; @@ -14,7 +10,6 @@ class QColor; class TextPointItem : public TextItem { public: - TextPointItem() : TextItem(0), _font(0), _img(0) {} TextPointItem(const QPoint &point, const QString *text, const QFont *font, const QImage *img, const QColor *color, const QColor *haloColor, const QColor *bgColor = 0, int padding = 0, double rotate = NAN);