29 #include <Qt3DRender/QGeometryRenderer> 
   30 #include <QMutexLocker> 
   34 static void _heightMapMinMax( 
const QByteArray &heightMap, 
float &zMin, 
float &zMax )
 
   36   const float *zBits = ( 
const float * ) heightMap.constData();
 
   37   int zCount = heightMap.count() / 
sizeof( float );
 
   40   zMin = zMax = std::numeric_limits<float>::quiet_NaN();
 
   41   for ( 
int i = 0; i < zCount; ++i )
 
   44     if ( std::isnan( z ) )
 
   51     zMin = std::min( zMin, z );
 
   52     zMax = std::max( zMax, z );
 
   57 QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node, 
QgsTerrainGenerator *terrainGenerator )
 
   58   : QgsTerrainTileLoader( terrain, node )
 
   62   QgsDemHeightMapGenerator *heightMapGenerator = 
nullptr;
 
   79   connect( heightMapGenerator, &QgsDemHeightMapGenerator::heightMapReady, 
this, &QgsDemTerrainTileLoader::onHeightMapReady );
 
   80   mHeightMapJobId = heightMapGenerator->render( node->tileId() );
 
   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 ) )
 
   96   QgsChunkNodeId nodeId = mNode->tileId();
 
  100   double side = extent.
width();
 
  101   double half = side / 2;
 
  104   QgsTerrainTileEntity *entity = 
new QgsTerrainTileEntity( nodeId );
 
  108   Qt3DRender::QGeometryRenderer *mesh = 
new Qt3DRender::QGeometryRenderer;
 
  109   mesh->setGeometry( 
new DemTerrainTileGeometry( mResolution, side, map.
terrainVerticalScale(), mSkirtHeight, mHeightMap, mesh ) );
 
  110   entity->addComponent( mesh ); 
 
  118   Qt3DCore::QTransform *transform = 
nullptr;
 
  119   transform = 
new Qt3DCore::QTransform();
 
  120   entity->addComponent( transform );
 
  122   transform->setScale( side );
 
  123   transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
 
  127   entity->setEnabled( 
false );
 
  128   entity->setParent( parent );
 
  132 void QgsDemTerrainTileLoader::onHeightMapReady( 
int jobId, 
const QByteArray &heightMap )
 
  134   if ( mHeightMapJobId == jobId )
 
  136     this->mHeightMap = heightMap;
 
  137     mHeightMapJobId = -1;
 
  149 #include <QtConcurrent/QtConcurrentRun> 
  150 #include <QFutureWatcher> 
  156   , mTilingScheme( tilingScheme )
 
  157   , mResolution( resolution )
 
  160   , mTransformContext( transformContext )
 
  164 QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
 
  166   delete mClonedProvider;
 
  172   QgsEventTracing::ScopedEvent e( QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ) );
 
  176   std::unique_ptr<QgsRasterProjector> projector;
 
  177   if ( provider->
crs() != destCrs )
 
  182     input = projector.get();
 
  184   std::unique_ptr< QgsRasterBlock > block( input->
block( 1, extent, res, res ) );
 
  190     data = block->data();
 
  193     if ( block->hasNoData() )
 
  196       float *floatData = 
reinterpret_cast<float *
>( data.data() );
 
  197       Q_ASSERT( data.count() % 
sizeof( 
float ) == 0 );
 
  198       int count = data.count() / 
sizeof( float );
 
  199       for ( 
int i = 0; i < count; ++i )
 
  201         if ( block->isNoData( i ) )
 
  202           floatData[i] = std::numeric_limits<float>::quiet_NaN();
 
  211   return downloader->
getHeightMap( extent, res, destCrs, context );
 
  214 int QgsDemHeightMapGenerator::render( 
const QgsChunkNodeId &nodeId )
 
  216   QgsEventTracing::addEvent( QgsEventTracing::AsyncBegin, QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ), nodeId.text() );
 
  219   QgsRectangle extent = mTilingScheme.tileToExtent( nodeId );
 
  220   float mapUnitsPerPixel = extent.
width() / mResolution;
 
  221   extent.
grow( mapUnitsPerPixel / 2 );
 
  223   QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
 
  227   jd.jobId = ++mLastJobId;
 
  233     jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
 
  235     jd.future = QtConcurrent::run( _readOnlineDtm, mDownloader.get(), extent, mResolution, mTilingScheme.crs(), mTransformContext );
 
  237   QFutureWatcher<QByteArray> *fw = 
new QFutureWatcher<QByteArray>( 
nullptr );
 
  238   fw->setFuture( jd.future );
 
  239   connect( fw, &QFutureWatcher<QByteArray>::finished, 
this, &QgsDemHeightMapGenerator::onFutureFinished );
 
  240   connect( fw, &QFutureWatcher<QByteArray>::finished, fw, &QObject::deleteLater );
 
  242   mJobs.insert( fw, jd );
 
  247 void QgsDemHeightMapGenerator::waitForFinished()
 
  249   for ( QFutureWatcher<QByteArray> *fw : mJobs.keys() )
 
  251     disconnect( fw, &QFutureWatcher<QByteArray>::finished, 
this, &QgsDemHeightMapGenerator::onFutureFinished );
 
  252     disconnect( fw, &QFutureWatcher<QByteArray>::finished, fw, &QObject::deleteLater );
 
  254   QVector<QFutureWatcher<QByteArray>*> toBeDeleted;
 
  255   for ( QFutureWatcher<QByteArray> *fw : mJobs.keys() )
 
  257     fw->waitForFinished();
 
  258     JobData jobData = mJobs.value( fw );
 
  259     toBeDeleted.push_back( fw );
 
  261     QByteArray data = jobData.future.result();
 
  262     emit heightMapReady( jobData.jobId, data );
 
  265   for ( QFutureWatcher<QByteArray> *fw : toBeDeleted )
 
  272 void QgsDemHeightMapGenerator::lazyLoadDtmCoarseData( 
int res, 
const QgsRectangle &rect )
 
  274   QMutexLocker locker( &mLazyLoadDtmCoarseDataMutex );
 
  275   if ( mDtmCoarseData.isEmpty() )
 
  277     std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, rect, res, res ) );
 
  279     mDtmCoarseData = block->data();
 
  280     mDtmCoarseData.detach();  
 
  284 float QgsDemHeightMapGenerator::heightAt( 
double x, 
double y )
 
  292   lazyLoadDtmCoarseData( res, rect );
 
  294   int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
 
  295   int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
 
  296   cellX = std::clamp( cellX, 0, res - 1 );
 
  297   cellY = std::clamp( cellY, 0, res - 1 );
 
  299   const float *data = ( 
const float * ) mDtmCoarseData.constData();
 
  300   return data[cellX + cellY * res];
 
  303 void QgsDemHeightMapGenerator::onFutureFinished()
 
  305   QFutureWatcher<QByteArray> *fw = 
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
 
  307   Q_ASSERT( mJobs.contains( fw ) );
 
  308   JobData jobData = mJobs.value( fw );
 
  313   QgsEventTracing::addEvent( QgsEventTracing::AsyncEnd, QStringLiteral( 
"3D" ), QStringLiteral( 
"DEM" ), jobData.tileId.text() );
 
  315   QByteArray data = jobData.future.result();
 
  316   emit heightMapReady( jobData.jobId, data );
 
@ Float32
Thirty two bit floating point (float)
QgsTerrainGenerator * terrainGenerator() const
Returns terrain generator. It takes care of producing terrain tiles from the input data.
double terrainVerticalScale() const
Returns vertical scale (exaggeration) of terrain.
bool isTerrainShadingEnabled() const
Returns whether terrain shading is enabled.
QgsPhongMaterialSettings terrainShadingMaterial() const
Returns terrain shading material.
QList< QgsMapLayer * > terrainLayers() const
Returns the list of map layers to be rendered as a texture of the terrain.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer)
float skirtHeight() const
Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between ...
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer)
float skirtHeight() const
Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between ...
Base class for raster data providers.
bool setInput(QgsRasterInterface *input) override
Set input.
Base class for processing filters like renderers, reprojector, resampler etc.
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.
Represents a raster layer.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void grow(double delta)
Grows the rectangle in place by the specified amount.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
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,...
@ Dem
Terrain is built from raster layer with digital elevation model.
@ Online
Terrain is built from downloaded tiles with digital elevation model.
const QgsTilingScheme & tilingScheme() const
Returns tiling scheme of the terrain.
virtual Type type() const =0
What texture generator implementation is this.
QgsRectangle tileToExtent(int x, int y, int z) const
Returns map coordinates of the extent of a tile.
double y() const
Returns Y coordinate.
double x() const
Returns X coordinate.