28using namespace Qt::StringLiterals;
39 const QgsPointXY topLeftLonLat( -180, 180.0 / M_PI * std::atan( std::sinh( M_PI ) ) );
40 const QgsPointXY bottomRightLonLat( 180, 180.0 / M_PI * std::atan( std::sinh( -M_PI ) ) );
43 mXSpan = ( bottomRight.
x() - topLeft.
x() );
57 ds.
uri =
"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png";
66 const QString uri = QString(
"type=xyz&url=%1&zmin=%2&zmax=%3" ).arg( mDataSource.uri ).arg( mDataSource.zMin ).arg( mDataSource.zMax );
67 mOnlineDtm = std::make_unique<QgsRasterLayer>( uri,
"terrarium",
"wms" );
71void QgsTerrainDownloader::adjustExtentAndResolution(
double mupp,
const QgsRectangle &extentOrig,
QgsRectangle &extent,
int &res )
73 const double xMin = floor( extentOrig.
xMinimum() / mupp ) * mupp;
74 const double xMax = ceil( extentOrig.
xMaximum() / mupp ) * mupp;
76 const double yMin = floor( extentOrig.
yMinimum() / mupp ) * mupp;
77 const double yMax = ceil( extentOrig.
yMaximum() / mupp ) * mupp;
80 res = round( ( xMax - xMin ) / mupp );
84double QgsTerrainDownloader::findBestTileResolution(
double requestedMupp )
const
87 for ( ; zoom <= 15; ++zoom )
89 const double tileMupp = mXSpan / ( 256 * ( 1 << zoom ) );
90 if ( tileMupp <= requestedMupp )
96 const double finalMupp = mXSpan / ( 256 * ( 1 << zoom ) );
101void QgsTerrainDownloader::tileImageToHeightMap(
const QImage &img, QByteArray &heightMap )
107 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( img.constBits() );
108 const int count = img.width() * img.height();
109 heightMap.resize(
sizeof(
float ) * count );
110 float *hData =
reinterpret_cast<float *
>( heightMap.data() );
111 for (
int i = 0; i < count; ++i )
113 const QRgb
c = rgb[i];
114 if ( qAlpha(
c ) == 255 )
116 const float h = qRed(
c ) * 256 + qGreen(
c ) + qBlue(
c ) / 256.f - 32768;
121 *hData++ = std::numeric_limits<float>::quiet_NaN();
129 if ( !mOnlineDtm || !mOnlineDtm->isValid() )
136 const double requestedMupp = extentTr.
width() / res;
137 const double finalMupp = findBestTileResolution( requestedMupp );
142 const int resOrig = res;
143 adjustExtentAndResolution( finalMupp, extentTr, extent, res );
147 QgsRasterBlock *b = mOnlineDtm->dataProvider()->block( 1, extent, res, res );
148 const QImage img = b->
image();
150 if ( !tmpFilenameImg.isEmpty() )
151 img.save( tmpFilenameImg );
155 QByteArray heightMap;
156 tileImageToHeightMap( img, heightMap );
162 if ( !tmpFilenameTif.isEmpty() )
167 if ( !hSrcDS || !hDstDS )
169 QgsDebugError(
"failed to create GDAL dataset for heightmap" );
173 const CPLErr err = GDALRasterIO( GDALGetRasterBand( hSrcDS.get(), 1 ), GF_Write, 0, 0, res, res, heightMap.data(), res, res, GDT_Float32, 0, 0 );
174 if ( err != CE_None )
176 QgsDebugError(
"failed to write heightmap data to GDAL dataset" );
183 QByteArray heightMapOut;
184 heightMapOut.resize( resOrig * resOrig *
sizeof(
float ) );
185 char *data = heightMapOut.data();
189 const CPLErr err2 = GDALRasterIO( GDALGetRasterBand( hDstDS.get(), 1 ), GF_Read, 0, 0, resOrig, resOrig, data, resOrig, resOrig, GDT_Float32, 0, 0 );
190 if ( err2 != CE_None )
192 QgsDebugError(
"failed to read heightmap data from GDAL dataset" );
static QgsRectangle tryReprojectExtent2D(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs1, const QgsCoordinateReferenceSystem &crs2, const QgsCoordinateTransformContext &context)
Reprojects extent from crs1 to crs2 coordinate reference system with context context.
Represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
QString calculateCoordinateOperation(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns the Proj coordinate operation string to use when transforming from the specified source CRS t...
static bool resampleSingleBandRaster(GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation)
Resamples a single band raster to the destination dataset with different resolution (and possibly wit...
static gdal::dataset_unique_ptr createSingleBandTiffDataset(const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band TIFF dataset with given parameters.
static gdal::dataset_unique_ptr createSingleBandMemoryDataset(GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band memory dataset with given parameters.
QImage image() const
Returns an image containing the block data, if the block's data type is color.
A rectangle specified with double values.
QgsTerrainDownloader(const QgsCoordinateTransformContext &transformContext)
Constructs a QgsTerrainDownloader object.
static DataSource defaultDataSource()
Returns the data source used by default.
QByteArray getHeightMap(const QgsRectangle &extentOrig, int res, const QgsCoordinateReferenceSystem &destCrs, const QgsCoordinateTransformContext &context=QgsCoordinateTransformContext(), QString tmpFilenameImg=QString(), QString tmpFilenameTif=QString())
For given extent and resolution (number of pixels for width/height) in specified CRS,...
void setDataSource(const DataSource &ds)
Configures data source to be used for download of terrain tiles.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define QgsDebugError(str)
Definition of data source for terrain tiles (assuming "terrarium" data encoding with usual XYZ tiling...
QString uri
HTTP(S) template for XYZ tiles requests (e.g. http://example.com/{z}/{x}/{y}.png).
int zMin
Minimum zoom level (Z) with valid data.
int zMax
Maximum zoom level (Z) with valid data.