1 /***************************************************************************
2   qgscameracontroller.h
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 #ifndef QGSCAMERACONTROLLER_H
17 #define QGSCAMERACONTROLLER_H
18 
19 #include "qgis_3d.h"
20 
21 #include <QPointer>
22 #include <QRect>
23 #include <Qt3DCore/QEntity>
24 
25 namespace Qt3DInput
26 {
27   class QKeyEvent;
28   class QKeyboardDevice;
29   class QKeyboardHandler;
30   class QMouseEvent;
31   class QMouseDevice;
32   class QMouseHandler;
33   class QWheelEvent;
34 }
35 
36 namespace Qt3DRender
37 {
38   class QCamera;
39   class QPickEvent;
40 }
41 
42 #include "qgscamerapose.h"
43 
44 class QDomDocument;
45 class QDomElement;
46 
47 class QgsCameraPose;
48 class QgsTerrainEntity;
49 class QgsVector3D;
50 
51 #define SIP_NO_FILE
52 
53 /**
54  * \ingroup 3d
55  * \brief Object that controls camera movement based on user input
56  * \note Not available in Python bindings
57  * \since QGIS 3.0
58  */
59 class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
60 {
61     Q_OBJECT
62     Q_PROPERTY( Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged )
63     Q_PROPERTY( QRect viewport READ viewport WRITE setViewport NOTIFY viewportChanged )
64   public:
65     //! Constructs the camera controller with optional parent node that will take ownership
66     QgsCameraController( Qt3DCore::QNode *parent = nullptr );
67 
68     //! Returns camera that is being controlled
camera()69     Qt3DRender::QCamera *camera() const { return mCamera; }
70     //! Returns viewport rectangle
viewport()71     QRect viewport() const { return mViewport; }
72 
73     /**
74      * Connects to object picker attached to terrain entity. Called internally from 3D scene.
75      * This allows camera controller understand how far from the camera is the terrain under mouse cursor.
76      * Also it allows adjustment of camera's view center to a point on terrain.
77      */
78     void setTerrainEntity( QgsTerrainEntity *te );
79 
80     //! Assigns camera that should be controlled by this class. Called internally from 3D scene.
81     void setCamera( Qt3DRender::QCamera *camera );
82     //! Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates.
83     void setViewport( QRect viewport );
84     //! Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/mouse input
85     void frameTriggered( float dt );
86 
87     //! Move camera back to the initial position (looking down towards origin of world's coordinates)
88     void resetView( float distance );
89 
90     //! Sets camera to look down towards given point in world coordinate, in given distance from plane with zero elevation
91     void setViewFromTop( float worldX, float worldY, float distance, float yaw = 0 );
92 
93     //! Returns the point in the world coordinates towards which the camera is looking
94     QgsVector3D lookingAtPoint() const;
95 
96     /**
97      * Sets the complete camera configuration: the point towards it is looking (in 3D world coordinates), the distance
98      * of the camera from the point, pitch angle in degrees (0 = looking from the top, 90 = looking from the side) and
99      * yaw angle in degrees.
100      * \since QGIS 3.4
101      */
102     void setLookingAtPoint( const QgsVector3D &point, float distance, float pitch, float yaw );
103 
104     /**
105      * Sets camera pose
106      * \since QGIS 3.4
107      */
108     void setCameraPose( const QgsCameraPose &camPose );
109 
110     /**
111      * Returns camera pose
112      * \since QGIS 3.4
113      */
cameraPose()114     QgsCameraPose cameraPose() const { return mCameraPose; }
115 
116     /**
117      * Returns distance of the camera from the point it is looking at.
118      * \since QGIS 3.4
119      */
distance()120     float distance() const { return mCameraPose.distanceFromCenterPoint(); }
121 
122     /**
123      * Returns pitch angle in degrees (0 = looking from the top, 90 = looking from the side).
124      * The angle should range from 0 to 180.
125      * \since QGIS 3.4
126      */
pitch()127     float pitch() const { return mCameraPose.pitchAngle(); }
128 
129     /**
130      * Returns yaw angle in degrees.  Yaw value of zero means the camera is pointing towards north.
131      * The angle should range from 0 to 360.
132      * \since QGIS 3.4
133      */
yaw()134     float yaw() const { return mCameraPose.headingAngle(); }
135 
136     //! Writes camera configuration to the given DOM element
137     QDomElement writeXml( QDomDocument &doc ) const;
138     //! Reads camera configuration from the given DOM element
139     void readXml( const QDomElement &elem );
140 
141     //! Zoom the map by \a factor
142     void zoom( float factor );
143     //! Tilt up the view by \a deltaPitch around the view center (camera moves)
144     void tiltUpAroundViewCenter( float deltaPitch );
145     //! Rotate clockwise the view by \a deltaYaw around the view center (camera moves)
146     void rotateAroundViewCenter( float deltaYaw );
147     //! Set camera heading to \a angle (used for rotating the view)
148     void setCameraHeadingAngle( float angle );
149     //! Move the map by \a tx and \a ty
150     void moveView( float tx, float ty );
151 
152   private:
153     void rotateCamera( float diffPitch, float diffYaw );
154     void updateCameraFromPose( bool centerPointChanged = false );
155 
156   signals:
157     //! Emitted when camera has been updated
158     void cameraChanged();
159     //! Emitted when viewport rectangle has been updated
160     void viewportChanged();
161 
162   private slots:
163     void onPositionChanged( Qt3DInput::QMouseEvent *mouse );
164     void onWheel( Qt3DInput::QWheelEvent *wheel );
165     void onMousePressed( Qt3DInput::QMouseEvent *mouse );
166     void onMouseReleased( Qt3DInput::QMouseEvent *mouse );
167     void onKeyPressed( Qt3DInput::QKeyEvent *event );
168     void onKeyReleased( Qt3DInput::QKeyEvent *event );
169     void onPickerMousePressed( Qt3DRender::QPickEvent *pick );
170 
171   private:
172     //! Camera that is being controlled
173     Qt3DRender::QCamera *mCamera = nullptr;
174     //! used for computation of translation when dragging mouse
175     QRect mViewport;
176     //! height of terrain when mouse button was last pressed - for camera control
177     float mLastPressedHeight = 0;
178 
179     QPointer<QgsTerrainEntity> mTerrainEntity;
180 
181     //! Keeps definition of the camera's position and towards where it is looking
182     QgsCameraPose mCameraPose;
183 
184     //! Last mouse position recorded
185     QPoint mMousePos;
186 
187     //! Delegates mouse events to the attached MouseHandler objects
188     Qt3DInput::QMouseDevice *mMouseDevice = nullptr;
189     Qt3DInput::QKeyboardDevice *mKeyboardDevice = nullptr;
190 
191     Qt3DInput::QMouseHandler *mMouseHandler = nullptr;
192     Qt3DInput::QKeyboardHandler *mKeyboardHandler = nullptr;
193 
194 };
195 
196 #endif // QGSCAMERACONTROLLER_H
197