From 3efbe291998885536afbc92e44fd9d41920507cf Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 22 May 2014 11:05:49 -0700 Subject: [PATCH 01/13] add landuse_snow bucket --- bin/style.js | 7 +++++++ ios/MVKMapKit | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/style.js b/bin/style.js index 325d7cbe0..bff0c08eb 100644 --- a/bin/style.js +++ b/bin/style.js @@ -186,6 +186,13 @@ module.exports = { "value": "rock", "type": "fill" }, + "landuse_snow": { + "source": "outdoors", + "layer": "landuse", + "field": "class", + "value": "snow", + "type": "fill" + }, "overlay_wetland": { "source": "outdoors", "layer": "landuse_overlay", diff --git a/ios/MVKMapKit b/ios/MVKMapKit index a9a7fa3ab..172218fa9 160000 --- a/ios/MVKMapKit +++ b/ios/MVKMapKit @@ -1 +1 @@ -Subproject commit a9a7fa3ab32ef14435dd22533c55db6554118e7f +Subproject commit 172218fa978dc061c31ce3a814294fd7cd5559b9 From 7012d686fcbd0d610e9029f2b7f216d692cdddea Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 22 May 2014 11:09:59 -0700 Subject: [PATCH 02/13] landuse_snow structure --- bin/style.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/style.js b/bin/style.js index bff0c08eb..91b73e39e 100644 --- a/bin/style.js +++ b/bin/style.js @@ -895,6 +895,10 @@ module.exports = { "name": "landuse_rock", "bucket": "landuse_rock" }, + { + "name": "landuse_snow", + "bucket": "landuse_snow" + }, { "name": "landuse_hospital", "bucket": "landuse_hospital" From 5bb1d151d475de4c691bf5898a3dbacaf17bf547 Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 22 May 2014 11:50:38 -0700 Subject: [PATCH 03/13] transition bigger airport poi --- bin/style.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/style.js b/bin/style.js index 91b73e39e..4dcd4f782 100644 --- a/bin/style.js +++ b/bin/style.js @@ -2264,6 +2264,10 @@ module.exports = { "translate": [0, 14] }, "poi_aerodrome": { + "opacity": ["stops", + {"z": 13, "val": 0}, + {"z": 13.25, "val": 1} + ], "antialias": false } } @@ -2956,6 +2960,10 @@ module.exports = { "translate": [0, 14] }, "poi_aerodrome": { + "opacity": ["stops", + {"z": 13, "val": 0}, + {"z": 13.25, "val": 1} + ], "antialias": false } } From cbe84299ed1a3e52483c38ef279f6bf29d65e476 Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 22 May 2014 12:01:34 -0700 Subject: [PATCH 04/13] slight adjustments to landcover colors for contrast discrepencies --- bin/style.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/style.js b/bin/style.js index 4dcd4f782..28ae151c5 100644 --- a/bin/style.js +++ b/bin/style.js @@ -1333,9 +1333,9 @@ module.exports = { "water": "#cdd", "water_dark": "#185869", "crop": "#eeeed4", - "grass": "#e7ebd1", - "scrub": "#e0e8cd", - "wood": "#d4e2c6", + "grass": "#e6e6cc", + "scrub": "#dfe5c8", + "wood": "#cee2bd", "snow": "#f4f8ff", "rock": "#ddd", "sand": "#ffd", From aa92e92595c385c5d7dcc88a361213818d715e73 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 12:46:53 -0700 Subject: [PATCH 05/13] support for style transitions --- include/llmr/style/properties.hpp | 59 +- include/llmr/style/style.hpp | 51 +- include/llmr/style/style_parser.hpp | 1 + include/llmr/util/transition.hpp | 31 +- src/map/map.cpp | 16 +- src/map/transform.cpp | 12 +- src/style/style.cpp | 956 +++++++++++++++++++++++++--- src/style/style_parser.cpp | 99 ++- src/util/raster.cpp | 2 +- src/util/transition.cpp | 63 +- 10 files changed, 1182 insertions(+), 108 deletions(-) diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 04f1819b3..37c26b470 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -5,12 +5,34 @@ #include #include #include +#include namespace llmr { // Stores a premultiplied color, with all four channels ranging from 0..1 typedef std::array Color; +struct PropertyTransition { + uint16_t duration = 0; + uint16_t delay = 0; +}; + +enum class TransitionablePropertyKey { + Translate = 1, + FillColor = 2, + StrokeColor = 3, + Opacity = 4, + Width = 5, + Offset = 6, + Color = 7, + DashArray = 8, + Radius = 9, + Blur = 10, + Halo = 11, + HaloRadius = 12, + HaloBlur = 13, +}; + enum class Winding { EvenOdd = 1, NonZero = 2 @@ -63,13 +85,19 @@ struct FunctionProperty { struct IconClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; + PropertyTransition translate_transition; TranslateAnchor translateAnchor = TranslateAnchor::Map; FunctionProperty size; Color color = {{ 1, 1, 1, 1 }}; + PropertyTransition color_transition; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; std::string image; FunctionProperty radius = 0; + PropertyTransition radius_transition; FunctionProperty blur = 0; + PropertyTransition blur_transition; + std::set specifiers; }; struct IconProperties { @@ -87,12 +115,19 @@ struct IconProperties { struct LineClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; + PropertyTransition translate_transition; TranslateAnchor translateAnchor = TranslateAnchor::Map; FunctionProperty width; + PropertyTransition width_transition; FunctionProperty offset; + PropertyTransition offset_transition; Color color = {{ 0, 0, 0, 1 }}; + PropertyTransition color_transition; std::array dash_array = {{ 1, -1 }}; + PropertyTransition dash_array_transition; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; + std::set specifiers; }; struct LineProperties { @@ -109,13 +144,18 @@ struct LineProperties { struct FillClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; + PropertyTransition translate_transition; TranslateAnchor translateAnchor = TranslateAnchor::Map; Winding winding = Winding::NonZero; FunctionProperty antialias = true; Color fill_color = {{ 0, 0, 0, 1 }}; + PropertyTransition fill_color_transition; Color stroke_color = {{ 0, 0, 0, std::numeric_limits::infinity() }}; + PropertyTransition stroke_color_transition; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; std::string image; + std::set specifiers; }; struct FillProperties { @@ -133,15 +173,22 @@ struct FillProperties { struct TextClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; + PropertyTransition translate_transition; TranslateAnchor translateAnchor = TranslateAnchor::Map; Color color = {{ 0, 0, 0, 1 }}; + PropertyTransition color_transition; Color halo = {{ 1, 1, 1, 0.75 }}; + PropertyTransition halo_transition; FunctionProperty halo_radius = 0.25f; + PropertyTransition halo_radius_transition; FunctionProperty halo_blur = 1.0f; + PropertyTransition halo_blur_transition; FunctionProperty size = 12.0f; FunctionProperty rotate = 0.0f; - FunctionProperty alwaysVisible = false; + FunctionProperty always_visible = false; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; + std::set specifiers; }; struct TextProperties { @@ -154,13 +201,16 @@ struct TextProperties { float halo_blur = 1.0f; float size = 12.0f; float rotate = 0.0f; - bool alwaysVisible = false; + bool always_visible = false; float opacity = 1.0; }; struct BackgroundClass { Color color = {{ 1, 1, 1, 1 }}; + PropertyTransition color_transition; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; + std::set specifiers; }; struct BackgroundProperties { @@ -171,7 +221,10 @@ struct BackgroundProperties { struct RasterClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; + PropertyTransition translate_transition; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; + std::set specifiers; }; struct RasterProperties { @@ -183,6 +236,8 @@ struct RasterProperties { struct CompositeClass { FunctionProperty enabled = true; FunctionProperty opacity = 1; + PropertyTransition opacity_transition; + std::set specifiers; }; struct CompositeProperties { diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 920d0c6c1..256ff4d6b 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -32,6 +34,12 @@ public: size_t layerCount() const; void cascade(float z); + bool needsTransition() const; + void updateTransitions(time now); + void cancelTransitions(); + + void setDefaultTransitionDuration(uint64_t duration = 0); + public: std::shared_ptr sprite; @@ -40,8 +48,7 @@ public: std::vector layers; std::map classes; - - // This are applied settings. + // Currently applied settings. std::set appliedClasses; struct { BackgroundProperties background; @@ -51,7 +58,47 @@ public: std::map texts; std::map rasters; std::map composites; + std::map> effective_classes; } computed; + +private: + bool transitionInProgress(std::string layer_name, TransitionablePropertyKey key); + bool transitionExists(std::string layer_name, TransitionablePropertyKey key); + bool inNeedOfTransition(std::string layer_name, TransitionablePropertyKey key); + uint64_t transitionDuration(std::string layer_name, TransitionablePropertyKey key); + uint64_t transitionDelay(std::string layer_name, TransitionablePropertyKey key); + +private: + // Last applied settings. + struct { + BackgroundProperties background; + std::map fills; + std::map lines; + std::map icons; + std::map texts; + std::map rasters; + std::map composites; + std::map> effective_classes; + } previous; + + // Settings values currently being transitioned. + struct { + BackgroundProperties background; + std::map fills; + std::map lines; + std::map icons; + std::map texts; + std::map rasters; + std::map composites; + } transitioning; + + std::map> properties_to_transition; + std::map>> transitions; + uint64_t default_transition_duration = 0; + bool initial_render_complete = false; + + mutable uv::rwlock mtx; + }; } diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 82dd7e9b5..6668048ff 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -46,6 +46,7 @@ private: Value parseValue(JSVal value); FunctionProperty::fn parseFunctionType(JSVal type); FunctionProperty parseFunction(JSVal value); + PropertyTransition parseTransition(JSVal value, std::string property_name); private: std::map constants; diff --git a/include/llmr/util/transition.hpp b/include/llmr/util/transition.hpp index cab73aab5..a981f6e83 100644 --- a/include/llmr/util/transition.hpp +++ b/include/llmr/util/transition.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace llmr { namespace util { @@ -19,39 +20,45 @@ public: duration(duration) {} inline float progress(time now) const { + if (duration == 0) return 1; + if (start > now) return 0; + return (float)(now - start) / duration; } virtual state update(time now) const = 0; virtual ~transition(); +protected: + double interpolateDouble(double from, double to, double t) const; + float interpolateFloat(float from, float to, double t) const; + Color interpolateColor(Color from, Color to, double t) const; + std::array interpolateFloatArray(std::array from, std::array to, double t) const; + protected: const time start, duration; }; +template class ease_transition : public transition { public: - // Disable automatic casts. - template - inline ease_transition(double from, double to, double& value, T1 start, T2 duration) = delete; + ease_transition(T from, T to, T& value, time start, time duration) + : transition(start, duration), + from(from), + to(to), + value(value) {} - // Actual constructor. - ease_transition(double from, double to, double& value, time start, time duration); state update(time now) const; private: - const double from, to; - double& value; + const T from, to; + T& value; + }; template class timeout : public transition { public: - // Disable automatic casts. - template - inline timeout(T final_value, T& value, T1 start, T2 duration) = delete; - - // Actual constructor. timeout(T final_value, T& value, time start, time duration) : transition(start, duration), final_value(final_value), diff --git a/src/map/map.cpp b/src/map/map.cpp index 9df6ecb4b..d70821380 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -374,17 +374,15 @@ bool Map::getDebug() const { } void Map::toggleRaster() { + style.setDefaultTransitionDuration(300); + style.cancelTransitions(); + auto it = sources.find("satellite"); if (it != sources.end()) { Source &satellite_source = *it->second; - if (satellite_source.enabled) { satellite_source.enabled = false; - - auto style_class = style.appliedClasses.find("satellite"); - if (style_class != style.appliedClasses.end()) { - style.appliedClasses.erase(style_class); - } + style.appliedClasses.erase("satellite"); } else { satellite_source.enabled = true; style.appliedClasses.insert("satellite"); @@ -458,6 +456,12 @@ void Map::prepare() { style.cascade(state.getNormalizedZoom()); } + animationTime = util::now(); + if (style.needsTransition()) { + style.updateTransitions(animationTime); + update(); + } + // Allow the sprite atlas to potentially pull new sprite images if needed. if (style.sprite && style.sprite->isLoaded()) { spriteAtlas.update(*style.sprite); diff --git a/src/map/transform.cpp b/src/map/transform.cpp index fb3458ade..93942edad 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -59,9 +59,9 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { // Use a common start time for all of the transitions to avoid divergent transitions. time start = util::now(); transitions.emplace_front( - std::make_shared(current.x, final.x, current.x, start, duration)); + std::make_shared>(current.x, final.x, current.x, start, duration)); transitions.emplace_front( - std::make_shared(current.y, final.y, current.y, start, duration)); + std::make_shared>(current.y, final.y, current.y, start, duration)); } } @@ -250,12 +250,12 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl } else { // Use a common start time for all of the transitions to avoid divergent transitions. time start = util::now(); - transitions.emplace_front(std::make_shared( + transitions.emplace_front(std::make_shared>( current.scale, final.scale, current.scale, start, duration)); transitions.emplace_front( - std::make_shared(current.x, final.x, current.x, start, duration)); + std::make_shared>(current.x, final.x, current.x, start, duration)); transitions.emplace_front( - std::make_shared(current.y, final.y, current.y, start, duration)); + std::make_shared>(current.y, final.y, current.y, start, duration)); } const double s = final.scale * util::tileSize; @@ -335,7 +335,7 @@ void Transform::_setAngle(double new_angle, const time duration) { current.angle = final.angle; } else { time start = util::now(); - transitions.emplace_front(std::make_shared( + transitions.emplace_front(std::make_shared>( current.angle, final.angle, current.angle, start, duration)); } } diff --git a/src/style/style.cpp b/src/style/style.cpp index 54528f527..b39a0bf5d 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -19,135 +19,945 @@ void Style::reset() { computed.texts.clear(); computed.rasters.clear(); computed.composites.clear(); + computed.background.color = {{ 1, 1, 1, 1 }}; + computed.background.opacity = 1.0; + + properties_to_transition.clear(); } void Style::cascade(float z) { + uv::writelock lock(mtx); + + time start = util::now(); + + previous.fills = computed.fills; + previous.lines = computed.lines; + previous.icons = computed.icons; + previous.texts = computed.texts; + previous.rasters = computed.rasters; + previous.background = computed.background; + + previous.effective_classes = computed.effective_classes; + reset(); // Accomodate for different tile size. // TODO: Make this per-layer once individual layers have a specific tile size. z += std::log(util::tileSize / 256.0f) / M_LN2; - // Recalculate style - // Basic cascading + // Recalculate style with basic cascading. Also store the last applied class + // for each property to assist in determining transitions. for (const auto& class_pair : classes) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; - // Not enabled + // Skip if not enabled. if (appliedClasses.find(class_name) == appliedClasses.end()) continue; - // Cascade fill classes + // Cascade fill classes. for (const auto& fill_pair : sheetClass.fill) { const std::string& layer_name = fill_pair.first; const llmr::FillClass& layer = fill_pair.second; - // TODO: This should be restricted to fill styles that have actual - // values so as to not override with default values. llmr::FillProperties& fill = computed.fills[layer_name]; - fill.enabled = layer.enabled.evaluate(z); - fill.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; - fill.translateAnchor = layer.translateAnchor; - fill.winding = layer.winding; - fill.antialias = layer.antialias.evaluate(z); - fill.fill_color = layer.fill_color; - fill.stroke_color = layer.stroke_color; - fill.opacity = layer.opacity.evaluate(z); - fill.image = layer.image; + + if (layer.specifiers.count("enabled")) { + fill.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("translate")) { + fill.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + fill.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("winding")) { + fill.winding = layer.winding; + } + + if (layer.specifiers.count("antialias")) { + fill.antialias = layer.antialias.evaluate(z); + } + + if (layer.specifiers.count("color")) { + fill.fill_color = layer.fill_color; + computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; + if (layer.fill_color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::FillColor] = layer.fill_color_transition; + } + } + + if (layer.specifiers.count("stroke")) { + fill.stroke_color = layer.stroke_color; + computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; + if (layer.stroke_color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::StrokeColor] = layer.stroke_color_transition; + } + } + + if (layer.specifiers.count("opacity")) { + fill.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + + if (layer.specifiers.count("image")) { + fill.image = layer.image; + } } - // Cascade line classes + // Cascade line classes. for (const auto& line_pair : sheetClass.line) { const std::string& layer_name = line_pair.first; const llmr::LineClass& layer = line_pair.second; - // TODO: This should be restricted to line styles that have actual - // values so as to not override with default values. llmr::LineProperties& stroke = computed.lines[layer_name]; - stroke.enabled = layer.enabled.evaluate(z); - stroke.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; - stroke.translateAnchor = layer.translateAnchor; - stroke.width = layer.width.evaluate(z); - stroke.offset = layer.offset.evaluate(z); - stroke.color = layer.color; - stroke.dash_array = {{ layer.dash_array[0].evaluate(z), - layer.dash_array[1].evaluate(z) }}; - stroke.opacity = layer.opacity.evaluate(z); + + if (layer.specifiers.count("enabled")) { + stroke.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("translate")) { + stroke.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + stroke.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("width")) { + stroke.width = layer.width.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; + if (layer.width_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Width] = layer.width_transition; + } + + } + + if (layer.specifiers.count("offset")) { + stroke.offset = layer.offset.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; + if (layer.offset_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Offset] = layer.offset_transition; + } + } + + if (layer.specifiers.count("color")) { + stroke.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("dasharray")) { + stroke.dash_array = {{ layer.dash_array[0].evaluate(z), + layer.dash_array[1].evaluate(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + if (layer.dash_array_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::DashArray] = layer.dash_array_transition; + } + } + + if (layer.specifiers.count("opacity")) { + stroke.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } } - // Cascade icon classes + // Cascade icon classes. for (const auto& icon_pair : sheetClass.icon) { const std::string& layer_name = icon_pair.first; const llmr::IconClass& layer = icon_pair.second; - // TODO: This should be restricted to icon styles that have actual - // values so as to not override with default values. llmr::IconProperties& icon = computed.icons[layer_name]; - icon.enabled = layer.enabled.evaluate(z); - icon.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; - icon.translateAnchor = layer.translateAnchor; - icon.color = layer.color; - icon.size = layer.size.evaluate(z); - icon.opacity = layer.opacity.evaluate(z); - icon.image = layer.image; - icon.radius = layer.radius.evaluate(z); - icon.blur = layer.blur.evaluate(z); + + if (layer.specifiers.count("enabled")) { + icon.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("translate")) { + icon.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + icon.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("color")) { + icon.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("size")) { + icon.size = layer.size.evaluate(z); + } + + if (layer.specifiers.count("opacity")) { + icon.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } + + if (layer.specifiers.count("image")) { + icon.image = layer.image; + } + + if (layer.specifiers.count("radius")) { + icon.radius = layer.radius.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; + if (layer.radius_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Radius] = layer.radius_transition; + } + } + + if (layer.specifiers.count("blur")) { + icon.blur = layer.blur.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; + if (layer.blur_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Blur] = layer.blur_transition; + } + } } - // Cascade text classes + // Cascade text classes. for (const auto& text_pair : sheetClass.text) { const std::string& layer_name = text_pair.first; const llmr::TextClass& layer = text_pair.second; - // TODO: This should be restricted to text styles that have actual - // values so as to not override with default values. llmr::TextProperties& text = computed.texts[layer_name]; - text.enabled = layer.enabled.evaluate(z); - text.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; - text.translateAnchor = layer.translateAnchor; - text.color = layer.color; - text.size = layer.size.evaluate(z); - text.halo = layer.halo; - text.halo_radius = layer.halo_radius.evaluate(z); - text.halo_blur = layer.halo_blur.evaluate(z); - text.rotate = layer.rotate.evaluate(z); - text.alwaysVisible = layer.alwaysVisible.evaluate(z); - text.opacity = layer.opacity.evaluate(z); + + if (layer.specifiers.count("enabled")) { + text.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("translate")) { + text.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + if (layer.translate_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + } + } + + if (layer.specifiers.count("translate-anchor")) { + text.translateAnchor = layer.translateAnchor; + } + + if (layer.specifiers.count("color")) { + text.color = layer.color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + if (layer.color_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + } + } + + if (layer.specifiers.count("size")) { + text.size = layer.size.evaluate(z); + } + + if (layer.specifiers.count("stroke")) { + text.halo = layer.halo; + computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; + if (layer.halo_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Halo] = layer.halo_transition; + } + } + + if (layer.specifiers.count("strokeWidth")) { + text.halo_radius = layer.halo_radius.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; + if (layer.halo_radius_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloRadius] = layer.halo_radius_transition; + } + } + + if (layer.specifiers.count("strokeBlur")) { + text.halo_blur = layer.halo_blur.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; + if (layer.halo_blur_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloBlur] = layer.halo_blur_transition; + } + } + + if (layer.specifiers.count("rotate")) { + text.rotate = layer.rotate.evaluate(z); + } + + if (layer.specifiers.count("alwaysVisible")) { + text.always_visible = layer.always_visible.evaluate(z); + } + + if (layer.specifiers.count("opacity")) { + text.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } } - // Cascade raster classes + // Cascade raster classes. for (const auto& raster_pair : sheetClass.raster) { const std::string& layer_name = raster_pair.first; const llmr::RasterClass& layer = raster_pair.second; - // TODO: This should be restricted to raster styles that have actual - // values so as to not override with default values. llmr::RasterProperties& raster = computed.rasters[layer_name]; - raster.enabled = layer.enabled.evaluate(z); - raster.opacity = layer.opacity.evaluate(z); + + if (layer.specifiers.count("enabled")) { + raster.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("opacity")) { + raster.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } } - // Cascade composite classes + // Cascade composite classes. for (const auto& composite_pair : sheetClass.composite) { const std::string& layer_name = composite_pair.first; const llmr::CompositeClass& layer = composite_pair.second; - // TODO: This should be restricted to composite styles that have actual - // values so as to not override with default values. llmr::CompositeProperties& composite = computed.composites[layer_name]; - composite.enabled = layer.enabled.evaluate(z); - composite.opacity = layer.opacity.evaluate(z); + + if (layer.specifiers.count("enabled")) { + composite.enabled = layer.enabled.evaluate(z); + } + + if (layer.specifiers.count("opacity")) { + composite.opacity = layer.opacity.evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; + if (layer.opacity_transition.duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + } + } } - - // Cascade background - computed.background.color = sheetClass.background.color; - computed.background.opacity = sheetClass.background.opacity.evaluate(z); + // Cascade background. + { + if (sheetClass.background.specifiers.count("color")) { + computed.background.color = sheetClass.background.color; + computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name; + if (sheetClass.background.color_transition.duration) { + properties_to_transition["background"][TransitionablePropertyKey::Color] = sheetClass.background.color_transition; + } + } + if (sheetClass.background.specifiers.count("opacity")) { + computed.background.opacity = sheetClass.background.opacity.evaluate(z); + computed.effective_classes["background"][TransitionablePropertyKey::Opacity] = class_name; + if (sheetClass.background.opacity_transition.duration) { + properties_to_transition["background"][TransitionablePropertyKey::Opacity] = sheetClass.background.opacity_transition; + } + } + } } + + // Apply transitions after the first time. + if (!initial_render_complete) { + initial_render_complete = true; + return; + } + + // Fills + for (const auto& fill_pair : computed.fills) { + const std::string& layer_name = fill_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.fills[layer_name].translate = previous.fills[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared>>(previous.fills[layer_name].translate, + computed.fills[layer_name].translate, + transitioning.fills[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; + } + + // fill color + if (transitionInProgress(layer_name, TransitionablePropertyKey::FillColor)) { + + computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::FillColor)) { + + transitioning.fills[layer_name].fill_color = previous.fills[layer_name].fill_color; + + transitions[layer_name][TransitionablePropertyKey::FillColor] = + std::make_shared>(previous.fills[layer_name].fill_color, + computed.fills[layer_name].fill_color, + transitioning.fills[layer_name].fill_color, + start + transitionDelay(layer_name, TransitionablePropertyKey::FillColor), + transitionDuration(layer_name, TransitionablePropertyKey::FillColor)); + + computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; + } + + // stroke color + if (transitionInProgress(layer_name, TransitionablePropertyKey::StrokeColor)) { + + computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::StrokeColor)) { + + transitioning.fills[layer_name].stroke_color = previous.fills[layer_name].stroke_color; + + transitions[layer_name][TransitionablePropertyKey::StrokeColor] = + std::make_shared>(previous.fills[layer_name].stroke_color, + computed.fills[layer_name].stroke_color, + transitioning.fills[layer_name].stroke_color, + start + transitionDelay(layer_name, TransitionablePropertyKey::StrokeColor), + transitionDuration(layer_name, TransitionablePropertyKey::StrokeColor)); + + computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.fills[layer_name].opacity = previous.fills[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.fills[layer_name].opacity, + computed.fills[layer_name].opacity, + transitioning.fills[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; + } + } + + // Lines + for (const auto& line_pair : computed.lines) { + const std::string& layer_name = line_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.lines[layer_name].translate = previous.lines[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared>>(previous.lines[layer_name].translate, + computed.lines[layer_name].translate, + transitioning.lines[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; + } + + // width + if (transitionInProgress(layer_name, TransitionablePropertyKey::Width)) { + + computed.lines[layer_name].width = transitioning.lines[layer_name].width; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Width)) { + + transitioning.lines[layer_name].width = previous.lines[layer_name].width; + + transitions[layer_name][TransitionablePropertyKey::Width] = + std::make_shared>(previous.lines[layer_name].width, + computed.lines[layer_name].width, + transitioning.lines[layer_name].width, + start + transitionDelay(layer_name, TransitionablePropertyKey::Width), + transitionDuration(layer_name, TransitionablePropertyKey::Width)); + + computed.lines[layer_name].width = transitioning.lines[layer_name].width; + } + + // offset + if (transitionInProgress(layer_name, TransitionablePropertyKey::Offset)) { + + computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Offset)) { + + transitioning.lines[layer_name].offset = previous.lines[layer_name].offset; + + transitions[layer_name][TransitionablePropertyKey::Offset] = + std::make_shared>(previous.lines[layer_name].offset, + computed.lines[layer_name].offset, + transitioning.lines[layer_name].offset, + start + transitionDelay(layer_name, TransitionablePropertyKey::Offset), + transitionDuration(layer_name, TransitionablePropertyKey::Offset)); + + computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.lines[layer_name].color = transitioning.lines[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.lines[layer_name].color = previous.lines[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared>(previous.lines[layer_name].color, + computed.lines[layer_name].color, + transitioning.lines[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.lines[layer_name].color = transitioning.lines[layer_name].color; + } + + // dasharray + if (transitionInProgress(layer_name, TransitionablePropertyKey::DashArray)) { + + computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::DashArray)) { + + transitioning.lines[layer_name].dash_array = previous.lines[layer_name].dash_array; + + transitions[layer_name][TransitionablePropertyKey::DashArray] = + std::make_shared>>(previous.lines[layer_name].dash_array, + computed.lines[layer_name].dash_array, + transitioning.lines[layer_name].dash_array, + start + transitionDelay(layer_name, TransitionablePropertyKey::DashArray), + transitionDuration(layer_name, TransitionablePropertyKey::DashArray)); + + computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.lines[layer_name].opacity = previous.lines[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.lines[layer_name].opacity, + computed.lines[layer_name].opacity, + transitioning.lines[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; + } + } + + // Icons + for (const auto& icon_pair : computed.icons) { + const std::string& layer_name = icon_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.icons[layer_name].translate = previous.icons[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared>>(previous.icons[layer_name].translate, + computed.icons[layer_name].translate, + transitioning.icons[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.icons[layer_name].color = transitioning.icons[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.icons[layer_name].color = previous.icons[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared>(previous.icons[layer_name].color, + computed.icons[layer_name].color, + transitioning.icons[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.icons[layer_name].color = transitioning.icons[layer_name].color; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.icons[layer_name].opacity = previous.icons[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.icons[layer_name].opacity, + computed.icons[layer_name].opacity, + transitioning.icons[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; + } + + // radius + if (transitionInProgress(layer_name, TransitionablePropertyKey::Radius)) { + + computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Radius)) { + + transitioning.icons[layer_name].radius = previous.icons[layer_name].radius; + + transitions[layer_name][TransitionablePropertyKey::Radius] = + std::make_shared>(previous.icons[layer_name].radius, + computed.icons[layer_name].radius, + transitioning.icons[layer_name].radius, + start + transitionDelay(layer_name, TransitionablePropertyKey::Radius), + transitionDuration(layer_name, TransitionablePropertyKey::Radius)); + + computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; + } + + // blur + if (transitionInProgress(layer_name, TransitionablePropertyKey::Blur)) { + + computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Blur)) { + + transitioning.icons[layer_name].blur = previous.icons[layer_name].blur; + + transitions[layer_name][TransitionablePropertyKey::Blur] = + std::make_shared>(previous.icons[layer_name].blur, + computed.icons[layer_name].blur, + transitioning.icons[layer_name].blur, + start + transitionDelay(layer_name, TransitionablePropertyKey::Blur), + transitionDuration(layer_name, TransitionablePropertyKey::Blur)); + + computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; + } + } + + // Text + for (const auto& text_pair : computed.texts) { + const std::string& layer_name = text_pair.first; + + // translate + if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate)) { + + computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { + + transitioning.texts[layer_name].translate = previous.texts[layer_name].translate; + + transitions[layer_name][TransitionablePropertyKey::Translate] = + std::make_shared>>(previous.texts[layer_name].translate, + computed.texts[layer_name].translate, + transitioning.texts[layer_name].translate, + start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), + transitionDuration(layer_name, TransitionablePropertyKey::Translate)); + + computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; + } + + // color + if (transitionInProgress(layer_name, TransitionablePropertyKey::Color)) { + + computed.texts[layer_name].color = transitioning.texts[layer_name].color; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { + + transitioning.texts[layer_name].color = previous.texts[layer_name].color; + + transitions[layer_name][TransitionablePropertyKey::Color] = + std::make_shared>(previous.texts[layer_name].color, + computed.texts[layer_name].color, + transitioning.texts[layer_name].color, + start + transitionDelay(layer_name, TransitionablePropertyKey::Color), + transitionDuration(layer_name, TransitionablePropertyKey::Color)); + + computed.texts[layer_name].color = transitioning.texts[layer_name].color; + } + + // halo + if (transitionInProgress(layer_name, TransitionablePropertyKey::Halo)) { + + computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Halo)) { + + transitioning.texts[layer_name].halo = previous.texts[layer_name].halo; + + transitions[layer_name][TransitionablePropertyKey::Halo] = + std::make_shared>(previous.texts[layer_name].halo, + computed.texts[layer_name].halo, + transitioning.texts[layer_name].halo, + start + transitionDelay(layer_name, TransitionablePropertyKey::Halo), + transitionDuration(layer_name, TransitionablePropertyKey::Halo)); + + computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; + } + + // halo radius + if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloRadius)) { + + computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloRadius)) { + + transitioning.texts[layer_name].halo_radius = previous.texts[layer_name].halo_radius; + + transitions[layer_name][TransitionablePropertyKey::HaloRadius] = + std::make_shared>(previous.texts[layer_name].halo_radius, + computed.texts[layer_name].halo_radius, + transitioning.texts[layer_name].halo_radius, + start + transitionDelay(layer_name, TransitionablePropertyKey::HaloRadius), + transitionDuration(layer_name, TransitionablePropertyKey::HaloRadius)); + + computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; + } + + // halo blur + if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloBlur)) { + + computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloBlur)) { + + transitioning.texts[layer_name].halo_blur = previous.texts[layer_name].halo_blur; + + transitions[layer_name][TransitionablePropertyKey::HaloBlur] = + std::make_shared>(previous.texts[layer_name].halo_blur, + computed.texts[layer_name].halo_blur, + transitioning.texts[layer_name].halo_blur, + start + transitionDelay(layer_name, TransitionablePropertyKey::HaloBlur), + transitionDuration(layer_name, TransitionablePropertyKey::HaloBlur)); + + computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; + } + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.texts[layer_name].opacity = previous.texts[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.texts[layer_name].opacity, + computed.texts[layer_name].opacity, + transitioning.texts[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; + } + } + + // Rasters + for (const auto& raster_pair : computed.rasters) { + const std::string& layer_name = raster_pair.first; + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.rasters[layer_name].opacity = previous.rasters[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.rasters[layer_name].opacity, + computed.rasters[layer_name].opacity, + transitioning.rasters[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; + } + } + + // Composites + for (const auto& composite_pair : computed.composites) { + const std::string& layer_name = composite_pair.first; + + // opacity + if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity)) { + + computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; + + } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { + + transitioning.composites[layer_name].opacity = previous.composites[layer_name].opacity; + + transitions[layer_name][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.composites[layer_name].opacity, + computed.composites[layer_name].opacity, + transitioning.composites[layer_name].opacity, + start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), + transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); + + computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; + } + } + + // Background + { + // color + if (transitionInProgress("background", TransitionablePropertyKey::Color)) { + + computed.background.color = transitioning.background.color; + + } else if (inNeedOfTransition("background", TransitionablePropertyKey::Color)) { + + transitioning.background.color = previous.background.color; + + transitions["background"][TransitionablePropertyKey::Color] = + std::make_shared>(previous.background.color, + computed.background.color, + transitioning.background.color, + start + transitionDelay("background", TransitionablePropertyKey::Color), + transitionDuration("background", TransitionablePropertyKey::Color)); + + computed.background.color = transitioning.background.color; + } + + // opacity + if (transitionInProgress("background", TransitionablePropertyKey::Opacity)) { + + computed.background.opacity = transitioning.background.opacity; + + } else if (inNeedOfTransition("background", TransitionablePropertyKey::Opacity)) { + + transitioning.background.opacity = previous.background.opacity; + + transitions["background"][TransitionablePropertyKey::Opacity] = + std::make_shared>(previous.background.opacity, + computed.background.opacity, + transitioning.background.opacity, + start + transitionDelay("background", TransitionablePropertyKey::Opacity), + transitionDuration("background", TransitionablePropertyKey::Opacity)); + + computed.background.opacity = transitioning.background.opacity; + } + } +} + +bool Style::transitionInProgress(std::string layer_name, TransitionablePropertyKey key) { + if (!transitionExists(layer_name, key)) return false; + + return (transitions[layer_name].find(key)->second->update(util::now()) != util::transition::complete); +} + +bool Style::transitionExists(std::string layer_name, TransitionablePropertyKey key) { + return (transitions[layer_name].count(key) != 0); +} + +bool Style::inNeedOfTransition(std::string layer_name, TransitionablePropertyKey key) { + if (!transitionDuration(layer_name, key)) return false; + if (transitionExists(layer_name, key)) return false; + + return (computed.effective_classes[layer_name][key] != previous.effective_classes[layer_name][key]); +} + +uint64_t Style::transitionDuration(std::string layer_name, TransitionablePropertyKey key) { + return (properties_to_transition[layer_name].count(key) ? + properties_to_transition[layer_name][key].duration : + default_transition_duration) * 1_millisecond; +} + +uint64_t Style::transitionDelay(std::string layer_name, TransitionablePropertyKey key) { + return (properties_to_transition[layer_name][key].delay * 1_millisecond); +} + +bool Style::needsTransition() const { + uv::readlock lock(mtx); + + for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { + auto& layer_transitions = layer_it->second; + if (layer_transitions.size()) { + return true; + } + } + + return false; +} + +void Style::updateTransitions(time now) { + uv::writelock lock(mtx); + + for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { + auto& layer_transitions = layer_it->second; + for (auto prop_it = layer_transitions.begin(); prop_it != layer_transitions.end();/**/) { + auto& transition = prop_it->second; + if (transition->update(now) == util::transition::complete) { + prop_it = layer_transitions.erase(prop_it); + } else { + prop_it++; + } + } + } +} + +void Style::cancelTransitions() { + uv::writelock lock(mtx); + + transitions.clear(); } size_t Style::layerCount() const { @@ -158,6 +968,10 @@ size_t Style::layerCount() const { return count; } +void Style::setDefaultTransitionDuration(uint64_t duration) { + default_transition_duration = duration; +} + void Style::loadJSON(const uint8_t *const data, size_t bytes) { rapidjson::Document doc; diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 2198d5c36..feef6e3e1 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -477,42 +477,82 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } +PropertyTransition StyleParser::parseTransition(JSVal value, std::string property_name) { + uint16_t duration = 0, delay = 0; + std::string transition_property = std::string("transition-").append(property_name); + if (value.HasMember(transition_property.c_str())) { + JSVal elements = value[transition_property.c_str()]; + if (elements.IsObject()) { + if (elements.HasMember("duration") && elements["duration"].IsNumber()) { + duration = elements["duration"].GetUint(); + } + if (elements.HasMember("delay") && elements["delay"].IsNumber()) { + delay = elements["delay"].GetUint(); + } + } + } + + PropertyTransition transition; + + transition.duration = duration; + transition.delay = delay; + + return transition; +} + FillClass StyleParser::parseFillClass(JSVal value) { FillClass klass; if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); + } + + if (value.HasMember("winding")) { + throw std::runtime_error("winding in stylesheets not yet supported"); } if (value.HasMember("color")) { klass.fill_color = parseColor(value["color"]); + klass.fill_color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.stroke_color = parseColor(value["stroke"]); + klass.stroke_color_transition = parseTransition(value, "stroke"); + klass.specifiers.insert("stroke"); } else { klass.stroke_color = klass.fill_color; + klass.specifiers.insert("stroke"); } if (value.HasMember("antialias")) { klass.antialias = parseBoolean(value["antialias"]); + klass.specifiers.insert("antialias"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); + klass.specifiers.insert("image"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -523,32 +563,44 @@ LineClass StyleParser::parseLineClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("width")) { klass.width = parseFunction(value["width"]); + klass.width_transition = parseTransition(value, "width"); + klass.specifiers.insert("width"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } if (value.HasMember("dasharray")) { std::vector values = parseArray(value["dasharray"], 2); klass.dash_array = std::array {{ values[0], values[1] }}; + klass.dash_array_transition = parseTransition(value, "dasharray"); + klass.specifiers.insert("dasharray"); } return klass; @@ -559,39 +611,53 @@ IconClass StyleParser::parseIconClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); + klass.specifiers.insert("image"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); + klass.specifiers.insert("size"); } if (value.HasMember("radius")) { klass.radius = parseFunction(value["radius"]); + klass.radius_transition = parseTransition(value, "radius"); + klass.specifiers.insert("radius"); } if (value.HasMember("blur")) { klass.blur = parseFunction(value["blur"]); + klass.blur_transition = parseTransition(value, "blur"); + klass.specifiers.insert("blur"); } return klass; @@ -602,43 +668,64 @@ TextClass StyleParser::parseTextClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; + klass.translate_transition = parseTransition(value, "translate"); + klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.halo = parseColor(value["stroke"]); + klass.halo_transition = parseTransition(value, "stroke"); + klass.specifiers.insert("stroke"); } if (value.HasMember("strokeWidth")) { klass.halo_radius = parseFunction(value["strokeWidth"]); + klass.halo_radius_transition = parseTransition(value, "strokeWidth"); + klass.specifiers.insert("strokeWidth"); } if (value.HasMember("strokeBlur")) { klass.halo_blur = parseFunction(value["strokeBlur"]); + klass.halo_blur_transition = parseTransition(value, "strokeBlur"); + klass.specifiers.insert("strokeBlur"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); + klass.specifiers.insert("size"); } if (value.HasMember("rotate")) { klass.rotate = parseFunction(value["rotate"]); + klass.specifiers.insert("rotate"); } if (value.HasMember("alwaysVisible")) { - klass.alwaysVisible = parseFunction(value["alwaysVisible"]); + klass.always_visible = parseFunction(value["alwaysVisible"]); + klass.specifiers.insert("alwaysVisible"); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -649,10 +736,13 @@ RasterClass StyleParser::parseRasterClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -663,10 +753,13 @@ CompositeClass StyleParser::parseCompositeClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); + klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; @@ -677,10 +770,14 @@ BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { if (value.HasMember("color")) { klass.color = parseColor(value["color"]); + klass.color_transition = parseTransition(value, "color"); + klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); + klass.opacity_transition = parseTransition(value, "opacity"); + klass.specifiers.insert("opacity"); } return klass; diff --git a/src/util/raster.cpp b/src/util/raster.cpp index 4f26f8b55..e08145231 100644 --- a/src/util/raster.cpp +++ b/src/util/raster.cpp @@ -70,7 +70,7 @@ void Raster::bind(bool linear) { void Raster::beginFadeInTransition() { time start = util::now(); - fade_transition = std::make_shared(opacity, 1.0, opacity, start, 250_milliseconds); + fade_transition = std::make_shared>(opacity, 1.0, opacity, start, 250_milliseconds); } bool Raster::needsTransition() const { diff --git a/src/util/transition.cpp b/src/util/transition.cpp index af5b5a70a..d15e3ef66 100644 --- a/src/util/transition.cpp +++ b/src/util/transition.cpp @@ -8,20 +8,69 @@ UnitBezier ease(0.25, 0.1, 0.25, 1); transition::~transition() {} -ease_transition::ease_transition(double from, double to, double &value, time start, time duration) - : transition(start, duration), - from(from), - to(to), - value(value) { +double transition::interpolateDouble(double from, double to, double t) const { + return from + (to - from) * t; } -transition::state ease_transition::update(time now) const { +float transition::interpolateFloat(float from, float to, double t) const { + return from + (to - from) * (float)t; +} + +llmr::Color transition::interpolateColor(llmr::Color from, llmr::Color to, double t) const { + return {{ interpolateFloat(from[0], to[0], t), + interpolateFloat(from[1], to[1], t), + interpolateFloat(from[2], to[2], t), + interpolateFloat(from[3], to[3], t) }}; +} + +std::array transition::interpolateFloatArray(std::array from, std::array to, double t) const { + return {{ interpolateFloat(from[0], to[0], t), interpolateFloat(from[1], to[1], t) }}; +} + +template <> +transition::state ease_transition::update(llmr::time now) const { float t = progress(now); if (t >= 1) { value = to; return complete; } else { - value = from + (to - from) * ease.solve(t, 0.001); + value = interpolateDouble(from, to, ease.solve(t, 0.001)); + return running; + } +} + +template <> +transition::state ease_transition::update(llmr::time now) const { + float t = progress(now); + if (t >= 1) { + value = to; + return complete; + } else { + value = interpolateColor(from, to, ease.solve(t, 0.001)); + return running; + } +} + +template <> +transition::state ease_transition::update(llmr::time now) const { + float t = progress(now); + if (t >= 1) { + value = to; + return complete; + } else { + value = interpolateFloat(from, to, ease.solve(t, 0.001)); + return running; + } +} + +template <> +transition::state ease_transition>::update(llmr::time now) const { + float t = progress(now); + if (t >= 1) { + value = to; + return complete; + } else { + value = interpolateFloatArray(from, to, ease.solve(t, 0.001)); return running; } } From 80cb89a6b5edef7ad43add8ff355287afea09eaf Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 12:52:06 -0700 Subject: [PATCH 06/13] be sure to track previous composites --- src/style/style.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/style/style.cpp b/src/style/style.cpp index b39a0bf5d..2d13ceef9 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -35,6 +35,7 @@ void Style::cascade(float z) { previous.icons = computed.icons; previous.texts = computed.texts; previous.rasters = computed.rasters; + previous.composites = computed.composites; previous.background = computed.background; previous.effective_classes = computed.effective_classes; From bccba9702077921af35ad31228fccca7ee2b5d04 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 14:22:54 -0700 Subject: [PATCH 07/13] style cascading needs to happen every render for transitions --- src/map/map.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/map/map.cpp b/src/map/map.cpp index d70821380..0cac0a512 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -438,7 +438,6 @@ void Map::prepare() { bool pixelRatioChanged = oldState.getPixelRatio() != state.getPixelRatio(); bool dimensionsChanged = oldState.getFramebufferWidth() != state.getFramebufferWidth() || oldState.getFramebufferHeight() != state.getFramebufferHeight(); - bool zoomChanged = oldState.getNormalizedZoom() != state.getNormalizedZoom(); if (pixelRatioChanged) { // We have a pixelratio change @@ -452,9 +451,7 @@ void Map::prepare() { painter.clearFramebuffers(); } - if (zoomChanged) { - style.cascade(state.getNormalizedZoom()); - } + style.cascade(state.getNormalizedZoom()); animationTime = util::now(); if (style.needsTransition()) { From 12594ce8f1c69061f477c50604b21a3211e5dd72 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 14:24:54 -0700 Subject: [PATCH 08/13] clearer comments --- src/map/map.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/map/map.cpp b/src/map/map.cpp index 0cac0a512..3c0fbbcbb 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -425,13 +425,12 @@ void Map::updateRenderState() { void Map::prepare() { view.make_active(); - // Update transitions + // Update transform transitions. animationTime = util::now(); if (transform.needsTransition()) { transform.updateTransitions(animationTime); } - const TransformState oldState = state; state = transform.currentState(); @@ -440,7 +439,6 @@ void Map::prepare() { oldState.getFramebufferHeight() != state.getFramebufferHeight(); if (pixelRatioChanged) { - // We have a pixelratio change style.sprite = std::make_shared(*this, state.getPixelRatio()); style.sprite->load(kSpriteURL); @@ -453,6 +451,7 @@ void Map::prepare() { style.cascade(state.getNormalizedZoom()); + // Update style transitions. animationTime = util::now(); if (style.needsTransition()) { style.updateTransitions(animationTime); From cb039d9b9e7cd7c26efb89de4f23e7a0a7424602 Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 22 May 2014 14:39:56 -0700 Subject: [PATCH 09/13] include noveg in wetland bucket --- bin/style.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/style.js b/bin/style.js index 28ae151c5..f8ce84b6c 100644 --- a/bin/style.js +++ b/bin/style.js @@ -197,7 +197,7 @@ module.exports = { "source": "outdoors", "layer": "landuse_overlay", "field": "class", - "value": "wetland", + "value": ["wetland", "wetland_noveg"], "type": "fill" }, "overlay_breakwater_pier": { From 1ff173a0494bdc76bc4a262948b62dd114ef1d61 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 16:11:21 -0700 Subject: [PATCH 10/13] fixes #48: constrain min zoom/vertical pan to within world --- include/llmr/map/transform.hpp | 2 ++ src/map/transform.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp index 550d14b14..4226ec7e4 100644 --- a/include/llmr/map/transform.hpp +++ b/include/llmr/map/transform.hpp @@ -68,6 +68,8 @@ private: void _clearRotating(); void _clearScaling(); + void constrain(double& scale, double& y); + private: mutable uv::rwlock mtx; diff --git a/src/map/transform.cpp b/src/map/transform.cpp index 93942edad..e05bb38f3 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -32,6 +32,7 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio, current.pixelRatio = final.pixelRatio = ratio; current.framebuffer[0] = final.framebuffer[0] = fb_w; current.framebuffer[1] = final.framebuffer[1] = fb_h; + constrain(current.scale, current.y); return true; } else { return false; @@ -52,6 +53,8 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { final.x = current.x + std::cos(current.angle) * dx + std::sin(current.angle) * dy; final.y = current.y + std::cos(current.angle) * dy + std::sin(-current.angle) * dx; + constrain(final.scale, final.y); + if (duration == 0) { current.x = final.x; current.y = final.y; @@ -243,6 +246,8 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl final.x = xn; final.y = yn; + constrain(final.scale, final.y); + if (duration == 0) { current.scale = final.scale; current.x = final.x; @@ -264,6 +269,19 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl Cc = s / (2 * M_PI); } +#pragma mark - Constraints + +void Transform::constrain(double& scale, double& y) { + // Constrain minimum zoom to avoid zooming out far enough to show off-world areas. + if (scale < (current.height / util::tileSize)) scale = (current.height / util::tileSize); + + // Constrain min/max vertical pan to avoid showing off-world areas. + double max_y = ((scale * util::tileSize) - current.height) / 2; + + if (y > max_y) y = max_y; + if (y < -max_y) y = -max_y; +} + #pragma mark - Angle void Transform::rotateBy(const double start_x, const double start_y, const double end_x, From dbd877cb80bf36197defa2a5ac8ea6df6f04eb24 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 16:47:17 -0700 Subject: [PATCH 11/13] disallow/undo rotation at low zooms --- src/map/transform.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/map/transform.cpp b/src/map/transform.cpp index e05bb38f3..4f13fdaf8 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -12,6 +12,7 @@ using namespace llmr; const double D2R = M_PI / 180.0; const double R2D = 180.0 / M_PI; const double M2PI = 2 * M_PI; +const double MIN_ROTATE_SCALE = 8; Transform::Transform() { setScale(current.scale); @@ -248,6 +249,9 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl constrain(final.scale, final.y); + // Undo rotation at low zooms. + if (final.scale < MIN_ROTATE_SCALE && current.angle) _setAngle(0, 500_milliseconds); + if (duration == 0) { current.scale = final.scale; current.x = final.x; @@ -349,6 +353,9 @@ void Transform::_setAngle(double new_angle, const time duration) { final.angle = new_angle; + // Prevent rotation at low zooms. + if (final.scale < MIN_ROTATE_SCALE) final.angle = 0; + if (duration == 0) { current.angle = final.angle; } else { From 3f55302fb52a70cc646ddcd57ab062e94ef514f1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 22 May 2014 16:54:04 -0700 Subject: [PATCH 12/13] reset angle on resize to small zooms --- src/map/transform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/map/transform.cpp b/src/map/transform.cpp index 4f13fdaf8..23e42b764 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -34,6 +34,7 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio, current.framebuffer[0] = final.framebuffer[0] = fb_w; current.framebuffer[1] = final.framebuffer[1] = fb_h; constrain(current.scale, current.y); + if (current.scale < MIN_ROTATE_SCALE && current.angle) _setAngle(0, 0); return true; } else { return false; From ce2270eafcb1e052e7b6aa089e2460cc0003c9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 23 May 2014 13:14:11 +0200 Subject: [PATCH 13/13] use boost optional to mark initialized values --- include/llmr/style/properties.hpp | 149 ++++++++-------- src/style/style.cpp | 282 +++++++++++++++--------------- src/style/style_parser.cpp | 42 ----- 3 files changed, 213 insertions(+), 260 deletions(-) diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 37c26b470..ba0979cb9 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace llmr { // Stores a premultiplied color, with all four channels ranging from 0..1 @@ -83,21 +85,20 @@ struct FunctionProperty { }; struct IconClass { - FunctionProperty enabled = true; - std::array translate = {{ 0, 0 }}; - PropertyTransition translate_transition; - TranslateAnchor translateAnchor = TranslateAnchor::Map; - FunctionProperty size; - Color color = {{ 1, 1, 1, 1 }}; - PropertyTransition color_transition; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::string image; - FunctionProperty radius = 0; - PropertyTransition radius_transition; - FunctionProperty blur = 0; - PropertyTransition blur_transition; - std::set specifiers; + boost::optional enabled; + boost::optional> translate; + boost::optional translate_transition; + boost::optional translateAnchor; + boost::optional size; + boost::optional color; + boost::optional color_transition; + boost::optional opacity; + boost::optional opacity_transition; + boost::optional image; + boost::optional radius; + boost::optional radius_transition; + boost::optional blur; + boost::optional blur_transition; }; struct IconProperties { @@ -113,21 +114,20 @@ struct IconProperties { }; struct LineClass { - FunctionProperty enabled = true; - std::array translate = {{ 0, 0 }}; - PropertyTransition translate_transition; - TranslateAnchor translateAnchor = TranslateAnchor::Map; - FunctionProperty width; - PropertyTransition width_transition; - FunctionProperty offset; - PropertyTransition offset_transition; - Color color = {{ 0, 0, 0, 1 }}; - PropertyTransition color_transition; - std::array dash_array = {{ 1, -1 }}; - PropertyTransition dash_array_transition; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::set specifiers; + boost::optional enabled; + boost::optional> translate; + boost::optional translate_transition; + boost::optional translateAnchor; + boost::optional width; + boost::optional width_transition; + boost::optional offset; + boost::optional offset_transition; + boost::optional color; + boost::optional color_transition; + boost::optional> dash_array; + boost::optional dash_array_transition; + boost::optional opacity; + boost::optional opacity_transition; }; struct LineProperties { @@ -142,20 +142,19 @@ struct LineProperties { }; struct FillClass { - FunctionProperty enabled = true; - std::array translate = {{ 0, 0 }}; - PropertyTransition translate_transition; - TranslateAnchor translateAnchor = TranslateAnchor::Map; - Winding winding = Winding::NonZero; - FunctionProperty antialias = true; - Color fill_color = {{ 0, 0, 0, 1 }}; - PropertyTransition fill_color_transition; - Color stroke_color = {{ 0, 0, 0, std::numeric_limits::infinity() }}; - PropertyTransition stroke_color_transition; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::string image; - std::set specifiers; + boost::optional enabled; + boost::optional> translate; + boost::optional translate_transition; + boost::optional translateAnchor; + boost::optional winding; + boost::optional antialias; + boost::optional fill_color; + boost::optional fill_color_transition; + boost::optional stroke_color; + boost::optional stroke_color_transition; + boost::optional opacity; + boost::optional opacity_transition; + boost::optional image; }; struct FillProperties { @@ -171,24 +170,23 @@ struct FillProperties { }; struct TextClass { - FunctionProperty enabled = true; - std::array translate = {{ 0, 0 }}; - PropertyTransition translate_transition; - TranslateAnchor translateAnchor = TranslateAnchor::Map; - Color color = {{ 0, 0, 0, 1 }}; - PropertyTransition color_transition; - Color halo = {{ 1, 1, 1, 0.75 }}; - PropertyTransition halo_transition; - FunctionProperty halo_radius = 0.25f; - PropertyTransition halo_radius_transition; - FunctionProperty halo_blur = 1.0f; - PropertyTransition halo_blur_transition; - FunctionProperty size = 12.0f; - FunctionProperty rotate = 0.0f; - FunctionProperty always_visible = false; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::set specifiers; + boost::optional enabled; + boost::optional> translate; + boost::optional translate_transition; + boost::optional translateAnchor; + boost::optional color; + boost::optional color_transition; + boost::optional halo; + boost::optional halo_transition; + boost::optional halo_radius; + boost::optional halo_radius_transition; + boost::optional halo_blur; + boost::optional halo_blur_transition; + boost::optional size; + boost::optional rotate; + boost::optional always_visible; + boost::optional opacity; + boost::optional opacity_transition; }; struct TextProperties { @@ -206,11 +204,10 @@ struct TextProperties { }; struct BackgroundClass { - Color color = {{ 1, 1, 1, 1 }}; - PropertyTransition color_transition; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::set specifiers; + boost::optional color; + boost::optional color_transition; + boost::optional opacity; + boost::optional opacity_transition; }; struct BackgroundProperties { @@ -219,12 +216,11 @@ struct BackgroundProperties { }; struct RasterClass { - FunctionProperty enabled = true; - std::array translate = {{ 0, 0 }}; - PropertyTransition translate_transition; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::set specifiers; + boost::optional enabled; + boost::optional> translate; + boost::optional translate_transition; + boost::optional opacity; + boost::optional opacity_transition; }; struct RasterProperties { @@ -234,10 +230,9 @@ struct RasterProperties { }; struct CompositeClass { - FunctionProperty enabled = true; - FunctionProperty opacity = 1; - PropertyTransition opacity_transition; - std::set specifiers; + boost::optional enabled; + boost::optional opacity; + boost::optional opacity_transition; }; struct CompositeProperties { diff --git a/src/style/style.cpp b/src/style/style.cpp index 2d13ceef9..918709924 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -62,57 +62,57 @@ void Style::cascade(float z) { llmr::FillProperties& fill = computed.fills[layer_name]; - if (layer.specifiers.count("enabled")) { - fill.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + fill.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("translate")) { - fill.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; + if (layer.translate) { + fill.translate = {{ layer.translate.get()[0].evaluate(z), + layer.translate.get()[1].evaluate(z) }}; computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (layer.translate_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + if (layer.translate_transition && layer.translate_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get(); } } - if (layer.specifiers.count("translate-anchor")) { - fill.translateAnchor = layer.translateAnchor; + if (layer.translateAnchor) { + fill.translateAnchor = layer.translateAnchor.get(); } - if (layer.specifiers.count("winding")) { - fill.winding = layer.winding; + if (layer.winding) { + fill.winding = layer.winding.get(); } - if (layer.specifiers.count("antialias")) { - fill.antialias = layer.antialias.evaluate(z); + if (layer.antialias) { + fill.antialias = layer.antialias.get().evaluate(z); } - if (layer.specifiers.count("color")) { - fill.fill_color = layer.fill_color; + if (layer.fill_color) { + fill.fill_color = layer.fill_color.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; - if (layer.fill_color_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::FillColor] = layer.fill_color_transition; + if (layer.fill_color_transition && layer.fill_color_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::FillColor] = layer.fill_color_transition.get(); } } - if (layer.specifiers.count("stroke")) { - fill.stroke_color = layer.stroke_color; + if (layer.stroke_color) { + fill.stroke_color = layer.stroke_color.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - if (layer.stroke_color_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::StrokeColor] = layer.stroke_color_transition; + if (layer.stroke_color_transition && layer.stroke_color_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::StrokeColor] = layer.stroke_color_transition.get(); } } - if (layer.specifiers.count("opacity")) { - fill.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + fill.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } - if (layer.specifiers.count("image")) { - fill.image = layer.image; + if (layer.image) { + fill.image = layer.image.get(); } } @@ -123,62 +123,62 @@ void Style::cascade(float z) { llmr::LineProperties& stroke = computed.lines[layer_name]; - if (layer.specifiers.count("enabled")) { - stroke.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + stroke.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("translate")) { - stroke.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; + if (layer.translate) { + stroke.translate = {{ layer.translate.get()[0].evaluate(z), + layer.translate.get()[1].evaluate(z) }}; computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (layer.translate_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + if (layer.translate_transition && layer.translate_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get(); } } - if (layer.specifiers.count("translate-anchor")) { - stroke.translateAnchor = layer.translateAnchor; + if (layer.translateAnchor) { + stroke.translateAnchor = layer.translateAnchor.get(); } - if (layer.specifiers.count("width")) { - stroke.width = layer.width.evaluate(z); + if (layer.width) { + stroke.width = layer.width.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; - if (layer.width_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Width] = layer.width_transition; + if (layer.width_transition && layer.width_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Width] = layer.width_transition.get(); } } - if (layer.specifiers.count("offset")) { - stroke.offset = layer.offset.evaluate(z); + if (layer.offset) { + stroke.offset = layer.offset.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; - if (layer.offset_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Offset] = layer.offset_transition; + if (layer.offset_transition && layer.offset_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Offset] = layer.offset_transition.get(); } } - if (layer.specifiers.count("color")) { - stroke.color = layer.color; + if (layer.color) { + stroke.color = layer.color.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + if (layer.color_transition && layer.color_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition.get(); } } - if (layer.specifiers.count("dasharray")) { - stroke.dash_array = {{ layer.dash_array[0].evaluate(z), - layer.dash_array[1].evaluate(z) }}; + if (layer.dash_array) { + stroke.dash_array = {{ layer.dash_array.get()[0].evaluate(z), + layer.dash_array.get()[1].evaluate(z) }}; computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; - if (layer.dash_array_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::DashArray] = layer.dash_array_transition; + if (layer.dash_array_transition && layer.dash_array_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::DashArray] = layer.dash_array_transition.get(); } } - if (layer.specifiers.count("opacity")) { - stroke.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + stroke.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } } @@ -190,60 +190,60 @@ void Style::cascade(float z) { llmr::IconProperties& icon = computed.icons[layer_name]; - if (layer.specifiers.count("enabled")) { - icon.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + icon.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("translate")) { - icon.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; + if (layer.translate) { + icon.translate = {{ layer.translate.get()[0].evaluate(z), + layer.translate.get()[1].evaluate(z) }}; computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (layer.translate_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + if (layer.translate_transition && layer.translate_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get(); } } - if (layer.specifiers.count("translate-anchor")) { - icon.translateAnchor = layer.translateAnchor; + if (layer.translateAnchor) { + icon.translateAnchor = layer.translateAnchor.get(); } - if (layer.specifiers.count("color")) { - icon.color = layer.color; + if (layer.color) { + icon.color = layer.color.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + if (layer.color_transition && layer.color_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition.get(); } } - if (layer.specifiers.count("size")) { - icon.size = layer.size.evaluate(z); + if (layer.size) { + icon.size = layer.size.get().evaluate(z); } - if (layer.specifiers.count("opacity")) { - icon.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + icon.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } - if (layer.specifiers.count("image")) { - icon.image = layer.image; + if (layer.image) { + icon.image = layer.image.get(); } - if (layer.specifiers.count("radius")) { - icon.radius = layer.radius.evaluate(z); + if (layer.radius) { + icon.radius = layer.radius.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; - if (layer.radius_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Radius] = layer.radius_transition; + if (layer.radius_transition && layer.radius_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Radius] = layer.radius_transition.get(); } } - if (layer.specifiers.count("blur")) { - icon.blur = layer.blur.evaluate(z); + if (layer.blur) { + icon.blur = layer.blur.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; - if (layer.blur_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Blur] = layer.blur_transition; + if (layer.blur_transition && layer.blur_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Blur] = layer.blur_transition.get(); } } } @@ -255,72 +255,72 @@ void Style::cascade(float z) { llmr::TextProperties& text = computed.texts[layer_name]; - if (layer.specifiers.count("enabled")) { - text.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + text.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("translate")) { - text.translate = {{ layer.translate[0].evaluate(z), - layer.translate[1].evaluate(z) }}; + if (layer.translate) { + text.translate = {{ layer.translate.get()[0].evaluate(z), + layer.translate.get()[1].evaluate(z) }}; computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (layer.translate_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition; + if (layer.translate_transition && layer.translate_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get(); } } - if (layer.specifiers.count("translate-anchor")) { - text.translateAnchor = layer.translateAnchor; + if (layer.translateAnchor) { + text.translateAnchor = layer.translateAnchor.get(); } - if (layer.specifiers.count("color")) { - text.color = layer.color; + if (layer.color) { + text.color = layer.color.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition; + if (layer.color_transition && layer.color_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Color] = layer.color_transition.get(); } } - if (layer.specifiers.count("size")) { - text.size = layer.size.evaluate(z); + if (layer.size) { + text.size = layer.size.get().evaluate(z); } - if (layer.specifiers.count("stroke")) { - text.halo = layer.halo; + if (layer.halo) { + text.halo = layer.halo.get(); computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; - if (layer.halo_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Halo] = layer.halo_transition; + if (layer.halo_transition && layer.halo_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Halo] = layer.halo_transition.get(); } } - if (layer.specifiers.count("strokeWidth")) { - text.halo_radius = layer.halo_radius.evaluate(z); + if (layer.halo_radius) { + text.halo_radius = layer.halo_radius.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; - if (layer.halo_radius_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::HaloRadius] = layer.halo_radius_transition; + if (layer.halo_radius_transition && layer.halo_radius_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloRadius] = layer.halo_radius_transition.get(); } } - if (layer.specifiers.count("strokeBlur")) { - text.halo_blur = layer.halo_blur.evaluate(z); + if (layer.halo_blur) { + text.halo_blur = layer.halo_blur.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; - if (layer.halo_blur_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::HaloBlur] = layer.halo_blur_transition; + if (layer.halo_blur_transition && layer.halo_blur_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::HaloBlur] = layer.halo_blur_transition.get(); } } - if (layer.specifiers.count("rotate")) { - text.rotate = layer.rotate.evaluate(z); + if (layer.rotate) { + text.rotate = layer.rotate.get().evaluate(z); } - if (layer.specifiers.count("alwaysVisible")) { - text.always_visible = layer.always_visible.evaluate(z); + if (layer.always_visible) { + text.always_visible = layer.always_visible.get().evaluate(z); } - if (layer.specifiers.count("opacity")) { - text.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + text.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } } @@ -332,15 +332,15 @@ void Style::cascade(float z) { llmr::RasterProperties& raster = computed.rasters[layer_name]; - if (layer.specifiers.count("enabled")) { - raster.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + raster.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("opacity")) { - raster.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + raster.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } } @@ -352,33 +352,33 @@ void Style::cascade(float z) { llmr::CompositeProperties& composite = computed.composites[layer_name]; - if (layer.specifiers.count("enabled")) { - composite.enabled = layer.enabled.evaluate(z); + if (layer.enabled) { + composite.enabled = layer.enabled.get().evaluate(z); } - if (layer.specifiers.count("opacity")) { - composite.opacity = layer.opacity.evaluate(z); + if (layer.opacity) { + composite.opacity = layer.opacity.get().evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (layer.opacity_transition.duration) { - properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition; + if (layer.opacity_transition && layer.opacity_transition.get().duration) { + properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get(); } } } // Cascade background. { - if (sheetClass.background.specifiers.count("color")) { - computed.background.color = sheetClass.background.color; + if (sheetClass.background.color) { + computed.background.color = sheetClass.background.color.get(); computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name; - if (sheetClass.background.color_transition.duration) { - properties_to_transition["background"][TransitionablePropertyKey::Color] = sheetClass.background.color_transition; + if (sheetClass.background.color_transition && sheetClass.background.color_transition.get().duration) { + properties_to_transition["background"][TransitionablePropertyKey::Color] = sheetClass.background.color_transition.get(); } } - if (sheetClass.background.specifiers.count("opacity")) { - computed.background.opacity = sheetClass.background.opacity.evaluate(z); + if (sheetClass.background.opacity) { + computed.background.opacity = sheetClass.background.opacity.get().evaluate(z); computed.effective_classes["background"][TransitionablePropertyKey::Opacity] = class_name; - if (sheetClass.background.opacity_transition.duration) { - properties_to_transition["background"][TransitionablePropertyKey::Opacity] = sheetClass.background.opacity_transition; + if (sheetClass.background.opacity_transition && sheetClass.background.opacity_transition.get().duration) { + properties_to_transition["background"][TransitionablePropertyKey::Opacity] = sheetClass.background.opacity_transition.get(); } } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index feef6e3e1..c299f1fd9 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -505,19 +505,16 @@ FillClass StyleParser::parseFillClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; klass.translate_transition = parseTransition(value, "translate"); - klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); - klass.specifiers.insert("translate-anchor"); } if (value.HasMember("winding")) { @@ -527,32 +524,26 @@ FillClass StyleParser::parseFillClass(JSVal value) { if (value.HasMember("color")) { klass.fill_color = parseColor(value["color"]); klass.fill_color_transition = parseTransition(value, "color"); - klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.stroke_color = parseColor(value["stroke"]); klass.stroke_color_transition = parseTransition(value, "stroke"); - klass.specifiers.insert("stroke"); } else { klass.stroke_color = klass.fill_color; - klass.specifiers.insert("stroke"); } if (value.HasMember("antialias")) { klass.antialias = parseBoolean(value["antialias"]); - klass.specifiers.insert("antialias"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); - klass.specifiers.insert("image"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } return klass; @@ -563,44 +554,37 @@ LineClass StyleParser::parseLineClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; klass.translate_transition = parseTransition(value, "translate"); - klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); - klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); klass.color_transition = parseTransition(value, "color"); - klass.specifiers.insert("color"); } if (value.HasMember("width")) { klass.width = parseFunction(value["width"]); klass.width_transition = parseTransition(value, "width"); - klass.specifiers.insert("width"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } if (value.HasMember("dasharray")) { std::vector values = parseArray(value["dasharray"], 2); klass.dash_array = std::array {{ values[0], values[1] }}; klass.dash_array_transition = parseTransition(value, "dasharray"); - klass.specifiers.insert("dasharray"); } return klass; @@ -611,53 +595,44 @@ IconClass StyleParser::parseIconClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; klass.translate_transition = parseTransition(value, "translate"); - klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); - klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); klass.color_transition = parseTransition(value, "color"); - klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } if (value.HasMember("image")) { klass.image = parseString(value["image"]); - klass.specifiers.insert("image"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); - klass.specifiers.insert("size"); } if (value.HasMember("radius")) { klass.radius = parseFunction(value["radius"]); klass.radius_transition = parseTransition(value, "radius"); - klass.specifiers.insert("radius"); } if (value.HasMember("blur")) { klass.blur = parseFunction(value["blur"]); klass.blur_transition = parseTransition(value, "blur"); - klass.specifiers.insert("blur"); } return klass; @@ -668,64 +643,53 @@ TextClass StyleParser::parseTextClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); klass.translate = std::array {{ values[0], values[1] }}; klass.translate_transition = parseTransition(value, "translate"); - klass.specifiers.insert("translate"); } if (value.HasMember("translate-anchor")) { klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); - klass.specifiers.insert("translate-anchor"); } if (value.HasMember("color")) { klass.color = parseColor(value["color"]); klass.color_transition = parseTransition(value, "color"); - klass.specifiers.insert("color"); } if (value.HasMember("stroke")) { klass.halo = parseColor(value["stroke"]); klass.halo_transition = parseTransition(value, "stroke"); - klass.specifiers.insert("stroke"); } if (value.HasMember("strokeWidth")) { klass.halo_radius = parseFunction(value["strokeWidth"]); klass.halo_radius_transition = parseTransition(value, "strokeWidth"); - klass.specifiers.insert("strokeWidth"); } if (value.HasMember("strokeBlur")) { klass.halo_blur = parseFunction(value["strokeBlur"]); klass.halo_blur_transition = parseTransition(value, "strokeBlur"); - klass.specifiers.insert("strokeBlur"); } if (value.HasMember("size")) { klass.size = parseFunction(value["size"]); - klass.specifiers.insert("size"); } if (value.HasMember("rotate")) { klass.rotate = parseFunction(value["rotate"]); - klass.specifiers.insert("rotate"); } if (value.HasMember("alwaysVisible")) { klass.always_visible = parseFunction(value["alwaysVisible"]); - klass.specifiers.insert("alwaysVisible"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } return klass; @@ -736,13 +700,11 @@ RasterClass StyleParser::parseRasterClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } return klass; @@ -753,13 +715,11 @@ CompositeClass StyleParser::parseCompositeClass(JSVal value) { if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); - klass.specifiers.insert("enabled"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } return klass; @@ -771,13 +731,11 @@ BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { if (value.HasMember("color")) { klass.color = parseColor(value["color"]); klass.color_transition = parseTransition(value, "color"); - klass.specifiers.insert("color"); } if (value.HasMember("opacity")) { klass.opacity = parseFunction(value["opacity"]); klass.opacity_transition = parseTransition(value, "opacity"); - klass.specifiers.insert("opacity"); } return klass;