32#include <Qt3DCore/QTransform> 
   33#include <Qt3DRender/QGeometryRenderer> 
   39class 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;
 
   60QgsTerrainEntity::QgsTerrainEntity( 
const Qgs3DMapSettings &map, Qt3DCore::QNode *parent )
 
   61  : QgsChunkedEntity( map.maxTerrainScreenError(), map.terrainGenerator(), false, std::numeric_limits<int>::max(), parent )
 
   75  connectToLayersRepaintRequest();
 
   77  mTextureGenerator = 
new QgsTerrainTextureGenerator( map );
 
   79  mUpdateJobFactory.reset( 
new TerrainMapUpdateJobFactory( mTextureGenerator ) );
 
   81  mTerrainTransform = 
new Qt3DCore::QTransform;
 
   82  mTerrainTransform->setScale( 1.0f );
 
   84  addComponent( mTerrainTransform );
 
   87QgsTerrainEntity::~QgsTerrainEntity()
 
   92  delete mTextureGenerator;
 
   95QVector<QgsRayCastingUtils::RayHit> QgsTerrainEntity::rayIntersection( 
const QgsRayCastingUtils::Ray3D &ray, 
const QgsRayCastingUtils::RayCastContext &context )
 const 
   98  QVector<QgsRayCastingUtils::RayHit> result;
 
  101  QVector3D intersectionPoint;
 
  102  switch ( mMap.terrainGenerator()->type() )
 
  106      if ( ray.direction().y() == 0 )
 
  109      const float dist = 
static_cast<float>( mMap.terrainElevationOffset() - ray.origin().y() ) / ray.direction().y();
 
  110      const QVector3D terrainPlanePoint = ray.origin() + ray.direction() * dist;
 
  112      if ( mMap.extent().contains( mapCoords.
x(), mapCoords.
y() ) )
 
  115        intersectionPoint = terrainPlanePoint;
 
  121      const QList<QgsChunkNode *> activeNodes = this->activeNodes();
 
  122      for ( QgsChunkNode *node : activeNodes )
 
  124        if ( node->entity() &&
 
  125             ( minDist < 0 || node->bbox().distanceFromPoint( ray.origin() ) < minDist ) &&
 
  126             QgsRayCastingUtils::rayBoxIntersection( ray, node->bbox() ) )
 
  128          Qt3DRender::QGeometryRenderer *rend = node->entity()->findChild<Qt3DRender::QGeometryRenderer *>();
 
  129          auto *geom = rend->geometry();
 
  130          Qt3DCore::QTransform *tr = node->entity()->findChild<Qt3DCore::QTransform *>();
 
  131          QVector3D nodeIntPoint;
 
  132          DemTerrainTileGeometry *demGeom = 
static_cast<DemTerrainTileGeometry *
>( geom );
 
  133          if ( demGeom->rayIntersection( ray, tr->matrix(), nodeIntPoint ) )
 
  135            const float dist = ( ray.origin() - intersectionPoint ).length();
 
  136            if ( minDist < 0 || dist < minDist )
 
  139              intersectionPoint = nodeIntPoint;
 
  151  if ( !intersectionPoint.isNull() )
 
  153    QgsRayCastingUtils::RayHit hit( minDist, intersectionPoint );
 
  154    result.append( hit );
 
  159void QgsTerrainEntity::onShowBoundingBoxesChanged()
 
  161  setShowBoundingBoxes( mMap.showTerrainBoundingBoxes() );
 
  165void QgsTerrainEntity::invalidateMapImages()
 
  167  QgsEventTracing::addEvent( QgsEventTracing::Instant, QStringLiteral( 
"3D" ), QStringLiteral( 
"Invalidate textures" ) );
 
  171  updateNodes( mActiveNodes, mUpdateJobFactory.get() );
 
  175  QList<QgsChunkNode *> inactiveNodes;
 
  176  const QList<QgsChunkNode *> descendants = mRootNode->descendants();
 
  177  for ( QgsChunkNode *node : descendants )
 
  179    if ( !node->entity() )
 
  181    if ( mActiveNodes.contains( node ) )
 
  183    inactiveNodes << node;
 
  186  updateNodes( inactiveNodes, mUpdateJobFactory.get() );
 
  188  setNeedsUpdate( 
true );
 
  191void QgsTerrainEntity::onLayersChanged()
 
  193  connectToLayersRepaintRequest();
 
  194  invalidateMapImages();
 
  197void QgsTerrainEntity::connectToLayersRepaintRequest()
 
  199  for ( 
QgsMapLayer *layer : std::as_const( mLayers ) )
 
  204  mLayers = mMap.layers();
 
  206  for ( 
QgsMapLayer *layer : std::as_const( mLayers ) )
 
  212void QgsTerrainEntity::onTerrainElevationOffsetChanged( 
float newOffset )
 
  214  mTerrainTransform->setTranslation( QVector3D( 0.0f, newOffset, 0.0f ) );
 
  217float QgsTerrainEntity::terrainElevationOffset()
 const 
  219  return mMap.terrainElevationOffset();
 
  226TerrainMapUpdateJob::TerrainMapUpdateJob( QgsTerrainTextureGenerator *textureGenerator, QgsChunkNode *node )
 
  227  : QgsChunkQueueJob( node )
 
  228  , mTextureGenerator( textureGenerator )
 
  230  QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( node->entity() );
 
  231  connect( textureGenerator, &QgsTerrainTextureGenerator::tileReady, 
this, &TerrainMapUpdateJob::onTileReady );
 
  232  mJobId = textureGenerator->render( entity->textureImage()->imageExtent(), node->tileId(), entity->textureImage()->imageDebugText() );
 
  235void TerrainMapUpdateJob::cancel()
 
  238    mTextureGenerator->cancelJob( mJobId );
 
  242void TerrainMapUpdateJob::onTileReady( 
int jobId, 
const QImage &image )
 
  244  if ( mJobId == jobId )
 
  246    QgsTerrainTileEntity *entity = qobject_cast<QgsTerrainTileEntity *>( mNode->entity() );
 
  247    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.
 
void terrainMapThemeChanged()
Emitted when terrain's map theme has changed.
 
float terrainElevationOffset() const
Returns the elevation offset of the terrain (used to move the terrain up or down)
 
QgsTerrainGenerator * terrainGenerator() const
Returns the terrain generator.
 
void showLabelsChanged()
Emitted when the flag whether labels are displayed on terrain tiles has changed.
 
void terrainElevationOffsetChanged(float newElevation)
Emitted when the terrain elevation offset is 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 QgsVector3D worldToMapCoordinates(const QgsVector3D &worldCoords, const QgsVector3D &origin)
Converts 3D world coordinates to map coordinates (applies offset and turns (x,y,z) into (x,...
 
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...
 
@ 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.
 
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.