/* -*-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 #include #include #include #include /** * GDAL (Geospatial Data Abstraction Library) Layers */ class GDALDataset; class GDALRasterBand; namespace osgEarth { namespace GDAL { /** * Encapsulates a user-supplied GDALDataset */ class OSGEARTH_EXPORT ExternalDataset : public osg::Referenced // NO EXPORT; header only { public: //! Default constructor ExternalDataset() = default; //! Init constructor ExternalDataset(GDALDataset* dataset, bool ownsDataset) : _dataset(dataset), _ownsDataset(ownsDataset) {} public: GDALDataset* dataset() const { return _dataset; }; void setDataset(GDALDataset* dataset) { _dataset = dataset; }; bool ownsDataset() const { return _ownsDataset; }; void setOwnsDataset(bool ownsDataset) { _ownsDataset = ownsDataset; }; private: GDALDataset* _dataset = nullptr; bool _ownsDataset = true; }; // GDAL-specific serialization data to be incorpoated by the LayerOptions below class OSGEARTH_EXPORT Options { public: Options() { } Options(const ConfigOptions& input); OE_OPTION(URI, url); OE_OPTION(std::string, connection); OE_OPTION(unsigned, subDataSet, 0u); OE_OPTION(RasterInterpolation, interpolation, INTERP_AVERAGE); OE_OPTION(ProfileOptions, warpProfile); OE_OPTION(bool, useVRT, false); OE_OPTION(bool, coverageUsesPaletteIndex, true); OE_OPTION(bool, singleThreaded, false); OE_OPTION(ProfileOptions, fallbackProfile); void readFrom(const Config& conf); void writeTo(Config& conf) const; }; /** * Driver for reading raster data using GDAL. * It is rarely necessary to use this object directly; use a * GDALImageLayer or GDALElevationLayer instead. */ class OSGEARTH_EXPORT Driver { public: using Ptr = std::shared_ptr; //! Constructs a new driver virtual ~Driver(); //! Value to interpet as "no data" void setNoDataValue(float value) { _noDataValue = value; } //! Minimum valid data value (anything less is "no data") void setMinValidValue(float value) { _minValidValue = value; } //! Maximum valid data value (anything more is "no data") void setMaxValidValue(float value) { _maxValidValue = value; } //! Maximum LOD at which to return real data void setMaxDataLevel(unsigned value) { _maxDataLevel = value; } //! Assign an external GDAL dataset to use. void setExternalDataset(ExternalDataset* value); //! Opens and initializes the connection to the dataset Status open( const std::string& name, const GDAL::Options& options, unsigned tileSize, const Profile* fallback_profile, DataExtentList* out_dataExtents, const osgDB::Options* readOptions, bool verbose); //! Creates an image if possible osg::Image* createImage( const TileKey& key, unsigned tileSize, bool isCoverage, ProgressCallback* progress); //! Creates a heightfield if possible osg::HeightField* createHeightField( const TileKey& key, unsigned tileSize, ProgressCallback* progress); //! Creates a heightfield if possible using a faster path that creates a temporary warped VRT. osg::HeightField* createHeightFieldWithVRT( const TileKey& key, unsigned tileSize, ProgressCallback* progress); //! Profile of the underlying data source const Profile* getProfile() { return _profile.get(); } private: void pixelToGeo(double, double, double&, double&); void geoToPixel(double, double, double&, double&); bool isValidValue(float, GDALRasterBand*); bool intersects(const TileKey&); float getInterpolatedValue(GDALRasterBand* band, double x, double y, bool applyOffset = true); optional _noDataValue, _minValidValue, _maxValidValue; optional _maxDataLevel = 30; GDALDataset* _srcDS = nullptr; GDALDataset* _warpedDS = nullptr; double _linearUnits = 1.0; double _geotransform[6]; double _invtransform[6]; GeoExtent _extents; Bounds _bounds; osg::ref_ptr _profile; GDAL::Options _gdalOptions; const GDAL::Options& gdalOptions() const { return _gdalOptions; } osg::ref_ptr _externalDataset; std::string _name; const std::string& getName() const { return _name; } }; //! Creates an OSG image from an entire GDAL dataset extern OSGEARTH_EXPORT osg::Image* reprojectImage( const osg::Image* srcImage, const std::string srcWKT, double srcMinX, double srcMinY, double srcMaxX, double srcMaxY, const std::string destWKT, double destMinX, double destMinY, double destMaxX, double destMaxY, int width = 0, int height = 0, bool useBilinearInterpolation = true); struct LayerBase { protected: mutable Util::PerThread _driverPerThread; mutable std::mutex _singleThreadingMutex; mutable GDAL::Driver::Ptr _driverSingleThreaded = nullptr; mutable Util::ReadWriteMutex _createCloseMutex; }; } } namespace osgEarth { /** * Image layer connected to a GDAL raster dataset */ class OSGEARTH_EXPORT GDALImageLayer : public ImageLayer, public GDAL::LayerBase { public: // serialization class OSGEARTH_EXPORT Options : public ImageLayer::Options, public GDAL::Options { public: META_LayerOptions(osgEarth, Options, ImageLayer::Options); virtual Config getConfig() const; private: void fromConfig(const Config&); }; public: META_Layer(osgEarth, GDALImageLayer, Options, ImageLayer, GDALImage); //! Base URL for TMS requests void setURL(const URI& value); const URI& getURL() const; //! Database connection for GDAL database queries (alternative to URL) void setConnection(const std::string& value); const std::string& getConnection() const; //! GDAL sub-dataset index (optional) void setSubDataSet(const unsigned& value); const unsigned& getSubDataSet() const; //! Interpolation method for resampling (default is bilinear) void setInterpolation(const RasterInterpolation& value); const RasterInterpolation& getInterpolation() const; //! Use a single-threaded driver (default is multi-threaded) void setSingleThreaded(bool value); bool getSingleThreaded() const; //! User-supplied external dataset void setExternalDataset(GDAL::ExternalDataset* value); public: // Layer //! Called by the constructor void init() override; //! Establishes a connection to the TMS repository Status openImplementation() override; //! Closes down any GDAL connections Status closeImplementation() override; //! Gets a raster image for the given tile key GeoImage createImageImplementation(const TileKey& key, ProgressCallback* progress) const override; }; //! Elevation layer connected to a GDAL facility class OSGEARTH_EXPORT GDALElevationLayer : public ElevationLayer, public GDAL::LayerBase { public: // serialization class OSGEARTH_EXPORT Options : public ElevationLayer::Options, public GDAL::Options { public: META_LayerOptions(osgEarth, Options, ElevationLayer::Options); virtual Config getConfig() const; private: void fromConfig(const Config&); }; public: META_Layer(osgEarth, GDALElevationLayer, Options, ElevationLayer, GDALElevation); //! Base URL for TMS requests void setURL(const URI& value); const URI& getURL() const; //! Database connection for GDAL database queries (alternative to URL) void setConnection(const std::string& value); const std::string& getConnection() const; //! GDAL sub-dataset index (optional) void setSubDataSet(const unsigned& value); const unsigned& getSubDataSet() const; //! Forced profile for reprojection (still need this?) void setWarpProfile(const ProfileOptions& value); const ProfileOptions& getWarpProfile() const; //! Interpolation method for resampling (default is bilinear) void setInterpolation(const RasterInterpolation& value); const RasterInterpolation& getInterpolation() const; //! User-supplied external dataset void setExternalDataset(GDAL::ExternalDataset* value); GDAL::ExternalDataset* getExtenalDataset() const; //! Use the new VRT read approach void setUseVRT(const bool& value); const bool& getUseVRT() const; //! Use a single-threaded driver (default is multi-threaded) void setSingleThreaded(bool value); bool getSingleThreaded() const; public: // Layer //! Called by the constructor void init() override; //! Establishes a connection to the repository Status openImplementation() override; //! Closes down any GDAL connections Status closeImplementation() override; //! Gets a heightfield for the given tile key GeoHeightField createHeightFieldImplementation(const TileKey& key, ProgressCallback* progress) const override; }; } // namespace osgEarth OSGEARTH_SPECIALIZE_CONFIG(osgEarth::GDALImageLayer::Options); OSGEARTH_SPECIALIZE_CONFIG(osgEarth::GDALElevationLayer::Options);