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 {
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)
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());
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));
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.
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)