QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgs3dmapcanvas.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgs3dmapcanvas.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 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 <Qt3DCore/QAspectEngine>
17#include <Qt3DCore/QEntity>
18#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
19#include <Qt3DCore/QCoreAspect>
20#endif
21#include <Qt3DExtras/QForwardRenderer>
22#include <Qt3DRender/QRenderSettings>
23#include <Qt3DRender/QRenderAspect>
24#include <Qt3DInput/QInputAspect>
25#include <Qt3DInput/QInputSettings>
26#include <Qt3DLogic/QLogicAspect>
27#include <Qt3DRender/QCamera>
28
29#include "qgs3dmapcanvas.h"
30
31#include <Qt3DLogic/QFrameAction>
32#include "qgs3dmapscene.h"
33#include "qgswindow3dengine.h"
34#include "qgs3dmapsettings.h"
35#include "qgs3dmaptool.h"
37#include "moc_qgs3dmapcanvas.cpp"
38
40 : m_aspectEngine( new Qt3DCore::QAspectEngine )
41 , m_renderAspect( new Qt3DRender::QRenderAspect )
42 , m_inputAspect( new Qt3DInput::QInputAspect )
43 , m_logicAspect( new Qt3DLogic::QLogicAspect )
44 , m_renderSettings( new Qt3DRender::QRenderSettings )
45 , m_defaultCamera( new Qt3DRender::QCamera )
46 , m_inputSettings( new Qt3DInput::QInputSettings )
47 , m_root( new Qt3DCore::QEntity )
48 , m_userRoot( nullptr )
49 , m_initialized( false )
50{
51 setSurfaceType( QSurface::OpenGLSurface );
52
53 // register aspects
54#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
55 m_aspectEngine->registerAspect( new Qt3DCore::QCoreAspect );
56#endif
57 m_aspectEngine->registerAspect( m_renderAspect );
58 m_aspectEngine->registerAspect( m_inputAspect );
59 m_aspectEngine->registerAspect( m_logicAspect );
60
61 m_defaultCamera->setParent( m_root );
62 m_inputSettings->setEventSource( this );
63
64 const QgsSettings setting;
65 mEngine = new QgsWindow3DEngine( this );
66
67 connect( mEngine, &QgsAbstract3DEngine::imageCaptured, this, [ = ]( const QImage & image )
68 {
69 image.save( mCaptureFileName, mCaptureFileFormat.toLocal8Bit().data() );
70 mEngine->setRenderCaptureEnabled( false );
71 emit savedAsImage( mCaptureFileName );
72 } );
73
74 setCursor( Qt::OpenHandCursor );
75 installEventFilter( this );
76}
77
79{
80 if ( mMapTool )
81 mMapTool->deactivate();
82 // make sure the scene is deleted while map settings object is still alive
83 mScene->deleteLater();
84 mScene = nullptr;
85 mMapSettings->deleteLater();
86 mMapSettings = nullptr;
87
88
89 delete m_aspectEngine;
90}
91
92void Qgs3DMapCanvas::setRootEntity( Qt3DCore::QEntity *root )
93{
94 if ( m_userRoot != root )
95 {
96 if ( m_userRoot )
97 m_userRoot->setParent( static_cast<Qt3DCore::QNode *>( nullptr ) );
98 if ( root )
99 root->setParent( m_root );
100 m_userRoot = root;
101 }
102}
103
104void Qgs3DMapCanvas::setActiveFrameGraph( Qt3DRender::QFrameGraphNode *activeFrameGraph )
105{
106 m_renderSettings->setActiveFrameGraph( activeFrameGraph );
107}
108
109Qt3DRender::QFrameGraphNode *Qgs3DMapCanvas::activeFrameGraph() const
110{
111 return m_renderSettings->activeFrameGraph();
112}
113
114Qt3DRender::QCamera *Qgs3DMapCanvas::camera() const
115{
116 return m_defaultCamera;
117}
118
119Qt3DRender::QRenderSettings *Qgs3DMapCanvas::renderSettings() const
120{
121 return m_renderSettings;
122}
123
124void Qgs3DMapCanvas::showEvent( QShowEvent *e )
125{
126 if ( !m_initialized )
127 {
128 m_root->addComponent( m_renderSettings );
129 m_root->addComponent( m_inputSettings );
130 m_aspectEngine->setRootEntity( Qt3DCore::QEntityPtr( m_root ) );
131
132 m_initialized = true;
133 }
134 QWindow::showEvent( e );
135}
136
137void Qgs3DMapCanvas::resizeEvent( QResizeEvent * )
138{
139 m_defaultCamera->setAspectRatio( float( width() ) / std::max( 1.f, static_cast<float>( height() ) ) );
140
141 mEngine->setSize( size() );
142}
143
145{
146 // TODO: eventually we want to get rid of this
147 Q_ASSERT( !mMapSettings );
148 Q_ASSERT( !mScene );
149
150 Qgs3DMapScene *newScene = new Qgs3DMapScene( *mapSettings, mEngine );
151
152 mEngine->setSize( size() );
153 mEngine->setRootEntity( newScene );
154
155 if ( mScene )
156 {
157 mScene->deleteLater();
158 }
159 mScene = newScene;
163
164 delete mMapSettings;
165 mMapSettings = mapSettings;
166
167 resetView();
168
169 connect( cameraController(), &QgsCameraController::setCursorPosition, this, [ = ]( QPoint point )
170 {
171 QCursor::setPos( mapToGlobal( point ) );
172 } );
175 connect( cameraController(), &QgsCameraController::navigationModeChanged, this, &Qgs3DMapCanvas::onNavigationModeChanged );
176 connect( cameraController(), &QgsCameraController::requestDepthBufferCapture, this, &Qgs3DMapCanvas::captureDepthBuffer );
177
179
180 emit mapSettingsChanged();
181}
182
184{
185 return mScene ? mScene->cameraController() : nullptr;
186}
187
189{
190 if ( !mScene )
191 return;
192
193 mScene->viewZoomFull();
194}
195
196void Qgs3DMapCanvas::setViewFromTop( const QgsPointXY &center, float distance, float rotation )
197{
198 if ( !mScene )
199 return;
200
201 const float worldX = center.x() - mMapSettings->origin().x();
202 const float worldY = center.y() - mMapSettings->origin().y();
203 mScene->cameraController()->setViewFromTop( worldX, worldY, distance, rotation );
204}
205
206void Qgs3DMapCanvas::saveAsImage( const QString &fileName, const QString &fileFormat )
207{
208 if ( !mScene || fileName.isEmpty() )
209 return;
210
211 mCaptureFileName = fileName;
212 mCaptureFileFormat = fileFormat;
213 mEngine->setRenderCaptureEnabled( true );
214 // Setup a frame action that is used to wait until next frame
215 Qt3DLogic::QFrameAction *screenCaptureFrameAction = new Qt3DLogic::QFrameAction;
216 mScene->addComponent( screenCaptureFrameAction );
217 // Wait to have the render capture enabled in the next frame
218 connect( screenCaptureFrameAction, &Qt3DLogic::QFrameAction::triggered, this, [ = ]( float )
219 {
220 mEngine->requestCaptureImage();
221 mScene->removeComponent( screenCaptureFrameAction );
222 screenCaptureFrameAction->deleteLater();
223 } );
224}
225
226void Qgs3DMapCanvas::captureDepthBuffer()
227{
228 if ( !mScene )
229 return;
230
231 // Setup a frame action that is used to wait until next frame
232 Qt3DLogic::QFrameAction *screenCaptureFrameAction = new Qt3DLogic::QFrameAction;
233 mScene->addComponent( screenCaptureFrameAction );
234 // Wait to have the render capture enabled in the next frame
235 connect( screenCaptureFrameAction, &Qt3DLogic::QFrameAction::triggered, this, [ = ]( float )
236 {
237 mEngine->requestDepthBufferCapture();
238 mScene->removeComponent( screenCaptureFrameAction );
239 screenCaptureFrameAction->deleteLater();
240 } );
241}
242
244{
245 if ( !mScene )
246 return;
247
248 if ( tool == mMapTool )
249 return;
250
251 // For Camera Control tool
252 if ( mMapTool && !tool )
253 {
254 mScene->cameraController()->setEnabled( true );
255 setCursor( Qt::OpenHandCursor );
256 }
257 else if ( !mMapTool && tool )
258 {
259 mScene->cameraController()->setEnabled( tool->allowsCameraControls() );
260 }
261
262 if ( mMapTool )
263 mMapTool->deactivate();
264
265 mMapTool = tool;
266
267 if ( mMapTool )
268 {
269 mMapTool->activate();
270 setCursor( mMapTool->cursor() );
271 }
272
273}
274
275bool Qgs3DMapCanvas::eventFilter( QObject *watched, QEvent *event )
276{
277 if ( watched != this )
278 return false;
279
280 if ( event->type() == QEvent::ShortcutOverride )
281 {
282 // if the camera controller will handle a key event, don't allow it to propagate
283 // outside of the 3d window or it may be grabbed by a parent window level shortcut
284 // and accordingly never be received by the camera controller
285 if ( cameraController() && cameraController()->willHandleKeyEvent( static_cast< QKeyEvent * >( event ) ) )
286 {
287 event->accept();
288 return true;
289 }
290 return false;
291 }
292
293 if ( !mMapTool )
294 return false;
295
296 switch ( event->type() )
297 {
298 case QEvent::MouseButtonPress:
299 mMapTool->mousePressEvent( static_cast<QMouseEvent *>( event ) );
300 break;
301 case QEvent::MouseButtonRelease:
302 mMapTool->mouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
303 break;
304 case QEvent::MouseMove:
305 mMapTool->mouseMoveEvent( static_cast<QMouseEvent *>( event ) );
306 break;
307 case QEvent::KeyPress:
308 mMapTool->keyPressEvent( static_cast<QKeyEvent *>( event ) );
309 break;
310 default:
311 break;
312 }
313 return false;
314}
315
317{
318 if ( mTemporalController )
319 disconnect( mTemporalController, &QgsTemporalController::updateTemporalRange, this, &Qgs3DMapCanvas::updateTemporalRange );
320
321 mTemporalController = temporalController;
322 connect( mTemporalController, &QgsTemporalController::updateTemporalRange, this, &Qgs3DMapCanvas::updateTemporalRange );
323}
324
325void Qgs3DMapCanvas::updateTemporalRange( const QgsDateTimeRange &temporalrange )
326{
327 if ( !mScene )
328 return;
329
330 mMapSettings->setTemporalRange( temporalrange );
331 mScene->updateTemporal();
332}
333
334void Qgs3DMapCanvas::onNavigationModeChanged( Qgis::NavigationMode mode )
335{
336 mMapSettings->setCameraNavigationMode( mode );
337}
338
340{
341 if ( !mScene )
342 return;
343
344 mScene->setViewFrom2DExtent( extent );
345}
346
348{
349 return mScene ? mScene->viewFrustum2DExtent() : QVector<QgsPointXY>();
350}
NavigationMode
The navigation mode used by 3D cameras.
Definition qgis.h:3872
void saveAsImage(const QString &fileName, const QString &fileFormat)
Saves the current scene as an image.
QVector< QgsPointXY > viewFrustum2DExtent()
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
Qgs3DMapSettings * mapSettings()
Returns access to the 3D scene configuration.
void setTemporalController(QgsTemporalController *temporalController)
Sets the temporal controller.
void mapSettingsChanged()
Emitted when the the map setting is changed.
Qt3DRender::QCamera * camera() const
Returns the default camera of the 3D Window.
void viewed2DExtentFrom3DChanged(QVector< QgsPointXY > extent)
Emitted when the viewed 2D extent seen by the 3D camera has changed.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes (at most every frame)
void setRootEntity(Qt3DCore::QEntity *root)
Sets the specified root entity of the scene.
void setViewFromTop(const QgsPointXY &center, float distance, float rotation=0)
Sets camera position to look down at the given point (in map coordinates) in given distance from plan...
void setActiveFrameGraph(Qt3DRender::QFrameGraphNode *activeFrameGraph)
Activates the specified activeFrameGraph.
void setMapSettings(Qgs3DMapSettings *mapSettings)
Configure map scene being displayed. Takes ownership.
void showEvent(QShowEvent *e) override
Manages the display events specified in e.
void cameraNavigationSpeedChanged(double speed)
Emitted when the camera navigation speed is changed.
Qt3DRender::QRenderSettings * renderSettings() const
Returns the render settings of the 3D Window.
Qt3DRender::QFrameGraphNode * activeFrameGraph() const
Returns the node of the active frame graph.
void setMapTool(Qgs3DMapTool *tool)
Sets the active map tool that will receive events from the 3D canvas.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent (top view)
void resizeEvent(QResizeEvent *) override
Resets the aspect ratio of the 3D window.
void resetView()
Resets camera position to the default: looking down at the origin of world coordinates.
void savedAsImage(const QString &fileName)
Emitted when the 3D map canvas was successfully saved as image.
void fpsCounterEnabledChanged(bool enabled)
Emitted when the FPS counter is enabled or disabeld.
QgsCameraController * cameraController()
Returns access to the view's camera controller. Returns nullptr if the scene has not been initialized...
bool eventFilter(QObject *watched, QEvent *event) override
void viewed2DExtentFrom3DChanged(QVector< QgsPointXY > extent)
Emitted when the viewed 2D extent seen by the 3D camera has changed.
void fpsCountChanged(float fpsCount)
Emitted when the FPS count changes.
void setViewFrom2DExtent(const QgsRectangle &extent)
Resets camera view to show the extent extent (top view)
QgsCameraController * cameraController() const
Returns camera controller.
void updateTemporal()
Updates the temporale entities.
void fpsCounterEnabledChanged(bool fpsCounterEnabled)
Emitted when the FPS counter is activated or deactivated.
QVector< QgsPointXY > viewFrustum2DExtent() const
Calculates the 2D extent viewed by the 3D camera as the vertices of the viewed trapezoid.
void viewZoomFull()
Resets camera view to show the whole scene (top view)
void setCameraNavigationMode(Qgis::NavigationMode navigationMode)
Sets the navigation mode for the camera.
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
virtual bool allowsCameraControls() const
Whether the default mouse controls to zoom/pan/rotate camera can stay enabled while the tool is activ...
virtual void mousePressEvent(QMouseEvent *event)
Reimplement to handle mouse event forwarded by the parent Qgs3DMapCanvas.
virtual QCursor cursor() const
Mouse cursor to be used when the tool is active.
virtual void mouseMoveEvent(QMouseEvent *event)
Reimplement to handle mouse move event forwarded by the parent Qgs3DMapCanvas.
virtual void keyPressEvent(QKeyEvent *event)
Reimplement to handle key press event forwarded by the parent Qgs3DMapCanvas.
virtual void deactivate()
Called when map tool is being deactivated.
virtual void activate()
Called when set as currently active map tool.
virtual void mouseReleaseEvent(QMouseEvent *event)
Reimplement to handle mouse release event forwarded by the parent Qgs3DMapCanvas.
void requestCaptureImage()
Starts a request for an image rendered by the engine.
void requestDepthBufferCapture()
Starts a request for an image containing the depth buffer data of the engine.
void imageCaptured(const QImage &image)
Emitted after a call to requestCaptureImage() to return the captured image.
void depthBufferCaptured(const QImage &image)
Emitted after a call to requestDepthBufferCapture() to return the captured depth buffer.
void setRenderCaptureEnabled(bool enabled)
Sets whether it will be possible to render to an image.
void navigationModeChanged(Qgis::NavigationMode mode)
Emitted when the navigation mode is changed using the hotkey ctrl + ~.
void requestDepthBufferCapture()
Emitted to ask for the depth buffer image.
void cameraMovementSpeedChanged(double speed)
Emitted whenever the camera movement speed is changed by the controller.
void setViewFromTop(float worldX, float worldY, float distance, float yaw=0)
Sets camera to look down towards given point in world coordinate, in given distance from plane with z...
void depthBufferCaptured(const QImage &depthImage)
Sets the depth buffer image used by the camera controller to calculate world position from a pixel's ...
void setCursorPosition(QPoint point)
Emitted when the mouse cursor position should be moved to the specified point on the map viewport.
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
A rectangle specified with double values.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
A controller base class for temporal objects, contains a signal for notifying updates of the objects ...
void updateTemporalRange(const QgsDateTimeRange &range)
Signals that a temporal range has changed and needs to be updated in all connected objects.
void setTemporalRange(const QgsDateTimeRange &range)
Sets the temporal range for the object.
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:50
double x() const
Returns X coordinate.
Definition qgsvector3d.h:48
void setRootEntity(Qt3DCore::QEntity *root) override
Sets root entity of the 3D scene.
void setSize(QSize s) override
Sets the size of the rendering area (in pixels)