diff --git a/src/osgEarth/StyleSelector b/src/osgEarth/StyleSelector index eb949409f8..52d5a4bc11 100644 --- a/src/osgEarth/StyleSelector +++ b/src/osgEarth/StyleSelector @@ -35,7 +35,7 @@ namespace osgEarth { public: /** Constructs a style selector */ - StyleSelector( const Config& conf =Config() ); + StyleSelector(const Config& conf = Config()); /** Constructs a style selector with a name and expression */ StyleSelector(const std::string& name, const StringExpression& expr); @@ -64,7 +64,7 @@ namespace osgEarth std::string getSelectedStyleName() const; //Configurable - virtual void mergeConfig( const Config& conf ); + virtual void mergeConfig(const Config& conf); virtual Config getConfig() const; protected: @@ -74,6 +74,27 @@ namespace osgEarth optional _query; }; + class OSGEARTH_EXPORT SelectorSymbol : public Symbol + { + public: + META_Object(osgEarth, SelectorSymbol); + + SelectorSymbol(const Config& conf = {}); + SelectorSymbol(const SelectorSymbol& rhs, const osg::CopyOp& op); + + //! A predicate function (in a scripting language) that returns true if the style should be selected. + OE_OPTION(std::string, predicate); + + public: + Config getConfig() const override; + void mergeConfig(const Config& conf) override; + static void parseSLD(const Config& c, class Style& style); + + protected: + + virtual ~SelectorSymbol() { } + }; + } // namespace osgEarth diff --git a/src/osgEarth/StyleSelector.cpp b/src/osgEarth/StyleSelector.cpp index 97d2cad48a..5e836fb762 100644 --- a/src/osgEarth/StyleSelector.cpp +++ b/src/osgEarth/StyleSelector.cpp @@ -67,3 +67,44 @@ StyleSelector::getConfig() const conf.set( "query", _query ); return conf; } + + + +OSGEARTH_REGISTER_SIMPLE_SYMBOL(select, SelectorSymbol); + +SelectorSymbol::SelectorSymbol(const Config& conf) : + Symbol(conf) +{ + mergeConfig(conf); +} + +SelectorSymbol::SelectorSymbol(const SelectorSymbol& rhs, const osg::CopyOp& copy) : + Symbol(rhs, copy), + _predicate(rhs._predicate) +{ + //nop +} + +Config +SelectorSymbol::getConfig() const +{ + auto conf = Symbol::getConfig(); + conf.key() = "selector"; + conf.set("predicate", predicate()); + return conf; +} + +void +SelectorSymbol::mergeConfig(const Config& conf) +{ + conf.get("predicate", predicate()); +} + +void +SelectorSymbol::parseSLD(const Config& c, Style& style) +{ + if (match(c.key(), "select") || match(c.key(), "select-if")) + { + style.getOrCreate()->predicate() = c.value(); + } +} diff --git a/src/osgEarth/StyleSheet.cpp b/src/osgEarth/StyleSheet.cpp index 22eb5a38d6..72ba1b277b 100644 --- a/src/osgEarth/StyleSheet.cpp +++ b/src/osgEarth/StyleSheet.cpp @@ -35,11 +35,12 @@ StyleSheet::Options::getConfig() const Config conf = Layer::Options::getConfig(); conf.remove("selector"); - for (StyleSelectors::const_iterator i = selectors().begin(); - i != selectors().end(); - ++i) + for(auto& selector_pair : selectors()) { - conf.add("selector", i->second.getConfig()); + if (selector_pair.first != "__oe_auto") // do not save the auto-gen one + { + conf.add("selector", selector_pair.second.getConfig()); + } } conf.remove("style"); @@ -72,10 +73,19 @@ StyleSheet::Options::getConfig() const scriptConf.set("language", _script->language); if (_script->uri.isSet()) scriptConf.set("url", _script->uri->base()); - //if (!_script->profile.empty()) - // scriptConf.set("profile", _script->profile); else if (!_script->code.empty()) + { + auto code = _script->code; + + // remove the auto-gen code + auto pos = code.find("// __oe_auto__"); + if (pos != std::string::npos) + { + code = code.substr(0, pos); + } + scriptConf.setValue(_script->code); + } conf.add(scriptConf); } @@ -184,6 +194,51 @@ StyleSheet::Options::fromConfig(const Config& conf) _styles[style.getName()] = style; } } + + // finally, parse each style and see if it contains a "select" symbol. + // if so, automatically add a selector and a script to support each one. + StyleSelector* auto_selector = nullptr; + std::stringstream auto_script; + + for (auto& style_entry : _styles) + { + auto& style = style_entry.second; + auto* selector_symbol = style.get(); + if (selector_symbol) + { + if (!auto_selector) + { + auto_selector = new StyleSelector(); + auto_selector->name() = "__oe_auto"; + auto_selector->styleExpression() = StringExpression("__oe_select_style()"); + _selectors[auto_selector->name().get()] = *auto_selector; + + auto_script << "// __oe_auto__\n"; + auto_script << "function __oe_select_style() {\n"; + } + + auto_script << " if (" << selector_symbol->predicate().get() << ") return \"" << style.getName() << "\";\n"; + } + } + + if (auto_selector) + { + auto_script << " return 'default';\n}\n"; + auto new_code = auto_script.str(); + + if (!_script) + { + _script = new ScriptDef(); + _script->language = "javascript"; + _script->code = new_code; + } + else + { + _script->code = _script->code + "\n\n" + new_code; + } + + //OE_INFO << LC << "Generated script:\n" << new_code << std::endl; + } } //................................................................... diff --git a/tests/feature_select_symbol.earth b/tests/feature_select_symbol.earth new file mode 100644 index 0000000000..c83d96cf27 --- /dev/null +++ b/tests/feature_select_symbol.earth @@ -0,0 +1,63 @@ + + + + + + + + + + ../data/world.shp + + + + + + + + + + + + + +