37#include <Qt3DCore/QTransform>
38#include <QtConcurrentRun>
40#include "moc_qgsrulebasedchunkloader_p.cpp"
42using namespace Qt::StringLiterals;
48 : mRenderContext( context )
50 , mRootRule( rootRule->clone() )
51 , mNodesAreLeafs( std::make_shared<NodeIsLeafMap>() )
52 , mMaxFeatures( maxFeatures )
58 QgsDebugError( u
"Vector layers in globe scenes are not supported yet!"_s );
59 setupQuadtree( QgsBox3D( -7e6, -7e6, -7e6, 7e6, 7e6, 7e6 ), -1, 3 );
66 if ( layerExtentInMapCrs.isValid() )
68 extent = context.extent().intersect( layerExtentInMapCrs );
70 if ( extent.isValid() )
72 QgsBox3D rootBox3D( extent, zMin, zMax );
74 rootBox3D.grow( 1.0 );
76 const float rootError = static_cast<float>( std::max<double>( rootBox3D.width(), rootBox3D.height() ) * QgsVectorLayer3DTilingSettings::tileGeometryErrorRatio() );
77 setupQuadtree( rootBox3D, rootError );
81QgsRuleBasedChunkLoader::~QgsRuleBasedChunkLoader() =
default;
83QFuture<QgsChunkLoaderResult> QgsRuleBasedChunkLoader::loadChunk( QgsChunkNode *node )
87 exprContext.
setFields( mLayer->fields() );
95 std::unique_ptr<QgsRuleBased3DRenderer::Rule> rootRule( mRootRule->clone() );
100 QSet<QString> attributeNames;
101 rootRule->
prepare( renderCtx, attributeNames, node->box3D(), handlers );
111 auto source = std::make_unique<QgsVectorLayerFeatureSource>( mLayer );
113 return QtConcurrent::run( &QgsRuleBasedChunkLoader::loadChunkInWorker, std::move( handlers ), std::move( renderCtx ), std::move( rootRule ), std::move( source ), std::move( req ), node, mMaxFeatures, mNodesAreLeafs )
114 .then(
this, [
this, node]( ChunkData data ) {
return QgsChunkLoaderResult { std::bind_front( &QgsRuleBasedChunkLoader::createEntity,
this, node, data ) }; } );
117void QgsRuleBasedChunkLoader::loadChunkInWorker(
118 QPromise<ChunkData> &promise,
121 const std::unique_ptr<QgsRuleBased3DRenderer::Rule> &rootRule,
122 const std::unique_ptr<QgsVectorLayerFeatureSource> &source,
126 const std::shared_ptr<NodeIsLeafMap> &nodesAreLeaves
129 const QgsScopedEvent e( u
"3D"_s, u
"RB chunk load"_s );
133 int featureCount = 0;
134 bool featureLimitReached =
false;
137 if ( promise.isCanceled() )
140 if ( ++featureCount > maxFeatures )
142 featureLimitReached =
true;
147 rootRule->registerFeature( f, renderCtx, handlers );
150 bool nodeIsLeaf =
false;
151 if ( !featureLimitReached )
153 QgsDebugMsgLevel( u
"All features fetched for node: %1"_s.arg( node->tileId().text() ), 3 );
160 QMutexLocker<QMutex> locker( &nodesAreLeaves->mutex );
161 nodesAreLeaves->map[node->tileId().text()] = nodeIsLeaf;
164 promise.addResult( ChunkData { .handlers = std::move( handlers ), .renderCtx = std::move( renderCtx ) } );
167Qt3DCore::QEntity *QgsRuleBasedChunkLoader::createEntity( QgsChunkNode *node, ChunkData data, Qt3DCore::QEntity *parent )
170 long long featureCount = 0;
171 for (
auto it = data.handlers.constBegin(); it != data.handlers.constEnd(); ++it )
173 featureCount += it.value()->featureCount();
175 if ( featureCount == 0 )
181 Qt3DCore::QEntity *entity =
new Qt3DCore::QEntity( parent );
182 float zMin = std::numeric_limits<float>::max();
183 float zMax = std::numeric_limits<float>::lowest();
184 for (
auto it = data.handlers.constBegin(); it != data.handlers.constEnd(); ++it )
186 QgsFeature3DHandler *handler = it.value();
187 handler->finalize( entity, data.renderCtx );
188 if ( handler->zMinimum() < zMin )
189 zMin = handler->zMinimum();
190 if ( handler->zMaximum() > zMax )
191 zMax = handler->zMaximum();
194 if ( zMin != std::numeric_limits<float>::max() && zMax != std::numeric_limits<float>::lowest() )
199 node->setExactBox3D( box );
200 node->updateParentBoundingBoxesRecursively();
204 qDeleteAll( data.handlers );
209QFuture<QVector<QgsChunkNode *>> QgsRuleBasedChunkLoader::createChildren( QgsChunkNode *node )
212 QMutexLocker<QMutex> locker( &mNodesAreLeafs->mutex );
213 if ( mNodesAreLeafs->map.value( node->tileId().text(),
false ) )
214 return QtFuture::makeReadyValueFuture( QVector<QgsChunkNode *> {} );
217 return QgsQuadtreeChunkLoader::createChildren( node );
222QgsRuleBasedChunkedEntity::QgsRuleBasedChunkedEntity(
225 : QgsAbstractFeatureBasedChunkedEntity( map, 3, new QgsRuleBasedChunkLoader(
Qgs3DRenderContext::fromMapSettings( map ), vl, rootRule, zMin, zMax, tilingSettings.maximumChunkFeatures() ), true )
227 onTerrainElevationOffsetChanged();
231QgsRuleBasedChunkedEntity::~QgsRuleBasedChunkedEntity()
238bool QgsRuleBasedChunkedEntity::applyTerrainOffset()
const
240 QgsRuleBasedChunkLoader *loader =
static_cast<QgsRuleBasedChunkLoader *
>( mChunkLoader );
245 for (
const auto &rule : rules )
247 if ( rule->symbol() )
249 QString symbolType = rule->symbol()->type();
250 if ( symbolType ==
"line" )
258 else if ( symbolType ==
"point" )
266 else if ( symbolType ==
"polygon" )
276 QgsDebugMsgLevel( u
"QgsRuleBasedChunkedEntityChunkedEntity::applyTerrainOffset, unhandled symbol type %1"_s.arg( symbolType ), 2 );
@ Absolute
Elevation is taken directly from feature and is independent of terrain height (final elevation = feat...
@ Geocentric
Geocentric CRS.
Rendering context for preparation of 3D entities.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system used in the 3D scene.
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsRectangle extent() const
Returns the 3D scene's 2D extent in the 3D scene's CRS.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
static QgsRectangle tryReprojectExtent2D(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs1, const QgsCoordinateReferenceSystem &crs2, const QgsCoordinateTransformContext &context)
Reprojects extent from crs1 to crs2 coordinate reference system with context context.
A 3-dimensional box composed of x, y, z coordinates.
void setZMinimum(double z)
Sets the minimum z value.
void setZMaximum(double z)
Sets the maximum z value.
Qgis::CrsType type() const
Returns the type of the CRS.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
3D symbol that draws linestring geometries as planar polygons (created from lines using a buffer with...
Qgis::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain).
3D symbol that draws point geometries as 3D objects using one of the predefined shapes.
Qgis::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain).
3D symbol that draws polygon geometries as planar polygons, optionally extruded (with added walls).
Qgis::AltitudeClamping altitudeClamping() const
Returns method that determines altitude (whether to clamp to feature to terrain).
A rectangle specified with double values.
A child rule for a QgsRuleBased3DRenderer.
void prepare(const Qgs3DRenderContext &context, QSet< QString > &attributeNames, const QgsBox3D &chunkExtent, RuleToHandlerMap &handlers) const
call prepare() on handlers and populate attributeNames
const QgsRuleBased3DRenderer::RuleList & children() const
Returns all children rules of this rule.
void createHandlers(QgsVectorLayer *layer, RuleToHandlerMap &handlers) const
add handlers
QHash< const QgsRuleBased3DRenderer::Rule *, QgsFeature3DHandler * > RuleToHandlerMap
QList< QgsRuleBased3DRenderer::Rule * > RuleList
Defines configuration of how a vector layer gets tiled for 3D rendering.
bool showBoundingBoxes() const
Returns whether to display bounding boxes of entity's tiles (for debugging).
static double maximumLeafExtent()
This is the maximum width or height a tile can have and still be considered a leaf node.
Represents a vector layer which manages a vector based dataset.
#define QgsDebugMsgLevel(str, level)
#define QGIS_CHECK_MAIN_THREAD_ACCESS