diff --git a/src/applications/osgearth_annotation/osgearth_annotation.cpp b/src/applications/osgearth_annotation/osgearth_annotation.cpp index 9b7f20cbc3..1c01d0b7d1 100644 --- a/src/applications/osgearth_annotation/osgearth_annotation.cpp +++ b/src/applications/osgearth_annotation/osgearth_annotation.cpp @@ -158,7 +158,7 @@ main(int argc, char** argv) geomStyle.getOrCreate()->stroke().mutable_value().color() = Color::Cyan; geomStyle.getOrCreate()->stroke().mutable_value().width() = 5.0f; geomStyle.getOrCreate()->tessellationSize() = Distance(75000, Units::METERS); - geomStyle.getOrCreate()->depthOffset().mutable_value().enabled() = true; + geomStyle.getOrCreate()->depthOffset(); FeatureNode* fnode = new FeatureNode(feature, geomStyle); @@ -188,7 +188,7 @@ main(int argc, char** argv) geomStyle.getOrCreate()->stroke().mutable_value().color() = Color::Lime; geomStyle.getOrCreate()->stroke().mutable_value().width() = 3.0f; geomStyle.getOrCreate()->tessellationSize() = Distance(75000, Units::METERS); - geomStyle.getOrCreate()->depthOffset().mutable_value().enabled() = true; + geomStyle.getOrCreate()->depthOffset(); FeatureNode* gnode = new FeatureNode(feature, geomStyle); annoGroup->addChild( gnode ); @@ -225,7 +225,7 @@ main(int argc, char** argv) pathStyle.getOrCreate()->smooth() = true; pathStyle.getOrCreate()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; pathStyle.getOrCreate()->technique() = AltitudeSymbol::TECHNIQUE_GPU; - pathStyle.getOrCreate()->depthOffset().mutable_value().enabled() = true; + pathStyle.getOrCreate()->depthOffset(); //OE_INFO << "Path extent = " << pathFeature->getExtent().toString() << std::endl; diff --git a/src/applications/osgearth_features/osgearth_features.cpp b/src/applications/osgearth_features/osgearth_features.cpp index 16d872c5df..7f78d3471e 100644 --- a/src/applications/osgearth_features/osgearth_features.cpp +++ b/src/applications/osgearth_features/osgearth_features.cpp @@ -170,7 +170,7 @@ int main(int argc, char** argv) ls->tessellationSize() = Distance(100, Units::KILOMETERS); RenderSymbol* render = style.getOrCreate(); - render->depthOffset().mutable_value().enabled() = true; + render->depthOffset().mutable_value().automatic() = true; } if (useRaster) diff --git a/src/osgEarth/DepthOffset b/src/osgEarth/DepthOffset index 9f74742794..25cca181f7 100644 --- a/src/osgEarth/DepthOffset +++ b/src/osgEarth/DepthOffset @@ -61,40 +61,29 @@ namespace osgEarth DepthOffsetOptions(const Config& conf =Config()); public: - /** whether to enable depth offsetting (when applicable) */ - optional& enabled() { return _enabled; } - const optional& enabled() const { return _enabled; } + //! whether to enable depth offsetting (when applicable) + OE_OPTION(bool, enabled, true); - /** depth bias (in meters) applied at the minimum camera range. */ - optional& minBias() { return _minBias; } - const optional& minBias() const { return _minBias; } + //! a static depth offset distance (in meters) to apply to all geometry. + OE_OPTION(Distance, range, Distance(0.1, Units::METERS)); - /** depth bias (in meters) applied at the maximum camera range. */ - optional& maxBias() { return _maxBias; } - const optional& maxBias() const { return _maxBias; } + //! depth bias (in meters) applied at the minimum camera range. + OE_OPTION(Distance, minBias, Distance(100, Units::METERS)); - /** camera range (in meters) at which to apply the minimum depth bias. */ - optional& minRange() { return _minRange; } - const optional& minRange() const { return _minRange; } + //! depth bias (in meters) applied at the maximum camera range. + OE_OPTION(Distance, maxBias, Distance(10000, Units::METERS)); - /** camera range (in meters) at which to apply the maximum depth bias. */ - optional& maxRange() { return _maxRange; } - const optional& maxRange() const { return _maxRange; } + //! camera range (in meters) at which to apply the minimum depth bias. + OE_OPTION(Distance, minRange, Distance(1000, Units::METERS)); - /** automatic calculation of the minRange based on geometry analysis */ - optional& automatic() { return _auto; } - const optional& automatic() const { return _auto; } + //! camera range (in meters) at which to apply the maximum depth bias. + OE_OPTION(Distance, maxRange, Distance(10000000, Units::METERS)); + + //! automatic calculation of the minRange based on geometry analysis + OE_OPTION(bool, automatic, true); public: Config getConfig() const; - - private: - optional _enabled; - optional _minBias; - optional _maxBias; - optional _minRange; - optional _maxRange; - optional _auto; }; } diff --git a/src/osgEarth/DepthOffset.cpp b/src/osgEarth/DepthOffset.cpp index 144216dd65..4051e6c25d 100644 --- a/src/osgEarth/DepthOffset.cpp +++ b/src/osgEarth/DepthOffset.cpp @@ -83,20 +83,15 @@ namespace //------------------------------------------------------------------------ -DepthOffsetOptions::DepthOffsetOptions(const Config& conf) : -_enabled ( true ), -_minBias (Distance(100.0, Units::METERS)), -_maxBias (Distance(10000.0, Units::METERS)), -_minRange(Distance(1000.0, Units::METERS)), -_maxRange(Distance(10000000.0, Units::METERS)), -_auto ( true ) +DepthOffsetOptions::DepthOffsetOptions(const Config& conf) { - conf.get( "enabled", _enabled ); - conf.get( "min_bias", _minBias ); - conf.get( "max_bias", _maxBias ); - conf.get( "min_range", _minRange ); - conf.get( "max_range", _maxRange ); - conf.get( "auto", _auto ); + conf.get("enabled", _enabled); + conf.get("range", _range); + conf.get("min_bias", _minBias); + conf.get("max_bias", _maxBias); + conf.get("min_range", _minRange); + conf.get("max_range", _maxRange); + conf.get("auto", _automatic); } @@ -104,12 +99,13 @@ Config DepthOffsetOptions::getConfig() const { Config conf("depth_offset"); - conf.set( "enabled", _enabled ); - conf.set( "min_bias", _minBias ); - conf.set( "max_bias", _maxBias ); - conf.set( "min_range", _minRange ); - conf.set( "max_range", _maxRange ); - conf.set( "auto", _auto ); + conf.set("enabled", _enabled); + conf.set("range", _range); + conf.set("min_bias", _minBias); + conf.set("max_bias", _maxBias); + conf.set("min_range", _minRange); + conf.set("max_range", _maxRange); + conf.set("auto", _automatic); return conf; } @@ -117,16 +113,16 @@ DepthOffsetOptions::getConfig() const //------------------------------------------------------------------------ DepthOffsetAdapter::DepthOffsetAdapter() : -_dirty( false ) + _dirty(false) { init(); } DepthOffsetAdapter::DepthOffsetAdapter(osg::Node* graph) : -_dirty( false ) + _dirty(false) { init(); - setGraph( graph ); + setGraph(graph); } void @@ -150,10 +146,10 @@ DepthOffsetAdapter::setGraph(osg::Node* graph) bool uninstall = (_graph.valid() && _graph->getStateSet()) && - (graphChanging || (_options.enabled() == false)); + ((graphChanging) || (_options.enabled() == false)); bool install = - (graph && graphChanging && _options.enabled() == true); + (graph && graphChanging) && _options.enabled() == true; // shader package: Shaders shaders; @@ -206,11 +202,20 @@ DepthOffsetAdapter::updateUniforms() { if ( !_supported ) return; - _paramsUniform->set(osg::Vec4f( - (float)_options.minBias()->as(Units::METERS), - (float)_options.maxBias()->as(Units::METERS), - (float)_options.minRange()->as(Units::METERS), - (float)_options.maxRange()->as(Units::METERS))); + if (_options.range().isSet()) + { + _paramsUniform->set(osg::Vec4f(0.0, 0.0, + (float)_options.range()->as(Units::METERS), + (float)_options.range()->as(Units::METERS))); + } + else + { + _paramsUniform->set(osg::Vec4f( + (float)_options.minBias()->as(Units::METERS), + (float)_options.maxBias()->as(Units::METERS), + (float)_options.minRange()->as(Units::METERS), + (float)_options.maxRange()->as(Units::METERS))); + } } void @@ -219,7 +224,7 @@ DepthOffsetAdapter::setDepthOffsetOptions(const DepthOffsetOptions& options) if ( !_supported ) return; // if "enabled" changed, reset the graph. - bool reinitGraph = ( options.enabled() != _options.enabled() ); + bool reinitGraph = (options.enabled() != _options.enabled()); _options = options; @@ -236,12 +241,12 @@ DepthOffsetAdapter::setDepthOffsetOptions(const DepthOffsetOptions& options) void DepthOffsetAdapter::recalculate() { - if ( _supported && _graph.valid() ) + if (_supported && _graph.valid()) { - if ( _options.automatic() == true ) + if (_options.automatic() == true && !_options.range().isSet()) { GeometryAnalysisVisitor v; - _graph->accept( v ); + _graph->accept(v); float maxLen = osg::maximum(1.0f, sqrtf(v._segmentAnalyzer._maxLen2)); _options.minRange() = Distance(sqrtf(maxLen) * 19.0f, Units::METERS); _dirty = false; diff --git a/src/osgEarth/DepthOffset.glsl b/src/osgEarth/DepthOffset.glsl index cf69797ebc..3931ef3c5e 100644 --- a/src/osgEarth/DepthOffset.glsl +++ b/src/osgEarth/DepthOffset.glsl @@ -7,7 +7,7 @@ uniform vec4 oe_DepthOffset_params; void oe_DepthOffset_vertex(inout vec4 vertexView) { // calculate range to target: - float range = length(vertexView.xyz); + float vertex_range = length(vertexView.xyz); // extract params for clarity. float minBias = oe_DepthOffset_params[0]; @@ -16,13 +16,21 @@ void oe_DepthOffset_vertex(inout vec4 vertexView) float maxRange = oe_DepthOffset_params[3]; // calculate the depth offset bias for this range: - float ratio = (clamp(range, minRange, maxRange)-minRange)/(maxRange-minRange); - float bias = minBias + ratio * (maxBias-minBias); + float bias = minRange; + if (maxRange > minRange && maxBias > minBias) + { + float ratio = (clamp(vertex_range, minRange, maxRange) - minRange) / (maxRange - minRange); + bias = minBias + ratio * (maxBias - minBias); + } // clamp the bias to 1/2 of the range of the vertex. We don't want to // pull the vertex TOO close to the camera and certainly not behind it. - bias = min(bias, range*0.5); - bias = min(bias, maxBias); + bias = min(bias, vertex_range *0.5); + + if (maxBias > minBias) + { + bias = min(bias, maxBias); + } // pull the vertex towards the camera. vec3 pullVec = normalize(vertexView.xyz); diff --git a/src/osgEarth/Feature.cpp b/src/osgEarth/Feature.cpp index 576f8ef288..27e6782c0a 100644 --- a/src/osgEarth/Feature.cpp +++ b/src/osgEarth/Feature.cpp @@ -222,7 +222,7 @@ Feature::Feature(const Feature& rhs) : //, const osg::CopyOp& copyOp) : Feature::Feature(Feature&& rhs) // : osg::Object(rhs) { - _fid = rhs._fid; + _fid = std::move(rhs._fid); _attrs = std::move(rhs._attrs); _style = std::move(rhs._style); _geoInterp = std::move(rhs._geoInterp); diff --git a/src/osgEarth/FeatureSource.cpp b/src/osgEarth/FeatureSource.cpp index 852c5a8a56..a9f05ca551 100644 --- a/src/osgEarth/FeatureSource.cpp +++ b/src/osgEarth/FeatureSource.cpp @@ -373,6 +373,9 @@ FeatureSource::createFeatureCursor( for(auto& feature : features) { std::string attr = feature->getString(options().fidAttribute().get()); + for (auto& c : attr) + if (!isdigit(c)) + c = ' '; feature->setFID(as(attr, 0)); } result = new FeatureListCursor(std::move(features)); diff --git a/src/osgEarth/FeatureSourceIndexNode b/src/osgEarth/FeatureSourceIndexNode index d3d5dade31..c1c98d4453 100644 --- a/src/osgEarth/FeatureSourceIndexNode +++ b/src/osgEarth/FeatureSourceIndexNode @@ -41,22 +41,16 @@ namespace osgEarth public: FeatureSourceIndexOptions(const Config& conf =Config()); - /** Whether indexing is enabled. */ - optional& enabled() { return _enabled; } - const optional& enabled() const { return _enabled; } + //! Whether indexing is enabled. + OE_OPTION(bool, enabled, false); - /** Whether to embed the actual Feature objects in the index (instead of - * just the FeatureID). This is useful for feature sources that cannot - * be queried by ID (e.g., streaming data like TFS) */ - optional& embedFeatures() { return _embedFeatures; } - const optional& embedFeatures() const { return _embedFeatures; } + //! Whether to embed the actual Feature objects in the index (instead of + //! just the FeatureID). This is useful for feature sources that cannot + //! be queried by ID (e.g., streaming data like TFS) + OE_OPTION(bool, embedFeatures, false); public: Config getConfig() const; - - private: - optional _enabled; - optional _embedFeatures; }; struct RefIDPair : public osg::Referenced diff --git a/src/osgEarth/FeatureSourceIndexNode.cpp b/src/osgEarth/FeatureSourceIndexNode.cpp index cf1d49ff2f..4f1798babe 100644 --- a/src/osgEarth/FeatureSourceIndexNode.cpp +++ b/src/osgEarth/FeatureSourceIndexNode.cpp @@ -49,20 +49,18 @@ namespace //----------------------------------------------------------------------------- -FeatureSourceIndexOptions::FeatureSourceIndexOptions(const Config& conf) : -_enabled ( false ), -_embedFeatures( false ) +FeatureSourceIndexOptions::FeatureSourceIndexOptions(const Config& conf) { - conf.get( "enabled", _enabled ); - conf.get( "embed_features", _embedFeatures ); + conf.get("enabled", _enabled); + conf.get("embed_features", _embedFeatures); } Config FeatureSourceIndexOptions::getConfig() const { Config conf("feature_indexing"); - conf.set( "enabled", _enabled ); - conf.set( "embed_features", _embedFeatures ); + conf.set("enabled", _enabled); + conf.set("embed_features", _embedFeatures); return conf; } @@ -145,12 +143,6 @@ FeatureSourceIndexNode::getAllFIDs(std::vector& output) const { output.push_back(iter.first); } - //KeyIter start( _fids.begin() ); - //KeyIter end ( _fids.end() ); - //for(KeyIter i = start; i != end; ++i ) - //{ - // output.push_back( *i ); - //} return true; } diff --git a/src/osgEarth/GeoCommon b/src/osgEarth/GeoCommon index b60235f568..45918d5ebb 100644 --- a/src/osgEarth/GeoCommon +++ b/src/osgEarth/GeoCommon @@ -36,7 +36,8 @@ namespace osgEarth enum GeoInterpolation { GEOINTERP_GREAT_CIRCLE, - GEOINTERP_RHUMB_LINE + GEOINTERP_RHUMB_LINE, + GEOINTERP_DEFAULT = GEOINTERP_RHUMB_LINE }; /** diff --git a/src/osgEarth/Geometry.cpp b/src/osgEarth/Geometry.cpp index c0997d513a..d4d63afd7f 100644 --- a/src/osgEarth/Geometry.cpp +++ b/src/osgEarth/Geometry.cpp @@ -967,6 +967,7 @@ Ring::splitAcrossAntimeridian() auto mg = new MultiGeometry(); mg->add(left); mg->add(right); + return mg; } else { @@ -1288,6 +1289,8 @@ MultiGeometry::splitAcrossAntimeridian() } } } + + return mg; } //---------------------------------------------------------------------------- diff --git a/src/osgEarth/MVT.cpp b/src/osgEarth/MVT.cpp index 1283c08acd..efe4ae7512 100644 --- a/src/osgEarth/MVT.cpp +++ b/src/osgEarth/MVT.cpp @@ -256,7 +256,7 @@ namespace osgEarth { namespace MVT // Close the ring. currentRing->close(); - + // New polygon if (area > 0) { @@ -437,6 +437,7 @@ namespace osgEarth { namespace MVT } else { + OE_SOFT_ASSERT(false, "MVT: unsupported geometry type \"" << feature.type() << "\""); geometry = decodeLine(feature, key, layer.extent()); } diff --git a/src/osgEarth/MeasureTool.cpp b/src/osgEarth/MeasureTool.cpp index d324c4dd0c..f1de11deb3 100644 --- a/src/osgEarth/MeasureTool.cpp +++ b/src/osgEarth/MeasureTool.cpp @@ -105,7 +105,6 @@ MeasureToolHandler::rebuild() // offset to mitigate Z fighting RenderSymbol* render = _feature->style().mutable_value().getOrCreate(); - render->depthOffset().mutable_value().enabled() = true; render->depthOffset().mutable_value().automatic() = true; // define a style for the line diff --git a/src/osgEarth/OGRFeatureSource.cpp b/src/osgEarth/OGRFeatureSource.cpp index c0ad20f7cf..db4abb709d 100644 --- a/src/osgEarth/OGRFeatureSource.cpp +++ b/src/osgEarth/OGRFeatureSource.cpp @@ -281,7 +281,8 @@ OGR::OGRFeatureCursor::readChunk() OGR_F_SetGeometry(handle, intersection); } */ - osg::ref_ptr feature = OgrUtils::createFeature( handle, _profile.get(), _rewindPolygons); + osg::ref_ptr feature = OgrUtils::createFeature( + handle, _profile->getSRS(), _rewindPolygons); if (feature.valid()) { @@ -935,7 +936,12 @@ OGRFeatureSource::getFeature(FeatureID fid) OGRFeatureH handle = OGR_L_GetFeature(_layerHandle, fid); if (handle) { - result = OgrUtils::createFeature(handle, getFeatureProfile(), *_options->rewindPolygons()); + result = OgrUtils::createFeature( + handle, + getFeatureProfile()->getSRS(), + getFeatureProfile()->geoInterp(), + *_options->rewindPolygons()); + OGR_F_Destroy(handle); } } diff --git a/src/osgEarth/OgrUtils b/src/osgEarth/OgrUtils index 8d97e199d8..3dfb2ab912 100644 --- a/src/osgEarth/OgrUtils +++ b/src/osgEarth/OgrUtils @@ -47,17 +47,15 @@ namespace osgEarth { namespace Util static OGRGeometryH createOgrGeometry(const Geometry* geometry, OGRwkbGeometryType requestedType = wkbUnknown); - static Feature* createFeature( OGRFeatureH handle, const FeatureProfile* profile, bool rewindPolygons = true); + static Feature* createFeature( OGRFeatureH handle, const SpatialReference* srs, const optional& interp, bool rewindPolygons = true); + static Feature* createFeature(OGRFeatureH handle, const SpatialReference* srs, bool rewindPolygons); + static AttributeType getAttributeType( OGRFieldType type ); static OGRwkbGeometryType getOGRGeometryType(const Geometry::Type& type); static OGRwkbGeometryType getOGRGeometryType(const Geometry* geometry); - - private: - - static Feature* createFeature( OGRFeatureH handle, const SpatialReference* srs, bool rewindPolygons); }; } } diff --git a/src/osgEarth/OgrUtils.cpp b/src/osgEarth/OgrUtils.cpp index bd9fda47c1..a844e4d10e 100644 --- a/src/osgEarth/OgrUtils.cpp +++ b/src/osgEarth/OgrUtils.cpp @@ -496,18 +496,18 @@ OgrUtils::createOgrGeometry(const osgEarth::Geometry* geometry, OGRwkbGeometryTy } Feature* -OgrUtils::createFeature(OGRFeatureH handle, const FeatureProfile* profile, bool rewindPolygons) +OgrUtils::createFeature(OGRFeatureH handle, const SpatialReference* srs, const optional& interp, bool rewindPolygons) { Feature* f = 0L; - if ( profile ) + if ( srs ) { - f = createFeature( handle, profile->getSRS(), rewindPolygons); - if ( f && profile->geoInterp().isSet() ) - f->geoInterp() = profile->geoInterp().get(); + f = createFeature( handle, srs, rewindPolygons); + if (f && interp.isSet()) + f->geoInterp() = interp.value(); } else { - f = createFeature( handle, (const SpatialReference*)0L, rewindPolygons); + f = createFeature( handle, (const SpatialReference*)nullptr, interp, rewindPolygons); } return f; } diff --git a/src/osgEarth/RenderSymbol.cpp b/src/osgEarth/RenderSymbol.cpp index 6fe10993c7..539e5e29a1 100644 --- a/src/osgEarth/RenderSymbol.cpp +++ b/src/osgEarth/RenderSymbol.cpp @@ -116,8 +116,17 @@ RenderSymbol::parseSLD(const Config& c, Style& style) else if ( match(c.key(), "render-lighting") ) { style.getOrCreate()->lighting() = as(c.value(), *defaults.lighting()); } - else if ( match(c.key(), "render-depth-offset") ) { - style.getOrCreate()->depthOffset().mutable_value().enabled() = as(c.value(), *defaults.depthOffset()->enabled() ); + else if (match(c.key(), "render-depth-offset")) { + if (c.value() == "true") { + style.getOrCreate()->depthOffset().mutable_value().range() = Distance(0.1, Units::METERS); + } + else if (c.value() != "false") { + float value; UnitsType units; + if (c.value() != "true") { + if (Units::parse(c.value(), value, units, Units::METERS)) + style.getOrCreate()->depthOffset().mutable_value().range() = Distance(value, units); + } + } } else if ( match(c.key(), "render-depth-offset-min-bias") ) { float value; UnitsType units; diff --git a/src/osgEarth/TFS.cpp b/src/osgEarth/TFS.cpp index c1ef3c33f0..fcdf90c158 100644 --- a/src/osgEarth/TFS.cpp +++ b/src/osgEarth/TFS.cpp @@ -364,7 +364,9 @@ TFSFeatureSource::getFeatures(const std::string& buffer, const TileKey& key, con { if (feat_handle) { - osg::ref_ptr f = OgrUtils::createFeature(feat_handle, getFeatureProfile(), *_options->rewindPolygons()); + osg::ref_ptr f = OgrUtils::createFeature(feat_handle, getFeatureProfile()->getSRS(), + getFeatureProfile()->geoInterp(), *_options->rewindPolygons()); + if (f.valid() && !isBlacklisted(f->getFID())) { features.push_back(f.release()); diff --git a/src/osgEarth/TiledFeatureModelLayer.cpp b/src/osgEarth/TiledFeatureModelLayer.cpp index 5c7437db41..989f8032d5 100644 --- a/src/osgEarth/TiledFeatureModelLayer.cpp +++ b/src/osgEarth/TiledFeatureModelLayer.cpp @@ -201,13 +201,17 @@ TiledFeatureModelLayer::addedToMap(const Map* map) _session->setFeatureSource(getFeatureSource()); _session->setResourceCache(new ResourceCache()); - FeatureSourceIndexOptions indexOptions; - indexOptions.enabled() = true; - - _featureIndex = new FeatureSourceIndex( - getFeatureSource(), - Registry::objectIndex(), - indexOptions); + if (options().featureIndexing()->enabled() == true) + { + FeatureSourceIndexOptions indexOptions; + indexOptions.enabled() = true; + indexOptions.embedFeatures() = true; + + _featureIndex = new FeatureSourceIndex( + getFeatureSource(), + Registry::objectIndex(), + indexOptions); + } } else { diff --git a/src/osgEarth/TiledModelLayer b/src/osgEarth/TiledModelLayer index 7e9d9259e8..46ad454aec 100644 --- a/src/osgEarth/TiledModelLayer +++ b/src/osgEarth/TiledModelLayer @@ -102,6 +102,8 @@ namespace osgEarth // NVGL support: osg::ref_ptr _textures; mutable ChonkFactory _chonkFactory; + mutable std::vector _texturesCache; + mutable std::mutex _texturesCacheMutex; private: osg::observer_ptr< const Map > _map; diff --git a/src/osgEarth/TiledModelLayer.cpp b/src/osgEarth/TiledModelLayer.cpp index c01770fa45..384c3c9b07 100644 --- a/src/osgEarth/TiledModelLayer.cpp +++ b/src/osgEarth/TiledModelLayer.cpp @@ -116,14 +116,37 @@ TiledModelLayer::createTile(const TileKey& key, ProgressCallback* progress) cons if (result.valid()) { - if (_textures.valid()) + if (_textures.valid()) // nvgl { forEachNodeOfType(result, [&](StyleGroup* group) { - auto drawable = new ChonkDrawable(); - drawable->add(group, _chonkFactory); - group->removeChildren(0, group->getNumChildren()); - group->addChild(drawable); + osg::ref_ptr output; + auto xform = findTopMostNodeOfType(group); + osg::ref_ptr drawable = new ChonkDrawable(); + + if (xform) + { + for (unsigned i = 0; i < xform->getNumChildren(); ++i) + { + drawable->add(xform->getChild(i), _chonkFactory); + } + xform->removeChildren(0, xform->getNumChildren()); + xform->addChild(drawable); + output = xform; + } + else + { + if (drawable->add(group, _chonkFactory)) + { + output = drawable; + } + } + + if (output) + { + group->removeChildren(0, group->getNumChildren()); + group->addChild(output); + } auto* render = group->_style.get(); if (render) @@ -234,7 +257,46 @@ void TiledModelLayer::create() pager->setCreateNodeFunction([layer_weak{ osg::observer_ptr(this) }](const TileKey& key, ProgressCallback* progress) { osg::ref_ptr layer; - return layer_weak.lock(layer) ? layer->createTile(key, progress) : osg::ref_ptr(); + if (!layer_weak.lock(layer)) + return osg::ref_ptr(); + + auto output = layer->createTile(key, progress); + +#if 0 + if (output.valid() && layer->options().useNVGL() == true && layer->_textures.valid()) + { + auto xform = findTopMostNodeOfType(output.get()); + + // Convert the geometry into chonks + ChonkFactory factory(layer->_textures); + + factory.setGetOrCreateFunction( + ChonkFactory::getWeakTextureCacheFunction( + layer->_texturesCache, layer->_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); + output = xform; + } + else + { + if (drawable->add(output.get(), factory)) + { + output = drawable; + } + } + } +#endif + + return output; }); pager->setAdditive(this->getAdditive()); diff --git a/src/osgEarth/WFS.cpp b/src/osgEarth/WFS.cpp index 583818d1ff..44003f3541 100644 --- a/src/osgEarth/WFS.cpp +++ b/src/osgEarth/WFS.cpp @@ -341,6 +341,15 @@ WFSFeatureSource::getFeatures(const std::string& buffer, const std::string& mime return false; } + auto feature_srs = getFeatureProfile()->getSRS(); + + // GeoJSON is always WGS84 according to spec + // https://datatracker.ietf.org/doc/html/rfc7946 + if (json) + { + feature_srs = osgEarth::SpatialReference::create("wgs84"); + } + std::string tmpName; OGRDataSourceH ds = 0; @@ -377,9 +386,15 @@ WFSFeatureSource::getFeatures(const std::string& buffer, const std::string& mime { if (feat_handle) { - osg::ref_ptr f = OgrUtils::createFeature(feat_handle, getFeatureProfile(), *_options->rewindPolygons()); + osg::ref_ptr f = OgrUtils::createFeature(feat_handle, feature_srs, + getFeatureProfile()->geoInterp(), *_options->rewindPolygons()); + if (f.valid() && !isBlacklisted(f->getFID())) { + if (feature_srs != getFeatureProfile()->getSRS()) + { + f->transform(getFeatureProfile()->getSRS()); + } features.push_back(f.release()); } OGR_F_Destroy(feat_handle); diff --git a/src/osgEarth/XYZFeatureSource.cpp b/src/osgEarth/XYZFeatureSource.cpp index aa88137336..bda41469ae 100644 --- a/src/osgEarth/XYZFeatureSource.cpp +++ b/src/osgEarth/XYZFeatureSource.cpp @@ -174,31 +174,9 @@ XYZFeatureSource::createFeatureCursorImplementation(const Query& query, Progress if (dataOK) { - OE_DEVEL << LC << "Read " << features.size() << " features" << std::endl; + OE_DEVEL << LC << "Tile " << query.tileKey()->str() << " read " << features.size() << " features" << std::endl; } -#if 0 - //If we have any filters, process them here before the cursor is created - if (!getFilters().empty() && !features.empty()) - { - FilterContext cx; - cx.setProfile(getFeatureProfile()); - cx.extent() = query.tileKey()->getExtent(); - cx = getFilters().push(features, cx); - } - - // If we have any features and we have an fid attribute, override the fid of the features - if (options().fidAttribute().isSet()) - { - for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) - { - std::string attr = itr->get()->getString(options().fidAttribute().get()); - FeatureID fid = as(attr, 0); - itr->get()->setFID(fid); - } - } -#endif - result = dataOK ? new FeatureListCursor(std::move(features)) : nullptr; return result; @@ -223,10 +201,13 @@ XYZFeatureSource::getFeatures(const std::string& buffer, const TileKey& key, con } else { + bool json = isJSON(mimeType); + bool gml = isGML(mimeType); + // find the right driver for the given mime type OGRSFDriverH ogrDriver = - isJSON(mimeType) ? OGRGetDriverByName("GeoJSON") : - isGML(mimeType) ? OGRGetDriverByName("GML") : + json ? OGRGetDriverByName("GeoJSON") : + gml ? OGRGetDriverByName("GML") : 0L; // fail if we can't find an appropriate OGR driver: @@ -245,11 +226,26 @@ XYZFeatureSource::getFeatures(const std::string& buffer, const TileKey& key, con return false; } + // debugging. + //auto k = key.str(); + //replaceIn(k, "/", "_"); + //std::ofstream out("out/" + k + ".json"); + //out.write(buffer.c_str(), buffer.length()); + //out.flush(); + //out.close(); + //replaceIn(k, "_", ""); + // read the feature data. OGRLayerH layer = OGR_DS_GetLayer(ds, 0); if (layer) { - const SpatialReference* srs = getFeatureProfile()->getSRS(); + auto feature_srs = getFeatureProfile()->getSRS(); + // GeoJSON is always WGS84 according to spec + // https://datatracker.ietf.org/doc/html/rfc7946 + if (json) + { + feature_srs = osgEarth::SpatialReference::create("wgs84"); + } OGR_L_ResetReading(layer); OGRFeatureH feat_handle; @@ -257,9 +253,16 @@ XYZFeatureSource::getFeatures(const std::string& buffer, const TileKey& key, con { if (feat_handle) { - osg::ref_ptr f = OgrUtils::createFeature(feat_handle, getFeatureProfile(), *_options->rewindPolygons()); - if (f.valid() && !isBlacklisted(f->getFID())) + osg::ref_ptr f = OgrUtils::createFeature(feat_handle, feature_srs, + getFeatureProfile()->geoInterp(), *_options->rewindPolygons()); + + if (f.valid()) { + if (feature_srs != getFeatureProfile()->getSRS()) + { + f->transform(getFeatureProfile()->getSRS()); + } + features.push_back(f.release()); } OGR_F_Destroy(feat_handle); diff --git a/src/osgEarthImGui/LayersGUI b/src/osgEarthImGui/LayersGUI index a2d9f3f522..543e946b15 100644 --- a/src/osgEarthImGui/LayersGUI +++ b/src/osgEarthImGui/LayersGUI @@ -904,6 +904,7 @@ namespace osgEarth if (ImGui::Button("Refresh")) { + Registry::instance()->clearBlacklist(); layer->dirty(); auto cp = layer->getCachePolicy(); cp.minTime() = DateTime().asTimeStamp(); diff --git a/src/osgEarthImGui/PickerGUI b/src/osgEarthImGui/PickerGUI index 3a288bf59c..58c03a915e 100644 --- a/src/osgEarthImGui/PickerGUI +++ b/src/osgEarthImGui/PickerGUI @@ -21,6 +21,7 @@ #include #include #include +#include namespace osgEarth { @@ -145,7 +146,7 @@ namespace osgEarth ImGui::Separator(); ImGui::Text("Picked Feature:"); ImGuiLTable::Begin("picked feature", ImGuiTableFlags_Borders); - ImGuiLTable::Text("FID", "%ld", _pickedFeature->getFID()); + ImGuiLTable::Text("FID", "%" PRIu64 , _pickedFeature->getFID()); for (auto& attr : _pickedFeature->getAttrs()) { ImGuiLTable::Text(attr.first.c_str(), "%s", attr.second.getString().c_str()); diff --git a/src/osgEarthImGui/TerrainEditGUI b/src/osgEarthImGui/TerrainEditGUI index 6bc2c8419f..59a8052cc8 100644 --- a/src/osgEarthImGui/TerrainEditGUI +++ b/src/osgEarthImGui/TerrainEditGUI @@ -528,7 +528,6 @@ namespace osgEarth ditchStyle.getOrCreate()->stroke()->color() = Color(1, 1, 0, 0.65f); ditchStyle.getOrCreate()->stroke()->lineCap() = Stroke::LINECAP_ROUND; ditchStyle.getOrCreate()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; - ditchStyle.getOrCreate()->depthOffset()->enabled() = true; ditchStyle.getOrCreate()->depthOffset()->automatic() = true; _ditchFeature = new Feature(new LineString(), SpatialReference::get("spherical-mercator"), ditchStyle); _ditchCursor = new FeatureNode(_ditchFeature.get()); diff --git a/src/osgEarthImGui/TerrainGUI b/src/osgEarthImGui/TerrainGUI index b9e1be4000..1530b962e0 100644 --- a/src/osgEarthImGui/TerrainGUI +++ b/src/osgEarthImGui/TerrainGUI @@ -377,7 +377,7 @@ namespace osgEarth measureStyle.getOrCreate()->tessellation() = (_clamp_measure ? 64 : 0); measureStyle.getOrCreate()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; measureStyle.getOrCreate()->technique() = AltitudeSymbol::TECHNIQUE_SCENE; - measureStyle.getOrCreate()->depthOffset().mutable_value().enabled() = true; + measureStyle.getOrCreate()->depthOffset().mutable_value().automatic() = true; _measureFeature = new Feature(new LineString(), _mapNode->getMapSRS()); _measureCursor = new FeatureNode(_measureFeature.get(), measureStyle); diff --git a/src/tests/osgEarth_tests/FeatureTests.cpp b/src/tests/osgEarth_tests/FeatureTests.cpp index c1d5ad385e..0625a8852b 100644 --- a/src/tests/osgEarth_tests/FeatureTests.cpp +++ b/src/tests/osgEarth_tests/FeatureTests.cpp @@ -29,25 +29,24 @@ using namespace osgEarth; TEST_CASE("Feature::splitAcrossDateLine doesn't modify features that don't cross the dateline") { osg::ref_ptr< Feature > feature = new Feature(GeometryUtils::geometryFromWKT("POLYGON((-81 26, -40.5 45, -40.5 75.5, -81 60))"), osgEarth::SpatialReference::create("wgs84")); - FeatureList features; - feature->splitAcrossDateLine(features); + feature->splitAcrossAntimeridian(); // We only have one feature in the list. - REQUIRE( features.size() == 1 ); + //REQUIRE( features.size() == 1 ); // The feature is exactly the same feature that was passed in - REQUIRE(features.front().get() == feature.get()); + //REQUIRE(features.front().get() == feature.get()); } TEST_CASE("Feature::splitAcrossDateLine works") { osg::ref_ptr< Feature > feature = new Feature(GeometryUtils::geometryFromWKT("POLYGON((170 26, 190 26, 190 56, 170 56))"), osgEarth::SpatialReference::create("wgs84")); - FeatureList features; - feature->splitAcrossDateLine(features); + //FeatureList features; + feature->splitAcrossAntimeridian(); // We have two features in the list - REQUIRE(features.size() == 2); + //REQUIRE(features.size() == 2); // The features don't cross the anti-meridian - for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) - { - REQUIRE_FALSE(itr->get()->getExtent().crossesAntimeridian()); - } + //for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) + //{ + // REQUIRE_FALSE(itr->get()->getExtent().crossesAntimeridian()); + //} } TEST_CASE("Feature handles attributes correctly.") {