31 #include <Qt3DCore/QTransform>
32 #include <Qt3DRender/QGeometryRenderer>
33 #include <Qt3DRender/QObjectPicker>
39 class TerrainMapUpdateJobFactory :
public QgsChunkQueueJobFactory
42 TerrainMapUpdateJobFactory( QgsTerrainTextureGenerator *textureGenerator )
43 : mTextureGenerator( textureGenerator )
47 QgsChunkQueueJob *createJob( QgsChunkNode *chunk )
override
49 return new TerrainMapUpdateJob( mTextureGenerator, chunk );
53 QgsTerrainTextureGenerator *mTextureGenerator =
nullptr;
60 QgsTerrainEntity::QgsTerrainEntity(
int maxLevel,
const Qgs3DMapSettings &map, Qt3DCore::QNode *parent )
61 : QgsChunkedEntity( map.terrainGenerator()->rootChunkBbox( map ),
62 map.terrainGenerator()->rootChunkError( map ),
63 map.maxTerrainScreenError(), maxLevel, map.terrainGenerator(), false, parent )
76 connectToLayersRepaintRequest();
80 mTextureGenerator =
new QgsTerrainTextureGenerator( map );
82 mUpdateJobFactory.reset(
new TerrainMapUpdateJobFactory( mTextureGenerator ) );
84 mTerrainPicker =
new Qt3DRender::QObjectPicker;
87 addComponent( mTerrainPicker );
90 QgsTerrainEntity::~QgsTerrainEntity()
95 delete mTextureGenerator;
96 delete mTerrainToMapTransform;
99 bool QgsTerrainEntity::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray, QVector3D &intersectionPoint )
109 QList<QgsChunkNode *> lst = activeNodes();
110 for ( QgsChunkNode *n : lst )
112 if ( n->entity() && ( minDist < 0 || n->bbox().distanceFromPoint( ray.origin() ) < minDist ) && QgsRayCastingUtils::rayBoxIntersection( ray, n->bbox() ) )
114 Qt3DRender::QGeometryRenderer *rend = n->entity()->findChild<Qt3DRender::QGeometryRenderer *>();
115 Qt3DRender::QGeometry *geom = rend->geometry();
116 DemTerrainTileGeometry *demGeom =
static_cast<DemTerrainTileGeometry *
>( geom );
117 Qt3DCore::QTransform *tr = n->entity()->findChild<Qt3DCore::QTransform *>();
118 QVector3D nodeIntPoint;
119 if ( demGeom->rayIntersection( ray, tr->matrix(), nodeIntPoint ) )
121 float dist = ( ray.origin() - intersectionPoint ).length();
122 if ( minDist < 0 || dist < minDist )
125 intersectionPoint = nodeIntPoint;
134 void QgsTerrainEntity::onShowBoundingBoxesChanged()
136 setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
140 void QgsTerrainEntity::invalidateMapImages()
142 QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral(
"3D" ), QStringLiteral(
"Invalidate textures" ) );
146 updateNodes( mActiveNodes, mUpdateJobFactory.get() );
150 QList<QgsChunkNode *> inactiveNodes;
151 Q_FOREACH ( QgsChunkNode *node, mRootNode->descendants() )
153 if ( !node->entity() )
155 if ( mActiveNodes.contains( node ) )
157 inactiveNodes << node;
160 updateNodes( inactiveNodes, mUpdateJobFactory.get() );
162 setNeedsUpdate(
true );
165 void QgsTerrainEntity::onLayersChanged()
167 connectToLayersRepaintRequest();
168 invalidateMapImages();
171 void QgsTerrainEntity::connectToLayersRepaintRequest()
178 mLayers = mMap.terrainLayers();
190 TerrainMapUpdateJob::TerrainMapUpdateJob( QgsTerrainTextureGenerator *textureGenerator, QgsChunkNode *node )
191 : QgsChunkQueueJob( node )
192 , mTextureGenerator( textureGenerator )
194 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( node->entity() );
195 connect( textureGenerator, &QgsTerrainTextureGenerator::tileReady,
this, &TerrainMapUpdateJob::onTileReady );
196 mJobId = textureGenerator->render( entity->textureImage()->imageExtent(), node->tileId(), entity->textureImage()->imageDebugText() );
199 void TerrainMapUpdateJob::cancel()
202 mTextureGenerator->cancelJob( mJobId );
206 void TerrainMapUpdateJob::onTileReady(
int jobId,
const QImage &image )
208 if ( mJobId == jobId )
210 QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( mNode->entity() );
211 entity->textureImage()->setImage( image );