Skip to content
Permalink
Browse files

[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.
  • Loading branch information
wonder-sk committed Dec 8, 2017
1 parent 5d4b581 commit 24c1c860a93fdec8e831073cd9a8293a261aa57a
@@ -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;
@@ -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";
}

@@ -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 )
{
@@ -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 );
@@ -340,6 +352,9 @@ void QgsChunkedEntity::onActiveJobFinished()

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

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

void QgsChunkedEntity::startJob()
@@ -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();
@@ -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;
@@ -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();
@@ -315,6 +320,10 @@ void Qgs3DMapScene::createTerrainDeferred()
}

mTerrainUpdateScheduled = false;

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

emit terrainEntityChanged();
}

void Qgs3DMapScene::onBackgroundColorChanged()
@@ -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 );
@@ -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();

@@ -18,6 +18,7 @@
#include "qgisapp.h"
#include "qgs3dmapcanvas.h"
#include "qgs3dmapconfigwidget.h"
#include "qgs3dmapscene.h"
#include "qgscameracontroller.h"
#include "qgsmapcanvas.h"

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

Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
@@ -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 )
@@ -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 ) );
}
@@ -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
@@ -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

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn commented on 24c1c86 Dec 12, 2017

Very nice UX improvement.

Please sign in to comment.
You can’t perform that action at this time.