From c7c4f990366739e66bcea6ed8cb2539268527c43 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 08:17:06 +0200 Subject: [PATCH 1/8] [core] Add ["text-section"] expression New expression evaluates to formatted section id (string | number) that can be used within decision expressions, such as 'match' or 'case', so that each formatted section can have different paint properties. --- include/mbgl/style/expression/dsl.hpp | 1 + include/mbgl/style/expression/expression.hpp | 15 ++- .../style/expression/format_expression.hpp | 15 +-- include/mbgl/style/expression/formatted.hpp | 22 +++- include/mbgl/style/property_expression.hpp | 103 ++++++------------ src/core-files.json | 1 + src/mbgl/style/conversion/function.cpp | 2 +- .../style/expression/compound_expression.cpp | 11 ++ src/mbgl/style/expression/dsl.cpp | 10 +- .../style/expression/format_expression.cpp | 62 +++++++++-- src/mbgl/style/expression/formatted.cpp | 42 ++++--- src/mbgl/style/expression/is_constant.cpp | 9 +- src/mbgl/style/property_expression.cpp | 68 ++++++++++++ 13 files changed, 240 insertions(+), 121 deletions(-) create mode 100644 src/mbgl/style/property_expression.cpp diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index bd94a765e73..fcbca25941b 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -82,6 +82,7 @@ std::unique_ptr concat(std::vector> inpu std::unique_ptr format(const char* value); std::unique_ptr format(std::unique_ptr); +std::unique_ptr textSection(); } // namespace dsl } // namespace expression diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 97b143b3d92..d868b17e004 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -25,18 +25,25 @@ class EvaluationError { class EvaluationContext { public: - EvaluationContext(float zoom_) : zoom(zoom_), feature(nullptr) {} - EvaluationContext(GeometryTileFeature const * feature_) : zoom(optional()), feature(feature_) {} + EvaluationContext() = default; + explicit EvaluationContext(float zoom_) : zoom(zoom_) {} + EvaluationContext(GeometryTileFeature const * feature_) : feature(feature_) {} EvaluationContext(float zoom_, GeometryTileFeature const * feature_) : zoom(zoom_), feature(feature_) {} EvaluationContext(optional zoom_, GeometryTileFeature const * feature_, optional colorRampParameter_) : zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_)) {} - + + EvaluationContext& withFormattedSection(const Value* formattedSection_) noexcept { + formattedSection = formattedSection_; + return *this; + }; + optional zoom; - GeometryTileFeature const * feature; + GeometryTileFeature const * feature = nullptr; optional colorRampParameter; + const Value* formattedSection = nullptr; }; template diff --git a/include/mbgl/style/expression/format_expression.hpp b/include/mbgl/style/expression/format_expression.hpp index b00674a88ef..09feaf4819c 100644 --- a/include/mbgl/style/expression/format_expression.hpp +++ b/include/mbgl/style/expression/format_expression.hpp @@ -1,11 +1,7 @@ #pragma once #include -#include #include -#include - -#include namespace mbgl { namespace style { @@ -14,16 +10,18 @@ namespace expression { struct FormatExpressionSection { FormatExpressionSection(std::unique_ptr text_, optional> fontScale_, - optional> textFont_); + optional> textFont_, + optional> sectionID_); std::shared_ptr text; optional> fontScale; optional> textFont; + optional> sectionID; }; -class FormatExpression : public Expression { +class FormatExpression final : public Expression { public: - FormatExpression(std::vector sections); + explicit FormatExpression(std::vector sections); EvaluationResult evaluate(const EvaluationContext&) const override; static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); @@ -42,9 +40,6 @@ class FormatExpression : public Expression { std::string getOperator() const override { return "format"; } private: std::vector sections; - std::unique_ptr text; - optional> fontScale; - optional> textFont; }; } // namespace expression diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp index 9e7e7308cb1..28964de9419 100644 --- a/include/mbgl/style/expression/formatted.hpp +++ b/include/mbgl/style/expression/formatted.hpp @@ -12,15 +12,33 @@ namespace mbgl { namespace style { namespace expression { +extern const char* const kFormattedSectionFontScale; +extern const char* const kFormattedSectionTextFont; +extern const char* const kFormattedSectionID; + +using FormattedSectionID = variant; + +template +optional toFormattedSectionID(const Variant& variant) { + return variant.match( + [] (double t) -> FormattedSectionID { return t; }, + [] (const std::string& t) -> FormattedSectionID { return t;}, + [] (auto&) -> optional { return nullopt; }); +} + struct FormattedSection { - FormattedSection(std::string text_, optional fontScale_, optional fontStack_) + FormattedSection(std::string text_, optional fontScale_, + optional fontStack_, optional id_) : text(std::move(text_)) , fontScale(std::move(fontScale_)) , fontStack(std::move(fontStack_)) + , id(std::move(id_)) {} + std::string text; optional fontScale; optional fontStack; + optional id; }; class Formatted { @@ -28,7 +46,7 @@ class Formatted { Formatted() = default; Formatted(const char* plainU8String) { - sections.emplace_back(std::string(plainU8String), nullopt, nullopt); + sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt); } Formatted(std::vector sections_) diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp index b198de02b22..43e80dfac48 100644 --- a/include/mbgl/style/property_expression.hpp +++ b/include/mbgl/style/property_expression.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -11,46 +10,38 @@ namespace mbgl { namespace style { -template -class PropertyExpression { +class PropertyExpressionBase { public: - // Second parameter to be used only for conversions from legacy functions. - PropertyExpression(std::unique_ptr expression_, optional defaultValue_ = {}) - : expression(std::move(expression_)), - defaultValue(std::move(defaultValue_)), - zoomCurve(expression::findZoomCurveChecked(expression.get())) { - } + explicit PropertyExpressionBase(std::unique_ptr); - bool isZoomConstant() const { return expression::isZoomConstant(*expression); } - bool isFeatureConstant() const { return expression::isFeatureConstant(*expression); } + bool isZoomConstant() const noexcept; + bool isFeatureConstant() const noexcept; + bool canEvaluateWith(const expression::EvaluationContext&) const noexcept; + float interpolationFactor(const Range&, const float) const noexcept; + Range getCoveringStops(const float, const float) const noexcept; + const expression::Expression& getExpression() const noexcept; - T evaluate(float zoom) const { - assert(!expression::isZoomConstant(*expression)); - assert(expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(zoom, nullptr)); - if (result) { - const optional typed = expression::fromExpressionValue(*result); - return typed ? *typed : defaultValue ? *defaultValue : T(); - } - return defaultValue ? *defaultValue : T(); - } + bool useIntegerZoom = false; - template - T evaluate(const Feature& feature, T finalDefaultValue) const { - assert(expression::isZoomConstant(*expression)); - assert(!expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(&feature)); - if (result) { - const optional typed = expression::fromExpressionValue(*result); - return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; - } - return defaultValue ? *defaultValue : finalDefaultValue; +protected: + std::shared_ptr expression; + variant zoomCurve; + bool isZoomConstant_; + bool isFeatureConstant_; +}; + +template +class PropertyExpression final : public PropertyExpressionBase { +public: + // Second parameter to be used only for conversions from legacy functions. + PropertyExpression(std::unique_ptr expression_, optional defaultValue_ = {}) + : PropertyExpressionBase(std::move(expression_)), + defaultValue(std::move(defaultValue_)) { } - template - T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { - assert(!expression::isFeatureConstant(*expression)); - const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext({zoom}, &feature)); + T evaluate(const expression::EvaluationContext& context, T finalDefaultValue = T()) const { + assert(canEvaluateWith(context)); + const expression::EvaluationResult result = expression->evaluate(context); if (result) { const optional typed = expression::fromExpressionValue(*result); return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; @@ -58,59 +49,29 @@ class PropertyExpression { return defaultValue ? *defaultValue : finalDefaultValue; } - float interpolationFactor(const Range& inputLevels, const float inputValue) const { - return zoomCurve.match( - [](std::nullptr_t) { - assert(false); - return 0.0f; - }, - [&](const expression::Interpolate* z) { - return z->interpolationFactor(Range { inputLevels.min, inputLevels.max }, inputValue); - }, - [&](const expression::Step*) { - return 0.0f; - } - ); + T evaluate(float zoom) const { + return evaluate(expression::EvaluationContext(zoom)); } - Range getCoveringStops(const float lower, const float upper) const { - return zoomCurve.match( - [](std::nullptr_t) { - assert(false); - return Range(0.0f, 0.0f); - }, - [&](auto z) { - return z->getCoveringStops(lower, upper); - } - ); + T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(&feature), finalDefaultValue); } - // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange - template - Range evaluate(const Range& zoomRange, const Feature& feature, T finalDefaultValue) { - return Range { - evaluate(zoomRange.min, feature, finalDefaultValue), - evaluate(zoomRange.max, feature, finalDefaultValue) - }; + T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(zoom, &feature), finalDefaultValue); } std::vector> possibleOutputs() const { return expression::fromExpressionValues(expression->possibleOutputs()); } - const expression::Expression& getExpression() const { return *expression; } - - bool useIntegerZoom = false; - friend bool operator==(const PropertyExpression& lhs, const PropertyExpression& rhs) { return *lhs.expression == *rhs.expression; } private: - std::shared_ptr expression; optional defaultValue; - variant zoomCurve; }; } // namespace style diff --git a/src/core-files.json b/src/core-files.json index 42a30a3ea87..f27bd268bdd 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -223,6 +223,7 @@ "src/mbgl/style/light.cpp", "src/mbgl/style/light_impl.cpp", "src/mbgl/style/parser.cpp", + "src/mbgl/style/property_expression.cpp", "src/mbgl/style/source.cpp", "src/mbgl/style/source_impl.cpp", "src/mbgl/style/sources/custom_geometry_source.cpp", diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index 5877d0eb7cc..79ad2fc7d80 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -41,7 +41,7 @@ bool hasTokens(const std::string& source) { std::unique_ptr convertTokenStringToFormatExpression(const std::string& source) { auto textExpression = convertTokenStringToExpression(source); std::vector sections; - sections.emplace_back(std::move(textExpression), nullopt, nullopt); + sections.emplace_back(std::move(textExpression), nullopt, nullopt, nullopt); return std::make_unique(sections); } diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index cc1d58025bc..27dfe6c151d 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -662,6 +662,16 @@ const auto& errorCompoundExpression() { return signature; } +const auto& textSectionCompoundExpression() { + static auto signature = detail::makeSignature("text-section", [](const EvaluationContext& params) -> Result { + if (!params.formattedSection) { + return EvaluationError {"Formatted section is unavailable in the current evaluation context."}; + } + return *params.formattedSection; + }); + return signature; +} + // Legacy Filters const auto& filterEqualsCompoundExpression() { static auto signature = detail::makeSignature("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result { @@ -907,6 +917,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry = mapbox::eternal { "concat", concatCompoundExpression }, { "resolved-locale", resolvedLocaleCompoundExpression }, { "error", errorCompoundExpression }, + { "text-section", textSectionCompoundExpression }, // Legacy Filters { "filter-==", filterEqualsCompoundExpression }, { "filter-id-==", filterIdEqualsCompoundExpression }, diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp index f5ff83a9e7f..f999c90b07f 100644 --- a/src/mbgl/style/expression/dsl.cpp +++ b/src/mbgl/style/expression/dsl.cpp @@ -189,13 +189,17 @@ std::unique_ptr concat(std::vector> inpu std::unique_ptr format(const char* value) { return std::make_unique(Formatted(value)); } - + std::unique_ptr format(std::unique_ptr input) { std::vector sections; - sections.emplace_back(std::move(input), nullopt, nullopt); + sections.emplace_back(std::move(input), nullopt, nullopt, nullopt); return std::make_unique(sections); } - + +std::unique_ptr textSection() { + return compound("text-section"); +} + } // namespace dsl } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/format_expression.cpp b/src/mbgl/style/expression/format_expression.cpp index 144df4b1608..57204313b48 100644 --- a/src/mbgl/style/expression/format_expression.cpp +++ b/src/mbgl/style/expression/format_expression.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include -#include +#include namespace mbgl { namespace style { @@ -10,15 +8,21 @@ namespace expression { FormatExpressionSection::FormatExpressionSection(std::unique_ptr text_, optional> fontScale_, - optional> textFont_) + optional> textFont_, + optional> sectionID_) : text(std::move(text_)) { if (fontScale_) { fontScale = std::shared_ptr(std::move(*fontScale_)); } + if (textFont_) { textFont = std::shared_ptr(std::move(*textFont_)); } + + if (sectionID_) { + sectionID = std::shared_ptr(std::move(*sectionID_)); + } } FormatExpression::FormatExpression(std::vector sections_) @@ -53,7 +57,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct return ParseResult(); } - const optional fontScaleOption = objectMember(options, "font-scale"); + const optional fontScaleOption = objectMember(options, kFormattedSectionFontScale); ParseResult fontScale; if (fontScaleOption) { fontScale = ctx.parse(*fontScaleOption, 1, {type::Number}); @@ -62,7 +66,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct } } - const optional textFontOption = objectMember(options, "text-font"); + const optional textFontOption = objectMember(options, kFormattedSectionTextFont); ParseResult textFont; if (textFontOption) { textFont = ctx.parse(*textFontOption, 1, {type::Array(type::String)}); @@ -70,7 +74,20 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct return ParseResult(); } } - sections.emplace_back(std::move(*text), std::move(fontScale), std::move(textFont)); + + const optional sectionIDOption = objectMember(options, kFormattedSectionID); + ParseResult sectionID; + if (sectionIDOption) { + sectionID = ctx.parse(*sectionIDOption, 1, {type::Value}); + if (!sectionID) { + return ParseResult(); + } + } + + sections.emplace_back(std::move(*text), + std::move(fontScale), + std::move(textFont), + std::move(sectionID)); } return ParseResult(std::make_unique(std::move(sections))); @@ -85,6 +102,9 @@ void FormatExpression::eachChild(const std::function& f if (section.textFont) { fn(**section.textFont); } + if (section.sectionID) { + fn(**section.sectionID); + } } } @@ -108,6 +128,10 @@ bool FormatExpression::operator==(const Expression& e) const { (!lhsSection.textFont && rhsSection.textFont)) { return false; } + if ((lhsSection.sectionID && (!rhsSection.sectionID || **lhsSection.sectionID != **rhsSection.sectionID)) || + (!lhsSection.sectionID && rhsSection.sectionID)) { + return false; + } } return true; } @@ -115,15 +139,18 @@ bool FormatExpression::operator==(const Expression& e) const { } mbgl::Value FormatExpression::serialize() const { - std::vector serialized{{ std::string("format") }}; + std::vector serialized{{ getOperator() }}; for (const auto& section : sections) { serialized.push_back(section.text->serialize()); std::unordered_map options; if (section.fontScale) { - options.emplace("font-scale", (*section.fontScale)->serialize()); + options.emplace(kFormattedSectionFontScale, (*section.fontScale)->serialize()); } if (section.textFont) { - options.emplace("text-font", (*section.textFont)->serialize()); + options.emplace(kFormattedSectionTextFont, (*section.textFont)->serialize()); + } + if (section.sectionID) { + options.emplace(kFormattedSectionID, (*section.sectionID)->serialize()); } serialized.push_back(options); } @@ -164,7 +191,20 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con } evaluatedTextFont = *textFontValue; } - evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont); + + optional evaluatedID; + if (section.sectionID) { + auto sectionIDResult = (*section.sectionID)->evaluate(params); + if (!sectionIDResult) { + return sectionIDResult.error(); + } + + evaluatedID = toFormattedSectionID(*sectionIDResult); + if (!evaluatedID) { + return EvaluationError { "Format section id option must evaluate to string or number" }; + } + } + evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont, evaluatedID); } return Formatted(evaluatedSections); } diff --git a/src/mbgl/style/expression/formatted.cpp b/src/mbgl/style/expression/formatted.cpp index 8232d0c6981..fef834b20c0 100644 --- a/src/mbgl/style/expression/formatted.cpp +++ b/src/mbgl/style/expression/formatted.cpp @@ -1,18 +1,15 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include namespace mbgl { namespace style { - namespace expression { +const char* const kFormattedSectionFontScale = "font-scale"; +const char* const kFormattedSectionTextFont = "text-font"; +const char* const kFormattedSectionID = "id"; + bool Formatted::operator==(const Formatted& other) const { if (other.sections.size() != sections.size()) { return false; @@ -22,14 +19,14 @@ bool Formatted::operator==(const Formatted& other) const { const auto& otherSection = other.sections.at(i); if (thisSection.text != otherSection.text || thisSection.fontScale != otherSection.fontScale || - thisSection.fontStack != otherSection.fontStack) { + thisSection.fontStack != otherSection.fontStack || + thisSection.id != otherSection.id) { return false; } } return true; } - - + std::string Formatted::toString() const { std::string result; for (const auto& section : sections) { @@ -37,7 +34,7 @@ std::string Formatted::toString() const { } return result; } - + } // namespace expression namespace conversion { @@ -65,6 +62,7 @@ optional Converter::operator()(const Convertible& value, E optional fontScale; optional textFont; + optional id; if (sectionLength > 1) { Convertible sectionParams = arrayMember(section, 1); if (!isObject(sectionParams)) { @@ -72,12 +70,12 @@ optional Converter::operator()(const Convertible& value, E return nullopt; } - optional fontScaleMember = objectMember(sectionParams, "font-scale"); + optional fontScaleMember = objectMember(sectionParams, kFormattedSectionFontScale); if (fontScaleMember) { fontScale = toDouble(*fontScaleMember); } - optional textFontMember = objectMember(sectionParams, "text-font"); + optional textFontMember = objectMember(sectionParams, kFormattedSectionTextFont); if (textFontMember) { if (isArray(*textFontMember)) { std::vector fontsVector; @@ -96,9 +94,23 @@ optional Converter::operator()(const Convertible& value, E return nullopt; } } + + optional sectionIDMember = objectMember(sectionParams, kFormattedSectionID); + if (sectionIDMember) { + auto result = toValue(*sectionIDMember); + if (!result) { + return nullopt; + } + + id = toFormattedSectionID(*result); + if (!id) { + error.message = "Section id has to be a string or a number."; + return nullopt; + } + } } - sections.push_back(FormattedSection(*sectionText, fontScale, textFont)); + sections.push_back(FormattedSection(*sectionText, fontScale, textFont, id)); } return Formatted(sections); } else if (optional result = toString(value)) { diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp index 3b20f49a861..8ac362373c8 100644 --- a/src/mbgl/style/expression/is_constant.cpp +++ b/src/mbgl/style/expression/is_constant.cpp @@ -17,15 +17,16 @@ bool isFeatureConstant(const Expression& expression) { return false; } else if (name == "has" && parameterCount && *parameterCount == 1) { return false; - } else if (0 == name.rfind(filter, 0)) { - // Legacy filters begin with "filter-" and are never constant. - return false; } else if ( name == "properties" || name == "geometry-type" || - name == "id" + name == "id" || + name == "text-section" ) { return false; + } else if (0 == name.rfind(filter, 0)) { + // Legacy filters begin with "filter-" and are never constant. + return false; } } diff --git a/src/mbgl/style/property_expression.cpp b/src/mbgl/style/property_expression.cpp new file mode 100644 index 00000000000..6ba0416ad3f --- /dev/null +++ b/src/mbgl/style/property_expression.cpp @@ -0,0 +1,68 @@ +#include + +namespace mbgl { +namespace style { + +PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr expression_) + : expression(std::move(expression_)), + zoomCurve(expression::findZoomCurveChecked(expression.get())) { + isZoomConstant_ = expression::isZoomConstant(*expression); + isFeatureConstant_ = expression::isFeatureConstant(*expression); +} + +bool PropertyExpressionBase::isZoomConstant() const noexcept { + return isZoomConstant_; +} + +bool PropertyExpressionBase::isFeatureConstant() const noexcept { + return isFeatureConstant_; +} + +bool PropertyExpressionBase::canEvaluateWith(const expression::EvaluationContext& context) const noexcept { + if (context.zoom) { + if (context.feature != nullptr) { + return !isFeatureConstant(); + } + return !isZoomConstant() && isFeatureConstant(); + } + + if (context.feature != nullptr) { + return isZoomConstant() && !isFeatureConstant(); + } + + return true; +} + +float PropertyExpressionBase::interpolationFactor(const Range& inputLevels, const float inputValue) const noexcept { + return zoomCurve.match( + [](std::nullptr_t) { + assert(false); + return 0.0f; + }, + [&](const expression::Interpolate* z) { + return z->interpolationFactor(Range { inputLevels.min, inputLevels.max }, inputValue); + }, + [&](const expression::Step*) { + return 0.0f; + } + ); +} + +Range PropertyExpressionBase::getCoveringStops(const float lower, const float upper) const noexcept { + return zoomCurve.match( + [](std::nullptr_t) { + assert(false); + return Range(0.0f, 0.0f); + }, + [&](auto z) { + return z->getCoveringStops(lower, upper); + } + ); +} + +const expression::Expression& PropertyExpressionBase::getExpression() const noexcept { + return *expression; +} + +} // namespace style +} // namespace mbgl From f72b2add0cf523ee1b69cffc03a24b1f18c0df74 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 08:43:00 +0200 Subject: [PATCH 2/8] [core] Unit test for text-section compound expression --- test/style/property_expression.test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/style/property_expression.test.cpp b/test/style/property_expression.test.cpp index e4ee5f115fb..a7d1d256602 100644 --- a/test/style/property_expression.test.cpp +++ b/test/style/property_expression.test.cpp @@ -121,3 +121,17 @@ TEST(PropertyExpression, Issue8460) { EXPECT_NEAR(600.0f, fn2.evaluate(18.0f, oneInteger, -1.0f), 0.00); EXPECT_NEAR(600.0f, fn2.evaluate(19.0f, oneInteger, -1.0f), 0.00); } + +TEST(PropertyExpression, TextSection) { + expression::Value formattedSection1 = 42.0; + PropertyExpression ts1(textSection()); + EXPECT_DOUBLE_EQ(42.0, ts1.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection1))); + + expression::Value formattedSection2{"header"s}; + PropertyExpression ts2(textSection()); + EXPECT_EQ("header"s, ts2.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection2))); + + // Evaluates to default, T(). + PropertyExpression ts3(textSection()); + EXPECT_EQ(Color(), ts3.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection1))); +} From 6802a2ec5c0bce57ac51462f123792f475c58419 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 08:58:23 +0200 Subject: [PATCH 3/8] [core] Add unit test for TaggedString --- test/text/tagged_string.test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/text/tagged_string.test.cpp b/test/text/tagged_string.test.cpp index 3c58ccd94bb..de74126db83 100644 --- a/test/text/tagged_string.test.cpp +++ b/test/text/tagged_string.test.cpp @@ -4,6 +4,7 @@ #include using namespace mbgl; +using namespace std::literals; TEST(TaggedString, Trim) { TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, 0)); @@ -25,3 +26,19 @@ TEST(TaggedString, Trim) { noTrim.trim(); EXPECT_EQ(noTrim.rawText(), u"no trim!"); } + +TEST(TaggedString, MultipleSections) { + TaggedString oneSection(u"One section", SectionOptions(1.0f, {})); + EXPECT_FALSE(oneSection.hasMultipleUniqueSections()); + + TaggedString twoSections; + twoSections.addSection(u"first section", 1.5f, {}); + twoSections.addSection(u"second section", 0.5f, {}); + EXPECT_FALSE(twoSections.hasMultipleUniqueSections()); + + TaggedString multipleSections(u"", SectionOptions(1.0f, {})); + multipleSections.addSection(u"title", 1.5f, {"DIN Offc Pro Bold"s, "Arial Unicode MS Bold"s}, {"header"s}); + multipleSections.addSection(u"content", 1.5f, {"DIN Offc Pro Italic"s, "Arial Unicode MS Regular"s}, {"footer"s}); + + EXPECT_TRUE(multipleSections.hasMultipleUniqueSections()); +} From 3bfdb110646f33953fe7c44a6f4db7cdbb540d6a Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 09:21:39 +0200 Subject: [PATCH 4/8] [core] Assign formatted section index to quads --- platform/default/src/mbgl/text/bidi.cpp | 2 +- platform/qt/src/bidi.cpp | 2 +- src/mbgl/text/bidi.hpp | 2 +- src/mbgl/text/glyph.hpp | 8 +++++--- src/mbgl/text/quads.cpp | 2 +- src/mbgl/text/quads.hpp | 7 +++++-- src/mbgl/text/shaping.cpp | 7 ++++--- src/mbgl/text/tagged_string.cpp | 24 ++++++++++++++++++++---- src/mbgl/text/tagged_string.hpp | 25 ++++++++++++++++++------- test/text/bidi.test.cpp | 10 +++++----- test/text/tagged_string.test.cpp | 10 +++++----- test/util/merge_lines.test.cpp | 2 +- 12 files changed, 67 insertions(+), 34 deletions(-) diff --git a/platform/default/src/mbgl/text/bidi.cpp b/platform/default/src/mbgl/text/bidi.cpp index 32a3dc23ef5..8e30017f5ff 100644 --- a/platform/default/src/mbgl/text/bidi.cpp +++ b/platform/default/src/mbgl/text/bidi.cpp @@ -148,7 +148,7 @@ std::vector BiDi::processStyledText(const StyledText& input, std::se // Each time we see a change in style, render a reversed chunk // of everything since the last change std::size_t styleRunStart = logicalEnd; - uint8_t currentStyleIndex = styleIndices.at(styleRunStart - 1); + std::size_t currentStyleIndex = styleIndices.at(styleRunStart - 1); for (std::size_t i = logicalEnd - 1; i >= logicalStart; i--) { if (currentStyleIndex != styleIndices.at(i) || i == logicalStart) { std::size_t styleRunEnd = i == logicalStart ? i : i + 1; diff --git a/platform/qt/src/bidi.cpp b/platform/qt/src/bidi.cpp index 6b680a97691..a99398959ad 100644 --- a/platform/qt/src/bidi.cpp +++ b/platform/qt/src/bidi.cpp @@ -41,7 +41,7 @@ std::vector BiDi::processStyledText(const StyledText& input, std::se for (std::size_t lineBreakPoint : lineBreakPoints) { transformedLines.emplace_back( input.first.substr(start, lineBreakPoint - start), - std::vector(input.second.begin() + start, input.second.begin() + lineBreakPoint)); + std::vector(input.second.begin() + start, input.second.begin() + lineBreakPoint)); start = lineBreakPoint; } diff --git a/src/mbgl/text/bidi.hpp b/src/mbgl/text/bidi.hpp index 5ce2887db86..8680e6f7e52 100644 --- a/src/mbgl/text/bidi.hpp +++ b/src/mbgl/text/bidi.hpp @@ -18,7 +18,7 @@ std::u16string applyArabicShaping(const std::u16string&); // the styling options to use for rendering that code point // The data structure is intended to accomodate the reordering/interleaving // of formatting that can happen when BiDi rearranges inputs -using StyledText = std::pair>; +using StyledText = std::pair>; class BiDi : private util::noncopyable { public: diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index 034784dc243..c97b242c107 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -19,7 +19,7 @@ namespace mbgl { using GlyphID = char16_t; using GlyphIDs = std::set; - + // Note: this only works for the BMP GlyphRange getGlyphRange(GlyphID glyph); @@ -59,8 +59,8 @@ using GlyphMap = std::map; class PositionedGlyph { public: - explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_, FontStackHash font_, float scale_) - : glyph(glyph_), x(x_), y(y_), vertical(vertical_), font(font_), scale(scale_) + explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_, FontStackHash font_, float scale_, std::size_t sectionIndex_ = 0) + : glyph(glyph_), x(x_), y(y_), vertical(vertical_), font(font_), scale(scale_), sectionIndex(sectionIndex_) {} GlyphID glyph = 0; @@ -70,6 +70,8 @@ class PositionedGlyph { FontStackHash font = 0; float scale = 0.0; + // Maps positioned glyph to TaggedString section + std::size_t sectionIndex; }; enum class WritingModeType : uint8_t; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 9d582f14d61..ec0045caad4 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -172,7 +172,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, br = util::matrixMultiply(matrix, br); } - quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset); + quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset, positionedGlyph.sectionIndex); } return quads; diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index 44a35a50147..f41a4fec66e 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -20,14 +20,16 @@ class SymbolQuad { Point br_, Rect tex_, WritingModeType writingMode_, - Point glyphOffset_) + Point glyphOffset_, + size_t sectionIndex_ = 0) : tl(std::move(tl_)), tr(std::move(tr_)), bl(std::move(bl_)), br(std::move(br_)), tex(std::move(tex_)), writingMode(writingMode_), - glyphOffset(glyphOffset_) {} + glyphOffset(glyphOffset_), + sectionIndex(sectionIndex_){} Point tl; Point tr; @@ -36,6 +38,7 @@ class SymbolQuad { Rect tex; WritingModeType writingMode; Point glyphOffset; + size_t sectionIndex; }; using SymbolQuads = std::vector; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 3a6335955b0..02dbf146e12 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -299,7 +299,8 @@ void shapeLines(Shaping& shaping, std::size_t lineStartIndex = shaping.positionedGlyphs.size(); for (std::size_t i = 0; i < line.length(); i++) { - const SectionOptions& section = line.getSection(i); + const std::size_t sectionIndex = line.getSectionIndex(i); + const SectionOptions& section = line.sectionAt(sectionIndex); char16_t codePoint = line.getCharCodeAt(i); auto glyphs = glyphMap.find(section.fontStackHash); if (glyphs == glyphMap.end()) { @@ -318,10 +319,10 @@ void shapeLines(Shaping& shaping, const Glyph& glyph = **it->second; if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(codePoint)) { - shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale); + shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale, sectionIndex); x += glyph.metrics.advance * section.scale + spacing; } else { - shaping.positionedGlyphs.emplace_back(codePoint, x, baselineOffset, true, section.fontStackHash, section.scale); + shaping.positionedGlyphs.emplace_back(codePoint, x, baselineOffset, true, section.fontStackHash, section.scale, sectionIndex); x += verticalHeight * section.scale + spacing; } } diff --git a/src/mbgl/text/tagged_string.cpp b/src/mbgl/text/tagged_string.cpp index 851e011c4f8..3755ad3a284 100644 --- a/src/mbgl/text/tagged_string.cpp +++ b/src/mbgl/text/tagged_string.cpp @@ -1,11 +1,12 @@ #include +#include #include namespace mbgl { -void TaggedString::addSection(const std::u16string& sectionText, double scale, FontStackHash fontStack) { +void TaggedString::addSection(const std::u16string& sectionText, double scale, FontStack fontStack, const optional& id) { styledText.first += sectionText; - sections.emplace_back(scale, fontStack); + sections.emplace_back(scale, fontStack, id); styledText.second.resize(styledText.first.size(), sections.size() - 1); } @@ -19,14 +20,14 @@ void TaggedString::trim() { std::size_t trailingWhitespace = styledText.first.find_last_not_of(u" \t\n\v\f\r") + 1; styledText.first = styledText.first.substr(beginningWhitespace, trailingWhitespace - beginningWhitespace); - styledText.second = std::vector(styledText.second.begin() + beginningWhitespace, styledText.second.begin() + trailingWhitespace); + styledText.second = std::vector(styledText.second.begin() + beginningWhitespace, styledText.second.begin() + trailingWhitespace); } } double TaggedString::getMaxScale() const { double maxScale = 0.0; for (std::size_t i = 0; i < styledText.first.length(); i++) { - maxScale = std::max(maxScale, getSection(i).scale); + maxScale = util::max(maxScale, getSection(i).scale); } return maxScale; } @@ -36,4 +37,19 @@ void TaggedString::verticalizePunctuation() { styledText.first = util::i18n::verticalizePunctuation(styledText.first); } +bool TaggedString::hasMultipleUniqueSections() const noexcept { + if (sections.size() < 2) { + return false; + } + + const auto& id = sections.at(0).id; + for (std::size_t i = 1; i < sections.size(); ++i) { + if (id != sections.at(i).id) { + return true; + } + } + + return false; +} + } // namespace mbgl diff --git a/src/mbgl/text/tagged_string.hpp b/src/mbgl/text/tagged_string.hpp index 476c2225f08..c40c2537533 100644 --- a/src/mbgl/text/tagged_string.hpp +++ b/src/mbgl/text/tagged_string.hpp @@ -1,17 +1,22 @@ #pragma once -#include #include +#include +#include namespace mbgl { +using style::expression::FormattedSectionID; + struct SectionOptions { - SectionOptions(double scale_, FontStackHash fontStackHash_) - : scale(scale_), fontStackHash(fontStackHash_) + SectionOptions(double scale_, FontStack fontStack_, const optional& id_ = {}) + : scale(scale_), fontStackHash(FontStackHasher()(fontStack_)), fontStack(std::move(fontStack_)), id(std::move(id_)) {} double scale; FontStackHash fontStackHash; + FontStack fontStack; + optional id; }; /** @@ -34,7 +39,7 @@ struct TaggedString { TaggedString(std::u16string text_, SectionOptions options) : styledText(std::move(text_), - std::vector(text_.size(), 0)) { + std::vector(text_.size(), 0)) { sections.push_back(std::move(options)); } @@ -71,7 +76,11 @@ struct TaggedString { return styledText; } - void addSection(const std::u16string& text, double scale, FontStackHash fontStack); + void addSection(const std::u16string& text, + double scale, + FontStack fontStack, + const optional& id = {}); + const SectionOptions& sectionAt(std::size_t index) const { return sections.at(index); } @@ -80,7 +89,7 @@ struct TaggedString { return sections; } - uint8_t getSectionIndex(std::size_t characterIndex) const { + std::size_t getSectionIndex(std::size_t characterIndex) const { return styledText.second.at(characterIndex); } @@ -88,7 +97,9 @@ struct TaggedString { void trim(); void verticalizePunctuation(); - + + bool hasMultipleUniqueSections() const noexcept; + private: StyledText styledText; std::vector sections; diff --git a/test/text/bidi.test.cpp b/test/text/bidi.test.cpp index 7c0eb828845..a3a2ac12a8d 100644 --- a/test/text/bidi.test.cpp +++ b/test/text/bidi.test.cpp @@ -61,27 +61,27 @@ TEST(BiDi, StyledText) { std::vector expected; StyledText input( applyArabicShaping(u"مكتبة الإسكندرية‎‎ Maktabat al-Iskandarīyah"), - std::vector{ 0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,4,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7 } + std::vector{ 0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,4,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7 } ); expected.emplace_back(StyledText( u"ﺔﺒﺘﻜﻣ", - std::vector{ 0,0,0,0,0 } + std::vector{ 0,0,0,0,0 } )); EXPECT_EQ(expected.rbegin()->first.size(), expected.rbegin()->second.size()); expected.emplace_back(StyledText( u" ‎‎ﺔﻳﺭﺪﻨﻜﺳﻹﺍ ", - std::vector{ 2,2,2,2,2,2,2,1,1,1,1,1,1 } + std::vector{ 2,2,2,2,2,2,2,1,1,1,1,1,1 } )); EXPECT_EQ(expected.rbegin()->first.size(), expected.rbegin()->second.size()); expected.emplace_back(StyledText( u"Maktabat al-", - std::vector{ 2,3,3,3,3,3,4,5,5,5,5,6 } + std::vector{ 2,3,3,3,3,3,4,5,5,5,5,6 } )); EXPECT_EQ(expected.rbegin()->first.size(), expected.rbegin()->second.size()); expected.emplace_back(StyledText( u"Iskandarīyah", - std::vector{ 6,6,6,6,6,6,6,6,6,7,7,7 } + std::vector{ 6,6,6,6,6,6,6,6,6,7,7,7 } )); EXPECT_EQ(expected.rbegin()->first.size(), expected.rbegin()->second.size()); diff --git a/test/text/tagged_string.test.cpp b/test/text/tagged_string.test.cpp index de74126db83..d3a2176eba5 100644 --- a/test/text/tagged_string.test.cpp +++ b/test/text/tagged_string.test.cpp @@ -7,22 +7,22 @@ using namespace mbgl; using namespace std::literals; TEST(TaggedString, Trim) { - TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, 0)); + TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, {})); basic.trim(); EXPECT_EQ(basic.rawText(), u"trim that and not this"); TaggedString twoSections; - twoSections.addSection(u" \t\ntrim that", 1.5f, 1); - twoSections.addSection(u" and not this \n\t", 0.5f, 2); + twoSections.addSection(u" \t\ntrim that", 1.5f, {}); + twoSections.addSection(u" and not this \n\t", 0.5f, {}); twoSections.trim(); EXPECT_EQ(twoSections.rawText(), u"trim that and not this"); - TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, 0)); + TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, {})); empty.trim(); EXPECT_EQ(empty.rawText(), u""); - TaggedString noTrim(u"no trim!", SectionOptions(1.0f, 0)); + TaggedString noTrim(u"no trim!", SectionOptions(1.0f, {})); noTrim.trim(); EXPECT_EQ(noTrim.rawText(), u"no trim!"); } diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp index f76a1ea72a5..1d4b0d230ef 100644 --- a/test/util/merge_lines.test.cpp +++ b/test/util/merge_lines.test.cpp @@ -25,7 +25,7 @@ class SymbolFeatureStub : public SymbolFeature { SymbolFeature(std::make_unique(std::move(id_), type_, std::move(geometry_), std::move(properties_))) { if (text_) { - formattedText = TaggedString(*text_, SectionOptions(1.0, 0)); + formattedText = TaggedString(*text_, SectionOptions(1.0, {})); } icon = std::move(icon_); index = index_; From 39dcc92f2a1e8ab20bba312f474d34f818be248e Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 09:37:22 +0200 Subject: [PATCH 5/8] [core] Populate symbol layer paint properties for text sections --- src/mbgl/layout/symbol_layout.cpp | 126 +++++++++++--------- src/mbgl/layout/symbol_layout.hpp | 18 ++- src/mbgl/renderer/buckets/symbol_bucket.hpp | 15 +-- src/mbgl/renderer/paint_property_binder.hpp | 38 +++--- 4 files changed, 102 insertions(+), 95 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index edacaf9dda7..e95fb56c1df 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -1,25 +1,16 @@ -#include #include #include #include -#include #include #include #include -#include #include #include -#include #include -#include #include #include #include -#include -#include -#include #include -#include #include #include @@ -31,11 +22,23 @@ using namespace style; template static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { return layout.get().match( - [&] (const typename Property::Type& t) { return !t.empty(); }, - [&] (const auto&) { return true; } + [] (const typename Property::Type& t) { return !t.empty(); }, + [] (const auto&) { return true; } ); } +namespace { +expression::Value sectionOptionsToValue(const SectionOptions& options) { + if (options.id) { + return (*options.id).match( + [] (double t) -> expression::Value { return t; }, + [] (const std::string& t) -> expression::Value { return t; }, + [] (auto&) -> expression::Value { return {}; }); + } + return {}; +} +} // namespace + SymbolLayout::SymbolLayout(const BucketParameters& parameters, const std::vector& layers, std::unique_ptr sourceLayer_, @@ -108,7 +111,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, auto formatted = layout.evaluate(zoom, ft); auto textTransform = layout.evaluate(zoom, ft); FontStack baseFontStack = layout.evaluate(zoom, ft); - FontStackHash baseFontStackHash = FontStackHasher()(baseFontStack); ft.formattedText = TaggedString(); for (std::size_t j = 0; j < formatted.sections.size(); j++) { @@ -122,8 +124,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.formattedText->addSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)), section.fontScale ? *section.fontScale : 1.0, - section.fontStack ? FontStackHasher()(*section.fontStack) : baseFontStackHash); - + section.fontStack ? *section.fontStack : baseFontStack, + section.id); } @@ -418,43 +420,57 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr sizeData = bucket->textSizeBinder->getVertexSizeData(feature); - bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, symbolInstance.writingModes, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedTextIndex = bucket->text.placedSymbols.size() - 1; - PlacedSymbol& horizontalSymbol = bucket->text.placedSymbols.back(); - - bool firstHorizontal = true; - for (const auto& symbol : symbolInstance.horizontalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, horizontalSymbol); - if (firstHorizontal) { - horizontalSymbol.vertexStartIndex = index; - firstHorizontal = false; - } + if (hasText && feature.formattedText) { + const auto& formattedText = *feature.formattedText; + std::function updatePaintProperties; + if (formattedText.hasMultipleUniqueSections()) { + updatePaintProperties = [&, currentSectionIndex = optional{}](std::size_t symbolSectionIndex, bool updateLastSection) mutable { + if (currentSectionIndex && (updateLastSection || *currentSectionIndex != symbolSectionIndex)) { + const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(*currentSectionIndex)); + for (auto& pair : bucket->paintProperties) { + pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); + } + } + currentSectionIndex = symbolSectionIndex; + }; + } else { + updatePaintProperties = [&](std::size_t, bool updateLastSection) { + if (updateLastSection) { + const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(0)); + for (auto& pair : bucket->paintProperties) { + pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); + } + } + }; } - if (symbolInstance.writingModes & WritingModeType::Vertical) { + const Range sizeData = bucket->textSizeBinder->getVertexSizeData(feature); + auto addSymbolGlyphQuads = [&](WritingModeType writingMode, + optional& placedIndex, + const SymbolQuads& glyphQuads) { bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, WritingModeType::Vertical, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedVerticalTextIndex = bucket->text.placedSymbols.size() - 1; - - PlacedSymbol& verticalSymbol = bucket->text.placedSymbols.back(); - bool firstVertical = true; - - for (const auto& symbol : symbolInstance.verticalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, verticalSymbol); - - if (firstVertical) { - verticalSymbol.vertexStartIndex = index; - firstVertical = false; + symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); + placedIndex = bucket->text.placedSymbols.size() - 1; + PlacedSymbol& placedSymbol = bucket->text.placedSymbols.back(); + + bool firstSymbol = true; + for (const auto& symbolQuad : glyphQuads) { + updatePaintProperties(symbolQuad.sectionIndex, false); + size_t index = addSymbol(bucket->text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol); + if (firstSymbol) { + placedSymbol.vertexStartIndex = index; + firstSymbol = false; } } + }; + + addSymbolGlyphQuads(symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); + + if (symbolInstance.writingModes & WritingModeType::Vertical) { + addSymbolGlyphQuads(WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads); } + + updatePaintProperties(0, true); } if (hasIcon) { @@ -466,12 +482,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptricon.placedSymbols.back(); iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad, symbolInstance.anchor, iconSymbol); - } - } - for (auto& pair : bucket->paintProperties) { - pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.vertexSize(), {}, {}); - pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}); + for (auto& pair : bucket->paintProperties) { + pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.vertexSize(), {}, {}); + } + } } } @@ -489,12 +504,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr -size_t SymbolLayout::addSymbol(Buffer& buffer, - const Range sizeData, - const SymbolQuad& symbol, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol) { +size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, + const Range sizeData, + const SymbolQuad& symbol, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol) { constexpr const uint16_t vertexLength = 4; const auto &tl = symbol.tl; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index ab6dc049a2a..870ad4b4150 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -6,18 +6,15 @@ #include #include #include -#include -#include +#include #include #include -#include #include namespace mbgl { class BucketParameters; -class SymbolBucket; class Anchor; class RenderLayer; class PlacedSymbol; @@ -26,7 +23,7 @@ namespace style { class Filter; } // namespace style -class SymbolLayout : public Layout { +class SymbolLayout final : public Layout { public: SymbolLayout(const BucketParameters&, const std::vector&, @@ -62,12 +59,11 @@ class SymbolLayout : public Layout { void addToDebugBuffers(SymbolBucket&); // Adds placed items to the buffer. - template - size_t addSymbol(Buffer&, - const Range sizeData, - const SymbolQuad&, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol); + size_t addSymbol(SymbolBucket::Buffer&, + const Range sizeData, + const SymbolQuad&, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 5b9b11cf4d6..ecf9a861df8 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -87,7 +87,7 @@ class SymbolBucket final : public Bucket { std::unique_ptr textSizeBinder; - struct TextBuffer { + struct Buffer { gl::VertexVector vertices; gl::VertexVector> dynamicVertices; gl::VertexVector> opacityVertices; @@ -103,19 +103,8 @@ class SymbolBucket final : public Bucket { std::unique_ptr iconSizeBinder; - struct IconBuffer { - gl::VertexVector vertices; - gl::VertexVector> dynamicVertices; - gl::VertexVector> opacityVertices; - gl::IndexVector triangles; - SegmentVector segments; - std::vector placedSymbols; + struct IconBuffer : public Buffer { PremultipliedImage atlasImage; - - optional> vertexBuffer; - optional>> dynamicVertexBuffer; - optional>> opacityVertexBuffer; - optional> indexBuffer; } icon; struct CollisionBuffer { diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 56f187507f2..9659384d330 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -95,7 +95,10 @@ class PaintPropertyBinder { virtual ~PaintPropertyBinder() = default; - virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) = 0; + virtual void populateVertexVector(const GeometryTileFeature& feature, + std::size_t length, const ImagePositions&, + const optional&, + const style::expression::Value&) = 0; virtual void upload(gl::Context& context) = 0; virtual void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) = 0; virtual std::tuple>...> attributeBinding(const PossiblyEvaluatedType& currentValue) const = 0; @@ -108,13 +111,13 @@ class PaintPropertyBinder { }; template -class ConstantPaintPropertyBinder : public PaintPropertyBinder, A> { +class ConstantPaintPropertyBinder final : public PaintPropertyBinder, A> { public: ConstantPaintPropertyBinder(T constant_) : constant(std::move(constant_)) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&) override {} + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&, const style::expression::Value&) override {} void upload(gl::Context&) override {} void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) override {}; @@ -135,13 +138,13 @@ class ConstantPaintPropertyBinder : public PaintPropertyBinder -class ConstantCrossFadedPaintPropertyBinder : public PaintPropertyBinder,PossiblyEvaluatedPropertyValue>, As...> { +class ConstantCrossFadedPaintPropertyBinder final : public PaintPropertyBinder,PossiblyEvaluatedPropertyValue>, As...> { public: ConstantCrossFadedPaintPropertyBinder(Faded constant_) : constant(std::move(constant_)), constantPatternPositions({}) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&) override {} + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&, const style::expression::Value&) override {} void upload(gl::Context&) override {} void setPatternParameters(const optional& posA, const optional& posB, CrossfadeParameters&) override { @@ -171,7 +174,7 @@ class ConstantCrossFadedPaintPropertyBinder : public PaintPropertyBinder -class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder, A> { +class SourceFunctionPaintPropertyBinder final : public PaintPropertyBinder, A> { public: using BaseAttributeType = A; using BaseAttributeValue = typename A::Value; @@ -184,8 +187,9 @@ class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) override { - auto evaluated = expression.evaluate(feature, defaultValue); + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + using style::expression::EvaluationContext; + auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { @@ -226,7 +230,7 @@ class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder -class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder, A> { +class CompositeFunctionPaintPropertyBinder final : public PaintPropertyBinder, A> { public: using AttributeType = ZoomInterpolatedAttributeType; @@ -239,8 +243,12 @@ class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) override { - Range range = expression.evaluate(zoomRange, feature, defaultValue); + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + using style::expression::EvaluationContext; + Range range = { + expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue), + expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSection(&formattedSection), defaultValue), + }; this->statistics.add(range.min); this->statistics.add(range.max); AttributeValue value = zoomInterpolatedAttributeValue( @@ -289,7 +297,7 @@ class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder -class CompositeCrossFadedPaintPropertyBinder : public PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2> { +class CompositeCrossFadedPaintPropertyBinder final : public PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2> { public: using AttributeType = ZoomInterpolatedAttributeType; using AttributeType2 = ZoomInterpolatedAttributeType; @@ -313,7 +321,7 @@ class CompositeCrossFadedPaintPropertyBinder : public PaintPropertyBinder& patternDependencies) override { + void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value&) override { if (patternDependencies->mid.empty()) { // Unlike other propperties with expressions that evaluate to null, the default value for `*-pattern` properties is an empty @@ -475,9 +483,9 @@ class PaintPropertyBinders> { PaintPropertyBinders(PaintPropertyBinders&&) = default; PaintPropertyBinders(const PaintPropertyBinders&) = delete; - void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies) { + void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value& formattedSection = {}) { util::ignore({ - (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies), 0)... + (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSection), 0)... }); } From b1fcbd5b50eb525623c369cd97a75cfcf7078257 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 09:46:19 +0200 Subject: [PATCH 6/8] [core] Add benchmark for style that uses text-section expression --- benchmark/api/render.benchmark.cpp | 12 + .../fixtures/api/style_formatted_labels.json | 3996 +++++++++++++++++ 2 files changed, 4008 insertions(+) create mode 100644 benchmark/fixtures/api/style_formatted_labels.json diff --git a/benchmark/api/render.benchmark.cpp b/benchmark/api/render.benchmark.cpp index a1b557777fa..80542a1a6c5 100644 --- a/benchmark/api/render.benchmark.cpp +++ b/benchmark/api/render.benchmark.cpp @@ -49,6 +49,17 @@ static void API_renderStill_reuse_map(::benchmark::State& state) { } } +static void API_renderStill_reuse_map_formatted_labels(::benchmark::State& state) { + RenderBenchmark bench; + HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool }; + Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, bench.fileSource, bench.threadPool, MapMode::Static}; + prepare(map, util::read_file("benchmark/fixtures/api/style_formatted_labels.json")); + + while (state.KeepRunning()) { + frontend.render(map); + } +} + static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) { RenderBenchmark bench; HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool }; @@ -74,5 +85,6 @@ static void API_renderStill_recreate_map(::benchmark::State& state) { } BENCHMARK(API_renderStill_reuse_map); +BENCHMARK(API_renderStill_reuse_map_formatted_labels); BENCHMARK(API_renderStill_reuse_map_switch_styles); BENCHMARK(API_renderStill_recreate_map); diff --git a/benchmark/fixtures/api/style_formatted_labels.json b/benchmark/fixtures/api/style_formatted_labels.json new file mode 100644 index 00000000000..efd258ef02b --- /dev/null +++ b/benchmark/fixtures/api/style_formatted_labels.json @@ -0,0 +1,3996 @@ +{ + "version": 8, + "name": "Mapbox Streets", + "metadata": { + "mapbox:autocomposite": true, + "mapbox:type": "default", + "mapbox:groups": { + "1444934828655.3389": { "name": "Aeroways", "collapsed": true }, + "1444933322393.2852": { "name": "POI labels (scalerank 1)", "collapsed": true }, + "1444855786460.0557": { "name": "Roads", "collapsed": true }, + "1444933575858.6992": { "name": "Highway shields", "collapsed": true }, + "1444934295202.7542": { "name": "Admin boundaries", "collapsed": true }, + "1444856151690.9143": { "name": "State labels", "collapsed": true }, + "1444933721429.3076": { "name": "Road labels", "collapsed": true }, + "1444933358918.2366": { "name": "POI labels (scalerank 2)", "collapsed": true }, + "1444933808272.805": { "name": "Water labels", "collapsed": true }, + "1444933372896.5967": { "name": "POI labels (scalerank 3)", "collapsed": true }, + "1444855799204.86": { "name": "Bridges", "collapsed": true }, + "1444856087950.3635": { "name": "Marine labels", "collapsed": true }, + "1456969573402.7817": { "name": "Hillshading", "collapsed": true }, + "1444862510685.128": { "name": "City labels", "collapsed": true }, + "1444855769305.6016": { "name": "Tunnels", "collapsed": true }, + "1456970288113.8113": { "name": "Landcover", "collapsed": true }, + "1444856144497.7825": { "name": "Country labels", "collapsed": true }, + "1444933456003.5437": { "name": "POI labels (scalerank 4)", "collapsed": true } + } + }, + "sources": { + "composite": { "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7", "type": "vector" } + }, + "sprite": "mapbox://sprites/mapbox/streets-v10", + "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", + "visibility": "public", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {}, + "paint": { + "background-color": { "base": 1, "stops": [ [ 11, "hsl(35, 32%, 91%)" ], [ 13, "hsl(35, 12%, 89%)" ] ] } + } + }, + { + "id": "landcover_snow", + "type": "fill", + "metadata": { "mapbox:group": "1456970288113.8113" }, + "source": "composite", + "source-layer": "landcover", + "filter": [ "==", "class", "snow" ], + "layout": {}, + "paint": { "fill-color": "hsl(0, 0%, 100%)", "fill-opacity": 0.2, "fill-antialias": false } + }, + { + "id": "landcover_wood", + "type": "fill", + "metadata": { "mapbox:group": "1456970288113.8113" }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ "==", "class", "wood" ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "landcover_scrub", + "type": "fill", + "metadata": { "mapbox:group": "1456970288113.8113" }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ "==", "class", "scrub" ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "landcover_grass", + "type": "fill", + "metadata": { "mapbox:group": "1456970288113.8113" }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ "==", "class", "grass" ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "landcover_crop", + "type": "fill", + "metadata": { "mapbox:group": "1456970288113.8113" }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ "==", "class", "crop" ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "national_park", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "filter": [ "==", "class", "national_park" ], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": { "base": 1, "stops": [ [ 5, 0 ], [ 6, 0.5 ] ] } + } + }, + { + "id": "hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "hospital" ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(340, 37%, 87%)" ], [ 16, "hsl(340, 63%, 89%)" ] ] } + } + }, + { + "id": "school", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "school" ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(50, 47%, 81%)" ], [ 16, "hsl(50, 63%, 84%)" ] ] } + } + }, + { + "id": "park", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "park" ], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": { "base": 1, "stops": [ [ 5, 0 ], [ 6, 1 ] ] } + } + }, + { + "id": "pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "pitch" ], + "layout": {}, + "paint": { "fill-color": "hsl(100, 57%, 72%)" } + }, + { + "id": "pitch-line", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "minzoom": 15, + "filter": [ "==", "class", "pitch" ], + "layout": { "line-join": "miter" }, + "paint": { "line-color": "hsl(75, 57%, 84%)" } + }, + { + "id": "cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "cemetery" ], + "layout": {}, + "paint": { "fill-color": "hsl(75, 37%, 81%)" } + }, + { + "id": "industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "industrial" ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(230, 15%, 86%)" ], [ 16, "hsl(230, 29%, 89%)" ] ] } + } + }, + { + "id": "sand", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ "==", "class", "sand" ], + "layout": {}, + "paint": { "fill-color": "hsl(60, 46%, 87%)" } + }, + { + "id": "hillshade_highlight_bright", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 94 ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": { "stops": [ [ 14, 0.12 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "hillshade_highlight_med", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 90 ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": { "stops": [ [ 14, 0.12 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_faint", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 89 ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { "stops": [ [ 14, 0.05 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_med", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 78 ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { "stops": [ [ 14, 0.05 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_dark", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 67 ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { "stops": [ [ 14, 0.06 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_extreme", + "type": "fill", + "metadata": { "mapbox:group": "1456969573402.7817" }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ "==", "level", 56 ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { "stops": [ [ 14, 0.06 ], [ 16, 0 ] ] }, + "fill-antialias": false + } + }, + { + "id": "waterway-river-canal", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 8, + "filter": [ "in", "class", "canal", "river" ], + "layout": { + "line-cap": { "base": 1, "stops": [ [ 0, "butt" ], [ 11, "round" ] ] }, + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": { "base": 1.3, "stops": [ [ 8.5, 0.1 ], [ 20, 8 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 8, 0 ], [ 8.5, 1 ] ] } + } + }, + { + "id": "waterway-small", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 13, + "filter": [ "!in", "class", "canal", "river" ], + "layout": { "line-join": "round", "line-cap": "round" }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": { "base": 1.35, "stops": [ [ 13.5, 0.1 ], [ 20, 3 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 13, 0 ], [ 13.5, 1 ] ] } + } + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(215, 84%, 69%)", + "fill-translate": { "base": 1.2, "stops": [ [ 7, [ 0, 0 ] ], [ 16, [ -1, -1 ] ] ] }, + "fill-translate-anchor": "viewport", + "fill-opacity": 1 + } + }, + { "id": "water", "ref": "water-shadow", "paint": { "fill-color": "hsl(196, 80%, 70%)" } }, + { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ "all", [ "==", "$type", "Polygon" ], [ "==", "class", "land" ] ], + "layout": {}, + "paint": { "fill-color": "hsl(35, 12%, 89%)" } + }, + { + "id": "barrier_line-land-line", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "class", "land" ] ], + "layout": { "line-cap": "round" }, + "paint": { + "line-width": { "base": 1.99, "stops": [ [ 14, 0.75 ], [ 20, 40 ] ] }, + "line-color": "hsl(35, 12%, 89%)" + } + }, + { + "id": "aeroway-polygon", + "type": "fill", + "metadata": { "mapbox:group": "1444934828655.3389" }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ "all", [ "==", "$type", "Polygon" ], [ "!=", "type", "apron" ] ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] }, + "fill-opacity": { "base": 1, "stops": [ [ 11, 0 ], [ 11.5, 1 ] ] } + } + }, + { + "id": "aeroway-runway", + "type": "line", + "metadata": { "mapbox:group": "1444934828655.3389" }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "runway" ] ], + "layout": {}, + "paint": { + "line-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 9, 1 ], [ 18, 80 ] ] } + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "metadata": { "mapbox:group": "1444934828655.3389" }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "taxiway" ] ], + "layout": {}, + "paint": { + "line-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 10, 0.5 ], [ 18, 20 ] ] } + } + }, + { + "id": "building-line", + "type": "line", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ "all", [ "!=", "type", "building:part" ], [ "==", "underground", "false" ] ], + "layout": {}, + "paint": { + "line-color": "hsl(35, 6%, 79%)", + "line-width": { "base": 1.5, "stops": [ [ 15, 0.75 ], [ 20, 3 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 15.5, 0 ], [ 16, 1 ] ] } + } + }, + { + "id": "building", + "type": "fill", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ "all", [ "!=", "type", "building:part" ], [ "==", "underground", "false" ] ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 15, "hsl(35, 11%, 88%)" ], [ 16, "hsl(35, 8%, 85%)" ] ] }, + "fill-opacity": { "base": 1, "stops": [ [ 15.5, 0 ], [ 16, 1 ] ] }, + "fill-outline-color": "hsl(35, 6%, 79%)" + } + }, + { + "id": "tunnel-street-low", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "tunnel-street_limited-low", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "tunnel-service-link-track-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "service", "track" ], + [ "==", "structure", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-dasharray": [ 3, 3 ] + } + }, + { + "id": "tunnel-street_limited-case", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-street_limited-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-dasharray": [ 3, 3 ], + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "tunnel-street-case", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-street-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-dasharray": [ 3, 3 ], + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "tunnel-secondary-tertiary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "in", "class", "secondary", "tertiary" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] }, + "line-dasharray": [ 3, 3 ], + "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-primary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "primary" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-dasharray": [ 3, 3 ], + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-trunk_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "trunk_link" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-dasharray": [ 3, 3 ] + } + }, + { + "id": "tunnel-motorway_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "motorway_link" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-dasharray": [ 3, 3 ] + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "trunk" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-opacity": 1, + "line-dasharray": [ 3, 3 ] + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "motorway" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-opacity": 1, + "line-dasharray": [ 3, 3 ] + } + }, + { + "id": "tunnel-construction", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "construction" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-join": "miter" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }, + "line-dasharray": { + "base": 1, + "stops": [ + [ 14, [ 0.4, 0.8 ] ], + [ 15, [ 0.3, 0.6 ] ], + [ 16, [ 0.2, 0.3 ] ], + [ 17, [ 0.2, 0.25 ] ], + [ 18, [ 0.15, 0.15 ] ] + ] + } + } + }, + { + "id": "tunnel-path", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "path" ], + [ "==", "structure", "tunnel" ], + [ "!=", "type", "steps" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] }, + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "tunnel-steps", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "steps" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] }, + "line-color": "hsl(35, 26%, 95%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "tunnel-trunk_link", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-trunk_link-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(46, 77%, 78%)", + "line-opacity": 1, + "line-dasharray": [ 1, 0 ] + } + }, + { + "id": "tunnel-motorway_link", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-motorway_link-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(26, 100%, 78%)", + "line-opacity": 1, + "line-dasharray": [ 1, 0 ] + } + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] } + } + }, + { + "id": "tunnel-service-link-track", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-service-link-track-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [ 1, 0 ] + } + }, + { + "id": "tunnel-street_limited", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-street_limited-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "tunnel-street", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-street-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "tunnel-secondary-tertiary", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-secondary-tertiary-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [ 1, 0 ], + "line-blur": 0 + } + }, + { + "id": "tunnel-primary", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-primary-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [ 1, 0 ], + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "path", "pedestrian", "service", "track" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-trunk", + "type": "line", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "trunk" ], [ "==", "structure", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(46, 77%, 78%)" + } + }, + { + "id": "tunnel-motorway", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "ref": "tunnel-motorway-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-dasharray": [ 1, 0 ], + "line-opacity": 1, + "line-color": "hsl(26, 100%, 78%)", + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-white", + "type": "symbol", + "metadata": { "mapbox:group": "1444855769305.6016" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "motorway", "motorway_link", "trunk" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "tunnel" ], + [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "ferry" ] ], + "layout": { "line-join": "round" }, + "paint": { + "line-color": { "base": 1, "stops": [ [ 15, "hsl(205, 73%, 63%)" ], [ 17, "hsl(230, 73%, 63%)" ] ] }, + "line-opacity": 1, + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] }, + "line-dasharray": { "base": 1, "stops": [ [ 12, [ 1, 0 ] ], [ 13, [ 12, 4 ] ] ] } + } + }, + { + "id": "ferry_auto", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "ferry_auto" ] ], + "layout": { "line-join": "round" }, + "paint": { + "line-color": { "base": 1, "stops": [ [ 15, "hsl(205, 73%, 63%)" ], [ 17, "hsl(230, 73%, 63%)" ] ] }, + "line-opacity": 1, + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] } + } + }, + { + "id": "road-path-bg", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "path" ], + [ "!in", "structure", "bridge", "tunnel" ], + [ "!in", "type", "crossing", "sidewalk", "steps" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] }, + "line-dasharray": [ 1, 0 ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] } + } + }, + { + "id": "road-steps-bg", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "!in", "structure", "bridge", "tunnel" ], [ "==", "type", "steps" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 17, 4.6 ], [ 18, 7 ] ] }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [ 1, 0 ], + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] } + } + }, + { + "id": "road-sidewalk-bg", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "!in", "structure", "bridge", "tunnel" ], + [ "in", "type", "crossing", "sidewalk" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] }, + "line-dasharray": [ 1, 0 ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 0.75 ] ] } + } + }, + { + "id": "turning-features-outline", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "class", "turning_circle", "turning_loop" ] ], + "layout": { + "icon-image": "turning-circle-outline", + "icon-size": { "base": 1.5, "stops": [ [ 14, 0.122 ], [ 18, 0.969 ], [ 20, 1 ] ] }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "road-pedestrian-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "none" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 2 ], [ 18, 14.5 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "road-street-low", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street" ], [ "==", "structure", "none" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11, 0 ], [ 11.25, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "road-street_limited-low", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "none" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11, 0 ], [ 11.25, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "road-service-link-track-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "service", "track" ], + [ "!in", "structure", "bridge", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] } + } + }, + { + "id": "road-street_limited-case", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-street_limited-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "road-street-case", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-street-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "road-secondary-tertiary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "secondary", "tertiary" ], + [ "!in", "structure", "bridge", "tunnel" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 9.99, 0 ], [ 10, 1 ] ] } + } + }, + { + "id": "road-primary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "primary" ], [ "!in", "structure", "bridge", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 9.99, 0 ], [ 10, 1 ] ] } + } + }, + { + "id": "road-motorway_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "motorway_link" ], [ "!in", "structure", "bridge", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] } + } + }, + { + "id": "road-trunk_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "!in", "structure", "bridge", "tunnel" ], [ "==", "type", "trunk_link" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] } + } + }, + { + "id": "road-trunk-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "trunk" ], [ "!in", "structure", "bridge", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 6, 0 ], [ 6.1, 1 ] ] } + } + }, + { + "id": "road-motorway-case", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "motorway" ], [ "!in", "structure", "bridge", "tunnel" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] } + } + }, + { + "id": "road-construction", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "construction" ], [ "==", "structure", "none" ] ] + ], + "layout": { "line-join": "miter" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }, + "line-dasharray": { + "base": 1, + "stops": [ + [ 14, [ 0.4, 0.8 ] ], + [ 15, [ 0.3, 0.6 ] ], + [ 16, [ 0.2, 0.3 ] ], + [ 17, [ 0.2, 0.25 ] ], + [ 18, [ 0.15, 0.15 ] ] + ] + } + } + }, + { + "id": "road-sidewalks", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-sidewalk-bg", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 1 ] ] } + } + }, + { + "id": "road-path", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-path-bg", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "road-steps", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-steps-bg", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "road-trunk_link", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-trunk_link-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(46, 85%, 67%)", + "line-opacity": 1 + } + }, + { + "id": "road-motorway_link", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-motorway_link-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(26, 100%, 68%)", + "line-opacity": 1 + } + }, + { + "id": "road-pedestrian", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-pedestrian-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] } + } + }, + { + "id": "road-pedestrian-polygon-fill", + "type": "fill", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ "==", "$type", "Polygon" ], + [ "all", [ "in", "class", "path", "pedestrian" ], [ "==", "structure", "none" ] ] + ], + "layout": {}, + "paint": { + "fill-color": { "base": 1, "stops": [ [ 16, "hsl(230, 16%, 94%)" ], [ 16.25, "hsl(230, 50%, 98%)" ] ] }, + "fill-outline-color": "hsl(230, 26%, 88%)", + "fill-opacity": 1 + } + }, + { + "id": "road-pedestrian-polygon-pattern", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-pedestrian-polygon-fill", + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "hsl(35, 10%, 83%)", + "fill-pattern": "pedestrian-polygon", + "fill-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 1 ] ] } + } + }, + { + "id": "road-polygon", + "type": "fill", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ "==", "$type", "Polygon" ], + [ + "all", + [ "!in", "class", "motorway", "path", "pedestrian", "trunk" ], + [ "!in", "structure", "bridge", "tunnel" ] + ] + ], + "layout": {}, + "paint": { "fill-color": "hsl(0, 0%, 100%)", "fill-outline-color": "#d6d9e6" } + }, + { + "id": "road-service-link-track", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-service-link-track-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "road-street_limited", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-street_limited-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "road-street", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-street-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "road-secondary-tertiary", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-secondary-tertiary-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-color": { "base": 1, "stops": [ [ 5, "hsl(35, 32%, 91%)" ], [ 8, "hsl(0, 0%, 100%)" ] ] }, + "line-opacity": { "base": 1.2, "stops": [ [ 5, 0 ], [ 5.5, 1 ] ] } + } + }, + { + "id": "road-primary", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-primary-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": { "base": 1, "stops": [ [ 5, "hsl(35, 32%, 91%)" ], [ 7, "hsl(0, 0%, 100%)" ] ] }, + "line-opacity": 1 + } + }, + { + "id": "road-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "path", "pedestrian", "service", "track" ], + [ "==", "oneway", "true" ], + [ "!in", "structure", "bridge", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ], + [ "==", "oneway", "true" ], + [ "!in", "structure", "bridge", "tunnel" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-trunk", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-trunk-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": { + "base": 1, + "stops": [ [ 6, "hsl(0, 0%, 100%)" ], [ 6.1, "hsl(46, 80%, 60%)" ], [ 9, "hsl(46, 85%, 67%)" ] ] + } + } + }, + { + "id": "road-motorway", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-motorway-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": { "base": 1, "stops": [ [ 8, "hsl(26, 87%, 62%)" ], [ 9, "hsl(26, 100%, 68%)" ] ] } + } + }, + { + "id": "road-rail", + "type": "line", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "major_rail", "minor_rail" ], + [ "!in", "structure", "bridge", "tunnel" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] } + } + }, + { + "id": "road-rail-tracks", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "ref": "road-rail", + "paint": { + "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 14, 4 ], [ 20, 8 ] ] }, + "line-dasharray": [ 0.1, 15 ], + "line-opacity": { "base": 1, "stops": [ [ 13.75, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "level-crossings", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ "all", [ "==", "$type", "Point" ], [ "==", "class", "level_crossing" ] ], + "layout": { "icon-size": 1, "icon-image": "level-crossing", "icon-allow-overlap": true }, + "paint": {} + }, + { + "id": "road-oneway-arrows-white", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "motorway", "motorway_link", "trunk" ], + [ "==", "oneway", "true" ], + [ "!in", "structure", "bridge", "tunnel" ], + [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] }, + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "turning-features", + "type": "symbol", + "metadata": { "mapbox:group": "1444855786460.0557" }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "class", "turning_circle", "turning_loop" ] ], + "layout": { + "icon-image": "turning-circle", + "icon-size": { "base": 1.5, "stops": [ [ 14, 0.095 ], [ 18, 1 ] ] }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "bridge-path-bg", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "path" ], + [ "==", "structure", "bridge" ], + [ "!=", "type", "steps" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] }, + "line-dasharray": [ 1, 0 ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { "base": 1, "stops": [ [ 15, 0 ], [ 15.25, 1 ] ] } + } + }, + { + "id": "bridge-steps-bg", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "bridge" ], [ "==", "type", "steps" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 17, 4.6 ], [ 18, 7 ] ] }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [ 1, 0 ], + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] } + } + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 2 ], [ 18, 14.5 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "bridge-street-low", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "bridge-street_limited-low", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] } + } + }, + { + "id": "bridge-service-link-track-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "service", "track" ], + [ "==", "structure", "bridge" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] } + } + }, + { + "id": "bridge-street_limited-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] } + } + }, + { + "id": "bridge-street-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "street" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }, + "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] } + } + }, + { + "id": "bridge-secondary-tertiary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "in", "class", "secondary", "tertiary" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-translate": [ 0, 0 ] + } + }, + { + "id": "bridge-primary-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "primary" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-translate": [ 0, 0 ] + } + }, + { + "id": "bridge-trunk_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ], + [ "==", "type", "trunk_link" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] } + } + }, + { + "id": "bridge-motorway_link-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway_link" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "trunk" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] } + } + }, + { + "id": "bridge-motorway-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] } + } + }, + { + "id": "bridge-construction", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "class", "construction" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "miter" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }, + "line-dasharray": { + "base": 1, + "stops": [ + [ 14, [ 0.4, 0.8 ] ], + [ 15, [ 0.3, 0.6 ] ], + [ 16, [ 0.2, 0.3 ] ], + [ 17, [ 0.2, 0.25 ] ], + [ 18, [ 0.15, 0.15 ] ] + ] + } + } + }, + { + "id": "bridge-path", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "path" ], + [ "==", "structure", "bridge" ], + [ "!=", "type", "steps" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "bridge-steps", + "metadata": { "mapbox:group": "1444855799204.86" }, + "ref": "bridge-steps-bg", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ] + }, + "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] } + } + }, + { + "id": "bridge-trunk_link", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ], + [ "==", "type", "trunk_link" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway_link" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-pedestrian", + "metadata": { "mapbox:group": "1444855799204.86" }, + "ref": "bridge-pedestrian-case", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] } + } + }, + { + "id": "bridge-service-link-track", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "service", "track" ], + [ "==", "structure", "bridge" ], + [ "!=", "type", "trunk_link" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "bridge-street_limited", + "metadata": { "mapbox:group": "1444855799204.86" }, + "ref": "bridge-street_limited-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "bridge-street", + "metadata": { "mapbox:group": "1444855799204.86" }, + "ref": "bridge-street-low", + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] } + } + }, + { + "id": "bridge-secondary-tertiary", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "bridge" ], [ "in", "type", "secondary", "tertiary" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { "base": 1.2, "stops": [ [ 5, 0 ], [ 5.5, 1 ] ] } + } + }, + { + "id": "bridge-primary", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "==", "structure", "bridge" ], [ "==", "type", "primary" ] ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1 + } + }, + { + "id": "bridge-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "path", "pedestrian", "service", "track" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-trunk", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "trunk" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway" ], + [ "!in", "layer", 2, 3, 4, 5 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-rail", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "all", [ "in", "class", "major_rail", "minor_rail" ], [ "==", "structure", "bridge" ] ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] } + } + }, + { + "id": "bridge-rail-tracks", + "metadata": { "mapbox:group": "1444855799204.86" }, + "ref": "bridge-rail", + "paint": { + "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] }, + "line-width": { "base": 1.5, "stops": [ [ 14, 4 ], [ 20, 8 ] ] }, + "line-dasharray": [ 0.1, 15 ], + "line-opacity": { "base": 1, "stops": [ [ 13.75, 0 ], [ 20, 1 ] ] } + } + }, + { + "id": "bridge-trunk_link-2-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ], + [ "==", "type", "trunk_link" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] } + } + }, + { + "id": "bridge-motorway_link-2-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway_link" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-2-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "trunk" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] } + } + }, + { + "id": "bridge-motorway-2-case", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] } + } + }, + { + "id": "bridge-trunk_link-2", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ], + [ "==", "type", "trunk_link" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link-2", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway_link" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-trunk-2", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "trunk" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway-2", + "type": "line", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "==", "class", "motorway" ], + [ ">=", "layer", 2 ], + [ "==", "structure", "bridge" ] + ] + ], + "layout": { "line-cap": "round", "line-join": "round" }, + "paint": { + "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-oneway-arrows-white", + "type": "symbol", + "metadata": { "mapbox:group": "1444855799204.86" }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "all", + [ "in", "class", "link", "motorway", "motorway_link", "trunk" ], + [ "==", "oneway", "true" ], + [ "==", "structure", "bridge" ], + [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "aerialway", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "class", "aerialway" ] ], + "layout": { "line-join": "round" }, + "paint": { + "line-color": "hsl(230, 10%, 74%)", + "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] } + } + }, + { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "metadata": { "mapbox:group": "1444934295202.7542" }, + "source": "composite", + "source-layer": "admin", + "filter": [ "all", [ ">=", "admin_level", 3 ], [ "==", "maritime", 0 ] ], + "layout": { "line-join": "bevel" }, + "paint": { + "line-color": { "base": 1, "stops": [ [ 8, "hsl(35, 12%, 89%)" ], [ 16, "hsl(230, 49%, 90%)" ] ] }, + "line-width": { "base": 1, "stops": [ [ 7, 3.75 ], [ 12, 5.5 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 7, 0 ], [ 8, 0.75 ] ] }, + "line-dasharray": [ 1, 0 ], + "line-translate": [ 0, 0 ], + "line-blur": { "base": 1, "stops": [ [ 3, 0 ], [ 8, 3 ] ] } + } + }, + { + "id": "admin-2-boundaries-bg", + "type": "line", + "metadata": { "mapbox:group": "1444934295202.7542" }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "maritime", 0 ] ], + "layout": { "line-join": "miter" }, + "paint": { + "line-width": { "base": 1, "stops": [ [ 3, 3.5 ], [ 10, 8 ] ] }, + "line-color": { "base": 1, "stops": [ [ 6, "hsl(35, 12%, 89%)" ], [ 8, "hsl(230, 49%, 90%)" ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 3, 0 ], [ 4, 0.5 ] ] }, + "line-translate": [ 0, 0 ], + "line-blur": { "base": 1, "stops": [ [ 3, 0 ], [ 10, 2 ] ] } + } + }, + { + "id": "admin-3-4-boundaries", + "type": "line", + "metadata": { "mapbox:group": "1444934295202.7542" }, + "source": "composite", + "source-layer": "admin", + "filter": [ "all", [ ">=", "admin_level", 3 ], [ "==", "maritime", 0 ] ], + "layout": { "line-join": "round", "line-cap": "round" }, + "paint": { + "line-dasharray": { "base": 1, "stops": [ [ 6, [ 2, 0 ] ], [ 7, [ 2, 2, 6, 2 ] ] ] }, + "line-width": { "base": 1, "stops": [ [ 7, 0.75 ], [ 12, 1.5 ] ] }, + "line-opacity": { "base": 1, "stops": [ [ 2, 0 ], [ 3, 1 ] ] }, + "line-color": { "base": 1, "stops": [ [ 3, "hsl(230, 14%, 77%)" ], [ 7, "hsl(230, 8%, 62%)" ] ] } + } + }, + { + "id": "admin-2-boundaries", + "type": "line", + "metadata": { "mapbox:group": "1444934295202.7542" }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "disputed", 0 ], [ "==", "maritime", 0 ] ], + "layout": { "line-join": "round", "line-cap": "round" }, + "paint": { + "line-color": "hsl(230, 8%, 51%)", + "line-width": { "base": 1, "stops": [ [ 3, 0.5 ], [ 10, 2 ] ] } + } + }, + { + "id": "admin-2-boundaries-dispute", + "type": "line", + "metadata": { "mapbox:group": "1444934295202.7542" }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "disputed", 1 ], [ "==", "maritime", 0 ] ], + "layout": { "line-join": "round" }, + "paint": { + "line-dasharray": [ 1.5, 1.5 ], + "line-color": "hsl(230, 8%, 51%)", + "line-width": { "base": 1, "stops": [ [ 3, 0.5 ], [ 10, 2 ] ] } + } + }, + { + "id": "housenum-label", + "type": "symbol", + "source": "composite", + "source-layer": "housenum_label", + "minzoom": 17, + "layout": { + "text-field": "{house_num}", + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-padding": 4, + "text-max-width": 7, + "text-size": 9.5 + }, + "paint": { + "text-color": "hsl(35, 2%, 69%)", + "text-halo-color": "hsl(35, 8%, 85%)", + "text-halo-width": 0.5, + "text-halo-blur": 0 + } + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "composite", + "source-layer": "waterway_label", + "minzoom": 12, + "filter": [ "in", "class", "canal", "river" ], + "layout": { + "text-field": "{name_en}", + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-max-angle": 30, + "text-size": { "base": 1, "stops": [ [ 13, 12 ], [ 18, 16 ] ] } + }, + "paint": { + "text-halo-width": 0.5, + "text-halo-color": "hsl(196, 80%, 70%)", + "text-color": "hsl(230, 48%, 44%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l15", + "type": "symbol", + "metadata": { "mapbox:group": "1444933456003.5437" }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 17, + "filter": [ + "all", + [ ">=", "localrank", 15 ], + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 4 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l1", + "type": "symbol", + "metadata": { "mapbox:group": "1444933456003.5437" }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ "<=", "localrank", 14 ], + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 4 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 1, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks_scalerank4", + "type": "symbol", + "metadata": { "mapbox:group": "1444933456003.5437" }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 4 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 1, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank3", + "type": "symbol", + "metadata": { "mapbox:group": "1444933372896.5967" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 3 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 1, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank3", + "type": "symbol", + "metadata": { "mapbox:group": "1444933372896.5967" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 3 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "road-label-small", + "type": "symbol", + "metadata": { "mapbox:group": "1444933721429.3076" }, + "source": "composite", + "source-layer": "road_label", + "minzoom": 15, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ + "!in", + "class", + "link", + "motorway", + "pedestrian", + "primary", + "secondary", + "street", + "street_limited", + "tertiary", + "trunk" + ] + ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 15, 10 ], [ 20, 13 ] ] }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-halo-blur": 1 + } + }, + { + "id": "road-label-medium", + "type": "symbol", + "metadata": { "mapbox:group": "1444933721429.3076" }, + "source": "composite", + "source-layer": "road_label", + "minzoom": 11, + "filter": [ + "all", + [ "==", "$type", "LineString" ], + [ "in", "class", "link", "pedestrian", "street", "street_limited" ] + ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 11, 10 ], [ 20, 14 ] ] }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-field": ["format", ["get", "name_en"], {"id": 1}], + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": ["match", + ["text-section"], + 1, "green", + "hsl(0, 0%, 0%)"], + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "road-label-large", + "type": "symbol", + "metadata": { "mapbox:group": "1444933721429.3076" }, + "source": "composite", + "source-layer": "road_label", + "filter": [ "in", "class", "motorway", "primary", "secondary", "tertiary", "trunk" ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 9, 10 ], [ 20, 16 ] ] }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "road-shields-black", + "type": "symbol", + "metadata": { "mapbox:group": "1444933575858.6992" }, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ "<=", "reflen", 6 ], + [ + "!in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": { "base": 1, "stops": [ [ 11, 150 ], [ 14, 200 ] ] }, + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ], + "symbol-placement": { "base": 1, "stops": [ [ 10, "point" ], [ 11, "line" ] ] }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 7%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "road-shields-white", + "type": "symbol", + "metadata": { "mapbox:group": "1444933575858.6992" }, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ "<=", "reflen", 6 ], + [ + "in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": { "base": 1, "stops": [ [ 11, 150 ], [ 14, 200 ] ] }, + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ], + "symbol-placement": { "base": 1, "stops": [ [ 10, "point" ], [ 11, "line" ] ] }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "motorway-junction", + "type": "symbol", + "metadata": { "mapbox:group": "1444933575858.6992" }, + "source": "composite", + "source-layer": "motorway_junction", + "minzoom": 14, + "filter": [ "all", [ ">", "reflen", 0 ], [ "<=", "reflen", 9 ] ], + "layout": { + "text-field": "{ref}", + "text-size": 9, + "icon-image": "motorway-exit-{reflen}", + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ] + }, + "paint": { "text-color": "hsl(0, 0%, 100%)", "text-translate": [ 0, 0 ] } + }, + { + "id": "poi-scalerank2", + "type": "symbol", + "metadata": { "mapbox:group": "1444933358918.2366" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 2 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 14, 11 ], [ 20, 14 ] ] }, + "icon-image": { "stops": [ [ 14, "{maki}-11" ], [ 15, "{maki}-15" ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank2", + "type": "symbol", + "metadata": { "mapbox:group": "1444933358918.2366" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "==", "scalerank", 2 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 14, 11 ], [ 20, 14 ] ] }, + "icon-image": { "stops": [ [ 14, "{maki}-11" ], [ 15, "{maki}-15" ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "rail-label", + "type": "symbol", + "source": "composite", + "source-layer": "rail_station_label", + "minzoom": 12, + "filter": [ "!=", "maki", "entrance" ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] }, + "icon-image": "{network}", + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-offset": [ 0, 0.85 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { "base": 1, "stops": [ [ 0, "" ], [ 13, "{name_en}" ] ] }, + "text-letter-spacing": 0.01, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }, + "text-halo-blur": 0.5 + } + }, + { + "id": "water-label-sm", + "type": "symbol", + "metadata": { "mapbox:group": "1444933808272.805" }, + "source": "composite", + "source-layer": "water_label", + "minzoom": 15, + "filter": [ "<=", "area", 10000 ], + "layout": { + "text-field": "{name_en}", + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-max-width": 7, + "text-size": { "base": 1, "stops": [ [ 16, 13 ], [ 20, 16 ] ] } + }, + "paint": { "text-color": "hsl(230, 48%, 44%)" } + }, + { + "id": "water-label", + "type": "symbol", + "metadata": { "mapbox:group": "1444933808272.805" }, + "source": "composite", + "source-layer": "water_label", + "minzoom": 5, + "filter": [ ">", "area", 10000 ], + "layout": { + "text-field": "{name_en}", + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-max-width": 7, + "text-size": { "base": 1, "stops": [ [ 13, 13 ], [ 18, 18 ] ] } + }, + "paint": { "text-color": "hsl(230, 48%, 44%)" } + }, + { + "id": "place-residential", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 18, + "filter": [ + "all", + [ "in", "$type", "LineString", "Point", "Polygon" ], + [ "all", [ "<=", "localrank", 10 ], [ "==", "type", "residential" ] ] + ], + "layout": { + "text-line-height": 1.2, + "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0 ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank1", + "type": "symbol", + "metadata": { "mapbox:group": "1444933322393.2852" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "<=", "scalerank", 1 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] }, + "icon-image": { "stops": [ [ 13, "{maki}-11" ], [ 14, "{maki}-15" ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank1", + "type": "symbol", + "metadata": { "mapbox:group": "1444933322393.2852" }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ "<=", "scalerank", 1 ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] }, + "icon-image": { "stops": [ [ 13, "{maki}-11" ], [ 14, "{maki}-15" ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.65 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "airport-label", + "type": "symbol", + "source": "composite", + "source-layer": "airport_label", + "minzoom": 9, + "filter": [ "<=", "scalerank", 2 ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 10, 12 ], [ 18, 18 ] ] }, + "icon-image": { "stops": [ [ 12, "{maki}-11" ], [ 13, "{maki}-15" ] ] }, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0.75 ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { "stops": [ [ 11, "{ref}" ], [ 12, "{name_en}" ] ] }, + "text-letter-spacing": 0.01, + "text-max-width": 9 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "place-islet-archipelago-aboriginal", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ "in", "type", "aboriginal_lands", "archipelago", "islet" ], + "layout": { + "text-line-height": 1.2, + "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 16 ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0 ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-neighbourhood", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ "==", "type", "neighbourhood" ], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-padding": 3, + "text-size": { "base": 1, "stops": [ [ 12, 11 ], [ 16, 16 ] ] } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-suburb", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ "==", "type", "suburb" ], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3, + "text-size": { "base": 1, "stops": [ [ 11, 11 ], [ 15, 18 ] ] } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-hamlet", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ "==", "type", "hamlet" ], + "layout": { + "text-field": "{name_en}", + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 12, 11.5 ], [ 15, 16 ] ] } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 8, + "maxzoom": 15, + "filter": [ "==", "type", "village" ], + "layout": { + "text-field": "{name_en}", + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-max-width": 7, + "text-size": { "base": 1, "stops": [ [ 10, 11.5 ], [ 16, 18 ] ] } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-town", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 6, + "maxzoom": 15, + "filter": [ "==", "type", "town" ], + "layout": { + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ 11, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 12, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-offset": { "base": 1, "stops": [ [ 7, [ 0, -0.15 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { "base": 1, "stops": [ [ 7, 11.5 ], [ 15, 20 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] } + } + }, + { + "id": "place-island", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ "==", "type", "island" ], + "layout": { + "text-line-height": 1.2, + "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 16 ] ] }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ], + "text-padding": 2, + "text-offset": [ 0, 0 ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-city-sm", + "type": "symbol", + "metadata": { "mapbox:group": "1444862510685.128" }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ "all", [ "!in", "scalerank", 0, 1, 2, 3, 4, 5 ], [ "==", "type", "city" ] ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 6, 12 ], [ 14, 22 ] ] }, + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.2 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] }, + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] } + } + }, + { + "id": "place-city-md-s", + "type": "symbol", + "metadata": { "mapbox:group": "1444862510685.128" }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + [ "in", "ldir", "E", "S", "SE", "SW" ], + [ "in", "scalerank", 3, 4, 5 ], + [ "==", "type", "city" ] + ], + "layout": { + "text-field": "{name_en}", + "icon-image": "dot-10", + "text-anchor": { "base": 1, "stops": [ [ 7, "top" ], [ 8, "center" ] ] }, + "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, 0.1 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-font": { + "base": 1, + "stops": [ + [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-size": { "base": 0.9, "stops": [ [ 5, 12 ], [ 12, 22 ] ] } + }, + "paint": { + "text-halo-width": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 1, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] } + } + }, + { + "id": "place-city-md-n", + "type": "symbol", + "metadata": { "mapbox:group": "1444862510685.128" }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + [ "in", "ldir", "N", "NE", "NW", "W" ], + [ "in", "scalerank", 3, 4, 5 ], + [ "==", "type", "city" ] + ], + "layout": { + "icon-image": "dot-10", + "text-font": { + "base": 1, + "stops": [ + [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.25 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { "base": 0.9, "stops": [ [ 5, 12 ], [ 12, 22 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-s", + "type": "symbol", + "metadata": { "mapbox:group": "1444862510685.128" }, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + [ "in", "ldir", "E", "S", "SE", "SW" ], + [ "<=", "scalerank", 2 ], + [ "==", "type", "city" ] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, 0.15 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-anchor": { "base": 1, "stops": [ [ 7, "top" ], [ 8, "center" ] ] }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { "base": 0.9, "stops": [ [ 4, 12 ], [ 10, 22 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-n", + "type": "symbol", + "metadata": { "mapbox:group": "1444862510685.128" }, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + [ "in", "ldir", "N", "NE", "NW", "W" ], + [ "<=", "scalerank", 2 ], + [ "==", "type", "city" ] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ], + [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ] + ] + }, + "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.25 ] ], [ 8, [ 0, 0 ] ] ] }, + "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { "base": 0.9, "stops": [ [ 4, 12 ], [ 10, 22 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-opacity": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }, + "text-halo-blur": 1 + } + }, + { + "id": "marine-label-sm-ln", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ "all", [ "==", "$type", "LineString" ], [ ">=", "labelrank", 4 ] ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1, "stops": [ [ 3, 12 ], [ 6, 16 ] ] }, + "symbol-spacing": { "base": 1, "stops": [ [ 4, 100 ], [ 6, 400 ] ] }, + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "marine-label-sm-pt", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ "all", [ "==", "$type", "Point" ], [ ">=", "labelrank", 4 ] ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 3, 12 ], [ 6, 16 ] ] } + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "marine-label-md-ln", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ "all", [ "==", "$type", "LineString" ], [ "in", "labelrank", 2, 3 ] ], + "layout": { + "text-line-height": 1.1, + "text-size": { "base": 1.1, "stops": [ [ 2, 12 ], [ 5, 20 ] ] }, + "symbol-spacing": 250, + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "symbol-placement": "line", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "marine-label-md-pt", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "labelrank", 2, 3 ] ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-size": { "base": 1.1, "stops": [ [ 2, 14 ], [ 5, 20 ] ] } + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "marine-label-lg-ln", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "labelrank", 1 ] ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "symbol-placement": "line", + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 1, 14 ], [ 4, 30 ] ] } + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "marine-label-lg-pt", + "type": "symbol", + "metadata": { "mapbox:group": "1444856087950.3635" }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ "all", [ "==", "$type", "Point" ], [ "==", "labelrank", 1 ] ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 1, 14 ], [ 4, 30 ] ] } + }, + "paint": { "text-color": "hsl(205, 83%, 88%)" } + }, + { + "id": "state-label-sm", + "type": "symbol", + "metadata": { "mapbox:group": "1444856151690.9143" }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 9, + "filter": [ "<", "area", 20000 ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 6, 10 ], [ 9, 14 ] ] }, + "text-transform": "uppercase", + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ], + "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 6, "{name_en}" ] ] }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-md", + "type": "symbol", + "metadata": { "mapbox:group": "1444856151690.9143" }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 8, + "filter": [ "all", [ "<", "area", 80000 ], [ ">=", "area", 20000 ] ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 5, 10 ], [ 8, 16 ] ] }, + "text-transform": "uppercase", + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ], + "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 5, "{name_en}" ] ] }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-lg", + "type": "symbol", + "metadata": { "mapbox:group": "1444856151690.9143" }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 7, + "filter": [ ">=", "area", 80000 ], + "layout": { + "text-size": { "base": 1, "stops": [ [ 4, 10 ], [ 7, 18 ] ] }, + "text-transform": "uppercase", + "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ], + "text-padding": 1, + "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 4, "{name_en}" ] ] }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "country-label-sm", + "type": "symbol", + "metadata": { "mapbox:group": "1444856144497.7825" }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 10, + "filter": [ ">=", "scalerank", 5 ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 6, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-size": { "base": 0.9, "stops": [ [ 5, 14 ], [ 9, 22 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-md", + "type": "symbol", + "metadata": { "mapbox:group": "1444856144497.7825" }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 8, + "filter": [ "in", "scalerank", 3, 4 ], + "layout": { + "text-field": { "base": 1, "stops": [ [ 0, "{code}" ], [ 2, "{name_en}" ] ] }, + "text-max-width": 6, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 3, 10 ], [ 8, 24 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-lg", + "type": "symbol", + "metadata": { "mapbox:group": "1444856144497.7825" }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 7, + "filter": [ "in", "scalerank", 1, 2 ], + "layout": { + "text-field": "{name_en}", + "text-max-width": { "base": 1, "stops": [ [ 0, 5 ], [ 3, 6 ] ] }, + "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ], + "text-size": { "base": 1, "stops": [ [ 1, 10 ], [ 6, 24 ] ] } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] }, + "text-halo-width": 1.25 + } + } + ] +} \ No newline at end of file From 156038efb2c762eaffb9237a780ef0393e27ceac Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 15:48:26 +0200 Subject: [PATCH 7/8] Review comments: minor changes + formattedSection => formattedSectionID --- include/mbgl/style/expression/expression.hpp | 7 ++++--- include/mbgl/style/expression/formatted.hpp | 2 +- include/mbgl/style/property_expression.hpp | 2 +- src/mbgl/layout/symbol_layout.cpp | 2 +- src/mbgl/renderer/paint_property_binder.hpp | 14 +++++++------- src/mbgl/style/expression/compound_expression.cpp | 4 ++-- src/mbgl/style/expression/is_constant.cpp | 2 +- src/mbgl/text/tagged_string.hpp | 2 +- test/style/property_expression.test.cpp | 6 +++--- 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index d868b17e004..6276b8dc937 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -35,15 +35,16 @@ class EvaluationContext { zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_)) {} - EvaluationContext& withFormattedSection(const Value* formattedSection_) noexcept { - formattedSection = formattedSection_; + EvaluationContext& withFormattedSectionID(const Value* formattedSectionID_) noexcept { + formattedSectionID = formattedSectionID_; return *this; }; optional zoom; GeometryTileFeature const * feature = nullptr; optional colorRampParameter; - const Value* formattedSection = nullptr; + // Contains formatted section ID (double | std::string) + const Value* formattedSectionID = nullptr; }; template diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp index 28964de9419..02e2f7c3d00 100644 --- a/include/mbgl/style/expression/formatted.hpp +++ b/include/mbgl/style/expression/formatted.hpp @@ -23,7 +23,7 @@ optional toFormattedSectionID(const Variant& variant) { return variant.match( [] (double t) -> FormattedSectionID { return t; }, [] (const std::string& t) -> FormattedSectionID { return t;}, - [] (auto&) -> optional { return nullopt; }); + [] (const auto&) -> optional { return nullopt; }); } struct FormattedSection { diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp index 43e80dfac48..32983e23805 100644 --- a/include/mbgl/style/property_expression.hpp +++ b/include/mbgl/style/property_expression.hpp @@ -34,7 +34,7 @@ template class PropertyExpression final : public PropertyExpressionBase { public: // Second parameter to be used only for conversions from legacy functions. - PropertyExpression(std::unique_ptr expression_, optional defaultValue_ = {}) + PropertyExpression(std::unique_ptr expression_, optional defaultValue_ = nullopt) : PropertyExpressionBase(std::move(expression_)), defaultValue(std::move(defaultValue_)) { } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index e95fb56c1df..d6d7eb8c134 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -33,7 +33,7 @@ expression::Value sectionOptionsToValue(const SectionOptions& options) { return (*options.id).match( [] (double t) -> expression::Value { return t; }, [] (const std::string& t) -> expression::Value { return t; }, - [] (auto&) -> expression::Value { return {}; }); + [] (const auto&) -> expression::Value { return {}; }); } return {}; } diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 9659384d330..3b2e253ba15 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -187,9 +187,9 @@ class SourceFunctionPaintPropertyBinder final : public PaintPropertyBinder&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSectionID) override { using style::expression::EvaluationContext; - auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue); + auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSectionID(&formattedSectionID), defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { @@ -243,11 +243,11 @@ class CompositeFunctionPaintPropertyBinder final : public PaintPropertyBinder&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSectionID) override { using style::expression::EvaluationContext; Range range = { - expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue), - expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSection(&formattedSection), defaultValue), + expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSectionID(&formattedSectionID), defaultValue), + expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSectionID(&formattedSectionID), defaultValue), }; this->statistics.add(range.min); this->statistics.add(range.max); @@ -483,9 +483,9 @@ class PaintPropertyBinders> { PaintPropertyBinders(PaintPropertyBinders&&) = default; PaintPropertyBinders(const PaintPropertyBinders&) = delete; - void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value& formattedSection = {}) { + void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value& formattedSectionID = {}) { util::ignore({ - (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSection), 0)... + (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSectionID), 0)... }); } diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 27dfe6c151d..3dd0ee237b3 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -664,10 +664,10 @@ const auto& errorCompoundExpression() { const auto& textSectionCompoundExpression() { static auto signature = detail::makeSignature("text-section", [](const EvaluationContext& params) -> Result { - if (!params.formattedSection) { + if (!params.formattedSectionID) { return EvaluationError {"Formatted section is unavailable in the current evaluation context."}; } - return *params.formattedSection; + return *params.formattedSectionID; }); return signature; } diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp index 8ac362373c8..25fa4fd4e5a 100644 --- a/src/mbgl/style/expression/is_constant.cpp +++ b/src/mbgl/style/expression/is_constant.cpp @@ -24,7 +24,7 @@ bool isFeatureConstant(const Expression& expression) { name == "text-section" ) { return false; - } else if (0 == name.rfind(filter, 0)) { + } else if (0u == name.rfind(filter, 0u)) { // Legacy filters begin with "filter-" and are never constant. return false; } diff --git a/src/mbgl/text/tagged_string.hpp b/src/mbgl/text/tagged_string.hpp index c40c2537533..015e263528b 100644 --- a/src/mbgl/text/tagged_string.hpp +++ b/src/mbgl/text/tagged_string.hpp @@ -9,7 +9,7 @@ namespace mbgl { using style::expression::FormattedSectionID; struct SectionOptions { - SectionOptions(double scale_, FontStack fontStack_, const optional& id_ = {}) + SectionOptions(double scale_, FontStack fontStack_, const optional& id_ = nullopt) : scale(scale_), fontStackHash(FontStackHasher()(fontStack_)), fontStack(std::move(fontStack_)), id(std::move(id_)) {} diff --git a/test/style/property_expression.test.cpp b/test/style/property_expression.test.cpp index a7d1d256602..a6ee22106af 100644 --- a/test/style/property_expression.test.cpp +++ b/test/style/property_expression.test.cpp @@ -125,13 +125,13 @@ TEST(PropertyExpression, Issue8460) { TEST(PropertyExpression, TextSection) { expression::Value formattedSection1 = 42.0; PropertyExpression ts1(textSection()); - EXPECT_DOUBLE_EQ(42.0, ts1.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection1))); + EXPECT_DOUBLE_EQ(42.0, ts1.evaluate(expression::EvaluationContext().withFormattedSectionID(&formattedSection1))); expression::Value formattedSection2{"header"s}; PropertyExpression ts2(textSection()); - EXPECT_EQ("header"s, ts2.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection2))); + EXPECT_EQ("header"s, ts2.evaluate(expression::EvaluationContext().withFormattedSectionID(&formattedSection2))); // Evaluates to default, T(). PropertyExpression ts3(textSection()); - EXPECT_EQ(Color(), ts3.evaluate(expression::EvaluationContext().withFormattedSection(&formattedSection1))); + EXPECT_EQ(Color(), ts3.evaluate(expression::EvaluationContext().withFormattedSectionID(&formattedSection1))); } From 89426debdef24436fdfcd5375ab9fd681d60f399 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 17:17:06 +0200 Subject: [PATCH 8/8] Review comments: Move lambdas to memeber methods --- src/mbgl/layout/symbol_layout.cpp | 95 ++++++++++++++++--------------- src/mbgl/layout/symbol_layout.hpp | 14 +++++ 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index d6d7eb8c134..50f3c7e9bef 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -275,6 +275,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, : layout.get(); const float textRepeatDistance = symbolSpacing / 2; + const auto evaluatedLayoutProperties = layout.evaluate(zoom, feature); IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { @@ -287,7 +288,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, // (1) render symbols that overlap into this tile // (2) approximate collision detection effects from neighboring symbols symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, - layout.evaluate(zoom, feature), layoutTextSize, + evaluatedLayoutProperties, layoutTextSize, textBoxScale, textPadding, textPlacement, textOffset, iconBoxScale, iconPadding, iconOffset, glyphPositions, indexedFeature, layoutFeatureIndex, feature.index, @@ -421,56 +422,13 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr updatePaintProperties; - if (formattedText.hasMultipleUniqueSections()) { - updatePaintProperties = [&, currentSectionIndex = optional{}](std::size_t symbolSectionIndex, bool updateLastSection) mutable { - if (currentSectionIndex && (updateLastSection || *currentSectionIndex != symbolSectionIndex)) { - const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(*currentSectionIndex)); - for (auto& pair : bucket->paintProperties) { - pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); - } - } - currentSectionIndex = symbolSectionIndex; - }; - } else { - updatePaintProperties = [&](std::size_t, bool updateLastSection) { - if (updateLastSection) { - const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(0)); - for (auto& pair : bucket->paintProperties) { - pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); - } - } - }; - } - - const Range sizeData = bucket->textSizeBinder->getVertexSizeData(feature); - auto addSymbolGlyphQuads = [&](WritingModeType writingMode, - optional& placedIndex, - const SymbolQuads& glyphQuads) { - bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - placedIndex = bucket->text.placedSymbols.size() - 1; - PlacedSymbol& placedSymbol = bucket->text.placedSymbols.back(); - - bool firstSymbol = true; - for (const auto& symbolQuad : glyphQuads) { - updatePaintProperties(symbolQuad.sectionIndex, false); - size_t index = addSymbol(bucket->text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol); - if (firstSymbol) { - placedSymbol.vertexStartIndex = index; - firstSymbol = false; - } - } - }; - - addSymbolGlyphQuads(symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); + std::size_t index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); if (symbolInstance.writingModes & WritingModeType::Vertical) { - addSymbolGlyphQuads(WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads); + index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, index); } - updatePaintProperties(0, true); + updatePaintPropertiesForSection(*bucket, feature, index); } if (hasIcon) { @@ -504,6 +462,49 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr& placedIndex, + const SymbolQuads& glyphQuads, + optional lastAddedSection) { + const Range sizeData = bucket.textSizeBinder->getVertexSizeData(feature); + const auto& formattedText = *feature.formattedText; + const bool hasMultipleSections = formattedText.hasMultipleUniqueSections(); + + bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, + symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); + placedIndex = bucket.text.placedSymbols.size() - 1; + PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back(); + + bool firstSymbol = true; + for (const auto& symbolQuad : glyphQuads) { + if (hasMultipleSections) { + if (lastAddedSection && *lastAddedSection != symbolQuad.sectionIndex) { + updatePaintPropertiesForSection(bucket, feature, *lastAddedSection); + } + lastAddedSection = symbolQuad.sectionIndex; + } + size_t index = addSymbol(bucket.text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol); + if (firstSymbol) { + placedSymbol.vertexStartIndex = index; + firstSymbol = false; + } + } + + return lastAddedSection ? *lastAddedSection : 0u; +} + size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, const Range sizeData, const SymbolQuad& symbol, diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 870ad4b4150..53c66d31fed 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -65,6 +65,20 @@ class SymbolLayout final : public Layout { const Anchor& labelAnchor, PlacedSymbol& placedSymbol); + // Adds symbol quads to bucket and returns formatted section index of last + // added quad. + std::size_t addSymbolGlyphQuads(SymbolBucket&, + SymbolInstance&, + const SymbolFeature&, + WritingModeType, + optional& placedIndex, + const SymbolQuads&, + optional lastAddedSection = nullopt); + + void updatePaintPropertiesForSection(SymbolBucket&, + const SymbolFeature&, + std::size_t sectionIndex); + // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. const std::unique_ptr sourceLayer;