QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsvectorlayerchunkloader_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerchunkloader_p.cpp
3  --------------------------------------
4  Date : July 2019
5  Copyright : (C) 2019 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include "qgs3dutils.h"
20 #include "qgschunknode_p.h"
21 #include "qgspolygon3dsymbol_p.h"
22 #include "qgseventtracing.h"
23 #include "qgslogger.h"
24 #include "qgsvectorlayer.h"
26 
27 #include "qgsline3dsymbol.h"
28 #include "qgspoint3dsymbol.h"
29 #include "qgspolygon3dsymbol.h"
30 
31 #include "qgsapplication.h"
32 #include "qgs3dsymbolregistry.h"
33 
34 #include <QtConcurrent>
35 #include <Qt3DCore/QTransform>
36 
38 
39 
40 QgsVectorLayerChunkLoader::QgsVectorLayerChunkLoader( const QgsVectorLayerChunkLoaderFactory *factory, QgsChunkNode *node )
41  : QgsChunkLoader( node )
42  , mFactory( factory )
43  , mContext( factory->mMap )
44  , mSource( new QgsVectorLayerFeatureSource( factory->mLayer ) )
45 {
46  if ( node->level() < mFactory->mLeafLevel )
47  {
48  QTimer::singleShot( 0, this, &QgsVectorLayerChunkLoader::finished );
49  return;
50  }
51 
52  QgsVectorLayer *layer = mFactory->mLayer;
53  const Qgs3DMapSettings &map = mFactory->mMap;
54 
55  QgsFeature3DHandler *handler = QgsApplication::symbol3DRegistry()->createHandlerForSymbol( layer, mFactory->mSymbol.get() );
56  if ( !handler )
57  {
58  QgsDebugMsg( QStringLiteral( "Unknown 3D symbol type for vector layer: " ) + mFactory->mSymbol->type() );
59  return;
60  }
61  mHandler.reset( handler );
62 
64  exprContext.setFields( layer->fields() );
65  mContext.setExpressionContext( exprContext );
66 
67  QSet<QString> attributeNames;
68  if ( !mHandler->prepare( mContext, attributeNames ) )
69  {
70  QgsDebugMsg( QStringLiteral( "Failed to prepare 3D feature handler!" ) );
71  return;
72  }
73 
74  // build the feature request
76  req.setDestinationCrs( map.crs(), map.transformContext() );
77  req.setSubsetOfAttributes( attributeNames, layer->fields() );
78 
79  // only a subset of data to be queried
80  const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), map.origin() );
81  req.setFilterRect( rect );
82 
83  //
84  // this will be run in a background thread
85  //
86  mFutureWatcher = new QFutureWatcher<void>( this );
87  connect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
88 
89  const QFuture<void> future = QtConcurrent::run( [req, this]
90  {
91  const QgsEventTracing::ScopedEvent e( QStringLiteral( "3D" ), QStringLiteral( "VL chunk load" ) );
92 
93  QgsFeature f;
94  QgsFeatureIterator fi = mSource->getFeatures( req );
95  while ( fi.nextFeature( f ) )
96  {
97  if ( mCanceled )
98  break;
99  mContext.expressionContext().setFeature( f );
100  mHandler->processFeature( f, mContext );
101  }
102  } );
103 
104  // emit finished() as soon as the handler is populated with features
105  mFutureWatcher->setFuture( future );
106 }
107 
108 QgsVectorLayerChunkLoader::~QgsVectorLayerChunkLoader()
109 {
110  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
111  {
112  disconnect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
113  mFutureWatcher->waitForFinished();
114  }
115 }
116 
117 void QgsVectorLayerChunkLoader::cancel()
118 {
119  mCanceled = true;
120 }
121 
122 Qt3DCore::QEntity *QgsVectorLayerChunkLoader::createEntity( Qt3DCore::QEntity *parent )
123 {
124  if ( mNode->level() < mFactory->mLeafLevel )
125  {
126  return new Qt3DCore::QEntity( parent ); // dummy entity
127  }
128 
129  if ( mHandler->featureCount() == 0 )
130  {
131  // an empty node, so we return no entity. This tags the node as having no data and effectively removes it.
132  return nullptr;
133  }
134 
135  Qt3DCore::QEntity *entity = new Qt3DCore::QEntity( parent );
136  mHandler->finalize( entity, mContext );
137 
138  // fix the vertical range of the node from the estimated vertical range to the true range
139  if ( mHandler->zMinimum() != std::numeric_limits<float>::max() && mHandler->zMaximum() != std::numeric_limits<float>::lowest() )
140  {
141  QgsAABB box = mNode->bbox();
142  box.yMin = mHandler->zMinimum();
143  box.yMax = mHandler->zMaximum();
144  mNode->setExactBbox( box );
145  mNode->updateParentBoundingBoxesRecursively();
146  }
147 
148  return entity;
149 }
150 
151 
153 
154 
155 QgsVectorLayerChunkLoaderFactory::QgsVectorLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsVectorLayer *vl, QgsAbstract3DSymbol *symbol, int leafLevel, double zMin, double zMax )
156  : mMap( map )
157  , mLayer( vl )
158  , mSymbol( symbol->clone() )
159  , mLeafLevel( leafLevel )
160 {
161  QgsAABB rootBbox = Qgs3DUtils::layerToWorldExtent( vl->extent(), zMin, zMax, vl->crs(), map.origin(), map.crs(), map.transformContext() );
162  // add small padding to avoid clipping of point features located at the edge of the bounding box
163  rootBbox.xMin -= 1.0;
164  rootBbox.xMax += 1.0;
165  rootBbox.yMin -= 1.0;
166  rootBbox.yMax += 1.0;
167  rootBbox.zMin -= 1.0;
168  rootBbox.zMax += 1.0;
169  setupQuadtree( rootBbox, -1, leafLevel ); // negative root error means that the node does not contain anything
170 }
171 
172 QgsChunkLoader *QgsVectorLayerChunkLoaderFactory::createChunkLoader( QgsChunkNode *node ) const
173 {
174  return new QgsVectorLayerChunkLoader( this, node );
175 }
176 
177 
179 
180 
181 QgsVectorLayerChunkedEntity::QgsVectorLayerChunkedEntity( QgsVectorLayer *vl, double zMin, double zMax, const QgsVectorLayer3DTilingSettings &tilingSettings, QgsAbstract3DSymbol *symbol, const Qgs3DMapSettings &map )
182  : QgsChunkedEntity( -1, // max. allowed screen error (negative tau means that we need to go until leaves are reached)
183  new QgsVectorLayerChunkLoaderFactory( map, vl, symbol, tilingSettings.zoomLevelsCount() - 1, zMin, zMax ), true )
184 {
185  mTransform = new Qt3DCore::QTransform;
186  mTransform->setTranslation( QVector3D( 0.0f, map.terrainElevationOffset(), 0.0f ) );
187  this->addComponent( mTransform );
188 
189  connect( &map, &Qgs3DMapSettings::terrainElevationOffsetChanged, this, &QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged );
190 
191  setShowBoundingBoxes( tilingSettings.showBoundingBoxes() );
192 }
193 
194 QgsVectorLayerChunkedEntity::~QgsVectorLayerChunkedEntity()
195 {
196  // cancel / wait for jobs
197  cancelActiveJobs();
198 }
199 
200 void QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged( float newOffset )
201 {
202  QgsDebugMsgLevel( QStringLiteral( "QgsVectorLayerChunkedEntity::onTerrainElevationOffsetChanged" ), 2 );
203  mTransform->setTranslation( QVector3D( 0.0f, newOffset, 0.0f ) );
204 }
205 
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
Qgs3DMapSettings::crs
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
Definition: qgs3dmapsettings.h:99
qgsline3dsymbol.h
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsVectorLayer3DTilingSettings::showBoundingBoxes
bool showBoundingBoxes() const
Returns whether to display bounding boxes of entity's tiles (for debugging)
Definition: qgsabstractvectorlayer3drenderer.h:58
QgsApplication::symbol3DRegistry
static Qgs3DSymbolRegistry * symbol3DRegistry()
Returns registry of available 3D symbols.
Definition: qgsapplication.cpp:2490
qgschunknode_p.h
qgsvectorlayerchunkloader_p.h
Qgs3DUtils::worldToMapExtent
static QgsRectangle worldToMapExtent(const QgsAABB &bbox, const QgsVector3D &mapOrigin)
Converts axis aligned bounding box in 3D world coordinates to extent in map coordinates.
Definition: qgs3dutils.cpp:599
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:228
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsAABB::zMax
float zMax
Definition: qgsaabb.h:86
QgsAABB::yMin
float yMin
Definition: qgsaabb.h:82
Qgs3DMapSettings::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Definition: qgs3dmapsettings.cpp:494
qgs3dsymbolregistry.h
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
qgsapplication.h
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:101
Qgs3DUtils::globalProjectLayerExpressionContext
static QgsExpressionContext globalProjectLayerExpressionContext(QgsVectorLayer *layer)
Returns expression context for use in preparation of 3D data of a layer.
Definition: qgs3dutils.cpp:662
qgseventtracing.h
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
QgsAbstract3DSymbol
Abstract base class for 3D symbols that are used by VectorLayer3DRenderer objects.
Definition: qgsabstract3dsymbol.h:46
QgsAbstractVectorLayer3DRenderer::tilingSettings
QgsVectorLayer3DTilingSettings tilingSettings() const
Returns tiling settings of the renderer.
Definition: qgsabstractvectorlayer3drenderer.h:90
qgs3dutils.h
QgsAbstractVectorLayer3DRenderer::layer
QgsVectorLayer * layer() const
Returns vector layer associated with the renderer.
Definition: qgsabstractvectorlayer3drenderer.cpp:53
qgsabstractvectorlayer3drenderer.h
QgsAABB::xMin
float xMin
Definition: qgsaabb.h:81
QgsAABB
Axis-aligned bounding box - in world coords.
Definition: qgsaabb.h:33
Qgs3DMapSettings
Definition of the world.
Definition: qgs3dmapsettings.h:57
qgsvectorlayerfeatureiterator.h
Qgs3DMapSettings::origin
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0)
Definition: qgs3dmapsettings.h:89
QgsVectorLayer::extent
QgsRectangle extent() const FINAL
Returns the extent of the layer.
Definition: qgsvectorlayer.cpp:894
Qgs3DMapSettings::terrainElevationOffset
float terrainElevationOffset() const
Returns the elevation offset of the terrain (used to move the terrain up or down)
Definition: qgs3dmapsettings.h:252
qgsvectorlayer.h
qgspolygon3dsymbol_p.h
qgspolygon3dsymbol.h
Qgs3DMapSettings::terrainElevationOffsetChanged
void terrainElevationOffsetChanged(float newElevation)
Emitted when the terrain elevation offset is changed.
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
qgspoint3dsymbol.h
QgsVectorLayerFeatureSource
Partial snapshot of vector layer's state (only the members necessary for access to features)
Definition: qgsvectorlayerfeatureiterator.h:52
QgsAABB::yMax
float yMax
Definition: qgsaabb.h:85
Qgs3DUtils::layerToWorldExtent
static QgsAABB layerToWorldExtent(const QgsRectangle &extent, double zMin, double zMax, const QgsCoordinateReferenceSystem &layerCrs, const QgsVector3D &mapOrigin, const QgsCoordinateReferenceSystem &mapCrs, const QgsCoordinateTransformContext &context)
Converts extent (in map layer's CRS) to axis aligned bounding box in 3D world coordinates.
Definition: qgs3dutils.cpp:576
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsFeatureRequest::setDestinationCrs
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Definition: qgsfeaturerequest.cpp:301
qgslogger.h
QgsAABB::zMin
float zMin
Definition: qgsaabb.h:83
QgsAABB::xMax
float xMax
Definition: qgsaabb.h:84
Qgs3DSymbolRegistry::createHandlerForSymbol
QgsFeature3DHandler * createHandlerForSymbol(QgsVectorLayer *layer, const QgsAbstract3DSymbol *symbol)
Creates a feature handler for a symbol, for the specified vector layer.
Definition: qgs3dsymbolregistry.cpp:60
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsVectorLayer3DTilingSettings
This class defines configuration of how a vector layer gets tiled for 3D rendering.
Definition: qgsabstractvectorlayer3drenderer.h:37