36#include <Qt3DCore/QTransform>
37#include <Qt3DRender/QGeometryRenderer>
39#include "moc_qgsterrainentity.cpp"
41using namespace Qt::StringLiterals;
46class TerrainMapUpdateJobFactory :
public QgsChunkQueueJobFactory
49 TerrainMapUpdateJobFactory( QgsTerrainTextureGenerator *textureGenerator )
50 : mTextureGenerator( textureGenerator )
53 QgsChunkQueueJob *createJob( QgsChunkNode *chunk )
override {
return new TerrainMapUpdateJob( mTextureGenerator, chunk ); }
56 QgsTerrainTextureGenerator *mTextureGenerator =
nullptr;
63QgsTerrainEntity::QgsTerrainEntity(
Qgs3DMapSettings *map, Qt3DCore::QNode *parent )
64 : QgsChunkedEntity( map, map->terrainSettings()->maximumScreenError(), map->terrainGenerator(), false, std::numeric_limits<int>::max(), parent )
70 connect( mLayerWatcher.get(), &QgsLayerStyleWatcher::styleChanged,
this, &QgsTerrainEntity::invalidateMapImages );
79 mTextureGenerator =
new QgsTerrainTextureGenerator( *map );
81 mUpdateJobFactory = std::make_unique<TerrainMapUpdateJobFactory>( mTextureGenerator );
83 mTerrainTransform =
new Qt3DCore::QTransform;
84 mTerrainTransform->setScale( 1.0f );
86 addComponent( mTerrainTransform );
89QgsTerrainEntity::~QgsTerrainEntity()
94 delete mTextureGenerator;
100 QList<QgsRayCastHit> result;
104 switch ( mMapSettings->terrainGenerator()->type() )
111 const float dist =
static_cast<float>( mMapSettings->terrainSettings()->elevationOffset() - ray.
origin().z() - mMapSettings->origin().z() ) / ray.
direction().z();
112 const QVector3D terrainPlanePoint = ray.
origin() + ray.
direction() * dist;
114 if ( mMapSettings->extent().contains( mapCoords.
x(), mapCoords.
y() ) )
117 intersectionPointMapCoords = mapCoords;
123 const QList<QgsChunkNode *> activeNodes = this->activeNodes();
124 QVector3D nearestIntersectionPoint;
125 for ( QgsChunkNode *node : activeNodes )
131 Qt3DRender::QGeometryRenderer *rend = node->entity()->findChild<Qt3DRender::QGeometryRenderer *>();
132 auto *geom = rend->geometry();
133 Qt3DCore::QTransform *tr = node->entity()->findChild<Qt3DCore::QTransform *>();
134 QVector3D nodeIntPoint;
135 DemTerrainTileGeometry *demGeom =
static_cast<DemTerrainTileGeometry *
>( geom );
136 if ( demGeom->rayIntersection( ray, context, tr->matrix(), nodeIntPoint ) )
138 const float dist = ( ray.
origin() - nodeIntPoint ).length();
139 if ( minDist < 0 || dist < minDist )
142 nearestIntersectionPoint = nodeIntPoint;
162 result.append( hit );
167void QgsTerrainEntity::onShowBoundingBoxesChanged()
172void QgsTerrainEntity::invalidateMapImages()
174 QgsEventTracing::addEvent( QgsEventTracing::Instant, u
"3D"_s, u
"Invalidate textures"_s );
178 updateNodes( mActiveNodes, mUpdateJobFactory.get() );
182 QList<QgsChunkNode *> inactiveNodes;
183 const QList<QgsChunkNode *> descendants = mRootNode->descendants();
184 for ( QgsChunkNode *node : descendants )
186 if ( !node->entity() )
188 if ( mActiveNodes.contains( node ) )
190 inactiveNodes << node;
193 updateNodes( inactiveNodes, mUpdateJobFactory.get() );
195 setNeedsUpdate(
true );
198void QgsTerrainEntity::onTerrainElevationOffsetChanged()
200 float newOffset = qobject_cast<Qgs3DMapSettings *>( sender() )->terrainSettings()->elevationOffset();
201 mTerrainTransform->setTranslation( QVector3D( 0.0f, 0.0f, newOffset ) );
204float QgsTerrainEntity::terrainElevationOffset()
const
206 return mMapSettings->terrainSettings()->elevationOffset();
213TerrainMapUpdateJob::TerrainMapUpdateJob( QgsTerrainTextureGenerator *textureGenerator, QgsChunkNode *node )
214 : QgsChunkQueueJob( node )
215 , mTextureGenerator( textureGenerator )
218void TerrainMapUpdateJob::start()
220 QgsChunkNode *node = chunk();
222 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( node->entity() );
223 connect( mTextureGenerator, &QgsTerrainTextureGenerator::tileReady,
this, &TerrainMapUpdateJob::onTileReady );
224 mJobId = mTextureGenerator->render( entity->textureImage()->imageExtent(), node->tileId(), entity->textureImage()->imageDebugText() );
227void TerrainMapUpdateJob::cancel()
230 mTextureGenerator->cancelJob( mJobId );
234void TerrainMapUpdateJob::onTileReady(
int jobId,
const QImage &image )
236 if ( mJobId == jobId )
238 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( mNode->entity() );
239 entity->textureImage()->setImage( image );
@ ShowTerrainBoundingBoxes
Displays bounding boxes of terrain tiles.
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 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).
Axis-aligned bounding box - in world coords.
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).
A representation of a ray in 3D.
QVector3D origin() const
Returns the origin of the ray.
QVector3D direction() const
Returns the direction of the ray see setDirection().
Responsible for defining parameters of the ray casting operations in 3D map canvases.
Contains details about the ray intersecting entities when ray casting in a 3D map canvas.
void setMapCoordinates(const QgsVector3D &point)
Sets the hit point position in 3d map coordinates.
void setDistance(double distance)
Sets the hit's distance from the ray's origin.
@ 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.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
double y() const
Returns Y coordinate.
double x() const
Returns X coordinate.
bool rayBoxIntersection(const QgsRay3D &ray, const QgsAABB &nodeBbox)
Tests whether an axis aligned box is intersected by a ray.
constexpr QObjectUniquePtr< Tp > make_qobject_unique(Args &&...args)
Create an object owned by a QObjectUniquePtr.