27 #include <Qt3DRender/QGeometryRenderer> 31 static void _heightMapMinMax(
const QByteArray &heightMap,
float &zMin,
float &zMax )
33 const float *zBits = (
const float * ) heightMap.constData();
34 int zCount = heightMap.count() /
sizeof( float );
37 zMin = zMax = std::numeric_limits<float>::quiet_NaN();
38 for (
int i = 0; i < zCount; ++i )
41 if ( std::isnan( z ) )
48 zMin = std::min( zMin, z );
49 zMax = std::max( zMax, z );
54 QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node )
55 : QgsTerrainTileLoader( terrain, node )
78 connect( heightMapGenerator, &QgsDemHeightMapGenerator::heightMapReady,
this, &QgsDemTerrainTileLoader::onHeightMapReady );
79 mHeightMapJobId = heightMapGenerator->render( node->tileX(), node->tileY(), node->tileZ() );
80 mResolution = heightMapGenerator->resolution();
83 Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent )
86 _heightMapMinMax( mHeightMap, zMin, zMax );
88 if ( std::isnan( zMin ) || std::isnan( zMax ) )
98 double side = extent.
width();
99 double half = side / 2;
102 QgsTerrainTileEntity *entity =
new QgsTerrainTileEntity;
106 Qt3DRender::QGeometryRenderer *mesh =
new Qt3DRender::QGeometryRenderer;
107 mesh->setGeometry(
new DemTerrainTileGeometry( mResolution, side, map.
terrainVerticalScale(), mSkirtHeight, mHeightMap, mesh ) );
108 entity->addComponent( mesh );
116 Qt3DCore::QTransform *transform =
nullptr;
117 transform =
new Qt3DCore::QTransform();
118 entity->addComponent( transform );
120 transform->setScale( side );
121 transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
125 entity->setEnabled(
false );
126 entity->setParent( parent );
130 void QgsDemTerrainTileLoader::onHeightMapReady(
int jobId,
const QByteArray &heightMap )
132 if ( mHeightMapJobId == jobId )
134 this->mHeightMap = heightMap;
135 mHeightMapJobId = -1;
147 #include <QtConcurrent/QtConcurrentRun> 148 #include <QFutureWatcher> 154 , mTilingScheme( tilingScheme )
155 , mResolution( resolution )
161 QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
163 delete mClonedProvider;
166 #include <QElapsedTimer> 175 std::unique_ptr<QgsRasterProjector> projector;
176 if ( provider->
crs() != destCrs )
181 input = projector.get();
183 std::unique_ptr< QgsRasterBlock > block( input->
block( 1, extent, res, res ) );
189 data = block->data();
192 if ( block->hasNoData() )
195 float *floatData =
reinterpret_cast<float *
>( data.data() );
196 Q_ASSERT( data.count() %
sizeof( float ) == 0 );
197 int count = data.count() /
sizeof( float );
198 for (
int i = 0; i < count; ++i )
200 if ( block->isNoData( i ) )
201 floatData[i] = std::numeric_limits<float>::quiet_NaN();
211 return downloader->
getHeightMap( extent, res, destCrs );
214 int QgsDemHeightMapGenerator::render(
int x,
int y,
int z )
216 Q_ASSERT( mJobs.isEmpty() );
219 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
220 float mapUnitsPerPixel = extent.
width() / mResolution;
221 extent.grow( mapUnitsPerPixel / 2 );
223 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
227 jd.jobId = ++mLastJobId;
232 jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
234 jd.future = QtConcurrent::run( _readOnlineDtm, mDownloader.get(),
extent, mResolution, mTilingScheme.crs() );
236 QFutureWatcher<QByteArray> *fw =
new QFutureWatcher<QByteArray>( nullptr );
237 fw->setFuture( jd.future );
238 connect( fw, &QFutureWatcher<QByteArray>::finished,
this, &QgsDemHeightMapGenerator::onFutureFinished );
240 mJobs.insert( fw, jd );
245 QByteArray QgsDemHeightMapGenerator::renderSynchronously(
int x,
int y,
int z )
248 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
249 float mapUnitsPerPixel = extent.
width() / mResolution;
250 extent.
grow( mapUnitsPerPixel / 2 );
252 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
255 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, extent, mResolution, mResolution ) );
261 data = block->data();
268 float QgsDemHeightMapGenerator::heightAt(
double x,
double y )
276 if ( mDtmCoarseData.isEmpty() )
278 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, rect, res, res ) );
280 mDtmCoarseData = block->data();
281 mDtmCoarseData.detach();
284 int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
285 int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
286 cellX = qBound( 0, cellX, res - 1 );
287 cellY = qBound( 0, cellY, res - 1 );
289 const float *data = (
const float * ) mDtmCoarseData.constData();
290 return data[cellX + cellY * res];
293 void QgsDemHeightMapGenerator::onFutureFinished()
295 QFutureWatcher<QByteArray> *fw =
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
297 Q_ASSERT( mJobs.contains( fw ) );
298 JobData jobData = mJobs.value( fw );
303 QByteArray data = jobData.future.result();
304 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.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
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...