QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
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 <memory>
19
20#include "qgs3dmapscene.h"
21#include "qgs3dutils.h"
22#include "qgscameracontroller.h"
23#include "qgslayout.h"
25#include "qgslayoutmodel.h"
28
29#include <QString>
30
31#include "moc_qgslayoutitem3dmap.cpp"
32
33using namespace Qt::StringLiterals;
34
37{
39
40 connect( this, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItem3DMap::onSizePositionChanged );
41}
42
44
45
50
55
57{
58 return QgsApplication::getThemeIcon( u"/mLayoutItem3DMap.svg"_s );
59}
60
62{
63 if ( !mLayout )
64 return;
65
66 QList<QgsLayoutItem3DMap *> mapsList;
67 mLayout->layoutItems( mapsList );
68
69 int maxId = -1;
70 bool used = false;
71 for ( QgsLayoutItem3DMap *map : std::as_const( mapsList ) )
72 {
73 if ( map == this )
74 continue;
75
76 if ( map->mMapId == mMapId )
77 used = true;
78
79 maxId = std::max( maxId, map->mMapId );
80 }
81 if ( used )
82 {
83 mMapId = maxId + 1;
84 mLayout->itemsModel()->updateItemDisplayName( this );
85 }
86 updateToolTip();
87}
88
90{
91 if ( !QgsLayoutItem::id().isEmpty() )
92 {
93 return QgsLayoutItem::id();
94 }
95
96 return tr( "3D Map %1" ).arg( mMapId );
97}
98
99void QgsLayoutItem3DMap::updateToolTip()
100{
101 setToolTip( displayName() );
102}
103
105{
106 QgsRenderContext &ctx = context.renderContext();
107 QPainter *painter = ctx.painter();
108
109 int w = static_cast<int>( std::ceil( rect().width() * ctx.scaleFactor() ) );
110 int h = static_cast<int>( std::ceil( rect().height() * ctx.scaleFactor() ) );
111 QRect r( 0, 0, w, h );
112
113 painter->save();
114
115 if ( !mSettings )
116 {
117 painter->drawText( r, Qt::AlignCenter, tr( "Scene not set" ) );
118 painter->restore();
119 return;
120 }
121
122 if ( mSettings->backgroundColor() != backgroundColor() )
123 {
124 mSettings->setBackgroundColor( backgroundColor() );
125 mCapturedImage = QImage();
126 }
127
128 if ( !mCapturedImage.isNull() )
129 {
130 painter->drawImage( r, mCapturedImage );
131 painter->restore();
132 return;
133 }
134
135 // we do not have a cached image of the rendered scene - let's request one from the engine
136
137 if ( mLayout->renderContext().isPreviewRender() )
138 {
139 painter->drawText( r, Qt::AlignCenter, tr( "Loading" ) );
140 painter->restore();
141 if ( mSettings->rendererUsage() != Qgis::RendererUsage::View )
142 {
143 mSettings->setRendererUsage( Qgis::RendererUsage::View );
144 mEngine.reset(); //we need to rebuild the scene to force the render again
145 }
146 }
147 else
148 {
149 if ( mSettings->rendererUsage() != Qgis::RendererUsage::Export )
150 {
151 mSettings->setRendererUsage( Qgis::RendererUsage::Export );
152 mEngine.reset(); //we need to rebuild the scene to force the render again
153 }
154 }
155
156 QSizeF sizePixels = mLayout->renderContext().measurementConverter().convert( sizeWithUnits(), Qgis::LayoutUnit::Pixels ).toQSizeF();
157 QSize sizePixelsInt = QSize( static_cast<int>( std::ceil( sizePixels.width() ) ), static_cast<int>( std::ceil( sizePixels.height() ) ) );
158
159 if ( isTemporal() )
160 mSettings->setTemporalRange( temporalRange() );
161
162 if ( !mEngine )
163 {
164 mEngine = std::make_unique<QgsOffscreen3DEngine>();
165 connect( mEngine.get(), &QgsAbstract3DEngine::imageCaptured, this, &QgsLayoutItem3DMap::onImageCaptured );
166
167 mEngine->setSize( sizePixelsInt );
168 mScene = new Qgs3DMapScene( *mSettings, mEngine.get() );
169 connect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );
170
171 mEngine->setRootEntity( mScene );
172 }
173
174 if ( mEngine->size() != sizePixelsInt )
175 mEngine->setSize( sizePixelsInt );
176
177 mScene->cameraController()->setCameraPose( mCameraPose );
178
179 if ( mLayout->renderContext().isPreviewRender() )
180 {
181 onSceneStateChanged();
182 }
183 else
184 {
185 // we can't just request a capture and hope it will arrive at some point later.
186 // this is not a preview, we need the rendered scene now!
187 if ( mDrawing )
188 return;
189 mDrawing = true;
190 disconnect( mEngine.get(), &QgsAbstract3DEngine::imageCaptured, this, &QgsLayoutItem3DMap::onImageCaptured );
191 disconnect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );
192
193 Qgs3DUtils::captureSceneImage( *mEngine.get(), mScene );
194 QImage img = Qgs3DUtils::captureSceneImage( *mEngine.get(), mScene );
195 painter->drawImage( r, img );
196 painter->restore();
197
198 connect( mEngine.get(), &QgsAbstract3DEngine::imageCaptured, this, &QgsLayoutItem3DMap::onImageCaptured );
199 connect( mScene, &Qgs3DMapScene::sceneStateChanged, this, &QgsLayoutItem3DMap::onSceneStateChanged );
200 mDrawing = false;
201 }
202}
203
204void QgsLayoutItem3DMap::onImageCaptured( const QImage &img )
205{
206 mCapturedImage = img;
207 update();
208}
209
210void QgsLayoutItem3DMap::onSceneStateChanged()
211{
212 if ( mCapturedImage.isNull() && mScene->sceneState() == Qgs3DMapScene::Ready )
213 {
214 mEngine->requestCaptureImage();
215 }
216}
217
218void QgsLayoutItem3DMap::onSizePositionChanged()
219{
220 mCapturedImage = QImage();
221 update();
222}
223
224
225bool QgsLayoutItem3DMap::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
226{
227 if ( mSettings )
228 {
229 QDomElement elemSettings = mSettings->writeXml( document, context );
230 element.appendChild( elemSettings );
231 }
232
233 QDomElement elemCameraPose = mCameraPose.writeXml( document );
234 element.appendChild( elemCameraPose );
235
236 //temporal settings
237 QDomElement elemTemporal = document.createElement( u"temporal-settings"_s );
238 elemTemporal.setAttribute( u"isTemporal"_s, isTemporal() ? 1 : 0 );
239 if ( isTemporal() )
240 {
241 elemTemporal.setAttribute( u"temporalRangeBegin"_s, temporalRange().begin().toString( Qt::ISODate ) );
242 elemTemporal.setAttribute( u"temporalRangeEnd"_s, temporalRange().end().toString( Qt::ISODate ) );
243 }
244 element.appendChild( elemTemporal );
245
246 return true;
247}
248
249bool QgsLayoutItem3DMap::readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context )
250{
251 Q_UNUSED( document )
252 QDomElement elemSettings = element.firstChildElement( u"qgis3d"_s );
253 if ( !elemSettings.isNull() )
254 {
255 mSettings = std::make_unique<Qgs3DMapSettings>();
256 mSettings->readXml( elemSettings, context );
257 if ( mLayout->project() )
258 {
259 mSettings->resolveReferences( *mLayout->project() );
260
261 mSettings->setTransformContext( mLayout->project()->transformContext() );
262 mSettings->setPathResolver( mLayout->project()->pathResolver() );
263 mSettings->setMapThemeCollection( mLayout->project()->mapThemeCollection() );
264 }
265 }
266
267 QDomElement elemCameraPose = element.firstChildElement( u"camera-pose"_s );
268 if ( !elemCameraPose.isNull() )
269 mCameraPose.readXml( elemCameraPose );
270
271 //temporal settings
272 QDomElement elemTemporal = element.firstChildElement( u"temporal-settings"_s );
273 setIsTemporal( elemTemporal.attribute( u"isTemporal"_s ).toInt() );
274 if ( isTemporal() )
275 {
276 QDateTime begin = QDateTime::fromString( elemTemporal.attribute( u"temporalRangeBegin"_s ), Qt::ISODate );
277 QDateTime end = QDateTime::fromString( elemTemporal.attribute( u"temporalRangeBegin"_s ), Qt::ISODate );
278 setTemporalRange( QgsDateTimeRange( begin, end ) );
279 }
280
281 return true;
282}
283
288
290{
291 mSettings.reset( settings );
292
293 mEngine.reset();
294 mScene = nullptr;
295
296 mCapturedImage = QImage();
297 update();
298}
299
301{
303
304 mCapturedImage = QImage();
305}
306
308{
309 if ( mCameraPose == pose )
310 return;
311
312 mCameraPose = pose;
313 mCapturedImage = QImage();
314 update();
315}
@ Pixels
Pixels.
Definition qgis.h:5307
@ Export
Renderer used for printing or exporting to a file.
Definition qgis.h:3518
@ View
Renderer used for displaying on screen.
Definition qgis.h:3517
Entity that encapsulates our 3D scene - contains all other entities (such as terrain) as children.
@ Ready
The scene is fully loaded/updated.
void sceneStateChanged()
Emitted when the scene's state has changed.
Definition of the world.
static QImage captureSceneImage(QgsAbstract3DEngine &engine, Qgs3DMapScene *scene)
Captures image of the current 3D scene of a 3D engine.
void imageCaptured(const QImage &image)
Emitted after a call to requestCaptureImage() to return the captured image.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Encapsulates camera pose in a 3D scene.
void setCameraPose(const QgsCameraPose &pose)
Configures camera view.
~QgsLayoutItem3DMap() override
QString displayName() const override
overridden to show "3D Map 1" type names
QgsLayoutItem3DMap(QgsLayout *layout)
Constructor for QgsLayoutItem3DMap, with the specified parent layout.
int type() const override
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
QIcon icon() const override
Returns the item's icon.
static QgsLayoutItem3DMap * create(QgsLayout *layout)
Returns a new 3D map item for the specified layout.
void setMapSettings(Qgs3DMapSettings *settings)
Configures map scene.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
void assignFreeId()
Sets the map id() to a number not yet used in the layout.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
Contains settings and helpers relating to a render of a QgsLayoutItem.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
friend class QgsLayout
QColor backgroundColor(bool useDataDefined=true) const
Returns the background color for this item.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
QgsLayoutItem(QgsLayout *layout, bool manageZValue=true)
Constructor for QgsLayoutItem, with the specified parent layout.
void sizePositionChanged()
Emitted when the item's size or position changes.
QString id() const
Returns the item's ID name.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
const QgsLayout * layout() const
Returns the layout the object is attached to.
QPointer< QgsLayout > mLayout
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
void setIsTemporal(bool enabled)
Sets whether the temporal range is enabled (i.e.
void setTemporalRange(const QgsDateTimeRange &range)
Sets the temporal range for the object.
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition qgsrange.h:764