7#include "mapcssresult.h" 
    8#include "mapcssdeclaration_p.h" 
    9#include "mapcssexpressioncontext_p.h" 
   10#include "mapcssstate_p.h" 
   11#include "mapcssvalue_p.h" 
   13#include <osm/datatypes.h> 
   14#include <osm/languages.h> 
   21struct MapCSSResultLayerTag {
 
   24    const MapCSSDeclaration *expression = 
nullptr;
 
   26    [[nodiscard]] 
inline bool operator<(OSM::TagKey rhs)
 const 
   32class MapCSSResultLayerPrivate {
 
   34    void setTag(OSM::TagKey key, QByteArray value);
 
   35    void setTag(OSM::TagKey key, 
const MapCSSDeclaration *expression);
 
   37    std::vector<const MapCSSDeclaration*> m_declarations;
 
   38    std::vector<ClassSelectorKey> m_classes;
 
   39    std::vector<MapCSSResultLayerTag> m_tags;
 
   40    LayerSelectorKey m_layer;
 
   45MapCSSResultLayer::MapCSSResultLayer()
 
   46    : d(new MapCSSResultLayerPrivate)
 
   55    d->m_declarations.clear();
 
   58    d->m_flags = MapCSSDeclaration::NoFlag;
 
   64    return d->m_flags & MapCSSDeclaration::AreaProperty;
 
 
   69    return d->m_flags & MapCSSDeclaration::LineProperty;
 
 
   74    return d->m_flags & MapCSSDeclaration::LabelProperty;
 
 
   79    return d->m_flags & MapCSSDeclaration::ExtrudeProperty;
 
 
   84    const auto it = std::lower_bound(d->m_declarations.begin(), d->m_declarations.end(), prop, [](
auto lhs, 
auto rhs) {
 
   85        return lhs->property() < rhs;
 
   87    if (it == d->m_declarations.end() || (*it)->property() != prop) {
 
 
   95    return d->m_declarations;
 
 
   98void MapCSSResultLayer::addDeclaration(
const MapCSSDeclaration *decl)
 
  100    const auto it = std::lower_bound(d->m_declarations.begin(), d->m_declarations.end(), decl, [](
auto lhs, 
auto rhs) {
 
  101        return lhs->property() < rhs->property();
 
  103    if (it == d->m_declarations.end() || (*it)->property() != decl->property()) {
 
  104        d->m_declarations.insert(it, decl);
 
  109    d->m_flags |= decl->propertyFlags();
 
  112void MapCSSResultLayer::addClass(ClassSelectorKey cls)
 
  114    const auto it = std::lower_bound(d->m_classes.begin(), d->m_classes.end(), cls);
 
  115    if (it == d->m_classes.end() || (*it) != cls) {
 
  116        d->m_classes.insert(it, cls);
 
  122    return std::binary_search(d->m_classes.begin(), d->m_classes.end(), cls);
 
 
  132    if (
const auto it = std::lower_bound(d->m_tags.begin(), d->m_tags.end(), key); it != d->m_tags.end() && (*it).key == key) {
 
  133        if ((*it).expression) {
 
  134            MapCSSExpressionContext context{ .state = state, .result = *
this };
 
  135            auto r = (*it).expression->evaluateExpression(context).asString();
 
  136            return r.isEmpty() ? std::optional<QByteArray>() : r;
 
  140    const auto tagEnd = state.element.tagsEnd();
 
  141    if (
const auto it = std::lower_bound(state.element.tagsBegin(), tagEnd, key); it != tagEnd && (*it).key == key) {
 
 
  150    if (
const auto it = std::find_if(d->m_tags.begin(), d->m_tags.end(), [key](
const auto &tag) { return std::strcmp(tag.key.name(), key) == 0; }); it != d->m_tags.end()) {
 
  151        if ((*it).expression) {
 
  152            MapCSSExpressionContext context{ .state = state, .result = *
this };
 
  153            auto v = (*it).expression->evaluateExpression(context).asString();
 
  154            return v.isEmpty() ? std::optional<QByteArray>() : v;
 
  158    auto v = state.element.tagValue(key);
 
  159    return v.isEmpty() ? std::optional<QByteArray>() : v;
 
 
  166    if (
const auto it = std::find_if(d->m_tags.begin(), d->m_tags.end(), [key](
const auto &tag) { return std::strcmp(tag.key.name(), key) == 0; }); it != d->m_tags.end()) {
 
  167        if ((*it).expression) {
 
  168            MapCSSExpressionContext context{ .state = state, .result = *
this };
 
  169            auto v = (*it).expression->evaluateExpression(context).asString();
 
  170            return v.isEmpty() ? std::optional<QByteArray>() : v;
 
  174    auto v = state.element.tagValue(languages, key);
 
  175    return v.isEmpty() ? std::optional<QByteArray>() : v;
 
  178void MapCSSResultLayer::setLayerSelector(LayerSelectorKey layer)
 
  183void MapCSSResultLayerPrivate::setTag(OSM::TagKey key, QByteArray value)
 
  185    const auto it = std::lower_bound(m_tags.begin(), m_tags.end(), key);
 
  186    if (it == m_tags.end() || (*it).key != key) {
 
  187        m_tags.insert(it, {.key = key, .value = std::move(value), .expression = 
nullptr });
 
  189        (*it).value = std::move(value);
 
  190        (*it).expression = 
nullptr;
 
  194void MapCSSResultLayerPrivate::setTag(OSM::TagKey key, 
const MapCSSDeclaration *expression)
 
  196    const auto it = std::lower_bound(m_tags.begin(), m_tags.end(), key);
 
  197    if (it == m_tags.end() || (*it).key != key) {
 
  198        m_tags.insert(it, {.key = key, .value = {}, .expression = expression});
 
  201        (*it).expression = expression;
 
  205void MapCSSResultLayer::applyDeclarations(
const std::vector<std::unique_ptr<MapCSSDeclaration>> &declarations)
 
  208        switch (decl->type()) {
 
  209            case MapCSSDeclaration::PropertyDeclaration:
 
  210                addDeclaration(decl.get());
 
  212            case MapCSSDeclaration::ClassDeclaration:
 
  213                addClass(decl->classSelectorKey());
 
  215            case MapCSSDeclaration::TagDeclaration:
 
  216                if (decl->hasExpression()) {
 
  217                    d->setTag(decl->tagKey(), decl.get());
 
  218                } 
else if (!std::isnan(decl->doubleValue())) {
 
  221                    d->setTag(decl->tagKey(), decl->stringValue().toUtf8());
 
  229namespace KOSMIndoorMap {
 
  230class MapCSSResultPrivate {
 
  232    std::vector<MapCSSResultLayer> m_results;
 
  233    std::vector<MapCSSResultLayer> m_inactivePool; 
 
  237MapCSSResult::MapCSSResult()
 
  238    : d(new MapCSSResultPrivate)
 
  242MapCSSResult::MapCSSResult(
MapCSSResult&&) noexcept = default;
 
  248    std::move(d->m_results.begin(), d->m_results.end(), std::back_inserter(d->m_inactivePool));
 
  249    d->m_results.clear();
 
  250    std::for_each(d->m_inactivePool.begin(), d->m_inactivePool.end(), std::mem_fn(&MapCSSResultLayer::clear));
 
 
  260    const auto it = std::find_if(d->m_results.begin(), d->m_results.end(), [layer](
const auto &res) {
 
  261        return res.layerSelector() == layer;
 
  263    if (it != d->m_results.end()) {
 
  267    if (!d->m_inactivePool.empty()) {
 
  268        auto res = std::move(d->m_inactivePool.back());
 
  269        d->m_inactivePool.pop_back();
 
  270        res.setLayerSelector(layer);
 
  271        d->m_results.push_back(std::move(res));
 
  273        MapCSSResultLayer res;
 
  274        res.setLayerSelector(layer);
 
  275        d->m_results.push_back(std::move(res));
 
  277    return d->m_results.back();
 
  282    const auto it = std::find_if(d->m_results.begin(), d->m_results.end(), [layer](
const auto &res) {
 
  283        return res.layerSelector() == layer;
 
  285    if (it != d->m_results.end()) {
 
  289    if (d->m_inactivePool.empty()) {
 
  290        d->m_inactivePool.emplace_back();
 
  292    return d->m_inactivePool.back();
 
 
Result of MapCSS stylesheet evaluation for a single layer selector.
 
bool hasClass(ClassSelectorKey cls) const
Check whether this result layer has class cls set.
 
LayerSelectorKey layerSelector() const
The layer selector for this result.
 
bool hasLineProperties() const
Returns true if a way/line needs to be drawn.
 
std::optional< QByteArray > resolvedTagValue(OSM::TagKey key, const MapCSSState &state) const
Returns the tag value set by preceding declarations, via MapCSS expressions or in the source data.
 
bool hasLabelProperties() const
Returns true if a label needs to be drawn.
 
const MapCSSDeclaration * declaration(MapCSSProperty prop) const
Returns the declaration for property @prop, or nullptr is this property isn't set.
 
bool hasExtrudeProperties() const
Returns true if a 3D extrusion is requested.
 
const std::vector< const MapCSSDeclaration * > & declarations() const
The active declarations for the queried element.
 
bool hasAreaProperties() const
Returns true if an area/polygon needs to be drawn.
 
Result of MapCSS stylesheet evaluation for all layer selectors.
 
void clear()
Reset result state from a previous evaluation, while retaining previously allocated resource for reus...
 
const MapCSSResultLayer & operator[](LayerSelectorKey layer) const
Access a specific result layer selector.
 
const std::vector< MapCSSResultLayer > & results() const
Results for all layer selectors.
 
Languages in preference order to consider when looking up translated tag values.
 
OSM-based multi-floor indoor maps for buildings.
 
MapCSSProperty
Known properties in MapCSS declarations.
 
QByteArray number(double n, char format, int precision)