Skip to content

Commit

Permalink
[3d] missing piece of the jigsaw: save 3d canvas as image (#5927)
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Dec 21, 2017
1 parent 909a0fc commit 1ddcac5
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/app/3d/qgs3dmapcanvas.cpp
Expand Up @@ -17,6 +17,7 @@

#include <QBoxLayout>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QRenderCapture>

#include "qgscameracontroller.h"
#include "qgs3dmapsettings.h"
Expand All @@ -27,6 +28,11 @@ Qgs3DMapCanvas::Qgs3DMapCanvas( QWidget *parent )
: QWidget( parent )
{
mWindow3D = new Qt3DExtras::Qt3DWindow;

mCapture = new Qt3DRender::QRenderCapture;
mWindow3D->activeFrameGraph()->setParent( mCapture );
mWindow3D->setActiveFrameGraph( mCapture );

mContainer = QWidget::createWindowContainer( mWindow3D );

QHBoxLayout *hLayout = new QHBoxLayout( this );
Expand Down Expand Up @@ -89,3 +95,19 @@ void Qgs3DMapCanvas::setViewFromTop( const QgsPointXY &center, float distance, f
float worldY = center.y() - mMap->origin().y();
mScene->cameraController()->setViewFromTop( worldX, -worldY, distance, rotation );
}

void Qgs3DMapCanvas::saveAsImage( const QString fileName, const QString fileFormat )
{
if ( !fileName.isEmpty() )
{
Qt3DRender::QRenderCaptureReply *captureReply;
captureReply = mCapture->requestCapture();
connect( captureReply, &Qt3DRender::QRenderCaptureReply::completed, this, [ = ]
{
captureReply->image().save( fileName, fileFormat.toLocal8Bit().data() );
emit savedAsImage( fileName );

captureReply->deleteLater();
} );
}
}
11 changes: 11 additions & 0 deletions src/app/3d/qgs3dmapcanvas.h
Expand Up @@ -17,6 +17,7 @@
#define QGS3DMAPCANVAS_H

#include <QWidget>
#include <Qt3DRender/QRenderCapture>

namespace Qt3DExtras
{
Expand Down Expand Up @@ -54,12 +55,22 @@ class Qgs3DMapCanvas : public QWidget
//! Sets camera position to look down at the given point (in map coordinates) in given distance from plane with zero elevation
void setViewFromTop( const QgsPointXY &center, float distance, float rotation = 0 );

//! Saves the current scene as an image
void saveAsImage( const QString fileName, const QString fileFormat );

signals:
//! Emitted when the 3D map canvas was successfully saved as image
void savedAsImage( const QString fileName );

protected:
void resizeEvent( QResizeEvent *ev ) override;

private:
//! 3D window with all the 3D magic inside
Qt3DExtras::Qt3DWindow *mWindow3D = nullptr;
//! Frame graph node for render capture
Qt3DRender::QRenderCapture *mCapture = nullptr;

//! Container QWidget that encapsulates mWindow3D so we can use it embedded in ordinary widgets app
QWidget *mContainer = nullptr;
//! Description of the 3D scene
Expand Down
17 changes: 17 additions & 0 deletions src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -30,6 +30,7 @@
#include <QDialogButtonBox>
#include <QProgressBar>
#include <QToolBar>
#include <QUrl>

Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
: QgsDockWidget( parent )
Expand All @@ -42,13 +43,20 @@ Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
toolBar->setIconSize( QgisApp::instance()->iconSize( true ) );
toolBar->addAction( QgsApplication::getThemeIcon( QStringLiteral( "mActionZoomFullExtent.svg" ) ),
tr( "Zoom Full" ), this, &Qgs3DMapCanvasDockWidget::resetView );
toolBar->addAction( QgsApplication::getThemeIcon( QStringLiteral( "mActionSaveMapAsImage.svg" ) ),
tr( "Save as image..." ), this, &Qgs3DMapCanvasDockWidget::saveAsImage );
toolBar->addAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconProperties.svg" ) ),
tr( "Configure" ), this, &Qgs3DMapCanvasDockWidget::configure );

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

connect( mCanvas, &Qgs3DMapCanvas::savedAsImage, this, [ = ]( const QString fileName )
{
QgisApp::instance()->messageBar()->pushSuccess( tr( "Save as Image" ), tr( "Successfully saved the 3D map to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( QFileInfo( fileName ).path() ).toString(), fileName ) );
} );

mLabelPendingJobs = new QLabel( this );
mProgressPendingJobs = new QProgressBar( this );
mProgressPendingJobs->setRange( 0, 0 );
Expand All @@ -74,6 +82,15 @@ Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
onTerrainPendingJobsCountChanged();
}

void Qgs3DMapCanvasDockWidget::saveAsImage()
{
QPair< QString, QString> fileNameAndFilter = QgsGuiUtils::getSaveAsImageName( this, tr( "Choose a file name to save the 3D map canvas to an image" ) );
if ( !fileNameAndFilter.first.isEmpty() )
{
mCanvas->saveAsImage( fileNameAndFilter.first, fileNameAndFilter.second );
}
}

void Qgs3DMapCanvasDockWidget::setMapSettings( Qgs3DMapSettings *map )
{
mCanvas->setMap( map );
Expand Down
1 change: 1 addition & 0 deletions src/app/3d/qgs3dmapcanvasdockwidget.h
Expand Up @@ -42,6 +42,7 @@ class Qgs3DMapCanvasDockWidget : public QgsDockWidget
private slots:
void resetView();
void configure();
void saveAsImage();

void onMainCanvasLayersChanged();
void onMainCanvasColorChanged();
Expand Down

0 comments on commit 1ddcac5

Please sign in to comment.