Skip to content

Commit fbde0c8

Browse files
committedNov 6, 2018
[3d] fix camera controller using wrong shift/ctrl status (fixes #20131)
We used Qt3DInput::QLogicalDevice with its axes and actions for camera controller, but over time this got quite impractical, moreover we started to have problems with shift/ctrl actions getting stuck in wrong state in case they were pressed or released while 3D canvas was not focused (which is in fact relatively common when using other widgets in the GUI) This commit switches over to using just QMouseHandler and QKeyboardHandler for handling key and mouse events and this not only makes the code easier to read, but also the issues with shift/ctrl go away (because we do not keep their status anymore, we just check whether they are active inside event handlers). The speed of change with mouse wheel and keys should be similar or a bit less than what it was before.
1 parent 1e16680 commit fbde0c8

File tree

4 files changed

+246
-270
lines changed

4 files changed

+246
-270
lines changed
 

‎src/3d/qgs3dmapscene.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717

1818
#include <Qt3DRender/QCamera>
1919
#include <Qt3DRender/QMesh>
20+
#include <Qt3DRender/QObjectPicker>
21+
#include <Qt3DRender/QPickEvent>
2022
#include <Qt3DRender/QPickingSettings>
23+
#include <Qt3DRender/QPickTriangleEvent>
24+
#include <Qt3DRender/QPointLight>
2125
#include <Qt3DRender/QRenderSettings>
2226
#include <Qt3DRender/QSceneLoader>
2327
#include <Qt3DExtras/QForwardRenderer>

‎src/3d/qgscameracontroller.cpp

Lines changed: 215 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -21,130 +21,43 @@
2121
#include "qgis.h"
2222

2323
#include <QDomDocument>
24+
#include <Qt3DRender/QCamera>
2425
#include <Qt3DRender/QObjectPicker>
2526
#include <Qt3DRender/QPickEvent>
27+
#include <Qt3DInput>
2628

2729

2830
QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
2931
: Qt3DCore::QEntity( parent )
3032
, mMouseDevice( new Qt3DInput::QMouseDevice() )
3133
, mKeyboardDevice( new Qt3DInput::QKeyboardDevice() )
3234
, mMouseHandler( new Qt3DInput::QMouseHandler )
33-
, mLogicalDevice( new Qt3DInput::QLogicalDevice() )
34-
, mLeftMouseButtonAction( new Qt3DInput::QAction() )
35-
, mLeftMouseButtonInput( new Qt3DInput::QActionInput() )
36-
, mMiddleMouseButtonAction( new Qt3DInput::QAction() )
37-
, mMiddleMouseButtonInput( new Qt3DInput::QActionInput() )
38-
, mRightMouseButtonAction( new Qt3DInput::QAction() )
39-
, mRightMouseButtonInput( new Qt3DInput::QActionInput() )
40-
, mShiftAction( new Qt3DInput::QAction() )
41-
, mShiftInput( new Qt3DInput::QActionInput() )
42-
, mCtrlAction( new Qt3DInput::QAction() )
43-
, mCtrlInput( new Qt3DInput::QActionInput() )
44-
, mWheelAxis( new Qt3DInput::QAxis() )
45-
, mMouseWheelInput( new Qt3DInput::QAnalogAxisInput() )
46-
, mTxAxis( new Qt3DInput::QAxis() )
47-
, mTyAxis( new Qt3DInput::QAxis() )
48-
, mKeyboardTxPosInput( new Qt3DInput::QButtonAxisInput() )
49-
, mKeyboardTyPosInput( new Qt3DInput::QButtonAxisInput() )
50-
, mKeyboardTxNegInput( new Qt3DInput::QButtonAxisInput() )
51-
, mKeyboardTyNegInput( new Qt3DInput::QButtonAxisInput() )
52-
, mTelevAxis( new Qt3DInput::QAxis() )
53-
, mKeyboardTelevPosInput( new Qt3DInput::QButtonAxisInput() )
54-
, mKeyboardTelevNegInput( new Qt3DInput::QButtonAxisInput() )
35+
, mKeyboardHandler( new Qt3DInput::QKeyboardHandler )
5536
{
5637

57-
// not using QAxis + QAnalogAxisInput for mouse X,Y because
58-
// it is only in action when a mouse button is pressed.
5938
mMouseHandler->setSourceDevice( mMouseDevice );
6039
connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
6140
this, &QgsCameraController::onPositionChanged );
41+
connect( mMouseHandler, &Qt3DInput::QMouseHandler::wheel,
42+
this, &QgsCameraController::onWheel );
43+
connect( mMouseHandler, &Qt3DInput::QMouseHandler::pressed,
44+
this, &QgsCameraController::onMousePressed );
45+
connect( mMouseHandler, &Qt3DInput::QMouseHandler::released,
46+
this, &QgsCameraController::onMouseReleased );
6247
addComponent( mMouseHandler );
6348

64-
// TODO: keep using QAxis and QAction approach or just switch to using QMouseHandler / QKeyboardHandler?
65-
// it does not feel like the former approach makes anything much simpler
66-
67-
// left mouse button
68-
mLeftMouseButtonInput->setButtons( QVector<int>() << Qt::LeftButton );
69-
mLeftMouseButtonInput->setSourceDevice( mMouseDevice );
70-
mLeftMouseButtonAction->addInput( mLeftMouseButtonInput );
71-
72-
// middle mouse button
73-
mMiddleMouseButtonInput->setButtons( QVector<int>() << Qt::MiddleButton );
74-
mMiddleMouseButtonInput->setSourceDevice( mMouseDevice );
75-
mMiddleMouseButtonAction->addInput( mMiddleMouseButtonInput );
76-
77-
// right mouse button
78-
mRightMouseButtonInput->setButtons( QVector<int>() << Qt::RightButton );
79-
mRightMouseButtonInput->setSourceDevice( mMouseDevice );
80-
mRightMouseButtonAction->addInput( mRightMouseButtonInput );
81-
82-
// Mouse Wheel (Y)
83-
mMouseWheelInput->setAxis( Qt3DInput::QMouseDevice::WheelY );
84-
mMouseWheelInput->setSourceDevice( mMouseDevice );
85-
mWheelAxis->addInput( mMouseWheelInput );
86-
87-
// Keyboard shift
88-
mShiftInput->setButtons( QVector<int>() << Qt::Key_Shift );
89-
mShiftInput->setSourceDevice( mKeyboardDevice );
90-
mShiftAction->addInput( mShiftInput );
91-
92-
// Keyboard ctrl
93-
mCtrlInput->setButtons( QVector<int>() << Qt::Key_Control );
94-
mCtrlInput->setSourceDevice( mKeyboardDevice );
95-
mCtrlAction->addInput( mCtrlInput );
96-
97-
// Keyboard Pos Tx
98-
mKeyboardTxPosInput->setButtons( QVector<int>() << Qt::Key_Right );
99-
mKeyboardTxPosInput->setScale( 1.0f );
100-
mKeyboardTxPosInput->setSourceDevice( mKeyboardDevice );
101-
mTxAxis->addInput( mKeyboardTxPosInput );
102-
103-
// Keyboard Pos Ty
104-
mKeyboardTyPosInput->setButtons( QVector<int>() << Qt::Key_Up );
105-
mKeyboardTyPosInput->setScale( 1.0f );
106-
mKeyboardTyPosInput->setSourceDevice( mKeyboardDevice );
107-
mTyAxis->addInput( mKeyboardTyPosInput );
108-
109-
// Keyboard Neg Tx
110-
mKeyboardTxNegInput->setButtons( QVector<int>() << Qt::Key_Left );
111-
mKeyboardTxNegInput->setScale( -1.0f );
112-
mKeyboardTxNegInput->setSourceDevice( mKeyboardDevice );
113-
mTxAxis->addInput( mKeyboardTxNegInput );
114-
115-
// Keyboard Neg Ty
116-
mKeyboardTyNegInput->setButtons( QVector<int>() << Qt::Key_Down );
117-
mKeyboardTyNegInput->setScale( -1.0f );
118-
mKeyboardTyNegInput->setSourceDevice( mKeyboardDevice );
119-
mTyAxis->addInput( mKeyboardTyNegInput );
120-
121-
// Keyboard Neg Telev
122-
mKeyboardTelevNegInput->setButtons( QVector<int>() << Qt::Key_PageDown );
123-
mKeyboardTelevNegInput->setScale( -1.0f );
124-
mKeyboardTelevNegInput->setSourceDevice( mKeyboardDevice );
125-
mTelevAxis->addInput( mKeyboardTelevNegInput );
126-
127-
// Keyboard Pos Telev
128-
mKeyboardTelevPosInput->setButtons( QVector<int>() << Qt::Key_PageUp );
129-
mKeyboardTelevPosInput->setScale( 1.0f );
130-
mKeyboardTelevPosInput->setSourceDevice( mKeyboardDevice );
131-
mTelevAxis->addInput( mKeyboardTelevPosInput );
132-
133-
mLogicalDevice->addAction( mLeftMouseButtonAction );
134-
mLogicalDevice->addAction( mMiddleMouseButtonAction );
135-
mLogicalDevice->addAction( mRightMouseButtonAction );
136-
mLogicalDevice->addAction( mShiftAction );
137-
mLogicalDevice->addAction( mCtrlAction );
138-
mLogicalDevice->addAxis( mWheelAxis );
139-
mLogicalDevice->addAxis( mTxAxis );
140-
mLogicalDevice->addAxis( mTyAxis );
141-
mLogicalDevice->addAxis( mTelevAxis );
142-
143-
// Disable the logical device when the entity is disabled
144-
connect( this, &Qt3DCore::QEntity::enabledChanged,
145-
mLogicalDevice, &Qt3DInput::QLogicalDevice::setEnabled );
49+
mKeyboardHandler->setSourceDevice( mKeyboardDevice );
50+
connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::pressed,
51+
this, &QgsCameraController::onKeyPressed );
52+
connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::released,
53+
this, &QgsCameraController::onKeyReleased );
54+
addComponent( mKeyboardHandler );
14655

147-
addComponent( mLogicalDevice );
56+
// Disable the handlers when the entity is disabled
57+
connect( this, &Qt3DCore::QEntity::enabledChanged,
58+
mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
59+
connect( this, &Qt3DCore::QEntity::enabledChanged,
60+
mKeyboardHandler, &Qt3DInput::QMouseHandler::setEnabled );
14861
}
14962

15063
void QgsCameraController::setTerrainEntity( QgsTerrainEntity *te )
@@ -257,130 +170,7 @@ void QgsCameraController::rotateCamera( float diffPitch, float diffYaw )
257170

258171
void QgsCameraController::frameTriggered( float dt )
259172
{
260-
if ( mCamera == nullptr )
261-
return;
262-
263-
QgsCameraPose oldCamPose = mCameraPose;
264-
float dist = mCameraPose.distanceFromCenterPoint();
265-
float yaw = mCameraPose.headingAngle();
266-
float pitch = mCameraPose.pitchAngle();
267-
QgsVector3D center = mCameraPose.centerPoint();
268-
269-
int dx = mMousePos.x() - mLastMousePos.x();
270-
int dy = mMousePos.y() - mLastMousePos.y();
271-
mLastMousePos = mMousePos;
272-
273-
double scaling = ( mCtrlAction->isActive() ? 0.1 : 1.0 );
274-
dist -= scaling * dist * mWheelAxis->value() * 10 * dt;
275-
276-
if ( mRightMouseButtonAction->isActive() )
277-
{
278-
dist -= dist * dy * 0.01;
279-
}
280-
281-
float tx = mTxAxis->value() * dt * dist * 1.5;
282-
float ty = -mTyAxis->value() * dt * dist * 1.5;
283-
float telev = mTelevAxis->value() * dt * 300;
284-
285-
mCameraPose.setDistanceFromCenterPoint( dist );
286-
287-
if ( !mShiftAction->isActive() && !mCtrlAction->isActive() && ( tx || ty ) )
288-
{
289-
// moving with keyboard - take into account yaw of camera
290-
float t = sqrt( tx * tx + ty * ty );
291-
float a = atan2( ty, tx ) - yaw * M_PI / 180;
292-
float dx = cos( a ) * t;
293-
float dy = sin( a ) * t;
294-
center.set( center.x() + dx, center.y(), center.z() + dy );
295-
mCameraPose.setCenterPoint( center );
296-
}
297-
298-
if ( ( mLeftMouseButtonAction->isActive() && mShiftAction->isActive() ) || mMiddleMouseButtonAction->isActive() )
299-
{
300-
// rotate/tilt using mouse (camera moves as it rotates around its view center)
301-
pitch += dy;
302-
yaw -= dx / 2;
303-
mCameraPose.setPitchAngle( pitch );
304-
mCameraPose.setHeadingAngle( yaw );
305-
}
306-
else if ( mShiftAction->isActive() && ( mTxAxis->value() || mTyAxis->value() ) )
307-
{
308-
// rotate/tilt using keyboard (camera moves as it rotates around its view center)
309-
pitch -= mTyAxis->value(); // down key = moving camera toward terrain
310-
yaw -= mTxAxis->value(); // right key = moving camera clockwise
311-
mCameraPose.setPitchAngle( pitch );
312-
mCameraPose.setHeadingAngle( yaw );
313-
}
314-
else if ( mCtrlAction->isActive() && mLeftMouseButtonAction->isActive() )
315-
{
316-
// rotate/tilt using mouse (camera stays at one position as it rotates)
317-
float diffPitch = 0.2 * dy;
318-
float diffYaw = 0.2 * -dx / 2;
319-
rotateCamera( diffPitch, diffYaw );
320-
}
321-
else if ( mCtrlAction->isActive() && ( mTxAxis->value() || mTyAxis->value() ) )
322-
{
323-
// rotate/tilt using keyboard (camera stays at one position as it rotates)
324-
float diffPitch = mTyAxis->value(); // down key = rotating camera down
325-
float diffYaw = -mTxAxis->value(); // right key = rotating camera to the right
326-
rotateCamera( diffPitch, diffYaw );
327-
}
328-
else if ( mLeftMouseButtonAction->isActive() && !mShiftAction->isActive() )
329-
{
330-
// translation works as if one grabbed a point on the plane and dragged it
331-
// i.e. find out x,z of the previous mouse point, find out x,z of the current mouse point
332-
// and use the difference
333-
334-
float z = mLastPressedHeight;
335-
QPointF p1 = screen_point_to_point_on_plane( QPointF( mMousePos - QPoint( dx, dy ) ), mViewport, mCamera, z );
336-
QPointF p2 = screen_point_to_point_on_plane( QPointF( mMousePos ), mViewport, mCamera, z );
337-
338-
center.set( center.x() - ( p2.x() - p1.x() ), center.y(), center.z() - ( p2.y() - p1.y() ) );
339-
mCameraPose.setCenterPoint( center );
340-
}
341-
342-
if ( telev != 0 )
343-
{
344-
center.set( center.x(), center.y() + telev, center.z() );
345-
mCameraPose.setCenterPoint( center );
346-
}
347-
348-
if ( std::isnan( mCameraPose.centerPoint().x() ) || std::isnan( mCameraPose.centerPoint().y() ) || std::isnan( mCameraPose.centerPoint().z() ) )
349-
{
350-
// something went horribly wrong but we need to at least try to fix it somehow
351-
qDebug() << "camera position got NaN!";
352-
center.set( 0, 0, 0 );
353-
mCameraPose.setCenterPoint( center );
354-
}
355-
356-
if ( mCameraPose.pitchAngle() > 180 )
357-
mCameraPose.setPitchAngle( 180 ); // prevent going over the head
358-
if ( mCameraPose.pitchAngle() < 0 )
359-
mCameraPose.setPitchAngle( 0 ); // prevent going over the head
360-
if ( mCameraPose.distanceFromCenterPoint() < 10 )
361-
mCameraPose.setDistanceFromCenterPoint( 10 );
362-
363-
if ( mCameraPose != oldCamPose )
364-
{
365-
mCameraPose.updateCamera( mCamera );
366-
367-
if ( mTerrainEntity && mCameraPose.centerPoint() != oldCamPose.centerPoint() )
368-
{
369-
// figure out our distance from terrain and update the camera's view center
370-
// so that camera tilting and rotation is around a point on terrain, not an point at fixed elevation
371-
QVector3D intersectionPoint;
372-
QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForCameraCenter( mCamera );
373-
if ( mTerrainEntity->rayIntersection( ray, intersectionPoint ) )
374-
{
375-
float dist = ( intersectionPoint - mCamera->position() ).length();
376-
mCameraPose.setDistanceFromCenterPoint( dist );
377-
mCameraPose.setCenterPoint( QgsVector3D( intersectionPoint ) );
378-
mCameraPose.updateCamera( mCamera );
379-
}
380-
}
381-
382-
emit cameraChanged();
383-
}
173+
Q_UNUSED( dt );
384174
}
385175

386176
void QgsCameraController::resetView( float distance )
@@ -453,11 +243,205 @@ void QgsCameraController::readXml( const QDomElement &elem )
453243
setLookingAtPoint( QgsVector3D( x, elev, y ), dist, pitch, yaw );
454244
}
455245

246+
void QgsCameraController::updateCameraFromPose( bool centerPointChanged )
247+
{
248+
if ( std::isnan( mCameraPose.centerPoint().x() ) || std::isnan( mCameraPose.centerPoint().y() ) || std::isnan( mCameraPose.centerPoint().z() ) )
249+
{
250+
// something went horribly wrong but we need to at least try to fix it somehow
251+
qDebug() << "camera position got NaN!";
252+
mCameraPose.setCenterPoint( QgsVector3D( 0, 0, 0 ) );
253+
}
254+
255+
if ( mCameraPose.pitchAngle() > 180 )
256+
mCameraPose.setPitchAngle( 180 ); // prevent going over the head
257+
if ( mCameraPose.pitchAngle() < 0 )
258+
mCameraPose.setPitchAngle( 0 ); // prevent going over the head
259+
if ( mCameraPose.distanceFromCenterPoint() < 10 )
260+
mCameraPose.setDistanceFromCenterPoint( 10 );
261+
262+
if ( mCamera )
263+
mCameraPose.updateCamera( mCamera );
264+
265+
if ( mCamera && mTerrainEntity && centerPointChanged )
266+
{
267+
// figure out our distance from terrain and update the camera's view center
268+
// so that camera tilting and rotation is around a point on terrain, not an point at fixed elevation
269+
QVector3D intersectionPoint;
270+
QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForCameraCenter( mCamera );
271+
if ( mTerrainEntity->rayIntersection( ray, intersectionPoint ) )
272+
{
273+
float dist = ( intersectionPoint - mCamera->position() ).length();
274+
mCameraPose.setDistanceFromCenterPoint( dist );
275+
mCameraPose.setCenterPoint( QgsVector3D( intersectionPoint ) );
276+
mCameraPose.updateCamera( mCamera );
277+
}
278+
}
279+
280+
emit cameraChanged();
281+
}
282+
456283
void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
457284
{
285+
int dx = mouse->x() - mMousePos.x();
286+
int dy = mouse->y() - mMousePos.y();
287+
288+
bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
289+
bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
290+
bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
291+
bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
292+
bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
293+
294+
if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
295+
{
296+
// rotate/tilt using mouse (camera moves as it rotates around its view center)
297+
float pitch = mCameraPose.pitchAngle();
298+
float yaw = mCameraPose.headingAngle();
299+
pitch += dy;
300+
yaw -= dx / 2;
301+
mCameraPose.setPitchAngle( pitch );
302+
mCameraPose.setHeadingAngle( yaw );
303+
updateCameraFromPose();
304+
}
305+
else if ( hasLeftButton && hasCtrl && !hasShift )
306+
{
307+
// rotate/tilt using mouse (camera stays at one position as it rotates)
308+
float diffPitch = 0.2f * dy;
309+
float diffYaw = 0.2f * -dx / 2;
310+
rotateCamera( diffPitch, diffYaw );
311+
updateCameraFromPose( true );
312+
}
313+
else if ( hasLeftButton && !hasShift && !hasCtrl )
314+
{
315+
// translation works as if one grabbed a point on the plane and dragged it
316+
// i.e. find out x,z of the previous mouse point, find out x,z of the current mouse point
317+
// and use the difference
318+
319+
float z = mLastPressedHeight;
320+
QPointF p1 = screen_point_to_point_on_plane( QPointF( mMousePos.x(), mMousePos.y() ), mViewport, mCamera, z );
321+
QPointF p2 = screen_point_to_point_on_plane( QPointF( mouse->x(), mouse->y() ), mViewport, mCamera, z );
322+
323+
QgsVector3D center = mCameraPose.centerPoint();
324+
center.set( center.x() - ( p2.x() - p1.x() ), center.y(), center.z() - ( p2.y() - p1.y() ) );
325+
mCameraPose.setCenterPoint( center );
326+
updateCameraFromPose( true );
327+
}
328+
else if ( hasRightButton && !hasShift && !hasCtrl )
329+
{
330+
// zoom in/out
331+
float dist = mCameraPose.distanceFromCenterPoint();
332+
dist -= dist * dy * 0.01f;
333+
mCameraPose.setDistanceFromCenterPoint( dist );
334+
updateCameraFromPose();
335+
}
336+
458337
mMousePos = QPoint( mouse->x(), mouse->y() );
459338
}
460339

340+
void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
341+
{
342+
float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) ? 0.1f : 1.0f ) / 1000.f;
343+
float dist = mCameraPose.distanceFromCenterPoint();
344+
dist -= dist * scaling * wheel->angleDelta().y();
345+
mCameraPose.setDistanceFromCenterPoint( dist );
346+
updateCameraFromPose();
347+
}
348+
349+
void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
350+
{
351+
Q_UNUSED( mouse );
352+
mKeyboardHandler->setFocus( true );
353+
}
354+
355+
void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
356+
{
357+
Q_UNUSED( mouse );
358+
}
359+
360+
void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
361+
{
362+
bool hasShift = ( event->modifiers() & Qt::ShiftModifier );
363+
bool hasCtrl = ( event->modifiers() & Qt::ControlModifier );
364+
365+
int tx = 0, ty = 0, tElev = 0;
366+
switch ( event->key() )
367+
{
368+
case Qt::Key_Left:
369+
tx -= 1;
370+
break;
371+
case Qt::Key_Right:
372+
tx += 1;
373+
break;
374+
375+
case Qt::Key_Up:
376+
ty += 1;
377+
break;
378+
case Qt::Key_Down:
379+
ty -= 1;
380+
break;
381+
382+
case Qt::Key_PageDown:
383+
tElev -= 1;
384+
break;
385+
case Qt::Key_PageUp:
386+
tElev += 1;
387+
break;
388+
}
389+
390+
if ( tx || ty )
391+
{
392+
if ( !hasShift && !hasCtrl )
393+
{
394+
float yaw = mCameraPose.headingAngle();
395+
float dist = mCameraPose.distanceFromCenterPoint();
396+
float x = tx * dist * 0.02f;
397+
float y = -ty * dist * 0.02f;
398+
399+
// moving with keyboard - take into account yaw of camera
400+
float t = sqrt( x * x + y * y );
401+
float a = atan2( y, x ) - yaw * M_PI / 180;
402+
float dx = cos( a ) * t;
403+
float dy = sin( a ) * t;
404+
405+
QgsVector3D center = mCameraPose.centerPoint();
406+
center.set( center.x() + dx, center.y(), center.z() + dy );
407+
mCameraPose.setCenterPoint( center );
408+
updateCameraFromPose( true );
409+
}
410+
else if ( hasShift && !hasCtrl )
411+
{
412+
// rotate/tilt using keyboard (camera moves as it rotates around its view center)
413+
float pitch = mCameraPose.pitchAngle();
414+
float yaw = mCameraPose.headingAngle();
415+
pitch -= ty; // down key = moving camera toward terrain
416+
yaw -= tx; // right key = moving camera clockwise
417+
mCameraPose.setPitchAngle( pitch );
418+
mCameraPose.setHeadingAngle( yaw );
419+
updateCameraFromPose();
420+
}
421+
else if ( hasCtrl && !hasShift )
422+
{
423+
// rotate/tilt using keyboard (camera stays at one position as it rotates)
424+
float diffPitch = ty; // down key = rotating camera down
425+
float diffYaw = -tx; // right key = rotating camera to the right
426+
rotateCamera( diffPitch, diffYaw );
427+
updateCameraFromPose( true );
428+
}
429+
}
430+
431+
if ( tElev )
432+
{
433+
QgsVector3D center = mCameraPose.centerPoint();
434+
center.set( center.x(), center.y() + tElev * 10, center.z() );
435+
mCameraPose.setCenterPoint( center );
436+
updateCameraFromPose( true );
437+
}
438+
}
439+
440+
void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
441+
{
442+
Q_UNUSED( event );
443+
}
444+
461445
void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
462446
{
463447
mLastPressedHeight = pick->worldIntersection().y();

‎src/3d/qgscameracontroller.h

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,26 @@
1818

1919
#include "qgis_3d.h"
2020

21+
#include <QPointer>
22+
#include <QRect>
2123
#include <Qt3DCore/QEntity>
22-
#include <Qt3DInput>
23-
#include <Qt3DRender>
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+
}
2441

2542
#include "qgscamerapose.h"
2643

@@ -120,6 +137,7 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
120137

121138
private:
122139
void rotateCamera( float diffPitch, float diffYaw );
140+
void updateCameraFromPose( bool centerPointChanged = false );
123141

124142
signals:
125143
//! Emitted when camera has been updated
@@ -129,6 +147,11 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
129147

130148
private slots:
131149
void onPositionChanged( Qt3DInput::QMouseEvent *mouse );
150+
void onWheel( Qt3DInput::QWheelEvent *wheel );
151+
void onMousePressed( Qt3DInput::QMouseEvent *mouse );
152+
void onMouseReleased( Qt3DInput::QMouseEvent *mouse );
153+
void onKeyPressed( Qt3DInput::QKeyEvent *event );
154+
void onKeyReleased( Qt3DInput::QKeyEvent *event );
132155
void onPickerMousePressed( Qt3DRender::QPickEvent *pick );
133156

134157
private:
@@ -146,50 +169,14 @@ class _3D_EXPORT QgsCameraController : public Qt3DCore::QEntity
146169

147170
//! Last mouse position recorded
148171
QPoint mMousePos;
149-
//! Mouse position used in the previous frame
150-
QPoint mLastMousePos;
151172

152173
//! Delegates mouse events to the attached MouseHandler objects
153174
Qt3DInput::QMouseDevice *mMouseDevice = nullptr;
154-
155175
Qt3DInput::QKeyboardDevice *mKeyboardDevice = nullptr;
156176

157177
Qt3DInput::QMouseHandler *mMouseHandler = nullptr;
178+
Qt3DInput::QKeyboardHandler *mKeyboardHandler = nullptr;
158179

159-
/**
160-
* Allows us to define a set of actions that we wish to use
161-
* (it is a component that can be attached to 3D scene)
162-
*/
163-
Qt3DInput::QLogicalDevice *mLogicalDevice = nullptr;
164-
165-
Qt3DInput::QAction *mLeftMouseButtonAction = nullptr;
166-
Qt3DInput::QActionInput *mLeftMouseButtonInput = nullptr;
167-
168-
Qt3DInput::QAction *mMiddleMouseButtonAction = nullptr;
169-
Qt3DInput::QActionInput *mMiddleMouseButtonInput = nullptr;
170-
171-
Qt3DInput::QAction *mRightMouseButtonAction = nullptr;
172-
Qt3DInput::QActionInput *mRightMouseButtonInput = nullptr;
173-
174-
Qt3DInput::QAction *mShiftAction = nullptr;
175-
Qt3DInput::QActionInput *mShiftInput = nullptr;
176-
177-
Qt3DInput::QAction *mCtrlAction = nullptr;
178-
Qt3DInput::QActionInput *mCtrlInput = nullptr;
179-
180-
Qt3DInput::QAxis *mWheelAxis = nullptr;
181-
Qt3DInput::QAnalogAxisInput *mMouseWheelInput = nullptr;
182-
183-
Qt3DInput::QAxis *mTxAxis = nullptr;
184-
Qt3DInput::QAxis *mTyAxis = nullptr;
185-
Qt3DInput::QButtonAxisInput *mKeyboardTxPosInput = nullptr;
186-
Qt3DInput::QButtonAxisInput *mKeyboardTyPosInput = nullptr;
187-
Qt3DInput::QButtonAxisInput *mKeyboardTxNegInput = nullptr;
188-
Qt3DInput::QButtonAxisInput *mKeyboardTyNegInput = nullptr;
189-
190-
Qt3DInput::QAxis *mTelevAxis = nullptr;
191-
Qt3DInput::QButtonAxisInput *mKeyboardTelevPosInput = nullptr;
192-
Qt3DInput::QButtonAxisInput *mKeyboardTelevNegInput = nullptr;
193180
};
194181

195182
#endif // QGSCAMERACONTROLLER_H

‎src/app/3d/qgs3dmapcanvas.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <QBoxLayout>
1919
#include <Qt3DExtras/Qt3DWindow>
2020
#include <Qt3DRender/QRenderCapture>
21+
#include <QMouseEvent>
2122

2223
#include "qgscameracontroller.h"
2324
#include "qgs3dmapsettings.h"

0 commit comments

Comments
 (0)
Please sign in to comment.