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 ) )
83 double side = extent.
width();
84 double half = side / 2;
87 QgsTerrainTileEntity *entity =
new QgsTerrainTileEntity;
91 Qt3DRender::QGeometryRenderer *mesh =
new Qt3DRender::QGeometryRenderer;
92 mesh->setGeometry(
new DemTerrainTileGeometry( mResolution, side, map.
terrainVerticalScale(), mSkirtHeight, mHeightMap, mesh ) );
93 entity->addComponent( mesh );
101 Qt3DCore::QTransform *transform =
nullptr;
102 transform =
new Qt3DCore::QTransform();
103 entity->addComponent( transform );
105 transform->setScale( side );
106 transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
110 entity->setEnabled(
false );
111 entity->setParent( parent );
115 void QgsDemTerrainTileLoader::onHeightMapReady(
int jobId,
const QByteArray &heightMap )
117 if ( mHeightMapJobId == jobId )
119 this->mHeightMap = heightMap;
120 mHeightMapJobId = -1;
132 #include <QtConcurrent/QtConcurrentRun> 133 #include <QFutureWatcher> 138 , mTilingScheme( tilingScheme )
139 , mResolution( resolution )
144 QgsDemHeightMapGenerator::~QgsDemHeightMapGenerator()
146 delete mClonedProvider;
149 #include <QElapsedTimer> 158 std::unique_ptr<QgsRasterProjector> projector;
159 if ( provider->
crs() != destCrs )
162 projector->setCrs( provider->
crs(), destCrs );
164 input = projector.get();
166 std::unique_ptr< QgsRasterBlock > block( input->
block( 1, extent, res, res ) );
172 data = block->data();
175 if ( block->hasNoData() )
178 float *floatData =
reinterpret_cast<float *
>( data.data() );
179 Q_ASSERT( data.count() %
sizeof( float ) == 0 );
180 int count = data.count() /
sizeof( float );
181 for (
int i = 0; i < count; ++i )
183 if ( block->isNoData( i ) )
184 floatData[i] = std::numeric_limits<float>::quiet_NaN();
191 int QgsDemHeightMapGenerator::render(
int x,
int y,
int z )
193 Q_ASSERT( mJobs.isEmpty() );
196 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
197 float mapUnitsPerPixel = extent.
width() / mResolution;
198 extent.grow( mapUnitsPerPixel / 2 );
200 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
204 jd.jobId = ++mLastJobId;
208 jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
210 QFutureWatcher<QByteArray> *fw =
new QFutureWatcher<QByteArray>( nullptr );
211 fw->setFuture( jd.future );
212 connect( fw, &QFutureWatcher<QByteArray>::finished,
this, &QgsDemHeightMapGenerator::onFutureFinished );
214 mJobs.insert( fw, jd );
219 QByteArray QgsDemHeightMapGenerator::renderSynchronously(
int x,
int y,
int z )
222 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
223 float mapUnitsPerPixel = extent.
width() / mResolution;
224 extent.
grow( mapUnitsPerPixel / 2 );
226 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
229 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, extent, mResolution, mResolution ) );
235 data = block->data();
242 float QgsDemHeightMapGenerator::heightAt(
double x,
double y )
247 if ( mDtmCoarseData.isEmpty() )
249 std::unique_ptr< QgsRasterBlock > block( mDtm->dataProvider()->block( 1, rect, res, res ) );
251 mDtmCoarseData = block->data();
252 mDtmCoarseData.detach();
255 int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
256 int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
257 cellX = qBound( 0, cellX, res - 1 );
258 cellY = qBound( 0, cellY, res - 1 );
260 const float *data = (
const float * ) mDtmCoarseData.constData();
261 return data[cellX + cellY * res];
264 void QgsDemHeightMapGenerator::onFutureFinished()
266 QFutureWatcher<QByteArray> *fw =
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
268 Q_ASSERT( mJobs.contains( fw ) );
269 JobData jobData = mJobs.value( fw );
274 QByteArray data = jobData.future.result();
275 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.
QgsPhongMaterialSettings terrainShadingMaterial() const
Returns terrain shading material.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
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)
double y() const
Returns Y coordinate.
3 Definition of the world
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
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.
Base class for processing filters like renderers, reprojector, resampler etc.
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...
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).
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...