Skip to content

Commit 81fe1c2

Browse files
NEDJIMAbelgacemwonder-sk
authored andcommittedFeb 10, 2021
experiments with point budget
1 parent eb1ff08 commit 81fe1c2

12 files changed

+171
-75
lines changed
 

‎src/3d/chunks/qgschunkedentity_p.cpp

Lines changed: 87 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,25 @@ void QgsChunkedEntity::update( const SceneState &state )
142142

143143
int enabled = 0, disabled = 0, unloaded = 0;
144144

145-
Q_FOREACH ( QgsChunkNode *node, mActiveNodes )
145+
QList<QgsChunkNode *> newActiveNodes;
146+
int rendered = 0;
147+
for ( QgsChunkNode *node : mActiveNodes )
148+
{
149+
QgsChunkLoader *nodeLoader = mChunkLoaderFactory->createChunkLoader( node );
150+
if ( nodeLoader->primitiveCount() + rendered > nodeLoader->primitiveBudget() )
151+
break;
152+
rendered += nodeLoader->primitiveCount();
153+
newActiveNodes.append( node );
154+
}
155+
156+
mActiveNodes = newActiveNodes;
157+
158+
for ( QgsChunkNode *node : mActiveNodes )
146159
{
147160
if ( activeBefore.contains( node ) )
161+
{
148162
activeBefore.remove( node );
163+
}
149164
else
150165
{
151166
node->entity()->setEnabled( true );
@@ -154,7 +169,7 @@ void QgsChunkedEntity::update( const SceneState &state )
154169
}
155170

156171
// disable those that were active but will not be anymore
157-
Q_FOREACH ( QgsChunkNode *node, activeBefore )
172+
for ( QgsChunkNode *node : activeBefore )
158173
{
159174
node->entity()->setEnabled( false );
160175
++disabled;
@@ -241,69 +256,87 @@ int QgsChunkedEntity::pendingJobsCount() const
241256
}
242257

243258

244-
void QgsChunkedEntity::update( QgsChunkNode *node, const SceneState &state )
259+
void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
245260
{
246-
if ( Qgs3DUtils::isCullable( node->bbox(), state.viewProjectionMatrix ) )
261+
int renderedCount = 0;
262+
QVector<QgsChunkNode *> currentNodes;
263+
currentNodes.append( root );
264+
while ( !currentNodes.empty() )
247265
{
248-
++mFrustumCulled;
249-
return;
250-
}
266+
QVector<QgsChunkNode *> nextNodes;
267+
for ( QgsChunkNode * node : currentNodes )
268+
{
269+
QgsChunkLoader *nodeLoader = mChunkLoaderFactory->createChunkLoader( node );
251270

252-
// ensure we have child nodes (at least skeletons) available, if any
253-
if ( node->childCount() == -1 )
254-
{
255-
node->populateChildren( mChunkLoaderFactory->createChildren( node ) );
256-
}
271+
if ( Qgs3DUtils::isCullable( node->bbox(), state.viewProjectionMatrix ) )
272+
{
273+
++mFrustumCulled;
274+
continue;
275+
}
257276

258-
// make sure all nodes leading to children are always loaded
259-
// so that zooming out does not create issues
260-
requestResidency( node );
277+
// ensure we have child nodes (at least skeletons) available, if any
278+
if ( node->childCount() == -1 )
279+
{
280+
node->populateChildren( mChunkLoaderFactory->createChildren( node ) );
281+
}
261282

262-
if ( !node->entity() )
263-
{
264-
// this happens initially when root node is not ready yet
265-
return;
266-
}
283+
// make sure all nodes leading to children are always loaded
284+
// so that zooming out does not create issues
285+
requestResidency( node );
267286

268-
//QgsDebugMsgLevel( QStringLiteral( "%1|%2|%3 %4 %5" ).arg( node->tileX() ).arg( node->tileY() ).arg( node->tileZ() ).arg( mTau ).arg( screenSpaceError( node, state ) ), 2 );
269-
if ( node->childCount() == 0 )
270-
{
271-
// there's no children available for this node, so regardless of whether it has an acceptable error
272-
// or not, it's the best we'll ever get...
273-
mActiveNodes << node;
274-
}
275-
else if ( mTau > 0 && screenSpaceError( node, state ) <= mTau )
276-
{
277-
// acceptable error for the current chunk - let's render it
287+
if ( !node->entity() )
288+
{
289+
// this happens initially when root node is not ready yet
290+
continue;
291+
}
278292

279-
mActiveNodes << node;
280-
}
281-
else if ( node->allChildChunksResident( mCurrentTime ) )
282-
{
283-
// error is not acceptable and children are ready to be used - recursive descent
293+
//QgsDebugMsgLevel( QStringLiteral( "%1|%2|%3 %4 %5" ).arg( node->tileX() ).arg( node->tileY() ).arg( node->tileZ() ).arg( mTau ).arg( screenSpaceError( node, state ) ), 2 );
294+
if ( node->childCount() == 0 )
295+
{
296+
if ( nodeLoader != nullptr )
297+
renderedCount += nodeLoader->primitiveCount();
298+
// there's no children available for this node, so regardless of whether it has an acceptable error
299+
// or not, it's the best we'll ever get...
300+
mActiveNodes << node;
301+
}
302+
else if ( mTau > 0 && screenSpaceError( node, state ) <= mTau )
303+
{
304+
// acceptable error for the current chunk - let's render it
305+
mActiveNodes << node;
306+
}
307+
else if ( node->allChildChunksResident( mCurrentTime ) )
308+
{
309+
// error is not acceptable and children are ready to be used - recursive descent
310+
311+
312+
if ( mAdditiveStrategy )
313+
{
314+
// With additive strategy enabled, also all parent nodes are added to active nodes.
315+
// This is desired when child nodes add more detailed data rather than just replace
316+
// coarser data in parents. We use this e.g. with point cloud data.
317+
mActiveNodes << node;
318+
}
319+
320+
QgsChunkNode *const *children = node->children();
321+
for ( int i = 0; i < node->childCount(); ++i )
322+
{
323+
nextNodes.push_back( children[ i ] );
324+
}
325+
}
326+
else
327+
{
328+
// error is not acceptable but children are not ready either - still use parent but request children
329+
mActiveNodes << node;
284330

285-
if ( mAdditiveStrategy )
286-
{
287-
// With additive strategy enabled, also all parent nodes are added to active nodes.
288-
// This is desired when child nodes add more detailed data rather than just replace
289-
// coarser data in parents. We use this e.g. with point cloud data.
290-
mActiveNodes << node;
331+
QgsChunkNode *const *children = node->children();
332+
for ( int i = 0; i < node->childCount(); ++i )
333+
requestResidency( children[i] );
334+
}
291335
}
292-
293-
QgsChunkNode *const *children = node->children();
294-
for ( int i = 0; i < node->childCount(); ++i )
295-
update( children[i], state );
336+
currentNodes = nextNodes;
296337
}
297-
else
298-
{
299-
// error is not acceptable but children are not ready either - still use parent but request children
300338

301-
mActiveNodes << node;
302-
303-
QgsChunkNode *const *children = node->children();
304-
for ( int i = 0; i < node->childCount(); ++i )
305-
requestResidency( children[i] );
306-
}
339+
// qDebug() << "Rendered points: " << renderedCount;
307340
}
308341

309342

‎src/3d/chunks/qgschunkloader_p.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ class QgsChunkLoader : public QgsChunkQueueJob
4444
Q_OBJECT
4545
public:
4646
//! Construct chunk loader for a node
47-
QgsChunkLoader( QgsChunkNode *node )
47+
QgsChunkLoader( QgsChunkNode *node, int primitiveBudget = 1000000 )
4848
: QgsChunkQueueJob( node )
49+
, mPrimitiveBudget( primitiveBudget )
4950
{
5051
}
5152

@@ -55,6 +56,10 @@ class QgsChunkLoader : public QgsChunkQueueJob
5556
*/
5657
virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) = 0;
5758

59+
virtual int primitiveCount() { return 0; }
60+
virtual int primitiveBudget() const { return mPrimitiveBudget; }
61+
protected:
62+
int mPrimitiveBudget = 1000000;
5863
};
5964

6065

‎src/3d/qgspointcloudlayer3drenderer.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Qt3DCore::QEntity *QgsPointCloudLayer3DRenderer::createEntity( const Qgs3DMapSet
123123

124124
return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), maximumScreenError(), showBoundingBoxes(),
125125
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zScale(),
126-
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zOffset() );
126+
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zOffset(), mPointBudget );
127127
}
128128

129129
void QgsPointCloudLayer3DRenderer::setSymbol( QgsPointCloud3DSymbol *symbol )
@@ -140,6 +140,7 @@ void QgsPointCloudLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWri
140140
elem.setAttribute( QStringLiteral( "layer" ), mLayerRef.layerId );
141141
elem.setAttribute( QStringLiteral( "max-screen-error" ), maximumScreenError() );
142142
elem.setAttribute( QStringLiteral( "show-bounding-boxes" ), showBoundingBoxes() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
143+
elem.setAttribute( QStringLiteral( "point-budget" ), mPointBudget );
143144

144145
QDomElement elemSymbol = doc.createElement( QStringLiteral( "symbol" ) );
145146
if ( mSymbol )
@@ -159,6 +160,7 @@ void QgsPointCloudLayer3DRenderer::readXml( const QDomElement &elem, const QgsRe
159160
const QString symbolType = elemSymbol.attribute( QStringLiteral( "type" ) );
160161
mMaximumScreenError = elem.attribute( QStringLiteral( "max-screen-error" ), QStringLiteral( "1.0" ) ).toDouble();
161162
mShowBoundingBoxes = elem.attribute( QStringLiteral( "show-bounding-boxes" ), QStringLiteral( "0" ) ).toInt();
163+
mPointBudget = elem.attribute( QStringLiteral( "point-budget" ), QStringLiteral( "1000000" ) ).toInt();
162164

163165
if ( symbolType == QLatin1String( "single-color" ) )
164166
mSymbol.reset( new QgsSingleColorPointCloud3DSymbol );
@@ -200,3 +202,8 @@ void QgsPointCloudLayer3DRenderer::setShowBoundingBoxes( bool showBoundingBoxes
200202
mShowBoundingBoxes = showBoundingBoxes;
201203
}
202204

205+
void QgsPointCloudLayer3DRenderer::setPointRenderingBudget( int budget )
206+
{
207+
qDebug() << budget;
208+
mPointBudget = budget;
209+
}

‎src/3d/qgspointcloudlayer3drenderer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,15 @@ class _3D_EXPORT QgsPointCloudLayer3DRenderer : public QgsAbstract3DRenderer
260260
*/
261261
void setShowBoundingBoxes( bool showBoundingBoxes );
262262

263+
int pointRenderingBudget() const { return mPointBudget; };
264+
void setPointRenderingBudget( int budget );
265+
263266
private:
264267
QgsMapLayerRef mLayerRef; //!< Layer used to extract mesh data from
265268
std::unique_ptr< QgsPointCloud3DSymbol > mSymbol;
266269
double mMaximumScreenError = 1.0;
267270
bool mShowBoundingBoxes = false;
271+
int mPointBudget = 1000000;
268272

269273
private:
270274
#ifdef SIP_RUN

‎src/3d/qgspointcloudlayerchunkloader_p.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@
4747
///////////////
4848

4949
QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
50-
double zValueScale, double zValueOffset )
51-
: QgsChunkLoader( node )
50+
double zValueScale, double zValueOffset, int pointBudget, int count )
51+
: QgsChunkLoader( node, pointBudget )
5252
, mFactory( factory )
5353
, mContext( factory->mMap, std::move( symbol ), zValueScale, zValueOffset )
54+
, mPointsCount( count )
5455
{
5556
mContext.setIsCanceledCallback( [this] { return mCanceled; } );
5657

@@ -125,16 +126,21 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit
125126
return entity;
126127
}
127128

129+
int QgsPointCloudLayerChunkLoader::primitiveCount()
130+
{
131+
return mPointsCount;
132+
}
128133

129134
///////////////
130135

131136

132137
QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
133-
double zValueScale, double zValueOffset )
138+
double zValueScale, double zValueOffset, int pointBudget )
134139
: mMap( map )
135140
, mPointCloudIndex( pc )
136141
, mZValueScale( zValueScale )
137142
, mZValueOffset( zValueOffset )
143+
, mPointBudget( pointBudget )
138144
{
139145
mSymbol.reset( symbol );
140146
}
@@ -143,7 +149,8 @@ QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChun
143149
{
144150
QgsChunkNodeId id = node->tileId();
145151
Q_ASSERT( mPointCloudIndex->hasNode( IndexedPointCloudNode( id.d, id.x, id.y, id.z ) ) );
146-
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() ) ), mZValueScale, mZValueOffset );
152+
QgsPointCloudBlock *block = mPointCloudIndex->nodeData( IndexedPointCloudNode( id.d, id.x, id.y, id.z ), QgsPointCloudRequest() );
153+
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() ) ), mZValueScale, mZValueOffset, mPointBudget, block->pointCount() );
147154
}
148155

149156
QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, double zValueOffset );
@@ -202,9 +209,9 @@ QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset
202209
}
203210

204211

205-
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset )
212+
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
206213
: QgsChunkedEntity( maxScreenError,
207-
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueScale, zValueOffset ), true )
214+
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueScale, zValueOffset, pointBudget ), true )
208215
{
209216
setUsingAdditiveStrategy( true );
210217
setShowBoundingBoxes( showBoundingBoxes );

‎src/3d/qgspointcloudlayerchunkloader_p.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
6060
* The factory takes ownership over the passed \a symbol
6161
*/
6262
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
63-
double zValueScale, double zValueOffset );
63+
double zValueScale, double zValueOffset, int pointBudget );
6464

6565
//! Creates loader for the given chunk node. Ownership of the returned is passed to the caller.
6666
virtual QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override;
@@ -71,6 +71,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
7171
std::unique_ptr< QgsPointCloud3DSymbol > mSymbol;
7272
double mZValueScale = 1.0;
7373
double mZValueOffset = 0;
74+
int mPointBudget = 1000000;
7475
};
7576

7677

@@ -90,9 +91,11 @@ class QgsPointCloudLayerChunkLoader : public QgsChunkLoader
9091
* Constructs the loader
9192
* QgsPointCloudLayerChunkLoader takes ownership over symbol
9293
*/
93-
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueScale, double zValueOffset );
94+
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueScale, double zValueOffset, int pointBudget, int count );
9495
~QgsPointCloudLayerChunkLoader() override;
9596

97+
int primitiveCount() override;
98+
9699
virtual void cancel() override;
97100
virtual Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) override;
98101

@@ -102,6 +105,7 @@ class QgsPointCloudLayerChunkLoader : public QgsChunkLoader
102105
QgsPointCloud3DRenderContext mContext;
103106
bool mCanceled = false;
104107
QFutureWatcher<void> *mFutureWatcher = nullptr;
108+
int mPointsCount;
105109
};
106110

107111

@@ -120,7 +124,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity
120124
Q_OBJECT
121125
public:
122126
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes,
123-
double zValueScale, double zValueOffset );
127+
double zValueScale, double zValueOffset, int pointBudget );
124128

125129
~QgsPointCloudLayerChunkedEntity();
126130
};

‎src/3d/symbols/qgspointcloud3dsymbol_p.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,11 @@ void QgsClassificationPointCloud3DSymbolHandler::finalize( Qt3DCore::QEntity *pa
650650
makeEntity( parent, context, outNormal, false );
651651
}
652652

653+
653654
Qt3DRender::QGeometry *QgsClassificationPointCloud3DSymbolHandler::makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride )
654655
{
655656
return new QgsColorRampPointCloud3DGeometry( parent, data, byteStride );
656657
}
657658

659+
658660
/// @endcond

‎src/3d/symbols/qgspointcloud3dsymbol_p.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class QgsSingleColorPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHand
7777
bool prepare( const QgsPointCloud3DRenderContext &context ) override;
7878
void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context ) override;
7979
void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override;
80+
8081
private:
8182
Qt3DRender::QGeometry *makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride ) override;
8283
};
@@ -89,6 +90,7 @@ class QgsColorRampPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHandle
8990
bool prepare( const QgsPointCloud3DRenderContext &context ) override;
9091
void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context ) override;
9192
void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override;
93+
9294
private:
9395
Qt3DRender::QGeometry *makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride ) override;
9496
};
@@ -101,6 +103,7 @@ class QgsRGBPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolHandler
101103
bool prepare( const QgsPointCloud3DRenderContext &context ) override;
102104
void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context ) override;
103105
void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override;
106+
104107
private:
105108
Qt3DRender::QGeometry *makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride ) override;
106109
};
@@ -113,6 +116,7 @@ class QgsClassificationPointCloud3DSymbolHandler : public QgsPointCloud3DSymbolH
113116
bool prepare( const QgsPointCloud3DRenderContext &context ) override;
114117
void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const QgsPointCloud3DRenderContext &context ) override;
115118
void finalize( Qt3DCore::QEntity *parent, const QgsPointCloud3DRenderContext &context ) override;
119+
116120
private:
117121
Qt3DRender::QGeometry *makeGeometry( Qt3DCore::QNode *parent, const QgsPointCloud3DSymbolHandler::PointData &data, unsigned int byteStride ) override;
118122
};

‎src/app/3d/qgspointcloud3dsymbolwidget.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *la
101101
connect( mColorRampShaderMaxEdit, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloud3DSymbolWidget::minMaxChanged );
102102

103103
connect( mMaxScreenErrorSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, [&]() { emitChangedSignal(); } );
104+
connect( mPointBudgetSpinBox, qgis::overload<int>::of( &QSpinBox::valueChanged ), this, [&]() { emitChangedSignal(); } );
104105
connect( mShowBoundingBoxesCheckBox, &QCheckBox::stateChanged, [&]() { emitChangedSignal(); } );
105106

106107
if ( !symbol ) // if we have a symbol, this was already handled in setSymbol above
@@ -607,6 +608,16 @@ void QgsPointCloud3DSymbolWidget::setShowBoundingBoxes( bool showBoundingBoxes )
607608
whileBlocking( mShowBoundingBoxesCheckBox )->setChecked( showBoundingBoxes );
608609
}
609610

611+
void QgsPointCloud3DSymbolWidget::setPointBudget( int budget )
612+
{
613+
whileBlocking( mPointBudgetSpinBox )->setValue( budget );
614+
}
615+
616+
int QgsPointCloud3DSymbolWidget::pointBudget() const
617+
{
618+
return mPointBudgetSpinBox->value();
619+
}
620+
610621
double QgsPointCloud3DSymbolWidget::showBoundingBoxes() const
611622
{
612623
return mShowBoundingBoxesCheckBox->isChecked();

‎src/app/3d/qgspointcloud3dsymbolwidget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DS
4141
void setShowBoundingBoxes( bool showBoundingBoxes );
4242
double showBoundingBoxes() const;
4343

44+
void setPointBudget( int budget );
45+
int pointBudget() const;
46+
4447
void connectChildPanels( QgsPanelWidget *parent );
4548

4649
private slots:

‎src/app/3d/qgspointcloudlayer3drendererwidget.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ void QgsPointCloudLayer3DRendererWidget::setRenderer( const QgsPointCloudLayer3D
4646
{
4747
mWidgetPointCloudSymbol->setSymbol( const_cast<QgsPointCloud3DSymbol *>( renderer->symbol() ) );
4848
mWidgetPointCloudSymbol->setMaximumScreenError( renderer->maximumScreenError() );
49+
mWidgetPointCloudSymbol->setPointBudget( renderer->pointRenderingBudget() );
4950
mWidgetPointCloudSymbol->setShowBoundingBoxes( renderer->showBoundingBoxes() );
5051
}
5152
}
@@ -57,6 +58,7 @@ QgsPointCloudLayer3DRenderer *QgsPointCloudLayer3DRendererWidget::renderer()
5758
renderer->setSymbol( sym );
5859
renderer->setLayer( qobject_cast<QgsPointCloudLayer *>( mLayer ) );
5960
renderer->setMaximumScreenError( mWidgetPointCloudSymbol->maximumScreenError() );
61+
renderer->setPointRenderingBudget( mWidgetPointCloudSymbol->pointBudget() );
6062
renderer->setShowBoundingBoxes( mWidgetPointCloudSymbol->showBoundingBoxes() );
6163
return renderer;
6264
}

‎src/ui/3d/qgspointcloud3dsymbolwidget.ui

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@
4141
<property name="rightMargin">
4242
<number>3</number>
4343
</property>
44+
<item row="3" column="0" colspan="2">
45+
<widget class="QCheckBox" name="mShowBoundingBoxesCheckBox">
46+
<property name="text">
47+
<string>Show bounding boxes</string>
48+
</property>
49+
</widget>
50+
</item>
51+
<item row="0" column="0">
52+
<widget class="QLabel" name="lblTransparency_4">
53+
<property name="text">
54+
<string>Point size</string>
55+
</property>
56+
</widget>
57+
</item>
4458
<item row="0" column="1">
4559
<widget class="QgsDoubleSpinBox" name="mPointSizeSpinBox">
4660
<property name="maximum">
@@ -51,10 +65,10 @@
5165
</property>
5266
</widget>
5367
</item>
54-
<item row="0" column="0">
55-
<widget class="QLabel" name="lblTransparency_4">
68+
<item row="1" column="0">
69+
<widget class="QLabel" name="labelMaximumScreenSpaceError">
5670
<property name="text">
57-
<string>Point size</string>
71+
<string>Maximum screen space error</string>
5872
</property>
5973
</widget>
6074
</item>
@@ -68,17 +82,17 @@
6882
</property>
6983
</widget>
7084
</item>
71-
<item row="1" column="0">
72-
<widget class="QLabel" name="label">
85+
<item row="2" column="0">
86+
<widget class="QLabel" name="labelPointBudget">
7387
<property name="text">
74-
<string>Maximum screen space error</string>
88+
<string>Point budget</string>
7589
</property>
7690
</widget>
7791
</item>
78-
<item row="2" column="0" colspan="2">
79-
<widget class="QCheckBox" name="mShowBoundingBoxesCheckBox">
80-
<property name="text">
81-
<string>Show bounding boxes</string>
92+
<item row="2" column="1">
93+
<widget class="QSpinBox" name="mPointBudgetSpinBox">
94+
<property name="maximum">
95+
<number>999999999</number>
8296
</property>
8397
</widget>
8498
</item>

0 commit comments

Comments
 (0)
Please sign in to comment.