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 = qMin( zMin, z );
48 zMax = qMax( 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();
171 data = block->
data();
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 )
183 floatData[i] = std::numeric_limits<float>::quiet_NaN();
192 int QgsDemHeightMapGenerator::render(
int x,
int y,
int z )
194 Q_ASSERT( mJobs.isEmpty() );
197 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
198 float mapUnitsPerPixel = extent.
width() / mResolution;
199 extent.grow( mapUnitsPerPixel / 2 );
201 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
202 extent = extent.
intersect( &fullExtent );
205 jd.jobId = ++mLastJobId;
209 jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution, mTilingScheme.crs() );
211 QFutureWatcher<QByteArray> *fw =
new QFutureWatcher<QByteArray>( nullptr );
212 fw->setFuture( jd.future );
213 connect( fw, &QFutureWatcher<QByteArray>::finished,
this, &QgsDemHeightMapGenerator::onFutureFinished );
215 mJobs.insert( fw, jd );
220 QByteArray QgsDemHeightMapGenerator::renderSynchronously(
int x,
int y,
int z )
223 QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
224 float mapUnitsPerPixel = extent.
width() / mResolution;
225 extent.
grow( mapUnitsPerPixel / 2 );
227 QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
228 extent = extent.
intersect( &fullExtent );
230 QgsRasterBlock *block = mDtm->dataProvider()->block( 1, extent, mResolution, mResolution );
236 data = block->
data();
244 float QgsDemHeightMapGenerator::heightAt(
double x,
double y )
249 if ( mDtmCoarseData.isEmpty() )
251 QgsRasterBlock *block = mDtm->dataProvider()->block( 1, rect, res, res );
253 mDtmCoarseData = block->
data();
254 mDtmCoarseData.detach();
258 int cellX = ( int )( ( x - rect.
xMinimum() ) / rect.
width() * res + .5f );
259 int cellY = ( int )( ( rect.
yMaximum() - y ) / rect.
height() * res + .5f );
260 cellX = qBound( 0, cellX, res - 1 );
261 cellY = qBound( 0, cellY, res - 1 );
263 const float *data = (
const float * ) mDtmCoarseData.constData();
264 return data[cellX + cellY * res];
267 void QgsDemHeightMapGenerator::onFutureFinished()
269 QFutureWatcher<QByteArray> *fw =
static_cast<QFutureWatcher<QByteArray>*
>( sender() );
271 Q_ASSERT( mJobs.contains( fw ) );
272 JobData jobData = mJobs.value( fw );
277 QByteArray data = jobData.future.result();
278 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.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QgsRectangle intersect(const QgsRectangle *rect) const
Return the intersection with the given rectangle.
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
bool isNoData(int row, int column)
Check if value at position is no data.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
bool convert(Qgis::DataType destDataType)
Convert data to different type.
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.
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.
QByteArray data() const
Get access to raw data.
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).
bool hasNoData() const
Returns true if the block may contain no data.
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...