Skip to content

Commit

Permalink
[3d] Show feedback when loading tiles for 3D view (fixes #17565)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wonder-sk committed Dec 12, 2017
1 parent 5d4b581 commit 24c1c86
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/3d/chunks/qgschunkedentity_p.cpp
Expand Up @@ -120,6 +120,8 @@ void QgsChunkedEntity::update( const SceneState &state )
QElapsedTimer t;
t.start();

int oldJobsCount = pendingJobsCount();

QSet<QgsChunkNode *> activeBefore = QSet<QgsChunkNode *>::fromList( mActiveNodes );
mActiveNodes.clear();
mFrustumCulled = 0;
Expand Down Expand Up @@ -170,6 +172,9 @@ void QgsChunkedEntity::update( const SceneState &state )

mNeedsUpdate = false; // just updated

if ( pendingJobsCount() != oldJobsCount )
emit pendingJobsCountChanged();

qDebug() << "update: active " << mActiveNodes.count() << " enabled " << enabled << " disabled " << disabled << " | culled " << mFrustumCulled << " | loading " << mChunkLoaderQueue->count() << " loaded " << mReplacementQueue->count() << " | unloaded " << unloaded << " elapsed " << t.elapsed() << "ms";
}

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

int QgsChunkedEntity::pendingJobsCount() const
{
return mChunkLoaderQueue->count() + ( mActiveJob ? 1 : 0 );
}


void QgsChunkedEntity::update( QgsChunkNode *node, const SceneState &state )
{
Expand Down Expand Up @@ -306,6 +316,8 @@ void QgsChunkedEntity::requestResidency( QgsChunkNode *node )

void QgsChunkedEntity::onActiveJobFinished()
{
int oldJobsCount = pendingJobsCount();

QgsChunkQueueJob *job = qobject_cast<QgsChunkQueueJob *>( sender() );
Q_ASSERT( job );
Q_ASSERT( job == mActiveJob );
Expand Down Expand Up @@ -340,6 +352,9 @@ void QgsChunkedEntity::onActiveJobFinished()

// start another job - if any
startJob();

if ( pendingJobsCount() != oldJobsCount )
emit pendingJobsCountChanged();
}

void QgsChunkedEntity::startJob()
Expand Down
7 changes: 7 additions & 0 deletions src/3d/chunks/qgschunkedentity_p.h
Expand Up @@ -82,6 +82,9 @@ class QgsChunkedEntity : public Qt3DCore::QEntity
//! Returns the root node of the whole quadtree hierarchy of nodes
QgsChunkNode *rootNode() const { return mRootNode; }

//! Returns number of jobs pending for this entity until it is fully loaded/updated in the current view
int pendingJobsCount() const;

protected:
//! Cancels the background job that is currently in progress
void cancelActiveJob();
Expand All @@ -99,6 +102,10 @@ class QgsChunkedEntity : public Qt3DCore::QEntity
private slots:
void onActiveJobFinished();

signals:
//! Emitted when the number of pending jobs changes (some jobs have finished or some jobs have been just created)
void pendingJobsCountChanged();

protected:
//! root node of the quadtree hierarchy
QgsChunkNode *mRootNode = nullptr;
Expand Down
9 changes: 9 additions & 0 deletions src/3d/qgs3dmapscene.cpp
Expand Up @@ -166,6 +166,11 @@ void Qgs3DMapScene::viewZoomFull()
mCameraController->resetView( side ); // assuming FOV being 45 degrees
}

int Qgs3DMapScene::terrainPendingJobsCount() const
{
return mTerrain ? mTerrain->pendingJobsCount() : 0;
}

QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController )
{
Qt3DRender::QCamera *camera = cameraController->camera();
Expand Down Expand Up @@ -315,6 +320,10 @@ void Qgs3DMapScene::createTerrainDeferred()
}

mTerrainUpdateScheduled = false;

connect( mTerrain, &QgsTerrainEntity::pendingJobsCountChanged, this, &Qgs3DMapScene::terrainPendingJobsCountChanged );

emit terrainEntityChanged();
}

void Qgs3DMapScene::onBackgroundColorChanged()
Expand Down
11 changes: 10 additions & 1 deletion src/3d/qgs3dmapscene.h
Expand Up @@ -57,11 +57,20 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
//! Returns camera controller
QgsCameraController *cameraController() { return mCameraController; }
//! Returns terrain entity
QgsTerrainEntity *terrain() { return mTerrain; }
QgsTerrainEntity *terrainEntity() { return mTerrain; }

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

//! Returns number of pending jobs of the terrain entity
int terrainPendingJobsCount() const;

signals:
//! Emitted when the current terrain entity is replaced by a new one
void terrainEntityChanged();
//! Emitted when the number of terrain's pending jobs changes
void terrainPendingJobsCountChanged();

private slots:
void onCameraChanged();
void onFrameTriggered( float dt );
Expand Down
4 changes: 4 additions & 0 deletions src/app/3d/qgs3dmapcanvas.h
Expand Up @@ -39,8 +39,12 @@ class Qgs3DMapCanvas : public QWidget
//! Configure map scene being displayed. Takes ownership.
void setMap( Qgs3DMapSettings *map );

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

//! Returns access to the 3D scene (root 3D entity)
Qgs3DMapScene *scene() { return mScene; }

//! Returns access to the view's camera controller. Returns null pointer if the scene has not been initialized yet with setMap()
QgsCameraController *cameraController();

Expand Down
36 changes: 33 additions & 3 deletions src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -18,6 +18,7 @@
#include "qgisapp.h"
#include "qgs3dmapcanvas.h"
#include "qgs3dmapconfigwidget.h"
#include "qgs3dmapscene.h"
#include "qgscameracontroller.h"
#include "qgsmapcanvas.h"

Expand All @@ -27,6 +28,7 @@
#include <QBoxLayout>
#include <QDialog>
#include <QDialogButtonBox>
#include <QProgressBar>
#include <QToolBar>

Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
Expand All @@ -45,19 +47,38 @@ Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )

mCanvas = new Qgs3DMapCanvas( contentsWidget );
mCanvas->setMinimumSize( QSize( 200, 200 ) );
mCanvas->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );

QVBoxLayout *layout = new QVBoxLayout( contentsWidget );
mLabelPendingJobs = new QLabel( this );
mProgressPendingJobs = new QProgressBar( this );
mProgressPendingJobs->setRange( 0, 0 );

QHBoxLayout *topLayout = new QHBoxLayout;
topLayout->setContentsMargins( 0, 0, 0, 0 );
topLayout->setSpacing( style()->pixelMetric( QStyle::PM_LayoutHorizontalSpacing ) );
topLayout->addWidget( toolBar );
topLayout->addStretch( 1 );
topLayout->addWidget( mLabelPendingJobs );
topLayout->addWidget( mProgressPendingJobs );

QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 0 );
layout->addWidget( toolBar );
layout->addWidget( mCanvas, 1 );
layout->addLayout( topLayout );
layout->addWidget( mCanvas );

contentsWidget->setLayout( layout );

setWidget( contentsWidget );

onTerrainPendingJobsCountChanged();
}

void Qgs3DMapCanvasDockWidget::setMapSettings( Qgs3DMapSettings *map )
{
mCanvas->setMap( map );

connect( mCanvas->scene(), &Qgs3DMapScene::terrainPendingJobsCountChanged, this, &Qgs3DMapCanvasDockWidget::onTerrainPendingJobsCountChanged );
}

void Qgs3DMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
Expand Down Expand Up @@ -116,3 +137,12 @@ void Qgs3DMapCanvasDockWidget::onMainCanvasColorChanged()
{
mCanvas->map()->setBackgroundColor( mMainCanvas->canvasColor() );
}

void Qgs3DMapCanvasDockWidget::onTerrainPendingJobsCountChanged()
{
int count = mCanvas->scene() ? mCanvas->scene()->terrainPendingJobsCount() : 0;
mProgressPendingJobs->setVisible( count );
mLabelPendingJobs->setVisible( count );
if ( count )
mLabelPendingJobs->setText( tr( "Loading %1 tiles" ).arg( count ) );
}
9 changes: 7 additions & 2 deletions src/app/3d/qgs3dmapcanvasdockwidget.h
Expand Up @@ -18,10 +18,12 @@

#include "qgsdockwidget.h"

class Qgs3DMapCanvas;
class QgsMapCanvas;
class QLabel;
class QProgressBar;

class Qgs3DMapCanvas;
class Qgs3DMapSettings;
class QgsMapCanvas;


class Qgs3DMapCanvasDockWidget : public QgsDockWidget
Expand All @@ -43,10 +45,13 @@ class Qgs3DMapCanvasDockWidget : public QgsDockWidget

void onMainCanvasLayersChanged();
void onMainCanvasColorChanged();
void onTerrainPendingJobsCountChanged();

private:
Qgs3DMapCanvas *mCanvas = nullptr;
QgsMapCanvas *mMainCanvas = nullptr;
QProgressBar *mProgressPendingJobs = nullptr;
QLabel *mLabelPendingJobs = nullptr;
};

#endif // QGS3DMAPCANVASDOCKWIDGET_H

1 comment on commit 24c1c86

@nirvn
Copy link
Contributor

@nirvn nirvn commented on 24c1c86 Dec 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice UX improvement.

Please sign in to comment.