21 #include <QDomDocument> 22 #include <Qt3DRender/QObjectPicker> 23 #include <Qt3DRender/QPickEvent> 28 , mMouseDevice( new Qt3DInput::QMouseDevice() )
29 , mKeyboardDevice( new Qt3DInput::QKeyboardDevice() )
30 , mMouseHandler( new Qt3DInput::QMouseHandler )
31 , mLogicalDevice( new Qt3DInput::QLogicalDevice() )
32 , mLeftMouseButtonAction( new Qt3DInput::QAction() )
33 , mLeftMouseButtonInput( new Qt3DInput::QActionInput() )
34 , mMiddleMouseButtonAction( new Qt3DInput::QAction() )
35 , mMiddleMouseButtonInput( new Qt3DInput::QActionInput() )
36 , mRightMouseButtonAction( new Qt3DInput::QAction() )
37 , mRightMouseButtonInput( new Qt3DInput::QActionInput() )
38 , mShiftAction( new Qt3DInput::QAction() )
39 , mShiftInput( new Qt3DInput::QActionInput() )
40 , mCtrlAction( new Qt3DInput::QAction() )
41 , mCtrlInput( new Qt3DInput::QActionInput() )
42 , mWheelAxis( new Qt3DInput::QAxis() )
43 , mMouseWheelInput( new Qt3DInput::QAnalogAxisInput() )
44 , mTxAxis( new Qt3DInput::QAxis() )
45 , mTyAxis( new Qt3DInput::QAxis() )
46 , mKeyboardTxPosInput( new Qt3DInput::QButtonAxisInput() )
47 , mKeyboardTyPosInput( new Qt3DInput::QButtonAxisInput() )
48 , mKeyboardTxNegInput( new Qt3DInput::QButtonAxisInput() )
49 , mKeyboardTyNegInput( new Qt3DInput::QButtonAxisInput() )
54 mMouseHandler->setSourceDevice( mMouseDevice );
55 connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
56 this, &QgsCameraController::onPositionChanged );
57 addComponent( mMouseHandler );
63 mLeftMouseButtonInput->setButtons( QVector<int>() << Qt::LeftButton );
64 mLeftMouseButtonInput->setSourceDevice( mMouseDevice );
65 mLeftMouseButtonAction->addInput( mLeftMouseButtonInput );
68 mMiddleMouseButtonInput->setButtons( QVector<int>() << Qt::MiddleButton );
69 mMiddleMouseButtonInput->setSourceDevice( mMouseDevice );
70 mMiddleMouseButtonAction->addInput( mMiddleMouseButtonInput );
73 mRightMouseButtonInput->setButtons( QVector<int>() << Qt::RightButton );
74 mRightMouseButtonInput->setSourceDevice( mMouseDevice );
75 mRightMouseButtonAction->addInput( mRightMouseButtonInput );
78 mMouseWheelInput->setAxis( Qt3DInput::QMouseDevice::WheelY );
79 mMouseWheelInput->setSourceDevice( mMouseDevice );
80 mWheelAxis->addInput( mMouseWheelInput );
83 mShiftInput->setButtons( QVector<int>() << Qt::Key_Shift );
84 mShiftInput->setSourceDevice( mKeyboardDevice );
85 mShiftAction->addInput( mShiftInput );
88 mCtrlInput->setButtons( QVector<int>() << Qt::Key_Control );
89 mCtrlInput->setSourceDevice( mKeyboardDevice );
90 mCtrlAction->addInput( mCtrlInput );
93 mKeyboardTxPosInput->setButtons( QVector<int>() << Qt::Key_Right );
94 mKeyboardTxPosInput->setScale( 1.0f );
95 mKeyboardTxPosInput->setSourceDevice( mKeyboardDevice );
96 mTxAxis->addInput( mKeyboardTxPosInput );
99 mKeyboardTyPosInput->setButtons( QVector<int>() << Qt::Key_Up );
100 mKeyboardTyPosInput->setScale( 1.0f );
101 mKeyboardTyPosInput->setSourceDevice( mKeyboardDevice );
102 mTyAxis->addInput( mKeyboardTyPosInput );
105 mKeyboardTxNegInput->setButtons( QVector<int>() << Qt::Key_Left );
106 mKeyboardTxNegInput->setScale( -1.0f );
107 mKeyboardTxNegInput->setSourceDevice( mKeyboardDevice );
108 mTxAxis->addInput( mKeyboardTxNegInput );
111 mKeyboardTyNegInput->setButtons( QVector<int>() << Qt::Key_Down );
112 mKeyboardTyNegInput->setScale( -1.0f );
113 mKeyboardTyNegInput->setSourceDevice( mKeyboardDevice );
114 mTyAxis->addInput( mKeyboardTyNegInput );
116 mLogicalDevice->addAction( mLeftMouseButtonAction );
117 mLogicalDevice->addAction( mMiddleMouseButtonAction );
118 mLogicalDevice->addAction( mRightMouseButtonAction );
119 mLogicalDevice->addAction( mShiftAction );
120 mLogicalDevice->addAction( mCtrlAction );
121 mLogicalDevice->addAxis( mWheelAxis );
122 mLogicalDevice->addAxis( mTxAxis );
123 mLogicalDevice->addAxis( mTyAxis );
126 connect(
this, &Qt3DCore::QEntity::enabledChanged,
127 mLogicalDevice, &Qt3DInput::QLogicalDevice::setEnabled );
129 addComponent( mLogicalDevice );
135 connect( picker, &Qt3DRender::QObjectPicker::pressed,
this, &QgsCameraController::onPickerMousePressed );
140 if ( mCamera == camera )
144 mCameraData.setCamera( mCamera );
153 if ( mViewport == viewport )
160 void QgsCameraController::setCameraData(
float x,
float y,
float dist,
float pitch,
float yaw )
164 mCameraData.dist = dist;
165 mCameraData.pitch = pitch;
166 mCameraData.yaw = yaw;
170 mCameraData.setCamera( mCamera );
175 static QVector3D unproject(
const QVector3D &v,
const QMatrix4x4 &modelView,
const QMatrix4x4 &projection,
const QRect &
viewport )
182 QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
184 QVector4D tmp( v, 1.0f );
185 tmp.setX( ( tmp.x() - float( viewport.x() ) ) / float( viewport.width() ) );
186 tmp.setY( ( tmp.y() - float( viewport.y() ) ) / float( viewport.height() ) );
187 tmp = tmp * 2.0f - QVector4D( 1.0f, 1.0f, 1.0f, 1.0f );
189 QVector4D obj = inverse * tmp;
193 return obj.toVector3D();
201 float k = ( y - y0 ) / d_y;
208 QVector3D l0 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 0 ), camera->viewMatrix(), camera->projectionMatrix(),
viewport );
209 QVector3D l1 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 1 ), camera->viewMatrix(), camera->projectionMatrix(),
viewport );
211 QVector3D p0( 0, y, 0 );
212 QVector3D n( 0, 1, 0 );
213 QVector3D l = l1 - l0;
214 float d = QVector3D::dotProduct( p0 - l0, n ) / QVector3D::dotProduct( l, n );
215 QVector3D p = d * l + l0;
217 return QPointF( p.x(), p.z() );
223 if ( mCamera ==
nullptr )
226 CameraData oldCamData = mCameraData;
228 int dx = mMousePos.x() - mLastMousePos.x();
229 int dy = mMousePos.y() - mLastMousePos.y();
230 mLastMousePos = mMousePos;
232 double scaling = ( mCtrlAction->isActive() ? 0.1 : 1.0 );
233 mCameraData.dist -= scaling * mCameraData.dist * mWheelAxis->value() * 10 * dt;
235 if ( mRightMouseButtonAction->isActive() )
237 mCameraData.dist -= mCameraData.dist * dy * 0.01;
240 float tx = mTxAxis->value() * dt * mCameraData.dist * 1.5;
241 float ty = -mTyAxis->value() * dt * mCameraData.dist * 1.5;
243 if ( !mShiftAction->isActive() && ( tx || ty ) )
246 float t = sqrt( tx * tx + ty * ty );
247 float a = atan2( ty, tx ) - mCameraData.yaw * M_PI / 180;
248 float dx = cos( a ) * t;
249 float dy = sin( a ) * t;
254 if ( ( mLeftMouseButtonAction->isActive() && mShiftAction->isActive() ) || mMiddleMouseButtonAction->isActive() )
257 mCameraData.pitch += dy;
258 mCameraData.yaw -= dx / 2;
260 else if ( mShiftAction->isActive() && ( mTxAxis->value() || mTyAxis->value() ) )
263 mCameraData.pitch -= mTyAxis->value();
264 mCameraData.yaw -= mTxAxis->value();
266 else if ( mLeftMouseButtonAction->isActive() && !mShiftAction->isActive() )
272 float z = mLastPressedHeight;
276 mCameraData.x -= p2.x() - p1.x();
277 mCameraData.y -= p2.y() - p1.y();
280 if ( std::isnan( mCameraData.x ) || std::isnan( mCameraData.y ) )
283 qDebug() <<
"camera position got NaN!";
284 mCameraData.x = mCameraData.y = 0;
287 if ( mCameraData.pitch > 80 )
288 mCameraData.pitch = 80;
289 if ( mCameraData.pitch < 0 )
290 mCameraData.pitch = 0;
291 if ( mCameraData.dist < 10 )
292 mCameraData.dist = 10;
294 if ( mCameraData != oldCamData )
296 mCameraData.setCamera( mCamera );
308 setCameraData( worldX, worldY, distance, 0, yaw );
310 mCamera->setNearPlane( distance / 2 );
311 mCamera->setFarPlane( distance * 2 );
318 return QgsVector3D( mCameraData.x, 0, mCameraData.y );
323 setCameraData( point.
x(), point.
z(), mCameraData.dist, mCameraData.pitch, mCameraData.yaw );
329 QDomElement elemCamera = doc.createElement(
"camera" );
330 elemCamera.setAttribute( QStringLiteral(
"x" ), mCameraData.x );
331 elemCamera.setAttribute( QStringLiteral(
"y" ), mCameraData.y );
332 elemCamera.setAttribute( QStringLiteral(
"dist" ), mCameraData.dist );
333 elemCamera.setAttribute( QStringLiteral(
"pitch" ), mCameraData.pitch );
334 elemCamera.setAttribute( QStringLiteral(
"yaw" ), mCameraData.yaw );
340 float x = elem.attribute( QStringLiteral(
"x" ) ).toFloat();
341 float y = elem.attribute( QStringLiteral(
"y" ) ).toFloat();
342 float dist = elem.attribute( QStringLiteral(
"dist" ) ).toFloat();
343 float pitch = elem.attribute( QStringLiteral(
"pitch" ) ).toFloat();
344 float yaw = elem.attribute( QStringLiteral(
"yaw" ) ).toFloat();
345 setCameraData( x, y, dist, pitch, yaw );
348 void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
350 mMousePos = QPoint( mouse->x(), mouse->y() );
353 void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
355 mLastPressedHeight = pick->worldIntersection().y();
void addTerrainPicker(Qt3DRender::QObjectPicker *picker)
Connects to object picker attached to terrain entity.
3 Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double preci...
void cameraChanged()
Emitted when camera has been updated.
QgsCameraController(Qt3DCore::QNode *parent=nullptr)
Constructs the camera controller with optional parent node that will take ownership.
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QRect viewport() const
Returns viewport rectangle.
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates) ...
double z() const
Returns Z coordinate.
float find_x_on_line(float x0, float y0, float x1, float y1, float y)
void viewportChanged()
Emitted when viewport rectangle has been updated.
void setLookingAtPoint(const QgsVector3D &point)
Sets the point toward which the camera is looking - this is used when world origin changes (e...
void readXml(const QDomElement &elem)
Reads camera configuration from the given DOM element.
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...
QDomElement writeXml(QDomDocument &doc) const
Writes camera configuration to the given DOM element.
void setCamera(Qt3DRender::QCamera *camera)
Assigns camera that should be controlled by this class. Called internally from 3D scene...
void setViewport(const QRect &viewport)
Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates...
QgsVector3D lookingAtPoint() const
Returns the point in the world coordinates towards which the camera is looking.
QPointF screen_point_to_point_on_plane(const QPointF &pt, const QRect &viewport, Qt3DRender::QCamera *camera, float y)
double x() const
Returns X coordinate.