diff --git a/data/svg/osmc-symbols/3rdparty/COPYRIGHT b/data/svg/osmc-symbols/3rdparty/COPYRIGHT new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/COPYRIGHT @@ -0,0 +1,11 @@ +This file explains who has the credit for all the images in this directory. + +horse.svg: Horse by Eren ÜLÜŞ from the Noun Project +heart.svg: Heart by dilayorganci from the Noun Project +tower.svg: Castle by Les Lunettes Bleues from the Noun Project +mine.svg: Mining Tools by Rob Armes from the Noun Project +hiker.svg: Hiker by National Park Service Collection from the Noun Project +bridleway.svg: By user:Andreas 06 [Public domain], via Wikimedia Commons +ammonit.svg: Shell by Caitlin McCormick from the Noun Project +shell.svg: Shell by Ricardo Luciano from the Noun Project +shell_modern.svg: Shell by B Barrett from the Noun Project diff --git a/data/svg/osmc-symbols/3rdparty/ammonit.svg b/data/svg/osmc-symbols/3rdparty/ammonit.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/ammonit.svg @@ -0,0 +1,48 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/bridleway.svg b/data/svg/osmc-symbols/3rdparty/bridleway.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/bridleway.svg @@ -0,0 +1,56 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/heart.svg b/data/svg/osmc-symbols/3rdparty/heart.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/heart.svg @@ -0,0 +1,34 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/hiker.svg b/data/svg/osmc-symbols/3rdparty/hiker.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/hiker.svg @@ -0,0 +1,46 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/horse.svg b/data/svg/osmc-symbols/3rdparty/horse.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/horse.svg @@ -0,0 +1,33 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/mine.svg b/data/svg/osmc-symbols/3rdparty/mine.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/mine.svg @@ -0,0 +1,33 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/shell.svg b/data/svg/osmc-symbols/3rdparty/shell.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/shell.svg @@ -0,0 +1,51 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/shell_modern.svg b/data/svg/osmc-symbols/3rdparty/shell_modern.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/shell_modern.svg @@ -0,0 +1,107 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/svg/osmc-symbols/3rdparty/tower.svg b/data/svg/osmc-symbols/3rdparty/tower.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/3rdparty/tower.svg @@ -0,0 +1,33 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/L.svg b/data/svg/osmc-symbols/L.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/L.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/arch.svg b/data/svg/osmc-symbols/arch.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/arch.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/backslash.svg b/data/svg/osmc-symbols/backslash.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/backslash.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/bar.svg b/data/svg/osmc-symbols/bar.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/bar.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/bowl.svg b/data/svg/osmc-symbols/bowl.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/bowl.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/circle.svg b/data/svg/osmc-symbols/circle.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/circle.svg @@ -0,0 +1,14 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/svg/osmc-symbols/corner.svg b/data/svg/osmc-symbols/corner.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/corner.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/cross.svg b/data/svg/osmc-symbols/cross.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/cross.svg @@ -0,0 +1,14 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/svg/osmc-symbols/diamond.svg b/data/svg/osmc-symbols/diamond.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/diamond.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/dot.svg b/data/svg/osmc-symbols/dot.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/dot.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/drop_line.svg b/data/svg/osmc-symbols/drop_line.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/drop_line.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/fork.svg b/data/svg/osmc-symbols/fork.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/fork.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/lower.svg b/data/svg/osmc-symbols/lower.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/lower.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/pointer.svg b/data/svg/osmc-symbols/pointer.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/pointer.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/rectangle.svg b/data/svg/osmc-symbols/rectangle.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/rectangle.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/rectangle_line.svg b/data/svg/osmc-symbols/rectangle_line.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/rectangle_line.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/slash.svg b/data/svg/osmc-symbols/slash.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/slash.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/stripe.svg b/data/svg/osmc-symbols/stripe.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/stripe.svg @@ -0,0 +1,35 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/triangle.svg b/data/svg/osmc-symbols/triangle.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/triangle.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/triangle_line.svg b/data/svg/osmc-symbols/triangle_line.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/triangle_line.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/triangle_turned.svg b/data/svg/osmc-symbols/triangle_turned.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/triangle_turned.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/turned_T.svg b/data/svg/osmc-symbols/turned_T.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/turned_T.svg @@ -0,0 +1,16 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/wolfshook.svg b/data/svg/osmc-symbols/wolfshook.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/wolfshook.svg @@ -0,0 +1,15 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/data/svg/osmc-symbols/x.svg b/data/svg/osmc-symbols/x.svg new file mode 100644 --- /dev/null +++ b/data/svg/osmc-symbols/x.svg @@ -0,0 +1,19 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/lib/marble/CMakeLists.txt b/src/lib/marble/CMakeLists.txt --- a/src/lib/marble/CMakeLists.txt +++ b/src/lib/marble/CMakeLists.txt @@ -272,6 +272,8 @@ NewstuffModel.cpp MarbleZip.cpp + OsmcSymbol.cpp + StyleBuilder.cpp BatchedPlacemarkRenderer.cpp @@ -618,6 +620,8 @@ routing/RoutingModel.h routing/RoutingProfile.h + OsmcSymbol.h + BatchedPlacemarkRenderer.h DESTINATION ${INCLUDE_INSTALL_DIR}/marble diff --git a/src/lib/marble/OsmcSymbol.h b/src/lib/marble/OsmcSymbol.h new file mode 100644 --- /dev/null +++ b/src/lib/marble/OsmcSymbol.h @@ -0,0 +1,53 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2017 Sergey Popov +// + +#ifndef OSMCSYMBOL_H +#define OSMCSYMBOL_H + +#include +#include +#include +#include + +class OsmcSymbol +{ +public: + OsmcSymbol(const QString &tag, const int side = 20); + ~OsmcSymbol(); + + QImage icon(); + QColor wayColor(); + +private: + bool parseTag(const QString &tag); + bool parseBackground(const QString &bg); + QSvgRenderer* parseForeground(const QString &fg); + + void render(); + + QColor m_wayColor; + QColor m_backgroundColor; + QString m_backgroundType; + QSvgRenderer *m_foreground; + QSvgRenderer *m_foreground2; + QString m_text; + QColor m_textColor; + + QImage m_image; + + QStringList m_backgroundTypes; + QStringList m_foregroundTypes; + QStringList m_precoloredForegroundTypes; + + int m_side; + int m_wayWidth; +}; + +#endif // OSMCSYMBOL_H diff --git a/src/lib/marble/OsmcSymbol.cpp b/src/lib/marble/OsmcSymbol.cpp new file mode 100644 --- /dev/null +++ b/src/lib/marble/OsmcSymbol.cpp @@ -0,0 +1,243 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2017 Sergey Popov +// + +#include +#include +#include +#include + +#include "OsmcSymbol.h" + +OsmcSymbol::OsmcSymbol(const QString &tag, const int side) + : m_wayColor(Qt::white) + , m_backgroundColor(Qt::black) + , m_foreground(nullptr) + , m_foreground2(nullptr) + , m_textColor(Qt::black) + , m_side(side) +{ + m_backgroundTypes + << "round" << "circle" << "frame"; + + m_foregroundTypes + << "dot" << "bowl" << "circle" << "bar" + << "stripe" << "cross" << "x" << "slash" + << "backslash" << "rectangle" << "rectangle_line" + << "triangle" << "triangle_turned" << "triangle_line" + << "diamond" << "pointer" << "fork" << "arch" + << "turned_T" << "L" << "lower" << "corner" + << "drop_line" << "horse" << "hiker"; + + m_precoloredForegroundTypes + << "wolfshook" << "shell" << "shell_modern" << "ammonit" + << "mine" << "hiker" << "heart" << "tower" << "bridleway"; + + if (parseTag(tag)) + render(); +} + +OsmcSymbol::~OsmcSymbol() +{ + if (m_foreground) + delete m_foreground; + if (m_foreground2) + delete m_foreground2; +} + +bool OsmcSymbol::parseTag(const QString &tag) +{ + QStringList parts = tag.split(":"); + + if (parts.size() < 2) { + return false; + } + + if (m_foreground) { delete m_foreground; m_foreground = nullptr; } + if (m_foreground2) { delete m_foreground2; m_foreground2 = nullptr; } + + // Determine way color + if (QColor::isValidColor(parts.at(0))) + m_wayColor.setNamedColor(parts.at(0)); + else + return false; + + if (!parseBackground(parts.at(1))) + return false; + + qDebug() << tag; + + if (parts.size() == 3) { + m_foreground = parseForeground(parts.at(2)); + } else if (parts.size() == 4) { + if (QColor::isValidColor(parts.at(3))) { + m_text = parts.at(2); + m_textColor = parts.at(3); + } else { + m_foreground = parseForeground(parts.at(2)); + m_foreground2 = parseForeground(parts.at(3)); + } + } else if (parts.size() == 5) { + m_foreground = parseForeground(parts.at(2)); + if (QColor::isValidColor(parts.at(4))) { + m_text = parts.at(3); + m_textColor = parts.at(4); + } else + return false; + } else if (parts.size() == 6) { + m_foreground = parseForeground(parts.at(2)); + m_foreground2 = parseForeground(parts.at(3)); + if (QColor::isValidColor(parts.at(5))) { + m_text = parts.at(4); + m_textColor.setNamedColor(parts.at(5)); + } else + return false; + } else + return false; + + return true; +} + +bool OsmcSymbol::parseBackground(const QString &bg) +{ + QString color = bg.section("_", 0, 0); + QString type = bg.section("_", 1, -1); + + if (!QColor::isValidColor(color)) + return false; + + // Plain color was provided + if (type.isEmpty()) { + m_backgroundColor.setNamedColor(color); + m_backgroundType = type; + } else if (m_backgroundTypes.contains(type)) { + m_backgroundColor.setNamedColor(color); + m_backgroundType = type; + } else + return false; + + return true; +} + +void setXMLAttribute(QDomElement &elem, QString tag, QString attr, QString attrValue); + +QSvgRenderer* OsmcSymbol::parseForeground(const QString &fg) +{ + if (m_precoloredForegroundTypes.contains(fg)) { + return new QSvgRenderer(QString(":/osmc-symbols/%1.svg").arg(fg)); + } + + QString color = fg.section("_", 0, 0); + QString type = fg.section("_", 1, -1); + if (QColor::isValidColor(color) && m_foregroundTypes.contains(type)) { + // Open svg resource and load contents to QByteArray + QFile file(QString(":/osmc-symbols/%1.svg").arg(type)); + file.open(QIODevice::ReadOnly); + QByteArray baData = file.readAll(); + + // Load svg contents to xml document + QDomDocument doc; + doc.setContent(baData); + + // Recurively change color + QDomElement rootElement = doc.documentElement(); + setXMLAttribute(rootElement, "path", "fill", color); + + // Create and return svg renderer with edited contents + return new QSvgRenderer(doc.toByteArray()); + } + + return nullptr; +} + +void OsmcSymbol::render() +{ + m_image = QImage(m_side, m_side, QImage::Format_ARGB32); + m_image.fill(Qt::transparent); + + QPainter painter(&m_image); + painter.setRenderHint(QPainter::Antialiasing); + + // Default size of background + int w = m_side, h = m_side; + + // If there is some text, our background size must be recalculated + if (m_text != QString()) { + QFont font = painter.font(); + font.setPixelSize(m_side * 0.8); + font.setBold(true); + painter.setFont(font); + QFontMetrics fm = QFontMetrics(font); + + w = fm.width(m_text); + h = fm.height(); + w = w > h ? w : h; + } + + const QRect bgRect = QRect((m_side - w)/2, (m_side - h)/2, w, h); + + // Draw symbol's background + if (m_backgroundType.isEmpty()) { + painter.fillRect(bgRect, m_backgroundColor); + } else if (m_backgroundType == "round") { + painter.setBrush(m_backgroundColor); + painter.setPen(m_backgroundColor); + painter.drawEllipse(bgRect); + } else if (m_backgroundType == "circle") { + painter.setBrush(Qt::white); + painter.setPen(QPen(m_backgroundColor, m_side/10)); + painter.drawEllipse(bgRect); + } else if (m_backgroundType == "frame") { + painter.setPen(QPen(m_backgroundColor, m_side/10)); + painter.fillRect(bgRect, Qt::white); + painter.drawRect(bgRect); + } + + QPixmap foregrounds(bgRect.size()); + foregrounds.fill(Qt::transparent); + QPainter fgPainter(&foregrounds); + m_foreground ? m_foreground->render(&fgPainter) : void(); + m_foreground2 ? m_foreground2->render(&fgPainter) : void(); + painter.drawPixmap(bgRect, foregrounds); + + if (m_text != QString()) { + // Draw text with provided color + painter.setPen(m_textColor); + painter.drawText(bgRect, Qt::AlignCenter, m_text); + } + + painter.end(); +} + +QImage OsmcSymbol::icon() +{ + return m_image; +} + +QColor OsmcSymbol::wayColor() +{ + return m_wayColor; +} + +void setXMLAttribute(QDomElement &elem, QString tag, QString attr, QString attrValue) +{ + // If elem's tag is equal to the provided one then overwrite desired attribute + if (elem.tagName() == tag) + elem.setAttribute(attr, attrValue); + + // Do the same for all the child nodes + for (int i = 0; i < elem.childNodes().count(); i++) + { + if (!elem.childNodes().at(i).isElement()) + continue; + + QDomElement child = elem.childNodes().at(i).toElement(); + setXMLAttribute(child, tag, attr, attrValue); + } +} diff --git a/src/lib/marble/StyleBuilder.cpp b/src/lib/marble/StyleBuilder.cpp --- a/src/lib/marble/StyleBuilder.cpp +++ b/src/lib/marble/StyleBuilder.cpp @@ -15,6 +15,7 @@ #include "MarbleDirs.h" #include "OsmPlacemarkData.h" +#include "OsmcSymbol.h" #include "GeoDataTypes.h" #include "GeoDataGeometry.h" #include "GeoDataPlacemark.h" @@ -1604,6 +1605,7 @@ GeoDataPolyStyle polyStyle = style->polyStyle(); GeoDataLineStyle lineStyle = style->lineStyle(); GeoDataLabelStyle labelStyle = style->labelStyle(); + GeoDataIconStyle iconStyle = style->iconStyle(); lineStyle.setCosmeticOutline(true); bool adjustStyle = false; @@ -1719,13 +1721,22 @@ float const width = widthValue.toFloat(&ok); lineStyle.setPhysicalWidth(ok ? qBound(0.1f, width, 200.0f) : 0.0f); } + } else if (visualCategory == GeoDataPlacemark::RouteHiking && osmData.containsTagKey(QStringLiteral("osmc:symbol"))) { + adjustStyle = true; + + QString const osmcSymbolValue = osmData.tagValue(QStringLiteral("osmc:symbol")); + OsmcSymbol symbol = OsmcSymbol(osmcSymbolValue); + + lineStyle.setColor(symbol.wayColor()); + iconStyle.setIcon(symbol.icon()); } if (adjustStyle) { GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setPolyStyle(polyStyle); newStyle->setLineStyle(lineStyle); newStyle->setLabelStyle(labelStyle); + newStyle->setIconStyle(iconStyle); style = newStyle; if (cacheSpecialStyle) { d->m_specialStyleCache.insert(specialStyleCacheKey, newStyle); diff --git a/src/lib/marble/libmarble.qrc b/src/lib/marble/libmarble.qrc --- a/src/lib/marble/libmarble.qrc +++ b/src/lib/marble/libmarble.qrc @@ -104,4 +104,38 @@ htmlfeatures/bootstrap.min.css htmlfeatures/bootstrap.inc + + ../../../data/svg/osmc-symbols/dot.svg + ../../../data/svg/osmc-symbols/bowl.svg + ../../../data/svg/osmc-symbols/circle.svg + ../../../data/svg/osmc-symbols/bar.svg + ../../../data/svg/osmc-symbols/stripe.svg + ../../../data/svg/osmc-symbols/x.svg + ../../../data/svg/osmc-symbols/backslash.svg + ../../../data/svg/osmc-symbols/slash.svg + ../../../data/svg/osmc-symbols/triangle.svg + ../../../data/svg/osmc-symbols/triangle_turned.svg + ../../../data/svg/osmc-symbols/triangle_line.svg + ../../../data/svg/osmc-symbols/diamond.svg + ../../../data/svg/osmc-symbols/rectangle.svg + ../../../data/svg/osmc-symbols/rectangle_line.svg + ../../../data/svg/osmc-symbols/pointer.svg + ../../../data/svg/osmc-symbols/fork.svg + ../../../data/svg/osmc-symbols/arch.svg + ../../../data/svg/osmc-symbols/turned_T.svg + ../../../data/svg/osmc-symbols/L.svg + ../../../data/svg/osmc-symbols/lower.svg + ../../../data/svg/osmc-symbols/corner.svg + ../../../data/svg/osmc-symbols/drop_line.svg + ../../../data/svg/osmc-symbols/wolfshook.svg + ../../../data/svg/osmc-symbols/3rdparty/ammonit.svg + ../../../data/svg/osmc-symbols/3rdparty/bridleway.svg + ../../../data/svg/osmc-symbols/3rdparty/heart.svg + ../../../data/svg/osmc-symbols/3rdparty/hiker.svg + ../../../data/svg/osmc-symbols/3rdparty/horse.svg + ../../../data/svg/osmc-symbols/3rdparty/mine.svg + ../../../data/svg/osmc-symbols/3rdparty/shell_modern.svg + ../../../data/svg/osmc-symbols/3rdparty/shell.svg + ../../../data/svg/osmc-symbols/3rdparty/tower.svg +