diff --git a/src/osgEarth/ElevationLayer.cpp b/src/osgEarth/ElevationLayer.cpp index 282ff50116..081a7ad916 100644 --- a/src/osgEarth/ElevationLayer.cpp +++ b/src/osgEarth/ElevationLayer.cpp @@ -635,6 +635,8 @@ ElevationLayer::createHeightFieldInKeyProfile(const TileKey& key, ProgressCallba return GeoHeightField::INVALID; } + bool applyVerticalDatumTransformation = !key.getExtent().getSRS()->isVertEquivalentTo(profile->getSRS()); + if (key.getProfile()->isHorizEquivalentTo(profile.get())) { Threading::ScopedReadLock lock(inUseMutex()); @@ -644,6 +646,9 @@ ElevationLayer::createHeightFieldInKeyProfile(const TileKey& key, ProgressCallba { // If the profiles are different, use a compositing method to assemble the tile. result = assembleHeightField(key, progress); + + // assembleHeightField already does this, and more efficiently: + applyVerticalDatumTransformation = false; } // Check for cancelation before writing to a cache @@ -671,10 +676,8 @@ ElevationLayer::createHeightFieldInKeyProfile(const TileKey& key, ProgressCallba // If the result is good, we now have a heightfield but its vertical values // are still relative to the source's vertical datum. Convert them. - if (hf.valid() && !key.getExtent().getSRS()->isVertEquivalentTo(profile->getSRS())) + if (applyVerticalDatumTransformation && hf.valid()) { - OE_PROFILING_ZONE_NAMED("vdatum xform"); - VerticalDatum::transform( profile->getSRS()->getVerticalDatum(), // from key.getExtent().getSRS()->getVerticalDatum(), // to diff --git a/src/osgEarth/ImageToHeightFieldConverter b/src/osgEarth/ImageToHeightFieldConverter index 0fd34cde2b..4f8de0ce7c 100644 --- a/src/osgEarth/ImageToHeightFieldConverter +++ b/src/osgEarth/ImageToHeightFieldConverter @@ -19,12 +19,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ - -#ifndef OSGEARTH_IMAGE_TO_HEIGHTFIELD_CONVERTER -#define OSGEARTH_IMAGE_TO_HEIGHTFIELD_CONVERTER 1 +#pragma once #include - +#include #include #include @@ -36,10 +34,7 @@ namespace osgEarth { namespace Util class OSGEARTH_EXPORT ImageToHeightFieldConverter { public: - ImageToHeightFieldConverter(); - - /** dtor */ - virtual ~ImageToHeightFieldConverter() { } + ImageToHeightFieldConverter() = default; /** * Instruct the converter to detect and replace "no data" values. It will @@ -71,9 +66,7 @@ namespace osgEarth { namespace Util osg::Image* convert16(const osg::HeightField* hf ) const; osg::Image* convert32(const osg::HeightField* hf ) const; - bool _replace_nodata; - float _nodata_value; + bool _replace_nodata = false; + float _nodata_value = NO_DATA_VALUE; }; } } - -#endif //OSGEARTH_IMAGE_TO_HEIGHTFIELD_CONVERTER diff --git a/src/osgEarth/ImageToHeightFieldConverter.cpp b/src/osgEarth/ImageToHeightFieldConverter.cpp index 8cba18f078..e192e5998c 100644 --- a/src/osgEarth/ImageToHeightFieldConverter.cpp +++ b/src/osgEarth/ImageToHeightFieldConverter.cpp @@ -37,13 +37,6 @@ namespace } } -ImageToHeightFieldConverter::ImageToHeightFieldConverter(): -_replace_nodata( false ), -_nodata_value( 0.0f ) -{ - //NOP -} - void ImageToHeightFieldConverter::setRemoveNoDataValues( bool which, float f ) { diff --git a/src/osgEarth/ImageUtils.cpp b/src/osgEarth/ImageUtils.cpp index 9ae5b25bc5..2d9afcaa32 100644 --- a/src/osgEarth/ImageUtils.cpp +++ b/src/osgEarth/ImageUtils.cpp @@ -2204,6 +2204,17 @@ namespace } }; + //! Select an appropriate reader for the given data type. + //! + //! NOTE!! + //! Fopr UNSIGNED data types, we are using a SIGNED reader, except in the case + //! of GL_UNSIGNED_BYTE. This is because the OSG TIFF reader always declares + //! the data to be unsigned even when it's not. That's a bug, but it does not + //! hurt us to generate signed data for unsigned input, so this is an acceptable + //! workaround. + //! + //! The exception is GL_UNSIGNED_BYTE which is commonly normalized into [0..1] + //! so we will maintain signed-ness for that. template inline ImageUtils::PixelReader::ReaderFunc chooseReader(GLenum dataType) @@ -2215,13 +2226,13 @@ namespace case GL_UNSIGNED_BYTE: return &ColorReader::read; case GL_SHORT: - return &ColorReader::read; case GL_UNSIGNED_SHORT: - return &ColorReader::read; + return &ColorReader::read; + //return &ColorReader::read; case GL_INT: - return &ColorReader::read; case GL_UNSIGNED_INT: - return &ColorReader::read; + return &ColorReader::read; + //return &ColorReader::read; case GL_FLOAT: return &ColorReader::read; case GL_UNSIGNED_SHORT_5_5_5_1: @@ -2235,6 +2246,7 @@ namespace } } + //! Selects a reader based on the input pixel format and type. inline ImageUtils::PixelReader::ReaderFunc getReader( GLenum pixelFormat, GLenum dataType ) { diff --git a/src/osgEarth/TMS.cpp b/src/osgEarth/TMS.cpp index f0e43c3a26..a4a0de2ec4 100644 --- a/src/osgEarth/TMS.cpp +++ b/src/osgEarth/TMS.cpp @@ -1416,23 +1416,26 @@ TMSElevationLayer::createHeightFieldImplementation(const TileKey& key, ProgressC { const osg::Image* image = geoImage.getImage(); +#if 0 + ImageToHeightFieldConverter converter; + osg::ref_ptr hf = converter.convert(image); + return GeoHeightField(hf.get(), key.getExtent()); + +#else // Allocate the heightfield. osg::HeightField* hf = new osg::HeightField(); hf->allocate(image->s(), image->t()); - ImageUtils::PixelReader reader(image); + ImageUtils::PixelReader read(image); osg::Vec4f pixel; - - for (int c = 0; c < image->s(); c++) - { - for (int r = 0; r < image->t(); r++) + read.forEachPixel([&](auto& i) { - reader(pixel, c, r); - hf->setHeight(c, r, decode(pixel)); - } - } + read(pixel, i.s(), i.t()); + hf->setHeight(i.s(), i.t(), decode(pixel)); + }); return GeoHeightField(hf, key.getExtent()); +#endif } return GeoHeightField::INVALID; diff --git a/src/osgEarth/TileLayer.cpp b/src/osgEarth/TileLayer.cpp index 42abc7bc6c..a62207f1b8 100644 --- a/src/osgEarth/TileLayer.cpp +++ b/src/osgEarth/TileLayer.cpp @@ -360,7 +360,7 @@ TileLayer::addedToMap(const Map* map) !map->getProfile()->getSRS()->isHorizEquivalentTo(getProfile()->getSRS())) { l2CacheSize = 16u; - OE_DEBUG << LC << "Map/Layer profiles differ; requesting L2 cache" << std::endl; + OE_INFO << LC << "Map/Layer profiles differ; requesting L2 cache" << std::endl; } // Use the user defined option if it's set. diff --git a/src/osgEarth/XYZ.cpp b/src/osgEarth/XYZ.cpp index d30a06fe16..1f97f8bba7 100644 --- a/src/osgEarth/XYZ.cpp +++ b/src/osgEarth/XYZ.cpp @@ -23,6 +23,7 @@ #include #include "MetaTile" #include +#include using namespace osgEarth; using namespace osgEarth::XYZ; @@ -311,7 +312,10 @@ XYZElevationLayer::openImplementation() if (status.isError()) return status; - setProfile(_imageLayer->getProfile()); + setProfile(_imageLayer->getProfile()); + + DataExtentList de{ DataExtent(getProfile()->getExtent()) }; + setDataExtents(de); return Status::NoError; } @@ -416,16 +420,19 @@ XYZElevationLayer::createHeightFieldImplementation(const TileKey& key, ProgressC osg::HeightField* hf = new osg::HeightField(); hf->allocate(image->s(), image->t()); - ImageUtils::PixelReader reader(image); + ImageUtils::PixelReader read(image); osg::Vec4f pixel; + read.forEachPixel([&](auto& i) + { + read(pixel, i.s(), i.t()); + hf->setHeight(i.s(), i.t(), decode(pixel)); + }); - for (int c = 0; c < image->s(); c++) + if (key.is(8, 70, 107)) { - for (int r = 0; r < image->t(); r++) - { - reader(pixel, c, r); - hf->setHeight(c, r, decode(pixel)); - } + ImageToHeightFieldConverter c; + auto out = c.convert(hf, 32); + osgDB::writeImageFile(*out, "test.tif"); } return GeoHeightField(hf, key.getExtent());