33   const QgsPointXY topLeftLonLat( -180, 180.0 / M_PI * std::atan( std::sinh( M_PI ) ) );
 
   34   const QgsPointXY bottomRightLonLat( 180, 180.0 / M_PI * std::atan( std::sinh( -M_PI ) ) );
 
   37   mXSpan = ( bottomRight.
x() - topLeft.
x() );
 
   51   ds.
uri = 
"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png";
 
   60   const QString uri = QString( 
"type=xyz&url=%1&zmin=%2&zmax=%3" ).arg( mDataSource.
uri ).arg( mDataSource.
zMin ).arg( mDataSource.
zMax );
 
   65 void QgsTerrainDownloader::adjustExtentAndResolution( 
double mupp, 
const QgsRectangle &extentOrig, 
QgsRectangle &extent, 
int &res )
 
   67   const double xMin = floor( extentOrig.
xMinimum() / mupp ) * mupp;
 
   68   const double xMax = ceil( extentOrig.
xMaximum() / mupp ) * mupp;
 
   70   const double yMin = floor( extentOrig.
yMinimum() / mupp ) * mupp;
 
   71   const double yMax = ceil( extentOrig.
yMaximum() / mupp ) * mupp;
 
   74   res = round( ( xMax - xMin ) / mupp );
 
   78 double QgsTerrainDownloader::findBestTileResolution( 
double requestedMupp )
 const 
   81   for ( ; zoom <= 15; ++zoom )
 
   83     const double tileMupp = mXSpan / ( 256 * ( 1 << zoom ) );
 
   84     if ( tileMupp <= requestedMupp )
 
   88   if ( zoom > 15 ) zoom = 15;
 
   89   const double finalMupp = mXSpan / ( 256 * ( 1 << zoom ) );
 
   94 void QgsTerrainDownloader::tileImageToHeightMap( 
const QImage &img, QByteArray &heightMap )
 
  100   const QRgb *rgb = 
reinterpret_cast<const QRgb *
>( img.constBits() );
 
  101   const int count = img.width() * img.height();
 
  102   heightMap.resize( 
sizeof( 
float ) * count );
 
  103   float *hData = 
reinterpret_cast<float *
>( heightMap.data() );
 
  104   for ( 
int i = 0; i < count; ++i )
 
  106     const QRgb 
c = rgb[i];
 
  107     if ( qAlpha( 
c ) == 255 )
 
  109       const float h = qRed( 
c ) * 256 + qGreen( 
c ) + qBlue( 
c ) / 256.f - 32768;
 
  114       *hData++ = std::numeric_limits<float>::quiet_NaN();
 
  122   if ( !mOnlineDtm || !mOnlineDtm->isValid() )
 
  129   if ( destCrs != mOnlineDtm->crs() )
 
  137   const double requestedMupp = extentTr.
width() / res;
 
  138   const double finalMupp = findBestTileResolution( requestedMupp );
 
  143   const int resOrig = res;
 
  144   adjustExtentAndResolution( finalMupp, extentTr, extent, res );
 
  148   QgsRasterBlock *b = mOnlineDtm->dataProvider()->block( 1, extent, res, res );
 
  149   const QImage img = b->
image();
 
  151   if ( !tmpFilenameImg.isEmpty() )
 
  152     img.save( tmpFilenameImg );
 
  156   QByteArray heightMap;
 
  157   tileImageToHeightMap( img, heightMap );
 
  163   if ( !tmpFilenameTif.isEmpty() )
 
  168   if ( !hSrcDS || !hDstDS )
 
  170     QgsDebugMsg( 
"failed to create GDAL dataset for heightmap" );
 
  174   const CPLErr err = GDALRasterIO( GDALGetRasterBand( hSrcDS.get(), 1 ), GF_Write, 0, 0, res, res, heightMap.data(), res, res, GDT_Float32, 0, 0 );
 
  175   if ( err != CE_None )
 
  177     QgsDebugMsg( 
"failed to write heightmap data to GDAL dataset" );
 
  185   QByteArray heightMapOut;
 
  186   heightMapOut.resize( resOrig * resOrig * 
sizeof( 
float ) );
 
  187   char *data = heightMapOut.data();
 
  191   const CPLErr err2 = GDALRasterIO( GDALGetRasterBand( hDstDS.get(), 1 ), GF_Read, 0, 0, resOrig, resOrig, data, resOrig, resOrig, GDT_Float32, 0, 0 );
 
  192   if ( err2 != CE_None )
 
  194     QgsDebugMsg( 
"failed to read heightmap data from GDAL dataset" );