2 #include <QXmlStreamReader>
5 #include <QImageReader>
6 #include "common/programpaths.h"
9 using namespace Mapsforge
;
11 static QString
resourcePath(const QString
&src
, const QString
&dir
)
14 if (url
.scheme().isEmpty())
17 return dir
+ "/" + url
.toLocalFile();
20 static QImage
image(const QString
&path
, int width
, int height
, int percent
,
23 QImageReader
ir(path
, "svg");
28 if (!height
&& !width
) {
32 width
= s
.height() / (s
.height() / (double)height
);
34 height
= s
.width() / (s
.width() / (double)width
);
37 width
*= percent
/ 100.0;
38 height
*= percent
/ 100.0;
41 ir
.setScaledSize(QSize(width
* ratio
, height
* ratio
));
42 QImage
img(ir
.read());
43 img
.setDevicePixelRatio(ratio
);
49 static QList
<unsigned> keyList(const MapData
&data
, const QList
<QByteArray
> &in
)
53 for (int i
= 0; i
< in
.size(); i
++) {
57 unsigned key
= data
.tagId(in
.at(i
));
66 static QList
<QByteArray
> valList(const QList
<QByteArray
> &in
)
68 QList
<QByteArray
> out
;
70 for (int i
= 0; i
< in
.size(); i
++) {
72 out
.append(QByteArray());
80 const Style::Menu::Layer
*Style::Menu::findLayer(const QString
&id
) const
82 for (int i
= 0; i
< _layers
.size(); i
++)
83 if (_layers
.at(i
).id() == id
)
84 return &_layers
.at(i
);
86 qWarning("%s: layer not found", qPrintable(id
));
91 void Style::Menu::addCats(const Layer
*layer
, QSet
<QString
> &cats
) const
96 if (!layer
->parent().isNull())
97 addCats(findLayer(layer
->parent()), cats
);
99 for (int i
= 0; i
< layer
->cats().size(); i
++)
100 cats
.insert(layer
->cats().at(i
));
102 for (int i
= 0; i
< layer
->overlays().size(); i
++) {
103 const Layer
*overlay
= findLayer(layer
->overlays().at(i
));
104 if (overlay
&& overlay
->enabled())
105 addCats(overlay
, cats
);
109 QSet
<QString
> Style::Menu::cats() const
112 addCats(findLayer(_defaultvalue
), c
);
116 Style::Rule::Filter::Filter(const MapData
&data
, const QList
<QByteArray
> &keys
,
117 const QList
<QByteArray
> &vals
) : _neg(false)
119 _keys
= keyList(data
, keys
);
121 QList
<QByteArray
> vc(vals
);
122 if (vc
.removeAll("~"))
127 bool Style::Rule::match(const QVector
<MapData::Tag
> &tags
) const
129 for (int i
= 0; i
< _filters
.size(); i
++)
130 if (!_filters
.at(i
).match(tags
))
136 bool Style::Rule::match(bool closed
, const QVector
<MapData::Tag
> &tags
) const
138 Closed cl
= closed
? YesClosed
: NoClosed
;
140 if (_closed
&& cl
!= _closed
)
143 for (int i
= 0; i
< _filters
.size(); i
++)
144 if (!_filters
.at(i
).match(tags
))
150 bool Style::Rule::match(int zoom
, bool closed
,
151 const QVector
<MapData::Tag
> &tags
) const
153 Closed cl
= closed
? YesClosed
: NoClosed
;
155 if (!_zooms
.contains(zoom
))
157 if (_closed
&& cl
!= _closed
)
160 for (int i
= 0; i
< _filters
.size(); i
++)
161 if (!_filters
.at(i
).match(tags
))
167 bool Style::Rule::match(int zoom
, const QVector
<MapData::Tag
> &tags
) const
169 if (!_zooms
.contains(zoom
))
172 for (int i
= 0; i
< _filters
.size(); i
++)
173 if (!_filters
.at(i
).match(tags
))
179 void Style::area(QXmlStreamReader
&reader
, const QString
&dir
, qreal ratio
,
180 qreal baseStrokeWidth
, const Rule
&rule
)
182 PathRender
ri(rule
, _paths
.size() + _circles
.size() + _hillShading
.isValid());
183 const QXmlStreamAttributes
&attr
= reader
.attributes();
186 int height
= 0, width
= 0, percent
= 100;
190 if (attr
.hasAttribute("fill"))
191 fillColor
= QColor(attr
.value("fill").toString());
192 if (attr
.hasAttribute("stroke"))
193 ri
._strokeColor
= QColor(attr
.value("stroke").toString());
194 if (attr
.hasAttribute("stroke-width")) {
195 ri
._strokeWidth
= attr
.value("stroke-width").toFloat(&ok
)
197 if (!ok
|| ri
._strokeWidth
< 0) {
198 reader
.raiseError("invalid stroke-width value");
202 if (attr
.hasAttribute("scale")) {
203 QString
scale(attr
.value("scale").toString());
205 ri
._scale
= PathRender::Scale::All
;
206 else if (scale
== "none")
207 ri
._scale
= PathRender::Scale::None
;
209 if (attr
.hasAttribute("src"))
210 file
= resourcePath(attr
.value("src").toString(), dir
);
211 if (attr
.hasAttribute("symbol-height")) {
212 height
= attr
.value("symbol-height").toInt(&ok
);
213 if (!ok
|| height
< 0) {
214 reader
.raiseError("invalid symbol-height value");
218 if (attr
.hasAttribute("symbol-width")) {
219 width
= attr
.value("symbol-width").toInt(&ok
);
220 if (!ok
|| width
< 0) {
221 reader
.raiseError("invalid symbol-width value");
225 if (attr
.hasAttribute("symbol-percent")) {
226 percent
= attr
.value("symbol-percent").toInt(&ok
);
227 if (!ok
|| percent
< 0) {
228 reader
.raiseError("invalid symbol-percent value");
234 ri
._brush
= QBrush(image(file
, width
, height
, percent
, ratio
));
235 else if (fillColor
.isValid())
236 ri
._brush
= QBrush(fillColor
);
238 if (ri
.rule()._type
== Rule::AnyType
|| ri
.rule()._type
== Rule::WayType
)
241 reader
.skipCurrentElement();
244 void Style::line(QXmlStreamReader
&reader
, qreal baseStrokeWidth
,
247 PathRender
ri(rule
, _paths
.size() + _circles
.size() + _hillShading
.isValid());
248 const QXmlStreamAttributes
&attr
= reader
.attributes();
251 ri
._brush
= Qt::NoBrush
;
253 if (attr
.hasAttribute("stroke"))
254 ri
._strokeColor
= QColor(attr
.value("stroke").toString());
255 if (attr
.hasAttribute("stroke-width")) {
256 ri
._strokeWidth
= attr
.value("stroke-width").toFloat(&ok
)
258 if (!ok
|| ri
._strokeWidth
< 0) {
259 reader
.raiseError("invalid stroke-width value");
263 if (attr
.hasAttribute("stroke-dasharray")) {
264 QStringList
l(attr
.value("stroke-dasharray").toString().split(','));
265 ri
._strokeDasharray
.resize(l
.size());
266 for (int i
= 0; i
< l
.size(); i
++) {
267 ri
._strokeDasharray
[i
] = l
.at(i
).toDouble(&ok
);
268 if (!ok
|| ri
._strokeDasharray
[i
] < 0) {
269 reader
.raiseError("invalid stroke-dasharray value");
274 if (attr
.hasAttribute("stroke-linecap")) {
275 QString
cap(attr
.value("stroke-linecap").toString());
277 ri
._strokeCap
= Qt::FlatCap
;
278 else if (cap
== "round")
279 ri
._strokeCap
= Qt::RoundCap
;
280 else if (cap
== "square")
281 ri
._strokeCap
= Qt::SquareCap
;
283 if (attr
.hasAttribute("stroke-linejoin")) {
284 QString
join(attr
.value("stroke-linejoin").toString());
286 ri
._strokeJoin
= Qt::MiterJoin
;
287 else if (join
== "round")
288 ri
._strokeJoin
= Qt::RoundJoin
;
289 else if (join
== "bevel")
290 ri
._strokeJoin
= Qt::BevelJoin
;
292 if (attr
.hasAttribute("scale")) {
293 QString
scale(attr
.value("scale").toString());
295 ri
._scale
= PathRender::Scale::All
;
296 else if (scale
== "none")
297 ri
._scale
= PathRender::Scale::None
;
299 if (attr
.hasAttribute("curve")) {
300 QString
curve(attr
.value("curve").toString());
301 if (curve
== "cubic")
304 if (attr
.hasAttribute("dy")) {
305 ri
._dy
= attr
.value("dy").toDouble(&ok
) * baseStrokeWidth
;
307 reader
.raiseError("invalid dy value");
312 if (ri
.rule()._type
== Rule::AnyType
|| ri
.rule()._type
== Rule::WayType
)
315 reader
.skipCurrentElement();
318 void Style::circle(QXmlStreamReader
&reader
, qreal baseStrokeWidth
,
321 CircleRender
ri(rule
, _paths
.size() + _circles
.size() + _hillShading
.isValid());
322 const QXmlStreamAttributes
&attr
= reader
.attributes();
324 QColor fillColor
, strokeColor
;
325 qreal strokeWidth
= 0;
327 if (attr
.hasAttribute("fill"))
328 fillColor
= QColor(attr
.value("fill").toString());
329 if (attr
.hasAttribute("stroke"))
330 strokeColor
= QColor(attr
.value("stroke").toString());
331 if (attr
.hasAttribute("stroke-width")) {
332 strokeWidth
= attr
.value("stroke-width").toFloat(&ok
) * baseStrokeWidth
;
333 if (!ok
|| strokeWidth
< 0) {
334 reader
.raiseError("invalid stroke-width value");
338 if (attr
.hasAttribute("radius")) {
339 ri
._radius
= attr
.value("radius").toDouble(&ok
) * baseStrokeWidth
;
340 if (!ok
|| ri
._radius
<= 0) {
341 reader
.raiseError("invalid radius value");
345 reader
.raiseError("missing radius");
348 if (attr
.hasAttribute("scale-radius")) {
349 if (attr
.value("scale-radius").toString() == "true")
353 ri
._pen
= (strokeColor
.isValid() && strokeWidth
> 0)
354 ? QPen(QBrush(strokeColor
), strokeWidth
) : Qt::NoPen
;
355 ri
._brush
= fillColor
.isValid() ? QBrush(fillColor
) : Qt::NoBrush
;
357 if (ri
.rule()._type
== Rule::AnyType
|| ri
.rule()._type
== Rule::NodeType
)
360 reader
.skipCurrentElement();
363 void Style::text(QXmlStreamReader
&reader
, const MapData
&data
, const Rule
&rule
,
364 QList
<QList
<TextRender
>*> &lists
)
367 const QXmlStreamAttributes
&attr
= reader
.attributes();
369 bool bold
= false, italic
= false;
370 QString
fontFamily("Helvetica");
371 QFont::Capitalization capitalization
= QFont::MixedCase
;
374 if (attr
.hasAttribute("k"))
375 ri
._key
= data
.tagId(attr
.value("k").toLatin1());
376 if (attr
.hasAttribute("fill"))
377 ri
._fillColor
= QColor(attr
.value("fill").toString());
378 if (attr
.hasAttribute("stroke"))
379 ri
._strokeColor
= QColor(attr
.value("stroke").toString());
380 if (attr
.hasAttribute("stroke-width")) {
381 ri
._strokeWidth
= attr
.value("stroke-width").toFloat(&ok
);
382 if (!ok
|| ri
._strokeWidth
< 0) {
383 reader
.raiseError("invalid stroke-width value");
387 if (attr
.hasAttribute("font-size")) {
388 fontSize
= attr
.value("font-size").toFloat(&ok
);
389 if (!ok
|| fontSize
< 0) {
390 reader
.raiseError("invalid font-size value");
394 if (attr
.hasAttribute("font-style")) {
395 QString
style(attr
.value("font-style").toString());
398 else if (style
== "italic")
400 else if (style
== "bold_italic") {
405 if (attr
.hasAttribute("font-family")) {
406 QString
family(attr
.value("font-family").toString());
407 if (family
== "monospace")
408 fontFamily
= "Courier New";
409 else if (family
== "serif")
410 fontFamily
= "Times New Roman";
412 if (attr
.hasAttribute("text-transform")) {
413 QString
transform(attr
.value("text-transform").toString());
414 if (transform
== "uppercase")
415 capitalization
= QFont::AllUppercase
;
416 else if (transform
== "lowercase")
417 capitalization
= QFont::AllLowercase
;
418 else if (transform
== "capitalize")
419 capitalization
= QFont::Capitalize
;
421 if (attr
.hasAttribute("priority")) {
422 ri
._priority
= attr
.value("priority").toInt(&ok
);
424 reader
.raiseError("invalid priority value");
428 if (attr
.hasAttribute("symbol-id"))
429 ri
._symbolId
= attr
.value("symbol-id").toString();
431 ri
._font
.setFamily(fontFamily
);
432 ri
._font
.setPixelSize(fontSize
);
433 ri
._font
.setBold(bold
);
434 ri
._font
.setItalic(italic
);
435 ri
._font
.setCapitalization(capitalization
);
438 for (int i
= 0; i
< lists
.size(); i
++)
439 lists
[i
]->append(ri
);
441 reader
.skipCurrentElement();
444 void Style::symbol(QXmlStreamReader
&reader
, const QString
&dir
, qreal ratio
,
445 const Rule
&rule
, QList
<Symbol
> &list
)
448 const QXmlStreamAttributes
&attr
= reader
.attributes();
450 int height
= 0, width
= 0, percent
= 100;
453 if (attr
.hasAttribute("src"))
454 file
= resourcePath(attr
.value("src").toString(), dir
);
456 reader
.raiseError("missing src value");
459 if (attr
.hasAttribute("symbol-height")) {
460 height
= attr
.value("symbol-height").toInt(&ok
);
461 if (!ok
|| height
< 0) {
462 reader
.raiseError("invalid symbol-height value");
466 if (attr
.hasAttribute("symbol-width")) {
467 width
= attr
.value("symbol-width").toInt(&ok
);
468 if (!ok
|| width
< 0) {
469 reader
.raiseError("invalid symbol-width value");
473 if (attr
.hasAttribute("symbol-percent")) {
474 percent
= attr
.value("symbol-percent").toInt(&ok
);
475 if (!ok
|| percent
< 0) {
476 reader
.raiseError("invalid symbol-percent value");
480 if (attr
.hasAttribute("priority")) {
481 ri
._priority
= attr
.value("priority").toInt(&ok
);
483 reader
.raiseError("invalid priority value");
487 if (attr
.hasAttribute("rotate")) {
488 if (attr
.value("rotate").toString() == "false")
491 if (attr
.hasAttribute("id"))
492 ri
._id
= attr
.value("id").toString();
494 ri
._img
= image(file
, width
, height
, percent
, ratio
);
498 reader
.skipCurrentElement();
501 void Style::rule(QXmlStreamReader
&reader
, const QString
&dir
,
502 const MapData
&data
, qreal ratio
, qreal baseStrokeWidth
,
503 const QSet
<QString
> &cats
, const Rule
&parent
)
506 const QXmlStreamAttributes
&attr
= reader
.attributes();
509 if (attr
.hasAttribute("cat")
510 && !cats
.contains(attr
.value("cat").toString())) {
511 reader
.skipCurrentElement();
515 if (attr
.value("e").toString() == "way")
516 r
.setType(Rule::WayType
);
517 else if (attr
.value("e").toString() == "node")
518 r
.setType(Rule::NodeType
);
520 if (attr
.hasAttribute("zoom-min")) {
521 r
.setMinZoom(attr
.value("zoom-min").toInt(&ok
));
522 if (!ok
|| r
._zooms
.min() < 0) {
523 reader
.raiseError("invalid zoom-min value");
527 if (attr
.hasAttribute("zoom-max")) {
528 r
.setMaxZoom(attr
.value("zoom-max").toInt(&ok
));
529 if (!ok
|| r
._zooms
.max() < 0) {
530 reader
.raiseError("invalid zoom-max value");
535 if (attr
.hasAttribute("closed")) {
536 if (attr
.value("closed").toString() == "yes")
537 r
.setClosed(Rule::YesClosed
);
538 else if (attr
.value("closed").toString() == "no")
539 r
.setClosed(Rule::NoClosed
);
542 QList
<QByteArray
> keys(attr
.value("k").toLatin1().split('|'));
543 QList
<QByteArray
> vals(attr
.value("v").toLatin1().split('|'));
544 r
.addFilter(Rule::Filter(data
, keys
, vals
));
546 while (reader
.readNextStartElement()) {
547 if (reader
.name() == QLatin1String("rule"))
548 rule(reader
, dir
, data
, ratio
, baseStrokeWidth
, cats
, r
);
549 else if (reader
.name() == QLatin1String("area"))
550 area(reader
, dir
, ratio
, baseStrokeWidth
, r
);
551 else if (reader
.name() == QLatin1String("line"))
552 line(reader
, baseStrokeWidth
, r
);
553 else if (reader
.name() == QLatin1String("circle"))
554 circle(reader
, baseStrokeWidth
, r
);
555 else if (reader
.name() == QLatin1String("pathText")) {
556 QList
<QList
<TextRender
>*> list
;
557 list
.append(&_pathLabels
);
558 text(reader
, data
, r
, list
);
559 } else if (reader
.name() == QLatin1String("caption")) {
560 QList
<QList
<TextRender
>*> list
;
561 if (r
._type
== Rule::WayType
|| r
._type
== Rule::AnyType
)
562 list
.append(&_areaLabels
);
563 if (r
._type
== Rule::NodeType
|| r
._type
== Rule::AnyType
)
564 list
.append(&_pointLabels
);
565 text(reader
, data
, r
, list
);
567 else if (reader
.name() == QLatin1String("symbol"))
568 symbol(reader
, dir
, ratio
, r
, _symbols
);
569 else if (reader
.name() == QLatin1String("lineSymbol"))
570 symbol(reader
, dir
, ratio
, r
, _lineSymbols
);
572 reader
.skipCurrentElement();
576 void Style::hillshading(QXmlStreamReader
&reader
, const QSet
<QString
> &cats
)
579 const QXmlStreamAttributes
&attr
= reader
.attributes();
583 if (attr
.hasAttribute("cat")
584 && !cats
.contains(attr
.value("cat").toString())) {
585 reader
.skipCurrentElement();
588 if (attr
.hasAttribute("zoom-min")) {
589 r
.setMinZoom(attr
.value("zoom-min").toInt(&ok
));
590 if (!ok
|| r
._zooms
.min() < 0) {
591 reader
.raiseError("invalid zoom-min value");
595 if (attr
.hasAttribute("zoom-max")) {
596 r
.setMaxZoom(attr
.value("zoom-max").toInt(&ok
));
597 if (!ok
|| r
._zooms
.max() < 0) {
598 reader
.raiseError("invalid zoom-max value");
602 if (attr
.hasAttribute("layer")) {
603 layer
= attr
.value("layer").toInt(&ok
);
604 if (!ok
|| layer
< 0) {
605 reader
.raiseError("invalid layer value");
610 _hillShading
= HillShadingRender(r
, _paths
.size() + _circles
.size(), layer
);
612 reader
.skipCurrentElement();
615 QString
Style::cat(QXmlStreamReader
&reader
)
617 const QXmlStreamAttributes
&attr
= reader
.attributes();
619 if (!attr
.hasAttribute("id")) {
620 reader
.raiseError("Missing id attribute");
624 QString
id(attr
.value("id").toString());
625 reader
.skipCurrentElement();
630 Style::Menu::Layer
Style::layer(QXmlStreamReader
&reader
)
632 const QXmlStreamAttributes
&attr
= reader
.attributes();
633 if (!attr
.hasAttribute("id")) {
634 reader
.raiseError("Missing id attribute");
635 return Menu::Layer();
638 Menu::Layer
l(attr
.value("id").toString(),
639 attr
.value("enabled").toString() == "true");
641 if (attr
.hasAttribute("parent"))
642 l
.setParent(attr
.value("parent").toString());
644 while (reader
.readNextStartElement()) {
645 if (reader
.name() == QLatin1String("cat"))
646 l
.addCat(cat(reader
));
647 else if (reader
.name() == QLatin1String("overlay"))
648 l
.addOverlay(cat(reader
));
650 reader
.skipCurrentElement();
656 Style::Menu
Style::stylemenu(QXmlStreamReader
&reader
)
658 const QXmlStreamAttributes
&attr
= reader
.attributes();
659 if (!attr
.hasAttribute("defaultvalue")) {
660 reader
.raiseError("Missing defaultvalue attribute");
664 Style::Menu
menu(attr
.value("defaultvalue").toString());
666 while (reader
.readNextStartElement()) {
667 if (reader
.name() == QLatin1String("layer"))
668 menu
.addLayer(layer(reader
));
670 reader
.skipCurrentElement();
676 void Style::rendertheme(QXmlStreamReader
&reader
, const QString
&dir
,
677 const MapData
&data
, qreal ratio
)
681 qreal baseStrokeWidth
= 1.0;
683 const QXmlStreamAttributes
&attr
= reader
.attributes();
684 if (attr
.hasAttribute("base-stroke-width")) {
686 baseStrokeWidth
= attr
.value("base-stroke-width").toFloat(&ok
);
687 if (!ok
|| baseStrokeWidth
< 0) {
688 reader
.raiseError("invalid base-stroke-width value");
693 while (reader
.readNextStartElement()) {
694 if (reader
.name() == QLatin1String("rule"))
695 rule(reader
, dir
, data
, ratio
, baseStrokeWidth
, cats
, r
);
696 else if (reader
.name() == QLatin1String("hillshading"))
697 hillshading(reader
, cats
);
698 else if (reader
.name() == QLatin1String("stylemenu")) {
699 Menu
menu(stylemenu(reader
));
702 reader
.skipCurrentElement();
706 bool Style::loadXml(const QString
&path
, const MapData
&data
, qreal ratio
)
709 if (!file
.open(QFile::ReadOnly
))
711 QXmlStreamReader
reader(&file
);
714 if (reader
.readNextStartElement()) {
715 if (reader
.name() == QLatin1String("rendertheme"))
716 rendertheme(reader
, fi
.absolutePath(), data
, ratio
);
718 reader
.raiseError("Not a Mapsforge style file");
722 qWarning("%s:%lld %s", qPrintable(path
), reader
.lineNumber(),
723 qPrintable(reader
.errorString()));
725 return !reader
.error();
728 void Style::load(const MapData
&data
, qreal ratio
)
730 QString
path(ProgramPaths::renderthemeFile());
732 if (!QFileInfo::exists(path
) || !loadXml(path
, data
, ratio
))
733 loadXml(":/mapsforge/default.xml", data
, ratio
);
741 _pointLabels
.clear();
744 _lineSymbols
.clear();
747 QList
<const Style::PathRender
*> Style::paths(int zoom
, bool closed
,
748 const QVector
<MapData::Tag
> &tags
) const
750 QList
<const PathRender
*> ri
;
752 for (int i
= 0; i
< _paths
.size(); i
++)
753 if (_paths
.at(i
).rule().match(zoom
, closed
, tags
))
754 ri
.append(&_paths
.at(i
));
759 QList
<const Style::CircleRender
*> Style::circles(int zoom
,
760 const QVector
<MapData::Tag
> &tags
) const
762 QList
<const CircleRender
*> ri
;
764 for (int i
= 0; i
< _circles
.size(); i
++)
765 if (_circles
.at(i
).rule().match(zoom
, tags
))
766 ri
.append(&_circles
.at(i
));
771 const Style::HillShadingRender
*Style::hillShading(int zoom
) const
773 return (_hillShading
.isValid() && _hillShading
.rule()._zooms
.contains(zoom
))
777 QList
<const Style::TextRender
*> Style::pathLabels(int zoom
) const
779 QList
<const TextRender
*> list
;
781 for (int i
= 0; i
< _pathLabels
.size(); i
++)
782 if (_pathLabels
.at(i
).rule()._zooms
.contains(zoom
))
783 list
.append(&_pathLabels
.at(i
));
788 QList
<const Style::TextRender
*> Style::pointLabels(int zoom
) const
790 QList
<const TextRender
*> list
;
792 for (int i
= 0; i
< _pointLabels
.size(); i
++)
793 if (_pointLabels
.at(i
).rule()._zooms
.contains(zoom
))
794 list
.append(&_pointLabels
.at(i
));
799 QList
<const Style::TextRender
*> Style::areaLabels(int zoom
) const
801 QList
<const TextRender
*> list
;
803 for (int i
= 0; i
< _areaLabels
.size(); i
++)
804 if (_areaLabels
.at(i
).rule()._zooms
.contains(zoom
))
805 list
.append(&_areaLabels
.at(i
));
810 QList
<const Style::Symbol
*> Style::pointSymbols(int zoom
) const
812 QList
<const Symbol
*> list
;
814 for (int i
= 0; i
< _symbols
.size(); i
++) {
815 const Symbol
&symbol
= _symbols
.at(i
);
816 const Rule
&rule
= symbol
.rule();
817 if (rule
._zooms
.contains(zoom
) && (rule
._type
== Rule::AnyType
818 || rule
._type
== Rule::NodeType
))
819 list
.append(&symbol
);
825 QList
<const Style::Symbol
*> Style::lineSymbols(int zoom
) const
827 QList
<const Symbol
*> list
;
829 for (int i
= 0; i
< _lineSymbols
.size(); i
++) {
830 const Symbol
&symbol
= _lineSymbols
.at(i
);
831 if (symbol
.rule()._zooms
.contains(zoom
))
832 list
.append(&symbol
);
838 QList
<const Style::Symbol
*> Style::areaSymbols(int zoom
) const
840 QList
<const Symbol
*> list
;
842 for (int i
= 0; i
< _symbols
.size(); i
++) {
843 const Symbol
&symbol
= _symbols
.at(i
);
844 const Rule
&rule
= symbol
.rule();
845 if (rule
._zooms
.contains(zoom
) && (rule
._type
== Rule::AnyType
846 || rule
._type
== Rule::WayType
))
847 list
.append(&symbol
);
853 QPen
Style::PathRender::pen(int zoom
) const
855 if (_strokeColor
.isValid()) {
856 qreal width
= (_scale
> None
&& zoom
>= 12)
857 ? pow(1.5, zoom
- 12) * _strokeWidth
: _strokeWidth
;
858 QPen
p(QBrush(_strokeColor
), width
, Qt::SolidLine
, _strokeCap
,
860 if (!_strokeDasharray
.isEmpty()) {
861 QVector
<qreal
>pattern(_strokeDasharray
);
862 for (int i
= 0; i
< _strokeDasharray
.size(); i
++) {
863 if (_scale
> Stroke
&& zoom
>= 12)
864 pattern
[i
] = (pow(1.5, zoom
- 12) * pattern
[i
]);
865 // QPainter pattern is specified in units of the pens width!
868 p
.setDashPattern(pattern
);
875 qreal
Style::PathRender::dy(int zoom
) const
877 return (_scale
&& zoom
>= 12) ? pow(1.5, zoom
- 12) * _dy
: _dy
;
880 qreal
Style::CircleRender::radius(int zoom
) const
882 return (_scale
&& zoom
>= 12) ? pow(1.5, zoom
- 12) * _radius
: _radius
;