17#include "moc_qgsterrainentity.cpp"
34#include <Qt3DCore/QTransform>
35#include <Qt3DRender/QGeometryRenderer>
41class TerrainMapUpdateJobFactory :
public QgsChunkQueueJobFactory
44 TerrainMapUpdateJobFactory( QgsTerrainTextureGenerator *textureGenerator )
45 : mTextureGenerator( textureGenerator )
49 QgsChunkQueueJob *createJob( QgsChunkNode *chunk )
override
51 return new TerrainMapUpdateJob( mTextureGenerator, chunk );
55 QgsTerrainTextureGenerator *mTextureGenerator =
nullptr;
62QgsTerrainEntity::QgsTerrainEntity(
Qgs3DMapSettings *map, Qt3DCore::QNode *parent )
63 : QgsChunkedEntity( map, map->terrainSettings()->maximumScreenError(), map->terrainGenerator(), false, std::numeric_limits<int>::max(), parent )
76 connectToLayersRepaintRequest();
78 mTextureGenerator =
new QgsTerrainTextureGenerator( *map );
80 mUpdateJobFactory.reset(
new TerrainMapUpdateJobFactory( mTextureGenerator ) );
82 mTerrainTransform =
new Qt3DCore::QTransform;
83 mTerrainTransform->setScale( 1.0f );
85 addComponent( mTerrainTransform );
88QgsTerrainEntity::~QgsTerrainEntity()
93 delete mTextureGenerator;
99 QVector<QgsRayCastingUtils::RayHit> result;
102 QVector3D intersectionPoint;
103 switch ( mMapSettings->terrainGenerator()->type() )
107 if ( ray.direction().z() == 0 )
110 const float dist =
static_cast<float>( mMapSettings->terrainSettings()->elevationOffset() - ray.origin().z() ) / ray.direction().z();
111 const QVector3D terrainPlanePoint = ray.origin() + ray.direction() * dist;
113 if ( mMapSettings->extent().contains( mapCoords.
x(), mapCoords.
y() ) )
116 intersectionPoint = terrainPlanePoint;
122 const QList<QgsChunkNode *> activeNodes = this->activeNodes();
123 for ( QgsChunkNode *node : activeNodes )
127 if ( node->entity() && ( minDist < 0 || nodeBbox.
distanceFromPoint( ray.origin() ) < minDist ) && QgsRayCastingUtils::rayBoxIntersection( ray, nodeBbox ) )
129 Qt3DRender::QGeometryRenderer *rend = node->entity()->findChild<Qt3DRender::QGeometryRenderer *>();
130 auto *geom = rend->geometry();
131 Qt3DCore::QTransform *tr = node->entity()->findChild<Qt3DCore::QTransform *>();
132 QVector3D nodeIntPoint;
133 DemTerrainTileGeometry *demGeom =
static_cast<DemTerrainTileGeometry *
>( geom );
134 if ( demGeom->rayIntersection( ray, tr->matrix(), nodeIntPoint ) )
136 const float dist = ( ray.origin() - intersectionPoint ).length();
137 if ( minDist < 0 || dist < minDist )
140 intersectionPoint = nodeIntPoint;
153 if ( !intersectionPoint.isNull() )
156 result.append( hit );
161void QgsTerrainEntity::onShowBoundingBoxesChanged()
163 setShowBoundingBoxes( mMapSettings->showTerrainBoundingBoxes() );
167void QgsTerrainEntity::invalidateMapImages()
169 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Invalidate textures" ) );
173 updateNodes( mActiveNodes, mUpdateJobFactory.get() );
177 QList<QgsChunkNode *> inactiveNodes;
178 const QList<QgsChunkNode *> descendants = mRootNode->descendants();
179 for ( QgsChunkNode *node : descendants )
181 if ( !node->entity() )
183 if ( mActiveNodes.contains( node ) )
185 inactiveNodes << node;
188 updateNodes( inactiveNodes, mUpdateJobFactory.get() );
190 setNeedsUpdate(
true );
193void QgsTerrainEntity::onLayersChanged()
195 connectToLayersRepaintRequest();
196 invalidateMapImages();
199void QgsTerrainEntity::connectToLayersRepaintRequest()
201 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
206 mLayers = mMapSettings->layers();
208 for (
QgsMapLayer *layer : std::as_const( mLayers ) )
214void QgsTerrainEntity::onTerrainElevationOffsetChanged()
216 float newOffset = qobject_cast<Qgs3DMapSettings *>( sender() )->terrainSettings()->elevationOffset();
217 mTerrainTransform->setTranslation( QVector3D( 0.0f, 0.0f, newOffset ) );
220float QgsTerrainEntity::terrainElevationOffset()
const
222 return mMapSettings->terrainSettings()->elevationOffset();
229TerrainMapUpdateJob::TerrainMapUpdateJob( QgsTerrainTextureGenerator *textureGenerator, QgsChunkNode *node )
230 : QgsChunkQueueJob( node )
231 , mTextureGenerator( textureGenerator )
233 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( node->entity() );
234 connect( textureGenerator, &QgsTerrainTextureGenerator::tileReady,
this, &TerrainMapUpdateJob::onTileReady );
235 mJobId = textureGenerator->render( entity->textureImage()->imageExtent(), node->tileId(), entity->textureImage()->imageDebugText() );
238void TerrainMapUpdateJob::cancel()
241 mTextureGenerator->cancelJob( mJobId );
245void TerrainMapUpdateJob::onTileReady(
int jobId,
const QImage &image )
247 if ( mJobId == jobId )
249 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( mNode->entity() );
250 entity->textureImage()->setImage( image );
void backgroundColorChanged()
Emitted when the background color has changed.
void showTerrainBoundingBoxesChanged()
Emitted when the flag whether terrain's bounding boxes are shown has changed.
const QgsAbstractTerrainSettings * terrainSettings() const
Returns the terrain settings.
void terrainMapThemeChanged()
Emitted when terrain's map theme has changed.
QgsTerrainGenerator * terrainGenerator() const
Returns the terrain generator.
void terrainSettingsChanged()
Emitted when the terrain settings are changed.
void showLabelsChanged()
Emitted when the flag whether labels are displayed on terrain tiles has changed.
void layersChanged()
Emitted when the list of map layers for 3d rendering has changed.
void showTerrainTilesInfoChanged()
Emitted when the flag whether terrain's tile info is shown has changed.
static QgsAABB mapToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsVector3D &mapOrigin)
Converts map extent to axis aligned bounding box in 3D world coordinates.
static QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords, const QgsVector3D &origin)
Converts 3D world coordinates to map coordinates (applies offset)
float distanceFromPoint(float x, float y, float z) const
Returns shortest distance from the box to a point.
double elevationOffset() const
Returns the elevation offset of the terrain (used to move the terrain up or down).
Base class for all map layer types.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
@ QuantizedMesh
Terrain is built from quantized mesh tiles.
@ Dem
Terrain is built from raster layer with digital elevation model.
@ Online
Terrain is built from downloaded tiles with digital elevation model.
@ Mesh
Terrain is built from mesh layer with z value on vertices.
@ Flat
The whole terrain is flat area.
virtual void setTerrain(QgsTerrainEntity *t)
Sets terrain entity for the generator (does not transfer ownership)
bool isValid() const
Returns whether the terrain generator is valid.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double x() const
Returns X coordinate.
Helper struct to store ray casting parameters.
Helper struct to store ray casting results.