Skip to content
Permalink
Browse files

[3d] missing piece of the jigsaw: save 3d canvas as image (#5927)

  • Loading branch information
nirvn committed Dec 21, 2017
1 parent 909a0fc commit 1ddcac501c8bb0931e50a7a2eb53bee8b7aed7a5
@@ -17,6 +17,7 @@

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

#include "qgscameracontroller.h"
#include "qgs3dmapsettings.h"
@@ -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 );
@@ -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();
} );
}
}
@@ -17,6 +17,7 @@
#define QGS3DMAPCANVAS_H

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

namespace Qt3DExtras
{
@@ -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
@@ -30,6 +30,7 @@
#include <QDialogButtonBox>
#include <QProgressBar>
#include <QToolBar>
#include <QUrl>

Qgs3DMapCanvasDockWidget::Qgs3DMapCanvasDockWidget( QWidget *parent )
: QgsDockWidget( parent )
@@ -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 );
@@ -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 );
@@ -42,6 +42,7 @@ class Qgs3DMapCanvasDockWidget : public QgsDockWidget
private slots:
void resetView();
void configure();
void saveAsImage();

void onMainCanvasLayersChanged();
void onMainCanvasColorChanged();

0 comments on commit 1ddcac5

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