QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrulebasedchunkloader_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrulebasedchunkloader_p.cpp
3  --------------------------------------
4  Date : November 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"
19 #include "qgschunknode_p.h"
20 #include "qgspolygon3dsymbol_p.h"
21 #include "qgseventtracing.h"
22 
23 #include "qgsvectorlayer.h"
25 
26 #include "qgsrulebased3drenderer.h"
27 
28 #include <QtConcurrent>
29 #include <Qt3DCore/QTransform>
30 
32 
33 
34 QgsRuleBasedChunkLoader::QgsRuleBasedChunkLoader( const QgsRuleBasedChunkLoaderFactory *factory, QgsChunkNode *node )
35  : QgsChunkLoader( node )
36  , mFactory( factory )
37  , mContext( factory->mMap )
38  , mSource( new QgsVectorLayerFeatureSource( factory->mLayer ) )
39 {
40  if ( node->level() < mFactory->mLeafLevel )
41  {
42  QTimer::singleShot( 0, this, &QgsRuleBasedChunkLoader::finished );
43  return;
44  }
45 
46  QgsVectorLayer *layer = mFactory->mLayer;
47  const Qgs3DMapSettings &map = mFactory->mMap;
48 
50  exprContext.setFields( layer->fields() );
51  mContext.setExpressionContext( exprContext );
52 
53  // factory is shared among multiple loaders which may be run at the same time
54  // so we need a local copy of our rule tree that does not intefere with others
55  // (e.g. it happened that filter expressions with invalid syntax would cause
56  // nasty crashes when trying to simultaneously record evaluation error)
57  mRootRule.reset( mFactory->mRootRule->clone() );
58 
59  mRootRule->createHandlers( layer, mHandlers );
60 
61  QSet<QString> attributeNames;
62  mRootRule->prepare( mContext, attributeNames, mHandlers );
63 
64  // build the feature request
66  req.setDestinationCrs( map.crs(), map.transformContext() );
67  req.setSubsetOfAttributes( attributeNames, layer->fields() );
68 
69  // only a subset of data to be queried
70  const QgsRectangle rect = Qgs3DUtils::worldToMapExtent( node->bbox(), map.origin() );
71  req.setFilterRect( rect );
72 
73  //
74  // this will be run in a background thread
75  //
76  mFutureWatcher = new QFutureWatcher<void>( this );
77  connect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
78 
79  const QFuture<void> future = QtConcurrent::run( [req, this]
80  {
81  const QgsEventTracing::ScopedEvent e( QStringLiteral( "3D" ), QStringLiteral( "RB chunk load" ) );
82 
83  QgsFeature f;
84  QgsFeatureIterator fi = mSource->getFeatures( req );
85  while ( fi.nextFeature( f ) )
86  {
87  if ( mCanceled )
88  break;
89  mContext.expressionContext().setFeature( f );
90  mRootRule->registerFeature( f, mContext, mHandlers );
91  }
92  } );
93 
94  // emit finished() as soon as the handler is populated with features
95  mFutureWatcher->setFuture( future );
96 }
97 
98 QgsRuleBasedChunkLoader::~QgsRuleBasedChunkLoader()
99 {
100  if ( mFutureWatcher && !mFutureWatcher->isFinished() )
101  {
102  disconnect( mFutureWatcher, &QFutureWatcher<void>::finished, this, &QgsChunkQueueJob::finished );
103  mFutureWatcher->waitForFinished();
104  }
105 
106  qDeleteAll( mHandlers );
107  mHandlers.clear();
108 }
109 
110 void QgsRuleBasedChunkLoader::cancel()
111 {
112  mCanceled = true;
113 }
114 
115 Qt3DCore::QEntity *QgsRuleBasedChunkLoader::createEntity( Qt3DCore::QEntity *parent )
116 {
117  if ( mNode->level() < mFactory->mLeafLevel )
118  {
119  return new Qt3DCore::QEntity( parent ); // dummy entity
120  }
121 
122  long long featureCount = 0;
123  for ( auto it = mHandlers.constBegin(); it != mHandlers.constEnd(); ++it )
124  {
125  featureCount += it.value()->featureCount();
126  }
127  if ( featureCount == 0 )
128  {
129  // an empty node, so we return no entity. This tags the node as having no data and effectively removes it.
130  return nullptr;
131  }
132 
133  Qt3DCore::QEntity *entity = new Qt3DCore::QEntity( parent );
134  float zMin = std::numeric_limits<float>::max();
135  float zMax = std::numeric_limits<float>::lowest();
136  for ( auto it = mHandlers.constBegin(); it != mHandlers.constEnd(); ++it )
137  {
138  QgsFeature3DHandler *handler = it.value();
139  handler->finalize( entity, mContext );
140  if ( handler->zMinimum() < zMin )
141  zMin = handler->zMinimum();
142  if ( handler->zMaximum() > zMax )
143  zMax = handler->zMaximum();
144  }
145 
146  // fix the vertical range of the node from the estimated vertical range to the true range
147  if ( zMin != std::numeric_limits<float>::max() && zMax != std::numeric_limits<float>::lowest() )
148  {
149  QgsAABB box = mNode->bbox();
150  box.yMin = zMin;
151  box.yMax = zMax;
152  mNode->setExactBbox( box );
153  mNode->updateParentBoundingBoxesRecursively();
154  }
155 
156  return entity;
157 }
158 
159 
161 
162 
163 QgsRuleBasedChunkLoaderFactory::QgsRuleBasedChunkLoaderFactory( const Qgs3DMapSettings &map, QgsVectorLayer *vl, QgsRuleBased3DRenderer::Rule *rootRule, int leafLevel, double zMin, double zMax )
164  : mMap( map )
165  , mLayer( vl )
166  , mRootRule( rootRule->clone() )
167  , mLeafLevel( leafLevel )
168 {
169  const QgsAABB rootBbox = Qgs3DUtils::layerToWorldExtent( vl->extent(), zMin, zMax, vl->crs(), map.origin(), map.crs(), map.transformContext() );
170  setupQuadtree( rootBbox, -1, leafLevel ); // negative root error means that the node does not contain anything
171 }
172 
173 QgsRuleBasedChunkLoaderFactory::~QgsRuleBasedChunkLoaderFactory() = default;
174 
175 QgsChunkLoader *QgsRuleBasedChunkLoaderFactory::createChunkLoader( QgsChunkNode *node ) const
176 {
177  return new QgsRuleBasedChunkLoader( this, node );
178 }
179 
180 
182 
183 QgsRuleBasedChunkedEntity::QgsRuleBasedChunkedEntity( QgsVectorLayer *vl, double zMin, double zMax, const QgsVectorLayer3DTilingSettings &tilingSettings, QgsRuleBased3DRenderer::Rule *rootRule, const Qgs3DMapSettings &map )
184  : QgsChunkedEntity( -1, // max. allowed screen error (negative tau means that we need to go until leaves are reached)
185  new QgsRuleBasedChunkLoaderFactory( map, vl, rootRule, tilingSettings.zoomLevelsCount() - 1, zMin, zMax ), true )
186 {
187  mTransform = new Qt3DCore::QTransform;
188  mTransform->setTranslation( QVector3D( 0.0f, map.terrainElevationOffset(), 0.0f ) );
189  this->addComponent( mTransform );
190  connect( &map, &Qgs3DMapSettings::terrainElevationOffsetChanged, this, &QgsRuleBasedChunkedEntity::onTerrainElevationOffsetChanged );
191 
192  setShowBoundingBoxes( tilingSettings.showBoundingBoxes() );
193 }
194 
195 QgsRuleBasedChunkedEntity::~QgsRuleBasedChunkedEntity()
196 {
197  // cancel / wait for jobs
198  cancelActiveJobs();
199 }
200 
201 void QgsRuleBasedChunkedEntity::onTerrainElevationOffsetChanged( float newOffset )
202 {
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
QgsRuleBased3DRenderer::Rule::createHandlers
void createHandlers(QgsVectorLayer *layer, RuleToHandlerMap &handlers) const
add handlers
Definition: qgsrulebased3drenderer.cpp:249
QgsVectorLayer3DTilingSettings::showBoundingBoxes
bool showBoundingBoxes() const
Returns whether to display bounding boxes of entity's tiles (for debugging)
Definition: qgsabstractvectorlayer3drenderer.h:58
qgschunknode_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
QgsRuleBased3DRenderer::Rule::prepare
void prepare(const Qgs3DRenderContext &context, QSet< QString > &attributeNames, RuleToHandlerMap &handlers) const
call prepare() on handlers and populate attributeNames
Definition: qgsrulebased3drenderer.cpp:268
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:228
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
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
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
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
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
qgsrulebasedchunkloader_p.h
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
QgsRuleBased3DRenderer::Rule::registerFeature
RegisterResult registerFeature(QgsFeature &feature, Qgs3DRenderContext &context, RuleToHandlerMap &handlers) const
register individual features
Definition: qgsrulebased3drenderer.cpp:293
qgspolygon3dsymbol_p.h
Qgs3DMapSettings::terrainElevationOffsetChanged
void terrainElevationOffsetChanged(float newElevation)
Emitted when the terrain elevation offset is changed.
qgsrulebased3drenderer.h
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
QgsRuleBased3DRenderer::Rule
A child rule for a QgsRuleBased3DRenderer.
Definition: qgsrulebased3drenderer.h:74
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
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