QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgslayoutitem3dmap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitem3dmap.cpp
3  --------------------------------------
4  Date : August 2018
5  Copyright : (C) 2018 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgslayoutitem3dmap.h"
17 
18 #include "qgs3dmapscene.h"
19 #include "qgs3dutils.h"
20 #include "qgscameracontroller.h"
21 #include "qgslayout.h"
22 #include "qgslayoutmodel.h"
23 #include "qgslayoutitemregistry.h"
24 #include "qgsoffscreen3dengine.h"
27 #include "qgswindow3dengine.h"
28 
30  : QgsLayoutItem( layout )
31 {
32  assignFreeId();
33 
34  connect( this, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItem3DMap::onSizePositionChanged );
35 }
36 
38 
39 
41 {
42  return new QgsLayoutItem3DMap( layout );
43 }
44 
46 {
48 }
49 
51 {
52  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItem3DMap.svg" ) );
53 }
54 
56 {
57  if ( !mLayout )
58  return;
59 
60  QList<QgsLayoutItem3DMap *> mapsList;
61  mLayout->layoutItems( mapsList );
62 
63  int maxId = -1;
64  bool used = false;
65  for ( QgsLayoutItem3DMap *map : qgis::as_const( mapsList ) )
66  {
67  if ( map == this )
68  continue;
69 
70  if ( map->mMapId == mMapId )
71  used = true;
72 
73  maxId = std::max( maxId, map->mMapId );
74  }
75  if ( used )
76  {
77  mMapId = maxId + 1;
78  mLayout->itemsModel()->updateItemDisplayName( this );
79  }
80  updateToolTip();
81 }
82 
84 {
85  if ( !QgsLayoutItem::id().isEmpty() )
86  {
87  return QgsLayoutItem::id();
88  }
89 
90  return tr( "3D Map %1" ).arg( mMapId );
91 }
92 
93 void QgsLayoutItem3DMap::updateToolTip()
94 {
95  setToolTip( displayName() );
96 }
97 
99 {
100  QgsRenderContext &ctx = context.renderContext();
101  QPainter *painter = ctx.painter();
102 
103  int w = static_cast<int>( std::ceil( rect().width() * ctx.scaleFactor() ) );
104  int h = static_cast<int>( std::ceil( rect().height() * ctx.scaleFactor() ) );
105  QRect r( 0, 0, w, h );
106 
107  painter->save();
108 
109  if ( !mSettings )
110  {
111  painter->drawText( r, Qt::AlignCenter, tr( "Scene not set" ) );
112  painter->restore();
113  return;
114  }
115 
116  if ( mSettings->backgroundColor() != backgroundColor() )
117  {
118  mSettings->setBackgroundColor( backgroundColor() );
119  mCapturedImage = QImage();
120  }
121 
122  if ( !mCapturedImage.isNull() )
123  {
124  painter->drawImage( r, mCapturedImage );
125  painter->restore();
126  return;
127  }
128 
129  // we do not have a cached image of the rendered scene - let's request one from the engine
130 
131  if ( mLayout->renderContext().isPreviewRender() )
132  {
133  painter->drawText( r, Qt::AlignCenter, tr( "Loading" ) );
134  painter->restore();
135  }
136 
137  QSizeF sizePixels = mLayout->renderContext().measurementConverter().convert( sizeWithUnits(), QgsUnitTypes::LayoutPixels ).toQSizeF();
138  QSize sizePixelsInt = QSize( static_cast<int>( std::ceil( sizePixels.width() ) ),
139  static_cast<int>( std::ceil( sizePixels.height() ) ) );
140 
141  if ( isTemporal() )
142  mSettings->setTemporalRange( temporalRange() );
143 
144  if ( !mEngine )
145  {
146  mEngine.reset( new QgsOffscreen3DEngine );
147  connect( mEngine.get(), &QgsAbstract3DEngine::imageCaptured, this, &QgsLayoutItem3DMap::onImageCaptured );
148 
149  mEngine->setSize( sizePixelsInt );
150  mScene = new Qgs3DMapScene( *mSettings, mEngine.get() );
151  connect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );
152 
153  mEngine->setRootEntity( mScene );
154 
155  }
156 
157  if ( mEngine->size() != sizePixelsInt )
158  mEngine->setSize( sizePixelsInt );
159 
160  mScene->cameraController()->setCameraPose( mCameraPose );
161 
162  if ( mLayout->renderContext().isPreviewRender() )
163  {
164  onSceneStateChanged();
165  }
166  else
167  {
168  // we can't just request a capture and hope it will arrive at some point later.
169  // this is not a preview, we need the rendered scene now!
170  if ( mDrawing )
171  return;
172  mDrawing = true;
173  Qgs3DUtils::captureSceneImage( *mEngine.get(), mScene );
174  QImage img = Qgs3DUtils::captureSceneImage( *mEngine.get(), mScene );
175  painter->drawImage( r, img );
176  painter->restore();
177  mDrawing = false;
178  }
179 }
180 
181 void QgsLayoutItem3DMap::onImageCaptured( const QImage &img )
182 {
183  mCapturedImage = img;
184  update();
185 }
186 
187 void QgsLayoutItem3DMap::onSceneStateChanged()
188 {
189  if ( mCapturedImage.isNull() && mScene->sceneState() == Qgs3DMapScene::Ready )
190  {
191  mEngine->requestCaptureImage();
192  }
193 }
194 
195 void QgsLayoutItem3DMap::onSizePositionChanged()
196 {
197  mCapturedImage = QImage();
198  update();
199 }
200 
201 
202 bool QgsLayoutItem3DMap::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
203 {
204  if ( mSettings )
205  {
206  QDomElement elemSettings = mSettings->writeXml( document, context );
207  element.appendChild( elemSettings );
208  }
209 
210  QDomElement elemCameraPose = mCameraPose.writeXml( document );
211  element.appendChild( elemCameraPose );
212 
213  //temporal settings
214  QDomElement elemTemporal = document.createElement( QStringLiteral( "temporal-settings" ) );
215  elemTemporal.setAttribute( QStringLiteral( "isTemporal" ), isTemporal() ? 1 : 0 );
216  if ( isTemporal() )
217  {
218  elemTemporal.setAttribute( QStringLiteral( "temporalRangeBegin" ), temporalRange().begin().toString( Qt::ISODate ) );
219  elemTemporal.setAttribute( QStringLiteral( "temporalRangeEnd" ), temporalRange().end().toString( Qt::ISODate ) );
220  }
221  element.appendChild( elemTemporal );
222 
223  return true;
224 }
225 
226 bool QgsLayoutItem3DMap::readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context )
227 {
228  Q_UNUSED( document )
229  QDomElement elemSettings = element.firstChildElement( QStringLiteral( "qgis3d" ) );
230  if ( !elemSettings.isNull() )
231  {
232  mSettings.reset( new Qgs3DMapSettings );
233  mSettings->readXml( elemSettings, context );
234  if ( mLayout->project() )
235  {
236  mSettings->resolveReferences( *mLayout->project() );
237 
238  mSettings->setTransformContext( mLayout->project()->transformContext() );
239  mSettings->setPathResolver( mLayout->project()->pathResolver() );
240  mSettings->setMapThemeCollection( mLayout->project()->mapThemeCollection() );
241  }
242  }
243 
244  QDomElement elemCameraPose = element.firstChildElement( QStringLiteral( "camera-pose" ) );
245  if ( !elemCameraPose.isNull() )
246  mCameraPose.readXml( elemCameraPose );
247 
248  //temporal settings
249  QDomElement elemTemporal = element.firstChildElement( QStringLiteral( "temporal-settings" ) );
250  setIsTemporal( elemTemporal.attribute( QStringLiteral( "isTemporal" ) ).toInt() );
251  if ( isTemporal() )
252  {
253  QDateTime begin = QDateTime::fromString( elemTemporal.attribute( QStringLiteral( "temporalRangeBegin" ) ), Qt::ISODate );
254  QDateTime end = QDateTime::fromString( elemTemporal.attribute( QStringLiteral( "temporalRangeBegin" ) ), Qt::ISODate );
255  setTemporalRange( QgsDateTimeRange( begin, end ) );
256  }
257 
258  return true;
259 }
260 
262 {
263  assignFreeId();
264 }
265 
267 {
268  mSettings.reset( settings );
269 
270  mEngine.reset();
271  mScene = nullptr;
272 
273  mCapturedImage = QImage();
274  update();
275 }
276 
278 {
280 
281  mCapturedImage = QImage();
282 }
283 
285 {
286  if ( mCameraPose == pose )
287  return;
288 
289  mCameraPose = pose;
290  mCapturedImage = QImage();
291  update();
292 }
QgsLayoutItem::id
QString id() const
Returns the item's ID name.
Definition: qgslayoutitem.h:357
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:126
QgsLayoutItem3DMap::writePropertiesToElement
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
Definition: qgslayoutitem3dmap.cpp:202
QgsLayoutItem3DMap::setMapSettings
void setMapSettings(Qgs3DMapSettings *settings)
Configures map scene.
Definition: qgslayoutitem3dmap.cpp:266
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
QgsLayoutItem::sizePositionChanged
void sizePositionChanged()
Emitted when the item's size or position changes.
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsUnitTypes::LayoutPixels
@ LayoutPixels
Pixels.
Definition: qgsunittypes.h:189
QgsTemporalRangeObject::isTemporal
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
Definition: qgstemporalrangeobject.cpp:30
QgsTemporalRangeObject::setIsTemporal
void setIsTemporal(bool enabled)
Sets whether the temporal range is enabled (i.e.
Definition: qgstemporalrangeobject.cpp:25
QgsLayoutItemRenderContext
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:45
QgsTemporalRangeObject::temporalRange
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
Definition: qgstemporalrangeobject.cpp:43
Qgs3DUtils::captureSceneImage
static QImage captureSceneImage(QgsAbstract3DEngine &engine, Qgs3DMapScene *scene)
Captures image of the current 3D scene of a 3D engine.
Definition: qgs3dutils.cpp:42
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsAbstract3DEngine::imageCaptured
void imageCaptured(const QImage &image)
Emitted after a call to requestCaptureImage() to return the captured image.
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:333
QgsLayoutItem3DMap
3
Definition: qgslayoutitem3dmap.h:45
QgsLayoutItem::sizeWithUnits
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
Definition: qgslayoutitem.h:671
qgsshadowrenderingframegraph.h
Qgs3DMapScene::sceneState
SceneState sceneState() const
Returns the current state of the scene.
Definition: qgs3dmapscene.h:100
Qgs3DMapScene::sceneStateChanged
void sceneStateChanged()
Emitted when the scene's state has changed.
QgsLayoutItem::backgroundColor
QColor backgroundColor() const
Returns the background color for this item.
Definition: qgslayoutitem.h:815
QgsCameraController::setCameraPose
void setCameraPose(const QgsCameraPose &camPose)
Sets camera pose.
Definition: qgscameracontroller.cpp:210
qgs3dutils.h
QgsLayoutItem3DMap::QgsLayoutItem3DMap
QgsLayoutItem3DMap(QgsLayout *layout)
Constructor for QgsLayoutItem3DMap, with the specified parent layout.
Definition: qgslayoutitem3dmap.cpp:29
Qgs3DMapScene::cameraController
QgsCameraController * cameraController()
Returns camera controller.
Definition: qgs3dmapscene.h:76
QgsLayoutItem3DMap::type
virtual int type() const override
Definition: qgslayoutitem3dmap.cpp:45
QgsLayoutItemRegistry::Layout3DMap
@ Layout3DMap
3D map item
Definition: qgslayoutitemregistry.h:336
Qgs3DMapSettings
3 Definition of the world
Definition: qgs3dmapsettings.h:54
qgswindow3dengine.h
QgsLayoutItem
Base class for graphical items within a QgsLayout.
Definition: qgslayoutitem.h:113
qgscameracontroller.h
QgsLayoutItem3DMap::displayName
QString displayName() const override
overridden to show "3D Map 1" type names
Definition: qgslayoutitem3dmap.cpp:83
qgslayout.h
QgsLayoutItem3DMap::refresh
void refresh() override
Definition: qgslayoutitem3dmap.cpp:277
QgsCameraPose
3 Class that encapsulates camera pose in a 3D scene.
Definition: qgscamerapose.h:45
QgsLayoutItem3DMap::finalizeRestoreFromXml
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
Definition: qgslayoutitem3dmap.cpp:261
QgsLayoutItem::refresh
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
Definition: qgslayoutitem.cpp:1176
Qgs3DMapScene
3 Entity that encapsulates our 3D scene - contains all other entities (such as terrain) as children.
Definition: qgs3dmapscene.h:69
QgsCameraPose::readXml
void readXml(const QDomElement &elem)
Reads configuration from a DOM element previously written using writeXml()
Definition: qgscamerapose.cpp:34
QgsLayoutItemRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
Qgs3DMapScene::Ready
@ Ready
The scene is fully loaded/updated.
Definition: qgs3dmapscene.h:95
QgsLayoutItem3DMap::draw
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Definition: qgslayoutitem3dmap.cpp:98
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:343
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsCameraPose::writeXml
QDomElement writeXml(QDomDocument &doc) const
Writes configuration to a new DOM element and returns it.
Definition: qgscamerapose.cpp:22
QgsLayoutItem3DMap::create
static QgsLayoutItem3DMap * create(QgsLayout *layout)
Returns a new 3D map item for the specified layout.
Definition: qgslayoutitem3dmap.cpp:40
QgsLayoutItem3DMap::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
Definition: qgslayoutitem3dmap.cpp:226
QgsTemporalRangeObject::setTemporalRange
void setTemporalRange(const QgsDateTimeRange &range)
Sets the temporal range for the object.
Definition: qgstemporalrangeobject.cpp:35
qgsoffscreen3dengine.h
QgsLayoutItem3DMap::setCameraPose
void setCameraPose(const QgsCameraPose &pose)
Configures camera view.
Definition: qgslayoutitem3dmap.cpp:284
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:179
QgsLayoutItem3DMap::assignFreeId
void assignFreeId()
Sets the map id() to a number not yet used in the layout.
Definition: qgslayoutitem3dmap.cpp:55
qgspostprocessingentity.h
QgsLayoutItem3DMap::icon
QIcon icon() const override
Returns the item's icon.
Definition: qgslayoutitem3dmap.cpp:50
qgslayoutitemregistry.h
QgsOffscreen3DEngine
3 Off-screen 3D engine implementation.
Definition: qgsoffscreen3dengine.h:65
qgslayoutmodel.h
QgsLayoutItem3DMap::~QgsLayoutItem3DMap
~QgsLayoutItem3DMap()
qgslayoutitem3dmap.h
qgs3dmapscene.h