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() - mMapSettings->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)
 
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).
 
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.
 
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.
 
Helper struct to store ray casting parameters.
 
Helper struct to store ray casting results.