/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2020 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #pragma once #include //! optional property macro for referencing another layer #define OE_OPTION_LAYER(TYPE, NAME) \ private: \ LayerReference< TYPE > _layerRef_ ## NAME ; \ public: \ LayerReference< TYPE >& NAME () { return _layerRef_ ## NAME ; } \ const LayerReference< TYPE >& NAME () const { return _layerRef_ ## NAME ; } namespace osgEarth { /** * Helper class for Layers that reference other layers. */ template class LayerReference { public: using TypedOptions = typename T::Options; //! User can call this to set the layer by hand (instead of finding it //! in the map or in an embedded options structure) void setLayer(T* layer) { _layer = layer; } //! Contained layer object T* getLayer() const { return _layer.get(); } //! Whether this reference is set at all. bool isSet() const { return _layer.valid() || _embeddedOptions || _externalLayerName.isSet(); } //! Whether the user called setLayer to establish the reference //! (as opposed to finding it in an embedded options or in the map) bool isSetByUser() const { return _layer.valid() && !_embeddedOptions && !_externalLayerName.isSet(); } //! open the layer pointed to in the reference and return a status code Status open(const osgDB::Options* readOptions) { if (_embeddedOptions) { auto typedLayer = Layer::create_as(*_embeddedOptions.get()); if (typedLayer) { typedLayer->setReadOptions(readOptions); const Status& layerStatus = typedLayer->open(); if (layerStatus.isError()) { return layerStatus; } _layer = typedLayer.get(); } } else if (_layer.valid() && !_layer->isOpen()) { _layer->setReadOptions(readOptions); const Status& layerStatus = _layer->open(); if (layerStatus.isError()) { return layerStatus; } } return Status::OK(); } void close() { _layer = NULL; } //! Find a layer in the map and set this reference to point at it void addedToMap(const Map* map) { if (!getLayer() && _externalLayerName.isSet()) { T* layer = map->getLayerByName(_externalLayerName.get()); if (layer) { _layer = layer; if (!layer->isOpen()) { layer->open(); } } } else if (getLayer() && _embeddedOptions) { _layer->addedToMap(map); } } //! If this reference was set by findInMap, release it. void removedFromMap(const Map* map) { if (map && _layer.valid()) { if (_embeddedOptions) { _layer->removedFromMap(map); } // Do not set _layer to nullptr. It may still be in use // and this is none of the Map's business. } } //! Get the layer ref from either a name or embedded option void get(const Config& conf, const std::string& tag) { // first try to store the name of another layer: conf.get(tag, _externalLayerName); if (!_externalLayerName.isSet()) { // next try to find a child called (tag) and try to make the layer // from it's children: if (conf.hasChild(tag) && conf.child(tag).children().size() >= 1) { const Config& tag_content = *conf.child(tag).children().begin(); { auto layer = Layer::create_as(tag_content); if (layer.valid()) { _embeddedOptions = std::make_shared(tag_content); } } } // failing that, try each child of the config. if (!_embeddedOptions) { for(auto& child_conf: conf.children()) { auto layer = Layer::create_as(child_conf); if (layer.valid()) { _embeddedOptions = std::make_shared(child_conf); break; } } } } } //! Set the layer ref options in the config void set(Config& conf, const std::string& tag) const { if (_externalLayerName.isSet()) { conf.set(tag, _externalLayerName); } else if (_embeddedOptions) { conf.set(_embeddedOptions->getConfig()); } else if (isSetByUser()) // should be true { conf.add(_layer->getConfig()); } } const std::shared_ptr& embeddedOptions() const { return _embeddedOptions; } void setEmbeddedOptions(const TypedOptions& value) { _embeddedOptions = std::make_shared(value); } const optional& externalLayerName() const { return _externalLayerName; } void setExternalLayerName(const std::string& value) { _externalLayerName = value; } private: osg::ref_ptr _layer; optional _externalLayerName; std::shared_ptr _embeddedOptions; }; }