26 #include <Qt3DRender/QGeometryRenderer> 30 static void _heightMapMinMax(
const QByteArray &heightMap,
float &zMin,
float &zMax )
32 const float *zBits = (
const float * ) heightMap.constData();
33 int zCount = heightMap.count() /
sizeof( float );
36 zMin = zMax = std::numeric_limits<float>::quiet_NaN();
37 for (
int i = 0; i < zCount; ++i )
40 if ( std::isnan( z ) )
47 zMin = std::min( zMin, z );
48 zMax = std::max( zMax, z );
53 QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node )
54 : QgsTerrainTileLoader( terrain, node )
62 connect( generator->
heightMapGenerator(), &QgsDemHeightMapGenerator::heightMapReady,
this, &QgsDemTerrainTileLoader::onHeightMapReady );
63 mHeightMapJobId = generator->
heightMapGenerator()->render( node->tileX(), node->tileY(), node->tileZ() );
68 Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent )
71 _heightMapMinMax( mHeightMap, zMin, zMax );
73 if ( std::isnan( zMin ) || std::isnan( zMax ) )
79 QgsTerrainTileEntity *entity =
new QgsTerrainTileEntity;
83 Qt3DRender::QGeometryRenderer *mesh =
new Qt3DRender::QGeometryRenderer;
84 mesh->setGeometry(
new DemTerrainTileGeometry( mResolution, mSkirtHeight, mHeightMap, mesh ) );
85 entity->addComponent( mesh );
89 createTextureComponent( entity );
93 Qt3DCore::QTransform *transform =
nullptr;
94 transform =
new Qt3DCore::QTransform();
95 entity->addComponent( transform );
101 double side = extent.
width();
102 double half = side / 2;
105 transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
109 entity->setEnabled(
false );
110 entity->setParent( parent );
114 void QgsDemTerrainTileLoader::onHeightMapReady(
int jobId,
const QByteArray &heightMap )
116 if ( mHeightMapJobId == jobId )
118 this->mHeightMap = heightMap;
119 mHeightMapJobId = -1;
131 #include <QtConcurrent/QtConcurrentRun> 132 #include <QFutureWatcher> 137 , mTilingScheme( tilingScheme )
138 , mResolution( resolution )
143 QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
145 delete mClonedProvider;
148 #include <QElapsedTimer> 157 std::unique_ptr<QgsRasterProjector> projector;
158 if ( provider->
crs() != destCrs )
161 projector->setCrs( provider->
crs(), destCrs );
163 input = projector.get();
165 std::unique_ptr< QgsRasterBlock > block( input->
block( 1, extent, res, res ) );
171 data = block->data();
174 if ( block->hasNoData() )
177 float *floatData =
reinterpret_cast<float *
>( data.data() );
178 Q_ASSERT( data.count() %
sizeof( float ) == 0 );
179 int count = data.count() /
sizeof( float );
180 for (
int i = 0; i < count; ++i )
182 if ( block->isNoData( i ) )
183 floatData[i] = std::numeric_limits<float>::quiet_NaN();
190 int QgsDemHeightMapGenerator::render(
int x,
int y,
int z )
192 Q_ASSERT( mJobs.isEmpty() );
195 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
196 float mapUnitsPerPixel = extent.
width() / mResolution;
197 extent.grow( mapUnitsPerPixel / 2 );
199 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
203 jd.jobId = ++mLastJobId;
207 jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
209 QFutureWatcher<QByteArray> *fw =
new QFutureWatcher<QByteArray>( nullptr );
210 fw->setFuture( jd.future );
211 connect( fw, &QFutureWatcher<QByteArray>::finished,
this, &QgsDemHeightMapGenerator::onFutureFinished );
213 mJobs.insert( fw, jd );
218 QByteArray QgsDemHeightMapGenerator::renderSynchronously(
int x,
int y,
int z )
221 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
222 float mapUnitsPerPixel = extent.
width() / mResolution;
223 extent.
grow( mapUnitsPerPixel / 2 );
225 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
228 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, extent, mResolution, mResolution ) );
234 data = block->data();
241 float QgsDemHeightMapGenerator::heightAt(
double x,
double y )
246 if ( mDtmCoarseData.isEmpty() )
248 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, rect, res, res ) );
250 mDtmCoarseData = block->data();
251 mDtmCoarseData.detach();
254 int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
255 int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
256 cellX = qBound( 0, cellX, res - 1 );
257 cellY = qBound( 0, cellY, res - 1 );
259 const float *data = (
const float * ) mDtmCoarseData.constData();
260 return data[cellX + cellY * res];
263 void QgsDemHeightMapGenerator::onFutureFinished()
265 QFutureWatcher<QByteArray> *fw =
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
267 Q_ASSERT( mJobs.contains( fw ) );
268 JobData jobData = mJobs.value( fw );
273 QByteArray data = jobData.future.result();
274 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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
Thirty two bit floating point (float)
const QgsTilingScheme & tilingScheme() const
Returns tiling scheme of the terrain.
3 Definition of the world
double x() const
Returns X coordinate.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
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.
QgsRectangle tileToExtent(int x, int y, int z) const
Returns map coordinates of the extent of a tile.
QgsRectangle extent() const override
extent of the terrain in terrain's CRS
int resolution() const
Returns resolution of the generator (how many elevation samples on one side of a terrain tile) ...
Base class for processing filters like renderers, reprojector, resampler etc.
double y() const
Returns Y coordinate.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
QgsDemHeightMapGenerator * heightMapGenerator()
Returns height map generator object - takes care of extraction of elevations from the layer) ...
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
3 Implementation of terrain generator that uses a raster layer with DEM to build terrain.
This class represents a coordinate reference system (CRS).
double width() const
Returns the width of the rectangle.
3 The class encapsulates tiling scheme (just like with WMTS / TMS / XYZ layers).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double terrainVerticalScale() const
Returns vertical scale (exaggeration) of terrain.
QgsTerrainGenerator * terrainGenerator() const
Returns terrain generator. It takes care of producing terrain tiles from the input data...
float skirtHeight() const
Returns skirt height (in world units). Skirts at the edges of terrain tiles help hide cracks between ...
double height() const
Returns the height of the rectangle.
Base class for raster data providers.