Commit 9fe0134b authored by Volker Krause's avatar Volker Krause
Browse files

Implement basic tag setting in MapCSS evaluation

We only use that to allow changing the layer tag from CSS rules so far.

This allows fixing buildings placed on two high layers above their
interior for a number of major railway stations for example. This is
caused by the layer tag being (ab)used as a z-inded for the outdoor
renderer there, but not being consistently applied to all elements.

In those cases we cap the layer to 0 now. More such rules are likely
needed though, there are more scenarios where layer tags interfere.
But that's much easier to extend now that this can be specified as a
simple CSS rule.
parent 016b4fb4
Pipeline #277659 passed with stage
in 7 minutes and 7 seconds
......@@ -251,6 +251,13 @@ area[tunnel]
{
z-index: -1;
}
/** Cap building layers, this is much more often a data issue than actually intended and
* causes misrenderings as building content then gets covered.
*/
area[building][layer>0]
{
set layer=0;
}
/** Airports */
......
......@@ -273,7 +273,7 @@ void SceneController::updateElement(OSM::Element e, int level, SceneGraph &sg, c
item->brush.setStyle(Qt::NoBrush);
}
addItem(sg, e, level, result.layerSelector(), std::move(baseItem));
addItem(sg, e, level, result, std::move(baseItem));
} else if (result.hasLineProperties()) {
auto baseItem = sg.findOrCreatePayload<PolylineItem>(e, level, result.layerSelector());
auto item = static_cast<PolylineItem*>(baseItem.get());
......@@ -294,7 +294,7 @@ void SceneController::updateElement(OSM::Element e, int level, SceneGraph &sg, c
finalizePen(item->casingPen, casingOpacity);
d->m_labelPlacementPath = item->path;
addItem(sg, e, level, result.layerSelector(), std::move(baseItem));
addItem(sg, e, level, result, std::move(baseItem));
}
if (result.hasLabelProperties()) {
......@@ -462,7 +462,7 @@ void SceneController::updateElement(OSM::Element e, int level, SceneGraph &sg, c
}
if (!item->icon.isNull() || !item->text.text().isEmpty()) {
addItem(sg, e, level, result.layerSelector(), std::move(baseItem));
addItem(sg, e, level, result, std::move(baseItem));
}
}
}
......@@ -643,17 +643,20 @@ void SceneController::finalizePen(QPen &pen, double opacity) const
}
}
void SceneController::addItem(SceneGraph &sg, OSM::Element e, int level, LayerSelectorKey layerSelector, std::unique_ptr<SceneGraphItemPayload> &&payload) const
void SceneController::addItem(SceneGraph &sg, OSM::Element e, int level, const MapCSSResultItem &result, std::unique_ptr<SceneGraphItemPayload> &&payload) const
{
SceneGraphItem item;
item.element = e;
item.layerSelector = layerSelector;
item.layerSelector = result.layerSelector();
item.level = level;
item.payload = std::move(payload);
// get the OSM layer, if set
if (!d->m_overlay) {
const auto layerStr = e.tagValue(d->m_layerTag);
auto layerStr = result.tagValue(d->m_layerTag);
if (layerStr.isNull()) {
layerStr = e.tagValue(d->m_layerTag);
}
if (!layerStr.isEmpty()) {
bool success = false;
const auto layer = layerStr.toInt(&success);
......
......@@ -67,7 +67,7 @@ private:
void initializePen(QPen &pen) const;
void finalizePen(QPen &pen, double opacity) const;
void addItem(SceneGraph &sg, OSM::Element e, int level, LayerSelectorKey layerSelector, std::unique_ptr<SceneGraphItemPayload> &&payload) const;
void addItem(SceneGraph &sg, OSM::Element e, int level, const MapCSSResultItem &result, std::unique_ptr<SceneGraphItemPayload> &&payload) const;
std::unique_ptr<SceneControllerPrivate> d;
};
......
......@@ -179,6 +179,11 @@ QVector<double> MapCSSDeclaration::dashesValue() const
return m_dashValue;
}
OSM::TagKey MapCSSDeclaration::tagKey() const
{
return m_tagKey;
}
void MapCSSDeclaration::setDoubleValue(double val)
{
m_doubleValue = val;
......@@ -304,6 +309,10 @@ void MapCSSDeclaration::compile(const OSM::DataSet &dataSet)
{
Q_UNUSED(dataSet);
// TODO resolve tag key if m_identValue is one
if (m_type == TagDeclaration) {
// TODO handle the case that the tag isn't actually available in dataSet
m_tagKey = dataSet.tagKey(m_identValue.constData());
}
}
void MapCSSDeclaration::write(QIODevice *out) const
......
......@@ -10,6 +10,8 @@
#include "kosmindoormap_export.h"
#include "mapcsstypes.h"
#include <osm/datatypes.h>
#include <QByteArray>
#include <QColor>
#include <QFont>
......@@ -141,6 +143,9 @@ public:
/** Line dashes. */
QVector<double> dashesValue() const;
/** Tag key of the tag to change in a tag setting declaration. */
OSM::TagKey tagKey() const;
Qt::PenCapStyle capStyle() const;
Qt::PenJoinStyle joinStyle() const;
QFont::Capitalization capitalizationStyle() const;
......@@ -185,6 +190,7 @@ private:
double m_doubleValue = NAN;
QVector<double> m_dashValue;
QString m_stringValue;
OSM::TagKey m_tagKey;
ClassSelectorKey m_class;
Unit m_unit = NoUnit;
Type m_type;
......
......@@ -6,6 +6,8 @@
#include "mapcssresult_p.h"
#include <osm/datatypes.h>
#include <algorithm>
using namespace KOSMIndoorMap;
......@@ -17,6 +19,7 @@ void MapCSSResultItem::clear()
{
m_declarations.clear();
m_classes.clear();
m_tags.clear();
m_flags = MapCSSDeclaration::NoFlag;
m_layer = {};
}
......@@ -84,11 +87,30 @@ LayerSelectorKey MapCSSResultItem::layerSelector() const
return m_layer;
}
QByteArray MapCSSResultItem::tagValue(OSM::TagKey key) const
{
const auto it = std::lower_bound(m_tags.begin(), m_tags.end(), key);
if (it != m_tags.end() && (*it).key == key) {
return (*it).value;
}
return {};
}
void MapCSSResultItem::setLayerSelector(LayerSelectorKey layer)
{
m_layer = layer;
}
void MapCSSResultItem::setTag(OSM::Tag &&tag)
{
const auto it = std::lower_bound(m_tags.begin(), m_tags.end(), tag);
if (it == m_tags.end() || (*it).key != tag.key) {
m_tags.insert(it, std::move(tag));
} else {
(*it) = std::move(tag);
}
}
MapCSSResult::MapCSSResult() = default;
MapCSSResult::~MapCSSResult() = default;
......
......@@ -12,6 +12,11 @@
#include <vector>
namespace OSM {
class Tag;
class TagKey;
}
namespace KOSMIndoorMap {
/** Result of MapCSS stylesheet evaluation for a single layer selector. */
......@@ -38,15 +43,20 @@ public:
/** The layer selector for this result. */
LayerSelectorKey layerSelector() const;
/** Tag lookup for tags overridden by the style sheet. */
QByteArray tagValue(OSM::TagKey key) const;
/** @internal */
void addDeclaration(const MapCSSDeclaration *decl);
void addClass(ClassSelectorKey cls);
bool hasClass(ClassSelectorKey cls) const;
void setLayerSelector(LayerSelectorKey layer);
void setTag(OSM::Tag &&tag);
private:
std::vector<const MapCSSDeclaration*> m_declarations;
std::vector<ClassSelectorKey> m_classes;
std::vector<OSM::Tag> m_tags;
LayerSelectorKey m_layer;
int m_flags = 0;
};
......
......@@ -11,6 +11,8 @@
#include <QDebug>
#include <QIODevice>
#include <cmath>
using namespace KOSMIndoorMap;
MapCSSRule::MapCSSRule() = default;
......@@ -37,8 +39,11 @@ void MapCSSRule::evaluate(const MapCSSState &state, MapCSSResult &result) const
result[layer].addClass(decl->classSelectorKey());
break;
case MapCSSDeclaration::TagDeclaration:
// TODO
qDebug() << "MapCSS tag declaration not implemented yet.";
if (!std::isnan(decl->doubleValue())) {
result[layer].setTag(OSM::Tag{decl->tagKey(), QByteArray::number(decl->doubleValue())});
} else {
result[layer].setTag(OSM::Tag{decl->tagKey(), decl->stringValue().toUtf8()});
}
break;
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment