28 #include <Qt3DRender/QGeometryRenderer>    32 static void _heightMapMinMax( 
const QByteArray &heightMap, 
float &zMin, 
float &zMax )
    34   const float *zBits = ( 
const float * ) heightMap.constData();
    35   int zCount = heightMap.count() / 
sizeof( float );
    38   zMin = zMax = std::numeric_limits<float>::quiet_NaN();
    39   for ( 
int i = 0; i < zCount; ++i )
    42     if ( std::isnan( z ) )
    49     zMin = std::min( zMin, z );
    50     zMax = std::max( zMax, z );
    55 QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node )
    56   : QgsTerrainTileLoader( terrain, node )
    79   connect( heightMapGenerator, &QgsDemHeightMapGenerator::heightMapReady, 
this, &QgsDemTerrainTileLoader::onHeightMapReady );
    80   mHeightMapJobId = heightMapGenerator->render( node->tileX(), node->tileY(), node->tileZ() );
    81   mResolution = heightMapGenerator->resolution();
    84 Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent )
    87   _heightMapMinMax( mHeightMap, zMin, zMax );
    89   if ( std::isnan( zMin ) || std::isnan( zMax ) )
    99   double side = extent.
width();
   100   double half = side / 2;
   103   QgsTerrainTileEntity *entity = 
new QgsTerrainTileEntity( mNode->tileId() );
   107   Qt3DRender::QGeometryRenderer *mesh = 
new Qt3DRender::QGeometryRenderer;
   108   mesh->setGeometry( 
new DemTerrainTileGeometry( mResolution, side, map.
terrainVerticalScale(), mSkirtHeight, mHeightMap, mesh ) );
   109   entity->addComponent( mesh ); 
   117   Qt3DCore::QTransform *transform = 
nullptr;
   118   transform = 
new Qt3DCore::QTransform();
   119   entity->addComponent( transform );
   121   transform->setScale( side );
   122   transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
   126   entity->setEnabled( 
false );
   127   entity->setParent( parent );
   131 void QgsDemTerrainTileLoader::onHeightMapReady( 
int jobId, 
const QByteArray &heightMap )
   133   if ( mHeightMapJobId == jobId )
   135     this->mHeightMap = heightMap;
   136     mHeightMapJobId = -1;
   148 #include <QtConcurrent/QtConcurrentRun>   149 #include <QFutureWatcher>   155   , mTilingScheme( tilingScheme )
   156   , mResolution( resolution )
   162 QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
   164   delete mClonedProvider;
   170   QgsEventTracing::ScopedEvent e( QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ) );
   174   std::unique_ptr<QgsRasterProjector> projector;
   175   if ( provider->
crs() != destCrs )
   180     input = projector.get();
   182   std::unique_ptr< QgsRasterBlock > block( input->
block( 1, extent, res, res ) );
   188     data = block->data();
   191     if ( block->hasNoData() )
   194       float *floatData = 
reinterpret_cast<float *
>( data.data() );
   195       Q_ASSERT( data.count() % 
sizeof( float ) == 0 );
   196       int count = data.count() / 
sizeof( float );
   197       for ( 
int i = 0; i < count; ++i )
   199         if ( block->isNoData( i ) )
   200           floatData[i] = std::numeric_limits<float>::quiet_NaN();
   210   return downloader->
getHeightMap( extent, res, destCrs );
   213 int QgsDemHeightMapGenerator::render( 
int x, 
int y, 
int z )
   215   QgsChunkNodeId tileId( x, y, z );
   217   QgsEventTracing::addEvent( QgsEventTracing::AsyncBegin, QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ), tileId.text() );
   220   QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
   221   float mapUnitsPerPixel = extent.
width() / mResolution;
   222   extent.grow( mapUnitsPerPixel / 2 );
   224   QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
   228   jd.jobId = ++mLastJobId;
   234     jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
   236     jd.future = QtConcurrent::run( _readOnlineDtm, mDownloader.get(), 
extent, mResolution, mTilingScheme.crs() );
   238   QFutureWatcher<QByteArray> *fw = 
new QFutureWatcher<QByteArray>( nullptr );
   239   fw->setFuture( jd.future );
   240   connect( fw, &QFutureWatcher<QByteArray>::finished, 
this, &QgsDemHeightMapGenerator::onFutureFinished );
   241   connect( fw, &QFutureWatcher<QByteArray>::finished, fw, &QObject::deleteLater );
   243   mJobs.insert( fw, jd );
   248 QByteArray QgsDemHeightMapGenerator::renderSynchronously( 
int x, 
int y, 
int z )
   251   QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
   252   float mapUnitsPerPixel = extent.
width() / mResolution;
   253   extent.
grow( mapUnitsPerPixel / 2 );
   255   QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
   258   std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, extent, mResolution, mResolution ) );
   264     data = block->data();
   271 float QgsDemHeightMapGenerator::heightAt( 
double x, 
double y )
   279   if ( mDtmCoarseData.isEmpty() )
   281     std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, rect, res, res ) );
   283     mDtmCoarseData = block->data();
   284     mDtmCoarseData.detach();  
   287   int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
   288   int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
   289   cellX = qBound( 0, cellX, res - 1 );
   290   cellY = qBound( 0, cellY, res - 1 );
   292   const float *data = ( 
const float * ) mDtmCoarseData.constData();
   293   return data[cellX + cellY * res];
   296 void QgsDemHeightMapGenerator::onFutureFinished()
   298   QFutureWatcher<QByteArray> *fw = 
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
   300   Q_ASSERT( mJobs.contains( fw ) );
   301   JobData jobData = mJobs.value( fw );
   306   QgsEventTracing::addEvent( QgsEventTracing::AsyncEnd, QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ), jobData.tileId.text() );
   308   QByteArray data = jobData.future.result();
   309   emit heightMapReady( jobData.jobId, data );
 3 Axis-aligned bounding box - in world coords. 
 
A rectangle specified with double values. 
 
bool setInput(QgsRasterInterface *input) override
Set input. 
 
QgsTerrainGenerator * clone() const override
Makes a copy of the current instance. 
 
bool isTerrainShadingEnabled() const
Returns whether terrain shading is enabled. 
 
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer) ...
 
QgsPhongMaterialSettings terrainShadingMaterial() const
Returns terrain shading material. 
 
Represents a raster layer. 
 
3 Implementation of terrain generator that uses online resources to download heightmaps. 
 
virtual Type type() const =0
What texture generator implementation is this. 
 
int resolution() const
Returns resolution of the generator (how many elevation samples on one side of a terrain tile) ...
 
Thirty two bit floating point (float) 
 
float skirtHeight() const
Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between ...
 
double y() const
Returns Y coordinate. 
 
3 Definition of the world 
 
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, download necessary tile images (if not cached already) and produce height map out of them (byte array of res*res float values) 
 
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0) 
 
Terrain is built from raster layer with digital elevation model. 
 
void grow(double delta)
Grows the rectangle in place by the specified amount. 
 
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size. 
 
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source. 
 
double width() const
Returns the width of the rectangle. 
 
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle. 
 
float skirtHeight() const
Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between ...
 
QgsRectangle extent() const override
extent of the terrain in terrain's CRS 
 
const QgsTilingScheme & tilingScheme() const
Returns tiling scheme of the terrain. 
 
Contains information about the context in which a coordinate transform is executed. 
 
Base class for processing filters like renderers, reprojector, resampler etc. 
 
3 Takes care of downloading terrain data from a publicly available data source. 
 
double terrainVerticalScale() const
Returns vertical scale (exaggeration) of terrain. 
 
double yMinimum() const
Returns the y minimum value (bottom side of rectangle). 
 
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
 
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context. 
 
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer) ...
 
3 Implementation of terrain generator that uses a raster layer with DEM to build terrain. 
 
This class represents a coordinate reference system (CRS). 
 
double xMinimum() const
Returns the x minimum value (left side of rectangle). 
 
double yMaximum() const
Returns the y maximum value (top side of rectangle). 
 
Terrain is built from downloaded tiles with digital elevation model. 
 
3 The class encapsulates tiling scheme (just like with WMTS / TMS / XYZ layers). 
 
QgsRectangle tileToExtent(int x, int y, int z) const
Returns map coordinates of the extent of a tile. 
 
double x() const
Returns X coordinate. 
 
double height() const
Returns the height of the rectangle. 
 
Base class for raster data providers. 
 
QgsTerrainGenerator * terrainGenerator() const
Returns terrain generator. It takes care of producing terrain tiles from the input data...