Skip to content

Commit

Permalink
Exclusive and Priority for SceneLayer (#2046)
Browse files Browse the repository at this point in the history
* Exclusive and Priority for SceneLayer

- Sort SceneLayers such that all exclusive layers come before
non-exclusive layers and in order of increasing priority

* Fix SceneLayer sorting and clean up parameters

* Remove declaration of un-implemented DrawRule method

* Clarify SceneLayer sorting and fix lexical comparison

* Don't store depth with layer, calculate during traversal

* More cleanup in DrawRule

* Refactor drawRuleTests to reduce repetition

* Refactor layerTests and add exclusive/priority checks

* Use 'exclusive' and 'priority' in demo scene

Co-authored-by: Matt Blair <[email protected]>
  • Loading branch information
tallytalwar and matteblair authored Mar 30, 2020
1 parent ab32ca9 commit d5cdf97
Show file tree
Hide file tree
Showing 11 changed files with 373 additions and 533 deletions.
8 changes: 4 additions & 4 deletions core/src/scene/dataLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace Tangram {

DataLayer::DataLayer(SceneLayer _layer, const std::string& _source, const std::vector<std::string>& _collections) :
SceneLayer(std::move(_layer)),
m_source(_source),
m_collections(_collections) {}
DataLayer::DataLayer(SceneLayer layer, std::string source, std::vector<std::string> collections) :
SceneLayer(std::move(layer)),
m_source(std::move(source)),
m_collections(std::move(collections)) {}

}
2 changes: 1 addition & 1 deletion core/src/scene/dataLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DataLayer : public SceneLayer {

public:

DataLayer(SceneLayer _layer, const std::string& _source, const std::vector<std::string>& _collections);
DataLayer(SceneLayer layer, std::string source, std::vector<std::string> collections);

const auto& source() const { return m_source; }
const auto& collections() const { return m_collections; }
Expand Down
59 changes: 26 additions & 33 deletions core/src/scene/drawRule.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "scene/drawRule.h"

#include "drawRuleWarnings.h"
#include "log.h"
#include "platform.h"
#include "scene/scene.h"
Expand Down Expand Up @@ -35,14 +34,14 @@ std::string DrawRuleData::toString() const {
return str;
}

DrawRule::DrawRule(const DrawRuleData& _ruleData, const std::string& _layerName, size_t _layerDepth) :
name(&_ruleData.name),
id(_ruleData.id) {
DrawRule::DrawRule(const DrawRuleData& ruleData, const std::string& layerName, int layerDepth) :
name(&ruleData.name),
id(ruleData.id) {

for (const auto& param : _ruleData.parameters) {
for (const auto& param : ruleData.parameters) {
auto key = static_cast<uint8_t>(param.key);
active[key] = true;
params[key] = { &param, _layerName.c_str(), _layerDepth };
params[key] = { &param, layerName.c_str(), layerDepth };
}
}

Expand All @@ -54,21 +53,15 @@ bool DrawRule::hasParameterSet(StyleParamKey _key) const {
return false;
}

void DrawRule::merge(const DrawRuleData& _ruleData, const SceneLayer& _layer) {
void DrawRule::merge(const DrawRuleData& ruleData, const std::string& layerName, int layerDepth) {

evalConflict(*this, _ruleData, _layer);

const auto depthNew = _layer.depth();
const char* layerNew = _layer.name().c_str();

for (const auto& paramNew : _ruleData.parameters) {
for (const auto& paramNew : ruleData.parameters) {

auto key = static_cast<uint8_t>(paramNew.key);
auto& param = params[key];

if (!active[key] || depthNew > param.depth ||
(depthNew == param.depth && strcmp(layerNew, param.name) > 0)) {
param = { &paramNew, layerNew, depthNew };
if (!active[key] || layerDepth > param.layerDepth) {
param = { &paramNew, layerName.c_str(), layerDepth };
active[key] = true;
}
}
Expand All @@ -81,7 +74,7 @@ bool DrawRule::contains(StyleParamKey _key) const {
const StyleParam& DrawRule::findParameter(StyleParamKey _key) const {
static const StyleParam NONE;

uint8_t key = static_cast<uint8_t>(_key);
auto key = static_cast<uint8_t>(_key);
if (!active[key]) { return NONE; }
return *params[key].param;
}
Expand All @@ -97,14 +90,10 @@ const std::string& DrawRule::getStyleName() const {
}
}

const char* DrawRule::getLayerName(StyleParamKey _key) const {
return params[static_cast<uint8_t>(_key)].name;
}

size_t DrawRule::getParamSetHash() const {
size_t seed = 0;
for (size_t i = 0; i < StyleParamKeySize; i++) {
if (active[i]) { hash_combine(seed, params[i].name); }
if (active[i]) { hash_combine(seed, params[i].layerName); }
}
return seed;
}
Expand All @@ -127,17 +116,18 @@ bool DrawRuleMergeSet::match(const Feature& _feature, const SceneLayer& _layer,
// If the first filter doesn't match, return immediately
if (!_layer.filter().eval(_feature, _ctx)) { return false; }

m_queuedLayers.push_back(&_layer);
m_queuedLayers.push_back({ &_layer, 1 });

// Iterate depth-first over the layer hierarchy
while (!m_queuedLayers.empty()) {

// Pop a layer off the top of the stack
const auto& layer = *m_queuedLayers.back();
const auto& layer = *m_queuedLayers.back().layer;
const auto depth = m_queuedLayers.back().depth;
m_queuedLayers.pop_back();

// Merge rules from layer into accumulated set
mergeRules(layer);
mergeRules(layer, depth);

// Push each of the layer's matching sublayers onto the stack
for (const auto& sublayer : layer.sublayers()) {
Expand All @@ -147,15 +137,18 @@ bool DrawRuleMergeSet::match(const Feature& _feature, const SceneLayer& _layer,
}

if (sublayer.filter().eval(_feature, _ctx)) {
m_queuedLayers.push_back(&sublayer);
m_queuedLayers.push_back({ &sublayer, depth + 1 });
if (sublayer.exclusive()) {
break;
}
}
}
}

return true;
}

bool DrawRuleMergeSet::evaluateRuleForContext(DrawRule& rule, StyleContext& ctx) {
bool DrawRuleMergeSet::evaluateRuleForContext(DrawRule& rule, StyleContext& context) {

bool visible;
if (rule.get(StyleParamKey::visible, visible) && !visible) {
Expand All @@ -179,7 +172,7 @@ bool DrawRuleMergeSet::evaluateRuleForContext(DrawRule& rule, StyleContext& ctx)
m_evaluated[i] = *param;
param = &m_evaluated[i];

if (!ctx.evalStyle(param->function, param->key, m_evaluated[i].value)) {
if (!context.evalStyle(param->function, param->key, m_evaluated[i].value)) {
if (StyleParam::isRequired(param->key)) {
valid = false;
break;
Expand All @@ -191,26 +184,26 @@ bool DrawRuleMergeSet::evaluateRuleForContext(DrawRule& rule, StyleContext& ctx)
m_evaluated[i] = *param;
param = &m_evaluated[i];

Stops::eval(*param->stops, param->key, ctx.getZoom(), m_evaluated[i].value);
Stops::eval(*param->stops, param->key, context.getZoom(), m_evaluated[i].value);
}
}

return valid;
}

void DrawRuleMergeSet::mergeRules(const SceneLayer& _layer) {
void DrawRuleMergeSet::mergeRules(const SceneLayer& layer, int depth) {

size_t pos, end = m_matchedRules.size();

for (const auto& rule : _layer.rules()) {
for (const auto& rule : layer.rules()) {
for (pos = 0; pos < end; pos++) {
if (m_matchedRules[pos].id == rule.id) { break; }
}

if (pos == end) {
m_matchedRules.emplace_back(rule, _layer.name(), _layer.depth());
m_matchedRules.emplace_back(rule, layer.name(), depth);
} else {
m_matchedRules[pos].merge(rule, _layer);
m_matchedRules[pos].merge(rule, layer.name(), depth);
}
}
}
Expand Down
26 changes: 13 additions & 13 deletions core/src/scene/drawRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ struct DrawRule {
struct {
const StyleParam* param;
// SceneLayer name and depth
const char* name;
size_t depth;

const char* layerName;
int layerDepth;
} params[StyleParamKeySize];

// A mask to indicate which parameters are set.
Expand All @@ -79,18 +78,14 @@ struct DrawRule {
uint32_t selectionColor = 0;
FeatureSelection* featureSelection = nullptr;

DrawRule(const DrawRuleData& _ruleData, const std::string& _layerName, size_t _layerDepth);

void merge(const DrawRuleData& _ruleData, const SceneLayer& _layer);
DrawRule(const DrawRuleData& ruleData, const std::string& layerName, int layerDepth);

bool isJSFunction(StyleParamKey _key) const;
void merge(const DrawRuleData& ruleData, const std::string& layerName, int layerDepth);

bool contains(StyleParamKey _key) const;

const std::string& getStyleName() const;

const char* getLayerName(StyleParamKey _key) const;

size_t getParamSetHash() const;

bool hasParameterSet(StyleParamKey _key) const;
Expand Down Expand Up @@ -121,20 +116,25 @@ struct DrawRule {
class DrawRuleMergeSet {

public:
bool evaluateRuleForContext(DrawRule& rule, StyleContext& ctx);
bool evaluateRuleForContext(DrawRule& rule, StyleContext& context);

// internal
bool match(const Feature& _feature, const SceneLayer& _layer, StyleContext& _ctx);
bool match(const Feature& feature, const SceneLayer& layer, StyleContext& context);

// internal
void mergeRules(const SceneLayer& _layer);
void mergeRules(const SceneLayer& layer, int depth = 0);

auto& matchedRules() { return m_matchedRules; }

private:
struct LayerMatch {
const SceneLayer* layer;
int depth;
};

// Reusable containers 'matchedRules' and 'queuedLayers'
std::vector<DrawRule> m_matchedRules;
std::vector<const SceneLayer*> m_queuedLayers;
std::vector<LayerMatch> m_queuedLayers;

// Container for dynamically-evaluated parameters
StyleParam m_evaluated[StyleParamKeySize];
Expand Down
45 changes: 0 additions & 45 deletions core/src/scene/drawRuleWarnings.h

This file was deleted.

50 changes: 27 additions & 23 deletions core/src/scene/sceneLayer.cpp
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
#include "scene/sceneLayer.h"

#include <algorithm>
#include <type_traits>

namespace Tangram {

static_assert(std::is_move_constructible<SceneLayer>::value, "check");

SceneLayer::SceneLayer(std::string _name, Filter _filter,
std::vector<DrawRuleData> _rules,
std::vector<SceneLayer> _sublayers,
bool _enabled) :
m_filter(std::move(_filter)),
m_name(_name),
m_rules(_rules),
m_sublayers(std::move(_sublayers)),
m_enabled(_enabled) {

setDepth(1);

}

void SceneLayer::setDepth(size_t _d) {

m_depth = _d;

for (auto& layer : m_sublayers) {
layer.setDepth(m_depth + 1);
}

SceneLayer::SceneLayer(std::string name, Filter filter,
std::vector<DrawRuleData> rules,
std::vector<SceneLayer> sublayers,
Options options) :
m_filter(std::move(filter)),
m_name(std::move(name)),
m_rules(std::move(rules)),
m_sublayers(std::move(sublayers)),
m_options(options) {

// Sort sublayers for precedence in matching operations. If multiple values for a parameter are assigned to the same
// draw group at the same layer depth, then the value that comes *first* in the layer list will be the final value.
std::sort(m_sublayers.begin(), m_sublayers.end(),
[](const SceneLayer& a, const SceneLayer& b) {
if (a.exclusive() != b.exclusive()) {
// Exclusive layers always precede non-exclusive layers.
return a.exclusive();
} else if (a.priority() != b.priority()) {
// Layers whose priority value is closer to -infinity take precedence.
return a.priority() < b.priority();
}
// If priority and exclusivity are the same for two layers, precedence is determined by reverse
// alphabetical ordering of their names (which must be unique among sibling layers). That is, if there
// are two sibling layers with the same exclusivity and priority named 'a' and 'b', then 'b' will come
// first.
return a.name() > b.name();
});
}

}
Loading

0 comments on commit d5cdf97

Please sign in to comment.