From 027f42764524973752464d3a9c2ee4613a6e29c1 Mon Sep 17 00:00:00 2001 From: Jason Beverage Date: Fri, 23 Feb 2024 10:40:12 -0500 Subject: [PATCH] Reworked TiledModelLayer to create the SimplePager in the base class and only require subclasses to implement createTileImplementation instead of requiring them to make their own pager. Added CompositeTiledModelLayer that allows you to merge multipe TiledModelLayers into a single layer. --- src/osgEarth/CMakeLists.txt | 6 +- src/osgEarth/CompositeTiledModelLayer | 95 +++++++++ src/osgEarth/CompositeTiledModelLayer.cpp | 191 ++++++++++++++++++ src/osgEarth/TiledFeatureModelGraph.cpp | 231 ---------------------- src/osgEarth/TiledFeatureModelLayer | 14 +- src/osgEarth/TiledFeatureModelLayer.cpp | 216 +++++++++++++++----- src/osgEarth/TiledModelLayer | 23 +++ src/osgEarth/TiledModelLayer.cpp | 99 ++++++++++ src/osgEarth/XYZModelGraph | 63 ------ src/osgEarth/XYZModelGraph.cpp | 149 -------------- src/osgEarth/XYZModelLayer | 37 ++-- src/osgEarth/XYZModelLayer.cpp | 201 ++++++++++--------- 12 files changed, 707 insertions(+), 618 deletions(-) create mode 100644 src/osgEarth/CompositeTiledModelLayer create mode 100644 src/osgEarth/CompositeTiledModelLayer.cpp delete mode 100644 src/osgEarth/TiledFeatureModelGraph.cpp delete mode 100644 src/osgEarth/XYZModelGraph delete mode 100644 src/osgEarth/XYZModelGraph.cpp diff --git a/src/osgEarth/CMakeLists.txt b/src/osgEarth/CMakeLists.txt index 294919d0d5..ce83d6063a 100644 --- a/src/osgEarth/CMakeLists.txt +++ b/src/osgEarth/CMakeLists.txt @@ -114,6 +114,7 @@ SET(LIB_PUBLIC_HEADERS ColorFilter Common Composite + CompositeTiledModelLayer Config Containers Coverage @@ -260,7 +261,6 @@ SET(LIB_PUBLIC_HEADERS TileHandler TileMesher TileRasterizer - TiledFeatureModelGraph TiledFeatureModelLayer TiledModelLayer TileSource @@ -283,7 +283,6 @@ SET(LIB_PUBLIC_HEADERS WMS XmlUtils XYZ - XYZModelGraph XYZModelLayer ActivityMonitorTool @@ -551,6 +550,7 @@ set(TARGET_SRC Color.cpp ColorFilter.cpp Composite.cpp + CompositeTiledModelLayer.cpp Compressors.cpp Config.cpp CoverageLayer.cpp @@ -676,7 +676,6 @@ set(TARGET_SRC TileHandler.cpp TileMesher.cpp TileRasterizer.cpp - TiledFeatureModelGraph.cpp TiledFeatureModelLayer.cpp TiledModelLayer.cpp TileVisitor.cpp @@ -699,7 +698,6 @@ set(TARGET_SRC WMS.cpp XmlUtils.cpp XYZ.cpp - XYZModelGraph.cpp XYZModelLayer.cpp ActivityMonitorTool.cpp diff --git a/src/osgEarth/CompositeTiledModelLayer b/src/osgEarth/CompositeTiledModelLayer new file mode 100644 index 0000000000..05650aeeda --- /dev/null +++ b/src/osgEarth/CompositeTiledModelLayer @@ -0,0 +1,95 @@ +/* -*-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 + */ +#ifndef OSGEARTH_COMPOSITE_TILED_MODEL_LAYER +#define OSGEARTH_COMPOSITE_TILED_MODEL_LAYER 1 + +#include +#include +#include + +namespace osgEarth { + class Map; +} + +namespace osgEarth +{ + class OSGEARTH_EXPORT CompositeTiledModelLayer : public TiledModelLayer + { + public: // serialization + struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options + { + META_LayerOptions(osgEarth, Options, TiledModelLayer::Options); + OE_OPTION(ProfileOptions, profile); + + OE_OPTION_VECTOR(ConfigOptions, layers); + + Config getConfig() const override; + void fromConfig(const Config& conf); + }; + + public: + META_Layer(osgEarth, CompositeTiledModelLayer, Options, TiledModelLayer, CompositeTiledModel); + + //! Tiling profile (required) + void setProfile(const Profile* profile); + const Profile* getProfile() const override { return _profile.get(); } + + unsigned getMinLevel() const override; + + //! Maximum level of detail to access + unsigned getMaxLevel() const override; + + public: // Layer + + //! opens the layer and returns the status + Status openImplementation() override; + + //! Serialization + Config getConfig() const override; + + public: // Layer + + //! called by the map when this layer is added + void addedToMap(const Map*) override; + + //! called by the map when this layer is removed + void removedFromMap(const Map*) override; + + protected: // TiledModelLayer + + //! Creates an OSG node from a tile key. + osg::ref_ptr createTileImplementation(const TileKey&, ProgressCallback*) const override; + + protected: + + virtual ~CompositeTiledModelLayer(); + + private: + osg::ref_ptr _profile; + osg::observer_ptr< const Map > _map; + + unsigned int _minLevel = 0; + unsigned int _maxLevel = 0; + + std::vector< osg::ref_ptr< TiledModelLayer > > _layers; + }; + +} // namespace osgEarth + +#endif // OSGEARTH_COMPOSITE_TILED_MODEL_LAYER diff --git a/src/osgEarth/CompositeTiledModelLayer.cpp b/src/osgEarth/CompositeTiledModelLayer.cpp new file mode 100644 index 0000000000..27893dc637 --- /dev/null +++ b/src/osgEarth/CompositeTiledModelLayer.cpp @@ -0,0 +1,191 @@ +/* -*-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 + */ +#include +#include +#include + +#include + +using namespace osgEarth; + +#define LC "[CompositeTiledModelLayer] " + +#define OE_TEST OE_NULL + +REGISTER_OSGEARTH_LAYER(CompositeTiledModel, CompositeTiledModelLayer); + +void CompositeTiledModelLayer::Options::fromConfig(const Config& conf) +{ + conf.get("profile", profile()); + + const ConfigSet& layers = conf.child("layers").children(); + for (ConfigSet::const_iterator i = layers.begin(); i != layers.end(); ++i) + { + _layers.push_back(ConfigOptions(*i)); + } +} + +Config +CompositeTiledModelLayer::Options::getConfig() const +{ + Config conf = TiledModelLayer::Options::getConfig(); + conf.set("profile", profile()); + + if (_layers.empty() == false) + { + Config layersConf("layers"); + for (std::vector::const_iterator i = _layers.begin(); i != _layers.end(); ++i) + { + layersConf.add(i->getConfig()); + } + conf.set(layersConf); + } + + return conf; +} + +//........................................................................... + +CompositeTiledModelLayer::~CompositeTiledModelLayer() +{ + //NOP +} + +void CompositeTiledModelLayer::setProfile(const Profile* profile) +{ + _profile = profile; + if (_profile) + { + options().profile() = profile->toProfileOptions(); + } +} + +Config +CompositeTiledModelLayer::getConfig() const +{ + Config conf = TiledModelLayer::getConfig(); + return conf; +} + +Status +CompositeTiledModelLayer::openImplementation() +{ + Status parent = super::openImplementation(); + if (parent.isError()) + return parent; + + _profile = Profile::create(*options().profile()); + + // Open all the layers + for (auto& layerConf : options().layers()) + { + osg::ref_ptr< Layer > layer = Layer::create(layerConf); + TiledModelLayer* tiledLayer = dynamic_cast(layer.get()); + if (tiledLayer) + { + tiledLayer->open(); + tiledLayer->setReadOptions(getReadOptions()); + _layers.push_back(tiledLayer); + } + else + { + OE_WARN << LC << "Layer is not a TiledModelLayer" << std::endl; + } + } + + return Status::NoError; +} + +void +CompositeTiledModelLayer::addedToMap(const Map* map) +{ + for (auto& layer : _layers) + { + layer->addedToMap(map); + } + + // Check to make sure the layers are all using the same profile + for (auto& layer : _layers) + { + if (!layer->getProfile()->isEquivalentTo(_profile)) + { + OE_WARN << LC << "Layer " << layer->getName() << " does not have the same profile as the composite layer" << std::endl; + } + } + + // Compute the min and max levels + if (!_layers.empty()) + { + _minLevel = 1000; + _maxLevel = 0; + for (auto& layer : _layers) + { + if (layer->getMinLevel() < _minLevel) + { + _minLevel = layer->getMinLevel(); + } + if (layer->getMaxLevel() > _maxLevel) + { + _maxLevel = layer->getMaxLevel(); + } + } + } + + super::addedToMap(map); +} + +void +CompositeTiledModelLayer::removedFromMap(const Map* map) +{ + super::removedFromMap(map); + + for (auto& layer : _layers) + { + layer->removedFromMap(map); + } +} + +osg::ref_ptr +CompositeTiledModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const +{ + osg::ref_ptr group = new osg::Group(); + + for (unsigned int i = 0; i < this->_layers.size(); i++) + { + osg::ref_ptr node = this->_layers[i]->createTile(key, progress); + if (node.valid()) + { + group->addChild(node); + } + } + return group; +} + +unsigned +CompositeTiledModelLayer::getMinLevel() const +{ + return _minLevel; +} + +unsigned +CompositeTiledModelLayer::getMaxLevel() const +{ + return _maxLevel; +} + diff --git a/src/osgEarth/TiledFeatureModelGraph.cpp b/src/osgEarth/TiledFeatureModelGraph.cpp deleted file mode 100644 index 1c95007d64..0000000000 --- a/src/osgEarth/TiledFeatureModelGraph.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* -*-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 - */ -#include -#include -#include -#include -#include - -using namespace osgEarth; - -TiledFeatureModelGraph::TiledFeatureModelGraph(const osgEarth::Map* map, - FeatureSource* features, - StyleSheet* styleSheet, - Session* session) : - SimplePager(map, (features && features->getFeatureProfile()) ? features->getFeatureProfile()->getTilingProfile() : nullptr), - _features(features), - _styleSheet(styleSheet), - _session(session) -{ - setMinLevel(features->getFeatureProfile()->getFirstLevel()); - setMaxLevel(features->getFeatureProfile()->getMaxLevel()); - - _session->setResourceCache(new ResourceCache()); - - - FeatureSourceIndexOptions indexOptions; - indexOptions.enabled() = true; - - _featureIndex = new FeatureSourceIndex( - features, - Registry::objectIndex(), - indexOptions); -} - -void -TiledFeatureModelGraph::setFilterChain(FeatureFilterChain* chain) -{ - _filterChain = chain; -} - -void -TiledFeatureModelGraph::setOwnerName(const std::string& value) -{ - _ownerName = value; -} - - -FeatureCursor* -TiledFeatureModelGraph::createCursor(FeatureSource* fs, FilterContext& cx, const Query& query, ProgressCallback* progress) const -{ - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - FeatureCursor* cursor = fs->createFeatureCursor(query, progress); - if (cursor && _filterChain.valid()) - { - cursor = new FilteredFeatureCursor(cursor, _filterChain.get(), &cx); - } - return cursor; -} - -osg::ref_ptr -TiledFeatureModelGraph::createNode(const TileKey& key, ProgressCallback* progress) -{ - if (progress && progress->isCanceled()) - return nullptr; - - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - // Get features for this key - Query query; - query.tileKey() = key; - - GeoExtent dataExtent = key.getExtent(); - - // set up for feature indexing if appropriate: - osg::ref_ptr< FeatureSourceIndexNode > index = 0L; - - if (_featureIndex.valid()) - { - index = new FeatureSourceIndexNode(_featureIndex.get()); - } - - FilterContext fc(_session.get(), new FeatureProfile(dataExtent), dataExtent, index); - - GeometryCompilerOptions options; - options.instancing() = true; - //options.mergeGeometry() = true; - GeometryCompiler gc(options); - - GeomFeatureNodeFactory factory(options); - - if (progress && progress->isCanceled()) - return nullptr; - - osg::ref_ptr< FeatureCursor > cursor = _features->createFeatureCursor( - query, - _filterChain.get(), - &fc, - progress); - - osg::ref_ptr node = new osg::Group; - if (cursor) - { - if (progress && progress->isCanceled()) - return nullptr; - - FeatureList features; - cursor->fill(features); - - if (_styleSheet->getSelectors().size() > 0) - { - osg::Group* group = new osg::Group; - - for (StyleSelectors::const_iterator i = _styleSheet->getSelectors().begin(); - i != _styleSheet->getSelectors().end(); - ++i) - { - typedef std::map< std::string, FeatureList > StyleToFeaturesMap; - StyleToFeaturesMap styleToFeatures; - - // pull the selected style... - const StyleSelector& sel = i->second; - - if (sel.styleExpression().isSet()) - { - // establish the working bounds and a context: - StringExpression styleExprCopy(sel.styleExpression().get()); - for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) - { - Feature* feature = itr->get(); - - feature->set("level", (long long)key.getLevelOfDetail()); - - const std::string& styleString = feature->eval(styleExprCopy, &fc); - if (!styleString.empty() && styleString != "null") - { - styleToFeatures[styleString].push_back(feature); - } - - if (progress && progress->isCanceled()) - return nullptr; - } - } - - std::unordered_map literal_styles; - - for (StyleToFeaturesMap::iterator itr = styleToFeatures.begin(); itr != styleToFeatures.end(); ++itr) - { - const std::string& styleString = itr->first; - Style* style = nullptr; - - if (styleString.length() > 0 && styleString[0] == '{') - { - Config conf("style", styleString); - conf.setReferrer(sel.styleExpression().get().uriContext().referrer()); - conf.set("type", "text/css"); - Style& literal_style = literal_styles[conf.toJSON()]; - if (literal_style.empty()) - literal_style = Style(conf); - style = &literal_style; - } - else - { - style = _styleSheet->getStyle(styleString); - } - - if (style) - { - osg::Group* styleGroup = factory.getOrCreateStyleGroup(*style, _session.get()); - osg::ref_ptr< osg::Node> styleNode; - osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(itr->second); - Query query; - factory.createOrUpdateNode(cursor.get(), *style, fc, styleNode, query); - if (styleNode.valid()) - { - styleGroup->addChild(styleNode); - if (!group->containsNode(styleGroup)) - { - group->addChild(styleGroup); - } - } - } - } - } - - - node = group; - } - else if (_styleSheet->getDefaultStyle()) - { - osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(features); - osg::ref_ptr< osg::Group > group = new osg::Group; - osg::ref_ptr< osg::Group > styleGroup = factory.getOrCreateStyleGroup(*_styleSheet->getDefaultStyle(), _session.get()); - osg::ref_ptr< osg::Node> styleNode; - factory.createOrUpdateNode(cursor.get(), *_styleSheet->getDefaultStyle(), fc, styleNode, query); - if (styleNode.valid()) - { - group->addChild(styleGroup); - styleGroup->addChild(styleNode); - node = group; - } - } - } - - if (!node->getBound().valid()) - { - return nullptr; - } - - if (index.valid()) - { - index->addChild(node); - return index; - } - - return node; -} \ No newline at end of file diff --git a/src/osgEarth/TiledFeatureModelLayer b/src/osgEarth/TiledFeatureModelLayer index 6829367bc1..09549c504c 100644 --- a/src/osgEarth/TiledFeatureModelLayer +++ b/src/osgEarth/TiledFeatureModelLayer @@ -76,10 +76,7 @@ namespace osgEarth //! Whether to support lighting void setEnableLighting(const bool& value); - const bool& getEnableLighting() const; - - //! Forces a rebuild on this FeatureModelLayer. - void dirty(); + const bool& getEnableLighting() const; public: // Layer @@ -89,9 +86,6 @@ namespace osgEarth // closes the layer Status closeImplementation() override; - // The Node representing this layer. - osg::Node* getNode() const override; - //! Extent of the feature layer, if available (INVALID if not) const GeoExtent& getExtent() const override; @@ -131,10 +125,8 @@ namespace osgEarth private: osg::ref_ptr _session; - osg::ref_ptr _root; - bool _graphDirty; - - void create(); + osg::ref_ptr _filters; + osg::ref_ptr< FeatureSourceIndex > _featureIndex; }; } // namespace osgEarth diff --git a/src/osgEarth/TiledFeatureModelLayer.cpp b/src/osgEarth/TiledFeatureModelLayer.cpp index e912238c1e..86ed286c5a 100644 --- a/src/osgEarth/TiledFeatureModelLayer.cpp +++ b/src/osgEarth/TiledFeatureModelLayer.cpp @@ -17,7 +17,8 @@ * along with this program. If not, see */ #include -#include +#include +#include using namespace osgEarth; @@ -86,26 +87,6 @@ void TiledFeatureModelLayer::init() { TiledModelLayer::init(); - - _root = new osg::Group(); - - // Assign the layer's state set to the root node: - _root->setStateSet(this->getOrCreateStateSet()); - - // Graph needs rebuilding - _graphDirty = true; - - // Depth sorting by default - getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); -} - -void TiledFeatureModelLayer::dirty() -{ - // feature source changed, so the graph needs rebuilding - _graphDirty = true; - - // create the scene graph - create(); } Config @@ -154,12 +135,6 @@ TiledFeatureModelLayer::getStyleSheet() const return options().styleSheet().getLayer(); } -osg::Node* -TiledFeatureModelLayer::getNode() const -{ - return _root.get(); -} - Status TiledFeatureModelLayer::openImplementation() { @@ -181,9 +156,9 @@ TiledFeatureModelLayer::openImplementation() Status TiledFeatureModelLayer::closeImplementation() { + super::closeImplementation(); options().featureSource().close(); options().styleSheet().close(); - _graphDirty = true; return getStatus(); } @@ -202,7 +177,7 @@ void TiledFeatureModelLayer::addedToMap(const Map* map) { OE_TEST << LC << "addedToMap" << std::endl; - TiledModelLayer::addedToMap(map); + options().featureSource().addedToMap(map); options().styleSheet().addedToMap(map); @@ -217,29 +192,36 @@ TiledFeatureModelLayer::addedToMap(const Map* map) getFeatureSource(), getReadOptions()); - // re-create the graph if necessary. - create(); + // connect the session to the features: + _session->setFeatureSource(getFeatureSource()); + _session->setResourceCache(new ResourceCache()); + + FeatureSourceIndexOptions indexOptions; + indexOptions.enabled() = true; + + _featureIndex = new FeatureSourceIndex( + getFeatureSource(), + Registry::objectIndex(), + indexOptions); } + + _filters = FeatureFilterChain::create(options().filters(), getReadOptions()); + + TiledModelLayer::addedToMap(map); } void TiledFeatureModelLayer::removedFromMap(const Map* map) { - TiledModelLayer::removedFromMap(map); + super::removedFromMap(map); options().featureSource().removedFromMap(map); options().styleSheet().removedFromMap(map); - if (_root.valid()) - { - osg::ref_ptr tfmg = findTopMostNodeOfType(_root.get()); - if (tfmg.valid()) tfmg->setDone(); - _root->removeChildren(0, _root->getNumChildren()); - } - _session = 0L; } +#if 0 void TiledFeatureModelLayer::create() { @@ -275,17 +257,163 @@ TiledFeatureModelLayer::create() } } } +#endif osg::ref_ptr TiledFeatureModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const { - osg::ref_ptr result; - auto fmg = osgEarth::findTopMostNodeOfType(_root.get()); - if (fmg) + if (progress && progress->isCanceled()) + return nullptr; + + NetworkMonitor::ScopedRequestLayer layerRequest(getName()); + // Get features for this key + Query query; + query.tileKey() = key; + + GeoExtent dataExtent = key.getExtent(); + + // set up for feature indexing if appropriate: + osg::ref_ptr< FeatureSourceIndexNode > index = 0L; + + if (_featureIndex.valid()) + { + index = new FeatureSourceIndexNode(_featureIndex.get()); + } + + FilterContext fc(_session.get(), new FeatureProfile(dataExtent), dataExtent, index); + + GeometryCompilerOptions options; + options.instancing() = true; + //options.mergeGeometry() = true; + GeometryCompiler gc(options); + + GeomFeatureNodeFactory factory(options); + + if (progress && progress->isCanceled()) + return nullptr; + + osg::ref_ptr< FeatureCursor > cursor = getFeatureSource()->createFeatureCursor( + query, + _filters.get(), + &fc, + progress); + + osg::ref_ptr node = new osg::Group; + if (cursor) + { + if (progress && progress->isCanceled()) + return nullptr; + + FeatureList features; + cursor->fill(features); + + if (getStyleSheet()->getSelectors().size() > 0) + { + osg::Group* group = new osg::Group; + + for (StyleSelectors::const_iterator i = getStyleSheet()->getSelectors().begin(); + i != getStyleSheet()->getSelectors().end(); + ++i) + { + typedef std::map< std::string, FeatureList > StyleToFeaturesMap; + StyleToFeaturesMap styleToFeatures; + + // pull the selected style... + const StyleSelector& sel = i->second; + + if (sel.styleExpression().isSet()) + { + // establish the working bounds and a context: + StringExpression styleExprCopy(sel.styleExpression().get()); + for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) + { + Feature* feature = itr->get(); + + feature->set("level", (long long)key.getLevelOfDetail()); + + const std::string& styleString = feature->eval(styleExprCopy, &fc); + if (!styleString.empty() && styleString != "null") + { + styleToFeatures[styleString].push_back(feature); + } + + if (progress && progress->isCanceled()) + return nullptr; + } + } + + std::unordered_map literal_styles; + + for (StyleToFeaturesMap::iterator itr = styleToFeatures.begin(); itr != styleToFeatures.end(); ++itr) + { + const std::string& styleString = itr->first; + Style* style = nullptr; + + if (styleString.length() > 0 && styleString[0] == '{') + { + Config conf("style", styleString); + conf.setReferrer(sel.styleExpression().get().uriContext().referrer()); + conf.set("type", "text/css"); + Style& literal_style = literal_styles[conf.toJSON()]; + if (literal_style.empty()) + literal_style = Style(conf); + style = &literal_style; + } + else + { + style = getStyleSheet()->getStyle(styleString); + } + + if (style) + { + osg::Group* styleGroup = factory.getOrCreateStyleGroup(*style, _session.get()); + osg::ref_ptr< osg::Node> styleNode; + osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(itr->second); + Query query; + factory.createOrUpdateNode(cursor.get(), *style, fc, styleNode, query); + if (styleNode.valid()) + { + styleGroup->addChild(styleNode); + if (!group->containsNode(styleGroup)) + { + group->addChild(styleGroup); + } + } + } + } + } + + + node = group; + } + else if (getStyleSheet()->getDefaultStyle()) + { + osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(features); + osg::ref_ptr< osg::Group > group = new osg::Group; + osg::ref_ptr< osg::Group > styleGroup = factory.getOrCreateStyleGroup(*getStyleSheet()->getDefaultStyle(), _session.get()); + osg::ref_ptr< osg::Node> styleNode; + factory.createOrUpdateNode(cursor.get(), *getStyleSheet()->getDefaultStyle(), fc, styleNode, query); + if (styleNode.valid()) + { + group->addChild(styleGroup); + styleGroup->addChild(styleNode); + node = group; + } + } + } + + if (!node->getBound().valid()) { - result = fmg->createNode(key, progress); + return nullptr; } - return result; + + if (index.valid()) + { + index->addChild(node); + return index; + } + + return node; } const Profile* diff --git a/src/osgEarth/TiledModelLayer b/src/osgEarth/TiledModelLayer index ce419e206e..66a6ca5336 100644 --- a/src/osgEarth/TiledModelLayer +++ b/src/osgEarth/TiledModelLayer @@ -68,10 +68,33 @@ namespace osgEarth void setRangeFactor(const float &value); const float& getRangeFactor() const; + //! Forces a rebuild on this layer. + void dirty(); + + public: // Layer + + // The Node representing this layer. + osg::Node* getNode() const override; + + // called by the map when this layer is added + void addedToMap(const Map*) override; + + // called by the map when this layer is removed + void removedFromMap(const Map*) override; + + // post-ctor initialization + void init() override; + protected: //! Subclasses must implement this to create a tile. //! @param key The tile key, in the underlying tiled data source's profile. //! @param progress A progress callback that can be checked for user cancellation. virtual osg::ref_ptr createTileImplementation(const TileKey& key, ProgressCallback* progress) const = 0; + + private: + osg::observer_ptr< const Map > _map; + osg::ref_ptr< osg::Group > _root; + bool _graphDirty; + void create(); }; } diff --git a/src/osgEarth/TiledModelLayer.cpp b/src/osgEarth/TiledModelLayer.cpp index 6cfae18c2a..4904ffd844 100644 --- a/src/osgEarth/TiledModelLayer.cpp +++ b/src/osgEarth/TiledModelLayer.cpp @@ -17,9 +17,29 @@ * along with this program. If not, see */ #include "TiledModelLayer" +#include +#include using namespace osgEarth; + +class TiledModelLayerPager : public SimplePager +{ +public: + TiledModelLayerPager(const Map* map, TiledModelLayer* layer): + SimplePager(map, layer->getProfile()), + _layer(layer) + { + } + + virtual osg::ref_ptr createNode(const TileKey& key, ProgressCallback* progress) override + { + return _layer->createTile(key, progress); + } + + osg::observer_ptr< TiledModelLayer > _layer; +}; + void TiledModelLayer::Options::fromConfig(const Config& conf) { additive().setDefault(false); @@ -79,3 +99,82 @@ TiledModelLayer::createTile(const TileKey& key, ProgressCallback* progress) cons return group; } } + +// The Node representing this layer. +osg::Node* TiledModelLayer::getNode() const +{ + return _root.get(); +} + +// called by the map when this layer is added +void +TiledModelLayer::addedToMap(const Map* map) +{ + super::addedToMap(map); + + _map = map; + + _graphDirty = true; + + // re-create the graph if necessary. + create(); +} + +// called by the map when this layer is removed +void +TiledModelLayer::removedFromMap(const Map* map) +{ + super::removedFromMap(map); + + if (_root.valid()) + { + osg::ref_ptr node = findTopMostNodeOfType(_root.get()); + if (node.valid()) node->setDone(); + _root->removeChildren(0, _root->getNumChildren()); + } +} + +void TiledModelLayer::dirty() +{ + _graphDirty = true; + + // create the scene graph + create(); +} + +// post-ctor initialization +void TiledModelLayer::init() +{ + super::init(); + + // Create the container group + + _root = new osg::Group(); + + // Assign the layer's state set to the root node: + _root->setStateSet(this->getOrCreateStateSet()); + + // Graph needs rebuilding + _graphDirty = true; + + // Depth sorting by default + getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); +} + +void TiledModelLayer::create() +{ + if (_map.valid() && _graphDirty) + { + _root->removeChildren(0, _root->getNumChildren()); + + TiledModelLayerPager* pager = new TiledModelLayerPager(_map.get(), this); + pager->setAdditive(this->getAdditive()); + pager->setRangeFactor(this->getRangeFactor()); + pager->setMinLevel(this->getMinLevel()); + pager->setMaxLevel(this->getMaxLevel()); + pager->build(); + // TODO: NVGL + _root->addChild(pager); + _graphDirty = false; + } +} \ No newline at end of file diff --git a/src/osgEarth/XYZModelGraph b/src/osgEarth/XYZModelGraph deleted file mode 100644 index a024ea51d8..0000000000 --- a/src/osgEarth/XYZModelGraph +++ /dev/null @@ -1,63 +0,0 @@ -/* --*-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 - */ - -#ifndef OSGEARTH_XYZ_MODEL_GRAPH_H -#define OSGEARTH_XYZ_MODEL_GRAPH_H 1 - -#include -#include -#include -#include -#include - -#include -#include - -namespace osgEarth { - - /** - * A scene graph node that loads pre-tiled quadtree model data. - */ - class OSGEARTH_EXPORT XYZModelGraph : public SimplePager - { - public: - XYZModelGraph(const osgEarth::Map* map, const Profile* profile, const URI& url, bool invertY, const osgDB::Options* options); - - void setOwnerName(const std::string& value); - - //! Whether to attempt to use NVGL extensions - void setUseNVGL(bool value); - - public: // SimplePager - - virtual osg::ref_ptr createNode(const TileKey& key, ProgressCallback* progress) override; - - private: - std::string _ownerName; - URI _url; - bool _invertY; - osg::ref_ptr< osgEarth::StateSetCache > _statesetCache; - osg::ref_ptr< osgDB::Options > _options; - osg::ref_ptr< TextureArena > _textures; - mutable std::vector _texturesCache; - mutable std::mutex _texturesCacheMutex; - }; -} - -#endif // OSGEARTH_XYZ_MODEL_GRAPH_H diff --git a/src/osgEarth/XYZModelGraph.cpp b/src/osgEarth/XYZModelGraph.cpp deleted file mode 100644 index 2563310146..0000000000 --- a/src/osgEarth/XYZModelGraph.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -*-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 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace osgEarth; - -XYZModelGraph::XYZModelGraph(const osgEarth::Map* map, const Profile* profile, const URI& url, bool invertY, const osgDB::Options* options) : - SimplePager(map, profile), - _url(url), - _invertY(invertY) -{ - _options = osgEarth::Registry::instance()->cloneOrCreateOptions(options); - _options->setObjectCacheHint(osgDB::Options::CACHE_IMAGES); - - _statesetCache = new StateSetCache(); -} - -void -XYZModelGraph::setUseNVGL(bool value) -{ - if (value == true && GLUtils::useNVGL() && !_textures.valid()) - { - _textures = new TextureArena(); - getOrCreateStateSet()->setAttribute(_textures, 1); - - // auto release requires that we install this update callback! - _textures->setAutoRelease(true); - - addUpdateCallback(new LambdaCallback<>([this](osg::NodeVisitor& nv) - { - _textures->update(nv); - return true; - })); - - getOrCreateStateSet()->setAttributeAndModes( - new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - } -} - -void -XYZModelGraph::setOwnerName(const std::string& value) -{ - _ownerName = value; -} - -osg::ref_ptr -XYZModelGraph::createNode(const TileKey& key, ProgressCallback* progress) -{ - OE_PROFILING_ZONE; - if (progress && progress->isCanceled()) - return nullptr; - - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - - unsigned x, y; - key.getTileXY(x, y); - unsigned cols = 0, rows = 0; - key.getProfile()->getNumTiles(key.getLevelOfDetail(), cols, rows); - unsigned inverted_y = rows - y - 1; - - if (_invertY == true) - { - y = inverted_y; - } - - std::string location = _url.full(); - - // support OpenLayers template style: - replaceIn(location, "${x}", Stringify() << x); - replaceIn(location, "${y}", Stringify() << y); - replaceIn(location, "${-y}", Stringify() << inverted_y); - replaceIn(location, "${z}", Stringify() << key.getLevelOfDetail()); - - - // failing that, legacy osgearth style: - replaceIn(location, "{x}", Stringify() << x); - replaceIn(location, "{y}", Stringify() << y); - replaceIn(location, "{-y}", Stringify() << inverted_y); - replaceIn(location, "{z}", Stringify() << key.getLevelOfDetail()); - - URI myUri(location, _url.context()); - - osg::ref_ptr< osg::Node > node = myUri.readNode(_options.get()).getNode(); - if (node.valid()) - { - if (_textures.valid()) - { - auto xform = findTopMostNodeOfType(node.get()); - - // Convert the geometry into chonks - ChonkFactory factory(_textures); - - factory.setGetOrCreateFunction( - ChonkFactory::getWeakTextureCacheFunction( - _texturesCache, _texturesCacheMutex)); - - osg::ref_ptr drawable = new ChonkDrawable(); - - if (xform) - { - for (unsigned i = 0; i < xform->getNumChildren(); ++i) - { - drawable->add(xform->getChild(i), factory); - } - xform->removeChildren(0, xform->getNumChildren()); - xform->addChild(drawable); - node = xform; - } - else - { - if (drawable->add(node.get(), factory)) - { - node = drawable; - } - } - } - else - { - osgEarth::Registry::shaderGenerator().run(node.get(), _statesetCache); - } - return node.release(); - } - return nullptr; -} \ No newline at end of file diff --git a/src/osgEarth/XYZModelLayer b/src/osgEarth/XYZModelLayer index 79ebb12cb0..4714e167f2 100644 --- a/src/osgEarth/XYZModelLayer +++ b/src/osgEarth/XYZModelLayer @@ -23,20 +23,23 @@ #include #include #include +#include +#include + namespace osgEarth { class Map; } namespace osgEarth -{ +{ /** * Layer that loads a pregenerated quadtree of model files */ class OSGEARTH_EXPORT XYZModelLayer : public TiledModelLayer { public: // serialization - struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options + struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options { META_LayerOptions(osgEarth, Options, TiledModelLayer::Options); OE_OPTION(URI, url); @@ -77,32 +80,17 @@ namespace osgEarth void setMaxLevel(unsigned value); unsigned getMaxLevel() const override; - //! Forces a rebuild on this layer. - void dirty(); - public: // Layer //! opens the layer and returns the status Status openImplementation() override; - //! closes the layer - Status closeImplementation() override; - - //! The Node representing this layer. - osg::Node* getNode() const override; + void addedToMap(const Map* map) override; //! Serialization Config getConfig() const override; - public: // Layer - - //! called by the map when this layer is added - void addedToMap(const Map*) override; - - //! called by the map when this layer is removed - void removedFromMap(const Map*) override; - - //! post-ctor initialization + // post-ctor initialization void init() override; protected: // TiledModelLayer @@ -115,12 +103,13 @@ namespace osgEarth virtual ~XYZModelLayer(); private: - osg::ref_ptr _root; osg::ref_ptr _profile; - osg::observer_ptr< const Map > _map; - bool _graphDirty; - - void create(); + + osg::ref_ptr< osgEarth::StateSetCache > _statesetCache; + osg::ref_ptr< osgDB::Options > _readOptions; + osg::ref_ptr< TextureArena > _textures; + mutable std::vector _texturesCache; + mutable std::mutex _texturesCacheMutex; }; } // namespace osgEarth diff --git a/src/osgEarth/XYZModelLayer.cpp b/src/osgEarth/XYZModelLayer.cpp index fbeaa9e6ff..fdcd6a6678 100644 --- a/src/osgEarth/XYZModelLayer.cpp +++ b/src/osgEarth/XYZModelLayer.cpp @@ -17,8 +17,14 @@ * along with this program. If not, see */ #include -#include #include +#include +#include +#include +#include +#include +#include +#include using namespace osgEarth; @@ -75,44 +81,52 @@ XYZModelLayer::getMaxLevel() const { return options().maxLevel().get(); } - -XYZModelLayer::~XYZModelLayer() +void XYZModelLayer::init() { - //NOP + super::init(); } -void XYZModelLayer::setProfile(const Profile* profile) +void XYZModelLayer::addedToMap(const Map* map) { - _profile = profile; - if (_profile) - { - options().profile() = profile->toProfileOptions(); - } -} + _readOptions = osgEarth::Registry::instance()->cloneOrCreateOptions(getReadOptions()); + _readOptions->setObjectCacheHint(osgDB::Options::CACHE_IMAGES); -void -XYZModelLayer::init() -{ - super::init(); + _statesetCache = new StateSetCache(); - _root = new osg::Group(); + if (*options().useNVGL() == true && GLUtils::useNVGL() && !_textures.valid()) + { + _textures = new TextureArena(); + getOrCreateStateSet()->setAttribute(_textures, 1); - // Assign the layer's state set to the root node: - _root->setStateSet(this->getOrCreateStateSet()); + // auto release requires that we install this update callback! + _textures->setAutoRelease(true); - // Graph needs rebuilding - _graphDirty = true; + getNode()->addUpdateCallback(new LambdaCallback<>([this](osg::NodeVisitor& nv) + { + _textures->update(nv); + return true; + })); - // Depth sorting by default - getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + getOrCreateStateSet()->setAttributeAndModes( + new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + super::addedToMap(map); } -void XYZModelLayer::dirty() +XYZModelLayer::~XYZModelLayer() { - _graphDirty = true; + //NOP +} - // create the scene graph - create(); +void XYZModelLayer::setProfile(const Profile* profile) +{ + _profile = profile; + if (_profile) + { + options().profile() = profile->toProfileOptions(); + } } Config @@ -122,12 +136,6 @@ XYZModelLayer::getConfig() const return conf; } -osg::Node* -XYZModelLayer::getNode() const -{ - return _root.get(); -} - Status XYZModelLayer::openImplementation() { @@ -140,73 +148,82 @@ XYZModelLayer::openImplementation() return Status::NoError; } -Status -XYZModelLayer::closeImplementation() +osg::ref_ptr +XYZModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const { - _graphDirty = true; - return getStatus(); -} + OE_PROFILING_ZONE; + if (progress && progress->isCanceled()) + return nullptr; -void -XYZModelLayer::addedToMap(const Map* map) -{ - OE_TEST << LC << "addedToMap" << std::endl; - super::addedToMap(map); + NetworkMonitor::ScopedRequestLayer layerRequest(getName()); - _map = map; + unsigned x, y; + key.getTileXY(x, y); + unsigned cols = 0, rows = 0; + key.getProfile()->getNumTiles(key.getLevelOfDetail(), cols, rows); + unsigned inverted_y = rows - y - 1; - _graphDirty = true; + if (*options().invertY() == true) + { + y = inverted_y; + } - // re-create the graph if necessary. - create(); -} + std::string location = options().url()->full(); -void -XYZModelLayer::removedFromMap(const Map* map) -{ - super::removedFromMap(map); + // support OpenLayers template style: + replaceIn(location, "${x}", Stringify() << x); + replaceIn(location, "${y}", Stringify() << y); + replaceIn(location, "${-y}", Stringify() << inverted_y); + replaceIn(location, "${z}", Stringify() << key.getLevelOfDetail()); - if (_root.valid()) - { - osg::ref_ptr node = findTopMostNodeOfType(_root.get()); - if (node.valid()) node->setDone(); - _root->removeChildren(0, _root->getNumChildren()); - } -} -void -XYZModelLayer::create() -{ - OE_TEST << LC << "create" << std::endl; - - if (_graphDirty && _profile) - { - osg::ref_ptr xyzGraph = new XYZModelGraph(_map.get(), _profile.get(), *_options->url(), *_options->invertY(), getReadOptions()); - xyzGraph->setOwnerName(getName()); - xyzGraph->setAdditive(*_options->additive()); - xyzGraph->setMinLevel(*_options->minLevel()); - xyzGraph->setMaxLevel(*_options->maxLevel()); - xyzGraph->setRangeFactor(*_options->rangeFactor()); - xyzGraph->setSceneGraphCallbacks(getSceneGraphCallbacks()); - xyzGraph->setUseNVGL(options().useNVGL().get()); - xyzGraph->build(); - - _root->removeChildren(0, _root->getNumChildren()); - _root->addChild(xyzGraph.get()); - - // clear the dirty flag. - _graphDirty = false; - - setStatus(Status::OK()); - } -} + // failing that, legacy osgearth style: + replaceIn(location, "{x}", Stringify() << x); + replaceIn(location, "{y}", Stringify() << y); + replaceIn(location, "{-y}", Stringify() << inverted_y); + replaceIn(location, "{z}", Stringify() << key.getLevelOfDetail()); -osg::ref_ptr -XYZModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const -{ - auto pager = osgEarth::findTopMostNodeOfType(_root.get()); - if (pager) - return pager->createNode(key, progress); - else - return {}; + URI myUri(location, options().url()->context()); + + osg::ref_ptr< osg::Node > node = myUri.readNode(_readOptions.get()).getNode(); + if (node.valid()) + { + if (_textures.valid()) + { + auto xform = findTopMostNodeOfType(node.get()); + + // Convert the geometry into chonks + ChonkFactory factory(_textures); + + factory.setGetOrCreateFunction( + ChonkFactory::getWeakTextureCacheFunction( + _texturesCache, _texturesCacheMutex)); + + osg::ref_ptr drawable = new ChonkDrawable(); + + if (xform) + { + for (unsigned i = 0; i < xform->getNumChildren(); ++i) + { + drawable->add(xform->getChild(i), factory); + } + xform->removeChildren(0, xform->getNumChildren()); + xform->addChild(drawable); + node = xform; + } + else + { + if (drawable->add(node.get(), factory)) + { + node = drawable; + } + } + } + else + { + osgEarth::Registry::shaderGenerator().run(node.get(), _statesetCache); + } + return node.release(); + } + return nullptr; }