Skip to content

Commit 24c1c86

Browse files
committedDec 12, 2017
[3d] Show feedback when loading tiles for 3D view (fixes #17565)
There was no indication whether something is going on behind the scenes, leaving user to wonder whether there is something to wait for or the scene is already loaded in full detail.
1 parent 5d4b581 commit 24c1c86

File tree

7 files changed

+85
-6
lines changed

7 files changed

+85
-6
lines changed
 

‎src/3d/chunks/qgschunkedentity_p.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ void QgsChunkedEntity::update( const SceneState &state )
120120
QElapsedTimer t;
121121
t.start();
122122

123+
int oldJobsCount = pendingJobsCount();
124+
123125
QSet<QgsChunkNode *> activeBefore = QSet<QgsChunkNode *>::fromList( mActiveNodes );
124126
mActiveNodes.clear();
125127
mFrustumCulled = 0;
@@ -170,6 +172,9 @@ void QgsChunkedEntity::update( const SceneState &state )
170172

171173
mNeedsUpdate = false; // just updated
172174

175+
if ( pendingJobsCount() != oldJobsCount )
176+
emit pendingJobsCountChanged();
177+
173178
qDebug() << "update: active " << mActiveNodes.count() << " enabled " << enabled << " disabled " << disabled << " | culled " << mFrustumCulled << " | loading " << mChunkLoaderQueue->count() << " loaded " << mReplacementQueue->count() << " | unloaded " << unloaded << " elapsed " << t.elapsed() << "ms";
174179
}
175180

@@ -215,6 +220,11 @@ void QgsChunkedEntity::updateNodes( const QList<QgsChunkNode *> &nodes, QgsChunk
215220
startJob();
216221
}
217222

223+
int QgsChunkedEntity::pendingJobsCount() const
224+
{
225+
return mChunkLoaderQueue->count() + ( mActiveJob ? 1 : 0 );
226+
}
227+
218228

219229
void QgsChunkedEntity::update( QgsChunkNode *node, const SceneState &state )
220230
{
@@ -306,6 +316,8 @@ void QgsChunkedEntity::requestResidency( QgsChunkNode *node )
306316

307317
void QgsChunkedEntity::onActiveJobFinished()
308318
{
319+
int oldJobsCount = pendingJobsCount();
320+
309321
QgsChunkQueueJob *job = qobject_cast<QgsChunkQueueJob *>( sender() );
310322
Q_ASSERT( job );
311323
Q_ASSERT( job == mActiveJob );
@@ -340,6 +352,9 @@ void QgsChunkedEntity::onActiveJobFinished()
340352

341353
// start another job - if any
342354
startJob();
355+
356+
if ( pendingJobsCount() != oldJobsCount )
357+
emit pendingJobsCountChanged();
343358
}
344359

345360
void QgsChunkedEntity::startJob()

‎src/3d/chunks/qgschunkedentity_p.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class QgsChunkedEntity : public Qt3DCore::QEntity
8282
//! Returns the root node of the whole quadtree hierarchy of nodes
8383
QgsChunkNode *rootNode() const { return mRootNode; }
8484

85+
//! Returns number of jobs pending for this entity until it is fully loaded/updated in the current view
86+
int pendingJobsCount() const;
87+
8588
protected:
8689
//! Cancels the background job that is currently in progress
8790
void cancelActiveJob();
@@ -99,6 +102,10 @@ class QgsChunkedEntity : public Qt3DCore::QEntity
99102
private slots:
100103
void onActiveJobFinished();
101104

105+
signals:
106+
//! Emitted when the number of pending jobs changes (some jobs have finished or some jobs have been just created)
107+
void pendingJobsCountChanged();
108+
102109
protected:
103110
//! root node of the quadtree hierarchy
104111
QgsChunkNode *mRootNode = nullptr;

‎src/3d/qgs3dmapscene.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ void Qgs3DMapScene::viewZoomFull()
166166
mCameraController->resetView( side ); // assuming FOV being 45 degrees
167167
}
168168

169+
int Qgs3DMapScene::terrainPendingJobsCount() const
170+
{
171+
return mTerrain ? mTerrain->pendingJobsCount() : 0;
172+
}
173+
169174
QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController )
170175
{
171176
Qt3DRender::QCamera *camera = cameraController->camera();
@@ -315,6 +320,10 @@ void Qgs3DMapScene::createTerrainDeferred()
315320
}
316321

317322
mTerrainUpdateScheduled = false;
323+
324+
connect( mTerrain, &QgsTerrainEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::terrainPendingJobsCountChanged );
325+
326+
emit terrainEntityChanged();
318327
}
319328

320329
void Qgs3DMapScene::onBackgroundColorChanged()

‎src/3d/qgs3dmapscene.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,20 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
5757
//! Returns camera controller
5858
QgsCameraController *cameraController() { return mCameraController; }
5959
//! Returns terrain entity
60-
QgsTerrainEntity *terrain() { return mTerrain; }
60+
QgsTerrainEntity *terrainEntity() { return mTerrain; }
6161

6262
//! Resets camera view to show the whole scene (top view)
6363
void viewZoomFull();
6464

65+
//! Returns number of pending jobs of the terrain entity
66+
int terrainPendingJobsCount() const;
67+
68+
signals:
69+
//! Emitted when the current terrain entity is replaced by a new one
70+
void terrainEntityChanged();
71+
//! Emitted when the number of terrain's pending jobs changes
72+
void terrainPendingJobsCountChanged();
73+
6574
private slots:
6675
void onCameraChanged();
6776
void onFrameTriggered( float dt );

‎src/app/3d/qgs3dmapcanvas.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ class Qgs3DMapCanvas : public QWidget
3939
//! Configure map scene being displayed. Takes ownership.
4040
void setMap( Qgs3DMapSettings *map );
4141

42+
//! Returns access to the 3D scene configuration
4243
Qgs3DMapSettings *map() { return mMap; }
4344

45+
//! Returns access to the 3D scene (root 3D entity)
46+
Qgs3DMapScene *scene() { return mScene; }
47+
4448
//! Returns access to the view's camera controller. Returns null pointer if the scene has not been initialized yet with setMap()
4549
QgsCameraController *cameraController();
4650

‎src/app/3d/qgs3dmapcanvasdockwidget.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "qgisapp.h"
1919
#include "qgs3dmapcanvas.h"
2020
#include "qgs3dmapconfigwidget.h"
21+
#include "qgs3dmapscene.h"
2122
#include "qgscameracontroller.h"
2223
#include "qgsmapcanvas.h"
2324

@@ -27,6 +28,7 @@
2728
#include <QBoxLayout>
2829
#include <QDialog>
2930
#include <QDialogButtonBox>
31+
#include <QProgressBar>
3032
#include <QToolBar>
3133

3234
Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
@@ -45,19 +47,38 @@ Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
4547

4648
mCanvas = new Qgs3DMapCanvas( contentsWidget );
4749
mCanvas->setMinimumSize( QSize( 200, 200 ) );
50+
mCanvas->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
4851

49-
QVBoxLayout *layout = new QVBoxLayout( contentsWidget );
52+
mLabelPendingJobs = new QLabel( this );
53+
mProgressPendingJobs = new QProgressBar( this );
54+
mProgressPendingJobs->setRange( 0, 0 );
55+
56+
QHBoxLayout *topLayout = new QHBoxLayout;
57+
topLayout->setContentsMargins( 0, 0, 0, 0 );
58+
topLayout->setSpacing( style()->pixelMetric( QStyle::PM_LayoutHorizontalSpacing ) );
59+
topLayout->addWidget( toolBar );
60+
topLayout->addStretch( 1 );
61+
topLayout->addWidget( mLabelPendingJobs );
62+
topLayout->addWidget( mProgressPendingJobs );
63+
64+
QVBoxLayout *layout = new QVBoxLayout;
5065
layout->setContentsMargins( 0, 0, 0, 0 );
5166
layout->setSpacing( 0 );
52-
layout->addWidget( toolBar );
53-
layout->addWidget( mCanvas, 1 );
67+
layout->addLayout( topLayout );
68+
layout->addWidget( mCanvas );
69+
70+
contentsWidget->setLayout( layout );
5471

5572
setWidget( contentsWidget );
73+
74+
onTerrainPendingJobsCountChanged();
5675
}
5776

5877
void Qgs3DMapCanvasDockWidget::setMapSettings( Qgs3DMapSettings *map )
5978
{
6079
mCanvas->setMap( map );
80+
81+
connect( mCanvas->scene(), &Qgs3DMapScene::terrainPendingJobsCountChanged, this, &Qgs3DMapCanvasDockWidget::onTerrainPendingJobsCountChanged );
6182
}
6283

6384
void Qgs3DMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
@@ -116,3 +137,12 @@ void Qgs3DMapCanvasDockWidget::onMainCanvasColorChanged()
116137
{
117138
mCanvas->map()->setBackgroundColor( mMainCanvas->canvasColor() );
118139
}
140+
141+
void Qgs3DMapCanvasDockWidget::onTerrainPendingJobsCountChanged()
142+
{
143+
int count = mCanvas->scene() ? mCanvas->scene()->terrainPendingJobsCount() : 0;
144+
mProgressPendingJobs->setVisible( count );
145+
mLabelPendingJobs->setVisible( count );
146+
if ( count )
147+
mLabelPendingJobs->setText( tr( "Loading %1 tiles" ).arg( count ) );
148+
}

‎src/app/3d/qgs3dmapcanvasdockwidget.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818

1919
#include "qgsdockwidget.h"
2020

21-
class Qgs3DMapCanvas;
22-
class QgsMapCanvas;
21+
class QLabel;
22+
class QProgressBar;
2323

24+
class Qgs3DMapCanvas;
2425
class Qgs3DMapSettings;
26+
class QgsMapCanvas;
2527

2628

2729
class Qgs3DMapCanvasDockWidget : public QgsDockWidget
@@ -43,10 +45,13 @@ class Qgs3DMapCanvasDockWidget : public QgsDockWidget
4345

4446
void onMainCanvasLayersChanged();
4547
void onMainCanvasColorChanged();
48+
void onTerrainPendingJobsCountChanged();
4649

4750
private:
4851
Qgs3DMapCanvas *mCanvas = nullptr;
4952
QgsMapCanvas *mMainCanvas = nullptr;
53+
QProgressBar *mProgressPendingJobs = nullptr;
54+
QLabel *mLabelPendingJobs = nullptr;
5055
};
5156

5257
#endif // QGS3DMAPCANVASDOCKWIDGET_H

1 commit comments

Comments
 (1)

nirvn commented on Dec 12, 2017

@nirvn
Contributor

Very nice UX improvement.

Please sign in to comment.