Skip to content

Commit 832d27c

Browse files
committed
Make the GUI work without crashing (avoid embedded event loop)
1 parent f08ebab commit 832d27c

6 files changed

+103
-16
lines changed

src/3d/qgscameracontroller.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ void QgsCameraController::setLookingAtPoint( const QgsVector3D &point, float dis
419419

420420
void QgsCameraController::setCameraPose( const QgsCameraPose &camPose )
421421
{
422+
if ( camPose == mCameraPose )
423+
return;
424+
422425
mCameraPose = camPose;
423426

424427
if ( mCamera )

src/3d/qgslayoutitem3dmap.cpp

+81-13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
QgsLayoutItem3DMap::QgsLayoutItem3DMap( QgsLayout *layout )
2727
: QgsLayoutItem( layout )
2828
{
29+
connect( this, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItem3DMap::onSizePositionChanged );
2930
}
3031

3132
QgsLayoutItem3DMap::~QgsLayoutItem3DMap() = default;
@@ -43,30 +44,80 @@ int QgsLayoutItem3DMap::type() const
4344

4445
void QgsLayoutItem3DMap::draw( QgsLayoutItemRenderContext &context )
4546
{
47+
QgsRenderContext &ctx = context.renderContext();
48+
QPainter *painter = ctx.painter();
49+
50+
int w = static_cast<int>( std::ceil( rect().width() * ctx.scaleFactor() ) );
51+
int h = static_cast<int>( std::ceil( rect().height() * ctx.scaleFactor() ) );
52+
QRect r( 0, 0, w, h );
53+
54+
painter->save();
55+
4656
if ( !mSettings )
57+
{
58+
painter->drawText( r, Qt::AlignCenter, tr( "Scene not set" ) );
59+
painter->restore();
60+
return;
61+
}
62+
63+
if ( !mCapturedImage.isNull() )
64+
{
65+
painter->drawImage( r, mCapturedImage );
66+
painter->restore();
4767
return;
68+
}
69+
70+
// we do not have a cached image of the rendered scene - let's request one from the engine
71+
72+
painter->drawText( r, Qt::AlignCenter, tr( "Loading" ) );
73+
painter->restore();
4874

49-
QgsOffscreen3DEngine engine;
5075
QSizeF sizePixels = mLayout->renderContext().measurementConverter().convert( sizeWithUnits(), QgsUnitTypes::LayoutPixels ).toQSizeF();
51-
engine.setSize( QSize( static_cast<int>( std::ceil( sizePixels.width() ) ),
52-
static_cast<int>( std::ceil( sizePixels.height() ) ) ) );
76+
QSize sizePixelsInt = QSize( static_cast<int>( std::ceil( sizePixels.width() ) ),
77+
static_cast<int>( std::ceil( sizePixels.height() ) ) );
5378

54-
Qgs3DMapScene *scene = new Qgs3DMapScene( *mSettings, &engine );
55-
engine.setRootEntity( scene );
79+
if ( !mEngine )
80+
{
81+
mEngine.reset( new QgsOffscreen3DEngine );
82+
connect( mEngine.get(), &QgsAbstract3DEngine::imageCaptured, this, &QgsLayoutItem3DMap::onImageCaptured );
5683

57-
scene->cameraController()->setCameraPose( mCameraPose );
84+
mEngine->setSize( sizePixelsInt );
5885

59-
// XXX this should not be needed, but without it the scene often
60-
// is not completely ready (e.g. a missing terrain tile).
61-
// leaving it here until a more robust solution is found...
62-
Qgs3DUtils::captureSceneImage( engine, scene );
86+
mScene = new Qgs3DMapScene( *mSettings, mEngine.get() );
87+
connect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );
6388

64-
QImage img = Qgs3DUtils::captureSceneImage( engine, scene );
89+
mEngine->setRootEntity( mScene );
90+
}
6591

66-
QgsRenderContext &ctx = context.renderContext();
67-
ctx.painter()->drawImage( 0, 0, img );
92+
if ( mEngine->size() != sizePixelsInt )
93+
mEngine->setSize( sizePixelsInt );
94+
95+
mScene->cameraController()->setCameraPose( mCameraPose );
96+
97+
onSceneStateChanged();
98+
}
99+
100+
void QgsLayoutItem3DMap::onImageCaptured( const QImage &img )
101+
{
102+
mCapturedImage = img;
103+
update();
104+
}
105+
106+
void QgsLayoutItem3DMap::onSceneStateChanged()
107+
{
108+
if ( mCapturedImage.isNull() && mScene->sceneState() == Qgs3DMapScene::Ready )
109+
{
110+
mEngine->requestCaptureImage();
111+
}
112+
}
113+
114+
void QgsLayoutItem3DMap::onSizePositionChanged()
115+
{
116+
mCapturedImage = QImage();
117+
update();
68118
}
69119

120+
70121
bool QgsLayoutItem3DMap::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
71122
{
72123
if ( mSettings )
@@ -83,6 +134,7 @@ bool QgsLayoutItem3DMap::writePropertiesToElement( QDomElement &element, QDomDoc
83134

84135
bool QgsLayoutItem3DMap::readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context )
85136
{
137+
Q_UNUSED( document );
86138
QDomElement elemSettings = element.firstChildElement( "qgis3d" );
87139
if ( !elemSettings.isNull() )
88140
{
@@ -102,4 +154,20 @@ bool QgsLayoutItem3DMap::readPropertiesFromElement( const QDomElement &element,
102154
void QgsLayoutItem3DMap::setMapSettings( Qgs3DMapSettings *settings )
103155
{
104156
mSettings.reset( settings );
157+
158+
mEngine.reset();
159+
mScene = nullptr;
160+
161+
mCapturedImage = QImage();
162+
update();
163+
}
164+
165+
void QgsLayoutItem3DMap::setCameraPose( const QgsCameraPose &pose )
166+
{
167+
if ( mCameraPose == pose )
168+
return;
169+
170+
mCameraPose = pose;
171+
mCapturedImage = QImage();
172+
update();
105173
}

src/3d/qgslayoutitem3dmap.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include "qgscamerapose.h"
2424

2525

26+
class Qgs3DMapScene;
2627
class Qgs3DMapSettings;
28+
class QgsOffscreen3DEngine;
2729

2830
/**
2931
* \ingroup 3d
@@ -74,7 +76,7 @@ class _3D_EXPORT QgsLayoutItem3DMap : public QgsLayoutItem
7476
virtual int type() const override;
7577

7678
//! Configures camera view
77-
void setCameraPose( const QgsCameraPose &pose ) { mCameraPose = pose; }
79+
void setCameraPose( const QgsCameraPose &pose );
7880
//! Returns camera view
7981
QgsCameraPose cameraPose() const { return mCameraPose; }
8082

@@ -92,9 +94,18 @@ class _3D_EXPORT QgsLayoutItem3DMap : public QgsLayoutItem
9294
bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
9395
bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override;
9496

97+
private slots:
98+
void onImageCaptured( const QImage &img );
99+
void onSceneStateChanged();
100+
void onSizePositionChanged();
101+
95102
private:
96103
std::unique_ptr<Qgs3DMapSettings> mSettings;
104+
std::unique_ptr<QgsOffscreen3DEngine> mEngine;
105+
Qgs3DMapScene *mScene = nullptr; //!< 3D scene (owned by the 3D engine)
106+
QImage mCapturedImage;
97107
QgsCameraPose mCameraPose;
108+
bool mDrawing = false;
98109
};
99110

100111
#endif // QGSLAYOUTITEM3DMAP_H

src/app/layout/qgslayout3dmapwidget.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ QgsLayout3DMapWidget::QgsLayout3DMapWidget( QgsLayoutItem3DMap *map3D )
2727
{
2828
setupUi( this );
2929

30+
//add widget for general composer item properties
31+
mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, map3D );
32+
mainLayout->addWidget( mItemPropertiesWidget );
33+
3034
mMenu3DCanvases = new QMenu( this );
3135
mCopySettingsButton->setMenu( mMenu3DCanvases );
3236
connect( mMenu3DCanvases, &QMenu::aboutToShow, this, [ = ]

src/app/layout/qgslayout3dmapwidget.h

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class QgsLayout3DMapWidget : public QgsLayoutItemBaseWidget, private Ui::QgsLayo
3434

3535
private:
3636
QPointer< QgsLayoutItem3DMap > mMap3D;
37+
QgsLayoutItemPropertiesWidget *mItemPropertiesWidget = nullptr;
3738
QMenu *mMenu3DCanvases = nullptr;
3839
};
3940

src/ui/layout/qgslayout3dmapwidgetbase.ui

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@
5454
<property name="geometry">
5555
<rect>
5656
<x>0</x>
57-
<y>-65</y>
57+
<y>0</y>
5858
<width>510</width>
5959
<height>635</height>
6060
</rect>
6161
</property>
62-
<layout class="QVBoxLayout" name="verticalLayout_6">
62+
<layout class="QVBoxLayout" name="mainLayout">
6363
<item>
6464
<widget class="QGroupBox" name="groupBox_3">
6565
<property name="title">

0 commit comments

Comments
 (0)