File indexing completed on 2024-11-17 04:17:27

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "mapcssstyle.h"
0008 #include "mapcssstyle_p.h"
0009 #include "mapcssparser.h"
0010 #include "mapcssresult.h"
0011 #include "mapcssrule_p.h"
0012 #include "mapcssstate_p.h"
0013 #include "mapcsstypes.h"
0014 
0015 #include <QDebug>
0016 #include <QIODevice>
0017 
0018 using namespace KOSMIndoorMap;
0019 
0020 MapCSSStyle::MapCSSStyle()
0021     : d(new MapCSSStylePrivate)
0022 {}
0023 
0024 MapCSSStyle::MapCSSStyle(MapCSSStyle&&) noexcept = default;
0025 MapCSSStyle::~MapCSSStyle() = default;
0026 MapCSSStyle& MapCSSStyle::operator=(MapCSSStyle&&) noexcept = default;
0027 
0028 bool MapCSSStyle::isEmpty() const
0029 {
0030     return d->m_rules.empty();
0031 }
0032 
0033 void MapCSSStyle::compile(const OSM::DataSet &dataSet)
0034 {
0035     d->m_areaKey = dataSet.tagKey("area");
0036     d->m_typeKey = dataSet.tagKey("type");
0037     for (const auto &rule : d->m_rules) {
0038         rule->compile(dataSet);
0039     }
0040 }
0041 
0042 void MapCSSStyle::evaluate(MapCSSState &&state, MapCSSResult &result) const
0043 {
0044     result.clear();
0045 
0046     // determine object type of the input element
0047     // This involves tag lookups (and thus cost), but as long as there is at least
0048     // one area and one line selector for each zoom level this is break-even. In practice
0049     // there are actually many more than that, which means this is a useful optimization
0050     // over doing this in MapCSSBasicSelector after checking for the zoom level
0051     switch (state.element.type()) {
0052         case OSM::Type::Null:
0053             Q_UNREACHABLE();
0054         case OSM::Type::Node:
0055             state.objectType = MapCSSObjectType::Node;
0056             break;
0057         case OSM::Type::Way:
0058         {
0059             if (!state.element.way()->isClosed()) {
0060                 state.objectType = MapCSSObjectType::Line;
0061                 break;
0062             }
0063             const auto area = state.element.tagValue(d->m_areaKey);
0064             if (area == "yes") {
0065                 state.objectType = MapCSSObjectType::Area;
0066             } else {
0067                 state.objectType = MapCSSObjectType::LineOrArea;
0068             }
0069             break;
0070         }
0071         case OSM::Type::Relation:
0072             state.objectType = state.element.tagValue(d->m_typeKey) == "multipolygon" ? MapCSSObjectType::Area : MapCSSObjectType::Relation;
0073             break;
0074     }
0075 
0076     for (const auto &rule : d->m_rules) {
0077         rule->evaluate(state, result);
0078     }
0079 }
0080 
0081 void MapCSSStyle::evaluateCanvas(const MapCSSState &state, MapCSSResult &result) const
0082 {
0083     result.clear();
0084     for (const auto &rule : d->m_rules) {
0085         rule->evaluateCanvas(state, result);
0086     }
0087 }
0088 
0089 void MapCSSStyle::write(QIODevice *out) const
0090 {
0091     for (const auto &rule : d->m_rules) {
0092         rule->write(out);
0093     }
0094 }
0095 
0096 ClassSelectorKey MapCSSStyle::classKey(const char *className) const
0097 {
0098     return d->m_classSelectorRegistry.key(className);
0099 }
0100 
0101 LayerSelectorKey MapCSSStyle::layerKey(const char *layerName) const
0102 {
0103     return d->m_layerSelectorRegistry.key(layerName);
0104 }