17#include "moc_qgscameracontroller.cpp"
26#include <QDomDocument>
27#include <Qt3DRender/QCamera>
36 , mCamera( scene->engine()->camera() )
38 , mMouseHandler( new
Qt3DInput::QMouseHandler )
39 , mKeyboardHandler( new
Qt3DInput::QKeyboardHandler )
40 , mOrigin( scene->mapSettings()->origin() )
42 mMouseHandler->setSourceDevice(
new Qt3DInput::QMouseDevice() );
43 connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
this, &QgsCameraController::onPositionChanged );
44 connect( mMouseHandler, &Qt3DInput::QMouseHandler::wheel,
this, &QgsCameraController::onWheel );
45 connect( mMouseHandler, &Qt3DInput::QMouseHandler::pressed,
this, &QgsCameraController::onMousePressed );
46 connect( mMouseHandler, &Qt3DInput::QMouseHandler::released,
this, &QgsCameraController::onMouseReleased );
47 addComponent( mMouseHandler );
49 mKeyboardHandler->setSourceDevice(
new Qt3DInput::QKeyboardDevice() );
50 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::pressed,
this, &QgsCameraController::onKeyPressed );
51 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::released,
this, &QgsCameraController::onKeyReleased );
52 addComponent( mKeyboardHandler );
55 connect(
this, &Qt3DCore::QEntity::enabledChanged, mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
56 connect(
this, &Qt3DCore::QEntity::enabledChanged, mKeyboardHandler, &Qt3DInput::QKeyboardHandler::setEnabled );
58 mFpsNavTimer =
new QTimer(
this );
59 mFpsNavTimer->setInterval( 10 );
60 connect( mFpsNavTimer, &QTimer::timeout,
this, &QgsCameraController::applyFlyModeKeyMovements );
61 mFpsNavTimer->start();
71QWindow *QgsCameraController::window()
const
74 return windowEngine ? windowEngine->
window() :
nullptr;
79 if ( navigationMode == mCameraNavigationMode )
82 mCameraNavigationMode = navigationMode;
83 mIgnoreNextMouseMove =
true;
89 if ( movementSpeed == mCameraMovementSpeed )
94 mCameraMovementSpeed = std::clamp( movementSpeed, 0.05, 150.0 );
100 mVerticalAxisInversion = inversion;
105 const float oldPitch = mCameraPose.
pitchAngle();
107 float newPitch = oldPitch + diffPitch;
108 float newHeading = oldHeading + diffHeading;
110 newPitch = std::clamp( newPitch, 0.f, 180.f );
116 const QQuaternion q = qNew * qOld.conjugated();
119 const QVector3D position = mCamera->position();
120 QVector3D viewCenter = mCamera->viewCenter();
121 const QVector3D viewVector = viewCenter - position;
122 const QVector3D cameraToCenter = q * viewVector;
123 viewCenter = position + cameraToCenter;
128 updateCameraFromPose();
133 const float oldPitch = mCameraPose.
pitchAngle();
136 newPitch = std::clamp( newPitch, 0.f, 180.f );
142 const QQuaternion q = qNew * qOld.conjugated();
144 const QVector3D newViewCenter = q * ( mCamera->viewCenter() - pivotPoint ) + pivotPoint;
149 updateCameraFromPose();
155 QVector3D newCamPosition = pivotPoint + ( oldCameraPosition - pivotPoint ) * zoomFactor;
160 QVector3D cameraToCenter = q * QVector3D( 0, 0, -newDistance );
161 QVector3D newViewCenter = newCamPosition + cameraToCenter;
165 updateCameraFromPose();
172 if ( mCameraChanged )
175 mCameraChanged =
false;
190 const float terrainElevationOffset = terrain ? terrain->terrainElevationOffset() : 0.0f;
196 mCamera->setNearPlane(
distance / 2 );
197 mCamera->setFarPlane(
distance * 2 );
229 if ( camPose == mCameraPose && !force )
232 mCameraPose = camPose;
233 updateCameraFromPose();
238 QDomElement elemCamera = doc.createElement( QStringLiteral(
"camera" ) );
239 elemCamera.setAttribute( QStringLiteral(
"x" ), mCameraPose.
centerPoint().
x() );
240 elemCamera.setAttribute( QStringLiteral(
"y" ), mCameraPose.
centerPoint().
z() );
241 elemCamera.setAttribute( QStringLiteral(
"elev" ), mCameraPose.
centerPoint().
y() );
243 elemCamera.setAttribute( QStringLiteral(
"pitch" ), mCameraPose.
pitchAngle() );
244 elemCamera.setAttribute( QStringLiteral(
"yaw" ), mCameraPose.
headingAngle() );
250 const float x = elem.attribute( QStringLiteral(
"x" ) ).toFloat();
251 const float y = elem.attribute( QStringLiteral(
"y" ) ).toFloat();
252 const float elev = elem.attribute( QStringLiteral(
"elev" ) ).toFloat();
253 const float dist = elem.attribute( QStringLiteral(
"dist" ) ).toFloat();
254 const float pitch = elem.attribute( QStringLiteral(
"pitch" ) ).toFloat();
255 const float yaw = elem.attribute( QStringLiteral(
"yaw" ) ).toFloat();
259double QgsCameraController::sampleDepthBuffer(
int px,
int py )
264 for (
int x = px - 3; x <= px + 3; ++x )
266 for (
int y = py - 3; y <= py + 3; ++y )
268 if ( mDepthBufferImage.valid( x, y ) )
277double QgsCameraController::depthBufferNonVoidAverage()
280 if ( mDepthBufferNonVoidAverage != -1 )
281 return mDepthBufferNonVoidAverage;
285 int samplesCount = 0;
287 Q_ASSERT( mDepthBufferImage.format() == QImage::Format_RGB32 );
288 for (
int y = 0; y < mDepthBufferImage.height(); ++y )
290 const QRgb *line =
reinterpret_cast<const QRgb *
>( mDepthBufferImage.constScanLine( y ) );
291 for (
int x = 0; x < mDepthBufferImage.width(); ++x )
303 if ( samplesCount == 0 )
306 depth /= samplesCount;
308 mDepthBufferNonVoidAverage = depth;
313QgsVector3D QgsCameraController::moveGeocentricPoint(
const QgsVector3D &point,
double latDiff,
double lonDiff )
318 pointLatLon.
setX( pointLatLon.
x() + lonDiff );
319 pointLatLon.
setY( std::clamp( pointLatLon.
y() + latDiff, -90., 90. ) );
325 QgsDebugError( QStringLiteral(
"moveGeocentricPoint: transform failed!" ) );
333 const QgsVector3D newViewCenter = moveGeocentricPoint( viewCenter, latDiff, lonDiff );
335 updateCameraFromPose();
341 updateCameraFromPose();
347 updateCameraFromPose();
353 updateCameraFromPose();
365 QgsDebugError( QStringLiteral(
"resetGlobe: transform failed!" ) );
375void QgsCameraController::updateCameraFromPose()
386 viewCenterLatLon = mGlobeCrsToLatLon.
transform( viewCenter );
390 QgsDebugError( QStringLiteral(
"updateCameraFromPose: transform failed!" ) );
400 mCameraChanged =
true;
404void QgsCameraController::moveCameraPositionBy(
const QVector3D &posDiff )
407 updateCameraFromPose();
410void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
412 if ( !mInputHandlersEnabled )
415 QgsEventTracing::ScopedEvent traceEvent( QStringLiteral(
"3D" ), QStringLiteral(
"QgsCameraController::onPositionChanged" ) );
417 switch ( mCameraNavigationMode )
420 onPositionChangedTerrainNavigation( mouse );
424 onPositionChangedFlyNavigation( mouse );
428 onPositionChangedGlobeTerrainNavigation( mouse );
433bool QgsCameraController::screenPointToWorldPos( QPoint position, Qt3DRender::QCamera *mCameraBefore,
double &depth, QVector3D &worldPosition )
435 depth = sampleDepthBuffer( position.x(), position.y() );
441 depth = depthBufferNonVoidAverage();
445 if ( !std::isfinite( worldPosition.x() ) || !std::isfinite( worldPosition.y() ) || !std::isfinite( worldPosition.z() ) )
447 QgsDebugMsgLevel( QStringLiteral(
"screenPointToWorldPos: position is NaN or Inf. This should not happen." ), 2 );
454void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseEvent *mouse )
456 if ( mIgnoreNextMouseMove )
458 mIgnoreNextMouseMove =
false;
459 mMousePos = QPoint( mouse->x(), mouse->y() );
463 const int dx = mouse->x() - mMousePos.x();
464 const int dy = mouse->y() - mMousePos.y();
466 const bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
467 const bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
468 const bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
469 const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
470 const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
472 if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
475 setMouseParameters( MouseOperation::RotationCenter, mMousePos );
477 float scale =
static_cast<float>( std::max( mScene->
engine()->
size().width(), mScene->
engine()->
size().height() ) );
478 float pitchDiff = 180.0f *
static_cast<float>( mouse->y() - mClickPoint.y() ) / scale;
479 float yawDiff = -180.0f *
static_cast<float>( mouse->x() - mClickPoint.x() ) / scale;
481 if ( !mDepthBufferIsReady )
484 if ( !mRotationCenterCalculated )
487 QVector3D worldPosition;
488 if ( screenPointToWorldPos( mClickPoint, mCameraBefore.get(), depth, worldPosition ) )
490 mRotationCenter = worldPosition;
491 mRotationDistanceFromCenter = ( mRotationCenter - mCameraBefore->position() ).length();
493 mRotationCenterCalculated =
true;
499 else if ( hasLeftButton && hasCtrl && !hasShift )
501 setMouseParameters( MouseOperation::RotationCamera );
503 const float diffPitch = 0.2f * dy;
504 const float diffYaw = -0.2f * dx;
507 else if ( hasLeftButton && !hasShift && !hasCtrl )
510 setMouseParameters( MouseOperation::Translation, mMousePos );
512 if ( !mDepthBufferIsReady )
515 if ( !mDragPointCalculated )
518 QVector3D worldPosition;
519 if ( screenPointToWorldPos( mClickPoint, mCameraBefore.get(), depth, worldPosition ) )
522 mDragPoint = worldPosition;
523 mDragPointCalculated =
true;
527 QVector3D cameraBeforeDragPos = mCameraBefore->position();
530 QVector3D cameraBeforeToMoveToPos = ( moveToPosition - mCameraBefore->position() ).normalized();
531 QVector3D cameraBeforeToDragPointPos = ( mDragPoint - mCameraBefore->position() ).normalized();
534 if ( cameraBeforeToMoveToPos.z() == 0 )
536 cameraBeforeToMoveToPos.setZ( 0.01 );
537 cameraBeforeToMoveToPos = cameraBeforeToMoveToPos.normalized();
540 if ( cameraBeforeToDragPointPos.z() == 0 )
542 cameraBeforeToDragPointPos.setZ( 0.01 );
543 cameraBeforeToDragPointPos = cameraBeforeToDragPointPos.normalized();
546 double d1 = ( mDragPoint.z() - cameraBeforeDragPos.z() ) / cameraBeforeToMoveToPos.z();
547 double d2 = ( mDragPoint.z() - cameraBeforeDragPos.z() ) / cameraBeforeToDragPointPos.z();
549 QVector3D from = cameraBeforeDragPos + d1 * cameraBeforeToMoveToPos;
550 QVector3D to = cameraBeforeDragPos + d2 * cameraBeforeToDragPointPos;
552 QVector3D shiftVector = to - from;
554 mCameraPose.
setCenterPoint( mCameraBefore->viewCenter() + shiftVector );
555 updateCameraFromPose();
557 else if ( hasLeftButton && hasShift && hasCtrl )
561 double tElev = mMousePos.y() - mouse->y();
562 center.
set( center.
x(), center.
y(), center.
z() + tElev * 0.5 );
564 updateCameraFromPose();
566 else if ( hasRightButton && !hasShift && !hasCtrl )
568 setMouseParameters( MouseOperation::Zoom, mMousePos );
569 if ( !mDepthBufferIsReady )
572 if ( !mDragPointCalculated )
575 QVector3D worldPosition;
576 if ( screenPointToWorldPos( mClickPoint, mCameraBefore.get(), depth, worldPosition ) )
578 mDragPoint = worldPosition;
579 mDragPointCalculated =
true;
583 float oldDist = ( mCameraBefore->position() - mDragPoint ).length();
584 float newDist = oldDist;
587 int screenHeight = mScene->
engine()->
size().height();
588 QWindow *win = window();
591 yOffset = win->mapToGlobal( QPoint( 0, 0 ) ).y();
592 screenHeight = win->screen()->size().height();
596 if ( mMousePos.y() > mClickPoint.y() )
598 double f = ( double ) ( mMousePos.y() - mClickPoint.y() ) / (
double ) ( screenHeight - mClickPoint.y() - yOffset );
599 f = std::max( 0.0, std::min( 1.0, f ) );
600 f = 1 - ( std::expm1( -2 * f ) ) / ( std::expm1( -2 ) );
601 newDist = newDist * f;
605 double f = 1 - ( double ) ( mMousePos.y() + yOffset ) / (
double ) ( mClickPoint.y() + yOffset );
606 f = std::max( 0.0, std::min( 1.0, f ) );
607 f = ( std::expm1( 2 * f ) ) / ( std::expm1( 2 ) );
608 newDist = newDist + 2 * newDist * f;
611 double zoomFactor = newDist / oldDist;
615 mMousePos = QPoint( mouse->x(), mouse->y() );
618void QgsCameraController::onPositionChangedGlobeTerrainNavigation( Qt3DInput::QMouseEvent *mouse )
620 if ( !( mouse->buttons() & Qt::LeftButton ) )
624 setMouseParameters( MouseOperation::Translation, mMousePos );
626 if ( !mDepthBufferIsReady )
629 if ( !mDragPointCalculated )
632 QVector3D worldPosition;
633 if ( !screenPointToWorldPos( mClickPoint, mCameraBefore.get(), depth, worldPosition ) )
637 mDragPoint = worldPosition;
638 mDragPointCalculated =
true;
643 double newDepth = sampleDepthBuffer( mouse->x(), mouse->y() );
648 if ( !std::isfinite( newWorldPosition.x() ) || !std::isfinite( newWorldPosition.y() ) || !std::isfinite( newWorldPosition.z() ) )
659 oldLatLon = mGlobeCrsToLatLon.
transform( mapPressPos );
660 newLatLon = mGlobeCrsToLatLon.
transform( newMapPos );
664 QgsDebugError( QStringLiteral(
"onPositionChangedGlobeTerrainNavigation: transform failed!" ) );
668 const double latDiff = oldLatLon.
y() - newLatLon.
y();
669 const double lonDiff = oldLatLon.
x() - newLatLon.
x();
671 const QgsVector3D newVC = moveGeocentricPoint( mMousePressViewCenter, latDiff, lonDiff );
674 updateCameraFromPose();
682 dist -= dist * factor * 0.01f;
684 updateCameraFromPose();
687void QgsCameraController::handleTerrainNavigationWheelZoom()
689 if ( !mDepthBufferIsReady )
692 if ( !mZoomPointCalculated )
695 QVector3D worldPosition;
696 if ( screenPointToWorldPos( mMousePos, mCameraBefore.get(), depth, worldPosition ) )
698 mZoomPoint = worldPosition;
699 mZoomPointCalculated =
true;
703 double oldDist = ( mZoomPoint - mCameraBefore->position() ).length();
705 double newDist = std::pow( 0.8, mCumulatedWheelY ) * oldDist;
707 newDist = std::max( newDist, 2.0 );
708 double zoomFactor = newDist / oldDist;
710 zoomFactor = std::clamp( zoomFactor, 0.01, 100.0 );
714 mCumulatedWheelY = 0;
715 setMouseParameters( MouseOperation::None );
718void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
720 if ( !mInputHandlersEnabled )
723 switch ( mCameraNavigationMode )
727 const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.1f : 1.0f ) / 1000.f;
728 setCameraMovementSpeed( mCameraMovementSpeed + mCameraMovementSpeed * scaling * wheel->angleDelta().y() );
736 const double scaling = ( 1.0 / 120.0 ) * ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.1 : 1.0 );
740 mCumulatedWheelY += scaling * wheel->angleDelta().y();
742 if ( mCurrentOperation != MouseOperation::ZoomWheel )
744 setMouseParameters( MouseOperation::ZoomWheel );
749 handleTerrainNavigationWheelZoom();
756 float wheelAmount =
static_cast<float>( wheel->angleDelta().y() );
757 float factor = abs( wheelAmount ) / 1000.f;
758 float mulFactor = wheelAmount > 0 ? ( 1 - factor ) : ( 1 + factor );
760 updateCameraFromPose();
766void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
768 if ( !mInputHandlersEnabled )
771 mKeyboardHandler->setFocus(
true );
773 if ( mouse->button() == Qt3DInput::QMouseEvent::MiddleButton || ( ( mouse->modifiers() & Qt::ShiftModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) || ( ( mouse->modifiers() & Qt::ControlModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) )
775 mMousePos = QPoint( mouse->x(), mouse->y() );
777 if ( mCaptureFpsMouseMovements )
778 mIgnoreNextMouseMove =
true;
780 const MouseOperation operation {
781 ( mouse->modifiers() & Qt::ControlModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ? MouseOperation::RotationCamera : MouseOperation::RotationCenter
783 setMouseParameters( operation, mMousePos );
786 else if ( mouse->button() == Qt3DInput::QMouseEvent::LeftButton || mouse->button() == Qt3DInput::QMouseEvent::RightButton )
788 mMousePos = QPoint( mouse->x(), mouse->y() );
790 if ( mCaptureFpsMouseMovements )
791 mIgnoreNextMouseMove =
true;
793 const MouseOperation operation = ( mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) ? MouseOperation::Translation : MouseOperation::Zoom;
794 setMouseParameters( operation, mMousePos );
798void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
801 if ( !mInputHandlersEnabled )
805 setMouseParameters( MouseOperation::None );
808void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
810 if ( !mInputHandlersEnabled )
813 if ( event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_QuoteLeft )
816 switch ( mCameraNavigationMode )
829 switch ( mCameraNavigationMode )
833 onKeyPressedFlyNavigation( event );
839 onKeyPressedTerrainNavigation( event );
845 onKeyPressedGlobeTerrainNavigation( event );
851void QgsCameraController::onKeyPressedTerrainNavigation( Qt3DInput::QKeyEvent *event )
853 const bool hasShift = (
event->modifiers() & Qt::ShiftModifier );
854 const bool hasCtrl = (
event->modifiers() & Qt::ControlModifier );
856 int tx = 0, ty = 0, tElev = 0;
857 switch ( event->key() )
873 case Qt::Key_PageDown:
883 if ( !hasShift && !hasCtrl )
887 else if ( hasShift && !hasCtrl )
893 else if ( hasCtrl && !hasShift )
896 const float diffPitch = ty;
897 const float diffYaw = -tx;
905 center.
set( center.
x(), center.
y(), center.
z() + tElev * 10 );
907 updateCameraFromPose();
911void QgsCameraController::onKeyPressedGlobeTerrainNavigation( Qt3DInput::QKeyEvent *event )
915 constexpr float MOVE_FACTOR = 0.000001f;
916 constexpr float ZOOM_FACTOR = 0.9f;
918 const bool hasShift = (
event->modifiers() & Qt::ShiftModifier );
920 switch ( event->key() )
946 case Qt::Key_PageDown:
957void QgsCameraController::onKeyPressedFlyNavigation( Qt3DInput::QKeyEvent *event )
959 switch ( event->key() )
961 case Qt::Key_QuoteLeft:
964 mCaptureFpsMouseMovements = !mCaptureFpsMouseMovements;
965 mIgnoreNextMouseMove =
true;
966 if ( mCaptureFpsMouseMovements )
968 qApp->setOverrideCursor( QCursor( Qt::BlankCursor ) );
972 qApp->restoreOverrideCursor();
980 if ( mCaptureFpsMouseMovements )
982 mCaptureFpsMouseMovements =
false;
983 mIgnoreNextMouseMove =
true;
984 qApp->restoreOverrideCursor();
994 if ( event->isAutoRepeat() )
997 mDepressedKeys.insert( event->key() );
1002 const QVector3D cameraUp = mCamera->upVector().normalized();
1004 const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
1006 QVector3D cameraPosDiff( 0.0f, 0.0f, 0.0f );
1010 cameraPosDiff +=
static_cast<float>( tx ) * cameraFront;
1014 cameraPosDiff +=
static_cast<float>( ty ) * cameraLeft;
1018 cameraPosDiff +=
static_cast<float>( tz ) * QVector3D( 0.0f, 0.0f, 1.0f );
1021 moveCameraPositionBy( cameraPosDiff );
1024void QgsCameraController::applyFlyModeKeyMovements()
1027 const bool shiftPressed = mDepressedKeys.contains( Qt::Key_Shift );
1028 const bool ctrlPressed = mDepressedKeys.contains( Qt::Key_Control );
1030 const double movementSpeed = mCameraMovementSpeed * ( shiftPressed ? 2 : 1 ) * ( ctrlPressed ? 0.1 : 1 );
1032 bool changed =
false;
1036 if ( mDepressedKeys.contains( Qt::Key_Left ) || mDepressedKeys.contains( Qt::Key_A ) )
1042 if ( mDepressedKeys.contains( Qt::Key_Right ) || mDepressedKeys.contains( Qt::Key_D ) )
1048 if ( mDepressedKeys.contains( Qt::Key_Up ) || mDepressedKeys.contains( Qt::Key_W ) )
1054 if ( mDepressedKeys.contains( Qt::Key_Down ) || mDepressedKeys.contains( Qt::Key_S ) )
1062 static constexpr double ELEVATION_MOVEMENT_SCALE = 0.5;
1063 if ( mDepressedKeys.contains( Qt::Key_PageUp ) || mDepressedKeys.contains( Qt::Key_E ) )
1066 z += ELEVATION_MOVEMENT_SCALE * movementSpeed;
1069 if ( mDepressedKeys.contains( Qt::Key_PageDown ) || mDepressedKeys.contains( Qt::Key_Q ) )
1072 z -= ELEVATION_MOVEMENT_SCALE * movementSpeed;
1079void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent *mouse )
1081 const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
1082 const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
1084 const double dx = mCaptureFpsMouseMovements ? QCursor::pos().x() - mMousePos.x() : mouse->x() - mMousePos.x();
1085 const double dy = mCaptureFpsMouseMovements ? QCursor::pos().y() - mMousePos.y() : mouse->y() - mMousePos.y();
1086 mMousePos = mCaptureFpsMouseMovements ? QCursor::pos() : QPoint( mouse->x(), mouse->y() );
1088 if ( mIgnoreNextMouseMove )
1090 mIgnoreNextMouseMove =
false;
1094 if ( hasMiddleButton )
1097 const QVector3D cameraUp = mCamera->upVector().normalized();
1099 const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
1100 const QVector3D cameraPosDiff = -dx * cameraLeft - dy * cameraUp;
1101 moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 10.0 );
1103 else if ( hasRightButton )
1107 const QVector3D cameraPosDiff = dy * cameraFront;
1108 moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 5.0 );
1112 if ( mCaptureFpsMouseMovements )
1114 float diffPitch = -0.2f * dy;
1115 switch ( mVerticalAxisInversion )
1126 const float diffYaw = -0.2f * dx;
1129 else if ( mouse->buttons() & Qt::LeftButton )
1131 float diffPitch = -0.2f * dy;
1132 switch ( mVerticalAxisInversion )
1142 const float diffYaw = -0.2f * dx;
1147 if ( mCaptureFpsMouseMovements )
1149 mIgnoreNextMouseMove =
true;
1156void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
1158 if ( !mInputHandlersEnabled )
1161 if ( event->isAutoRepeat() )
1164 mDepressedKeys.remove( event->key() );
1171 pitch -= deltaPitch;
1173 updateCameraFromPose();
1182 updateCameraFromPose();
1188 updateCameraFromPose();
1195 const float x = tx * dist * 0.02f;
1196 const float y = -ty * dist * 0.02f;
1199 const float t = sqrt( x * x + y * y );
1200 const float a = atan2( y, x ) -
yaw * M_PI / 180;
1201 const float dx = cos( a ) * t;
1202 const float dy = sin( a ) * t;
1205 center.
set( center.
x() + dx, center.
y() - dy, center.
z() );
1207 updateCameraFromPose();
1212 if ( event->key() == Qt::Key_QuoteLeft )
1215 switch ( mCameraNavigationMode )
1219 switch ( event->key() )
1229 case Qt::Key_PageUp:
1231 case Qt::Key_PageDown:
1235 case Qt::Key_Escape:
1236 if ( mCaptureFpsMouseMovements )
1248 switch ( event->key() )
1254 case Qt::Key_PageUp:
1255 case Qt::Key_PageDown:
1266 switch ( event->key() )
1272 case Qt::Key_PageUp:
1273 case Qt::Key_PageDown:
1287 mDepthBufferImage = depthImage;
1288 mDepthBufferIsReady =
true;
1289 mDepthBufferNonVoidAverage = -1;
1291 if ( mCurrentOperation == MouseOperation::ZoomWheel )
1293 handleTerrainNavigationWheelZoom();
1297bool QgsCameraController::isATranslationRotationSequence( MouseOperation newOperation )
const
1299 return std::find( mTranslateOrRotate.begin(), mTranslateOrRotate.end(), newOperation ) != std::end( mTranslateOrRotate ) && std::find( mTranslateOrRotate.begin(), mTranslateOrRotate.end(), mCurrentOperation ) != std::end( mTranslateOrRotate );
1302void QgsCameraController::setMouseParameters(
const MouseOperation &newOperation,
const QPoint &clickPoint )
1304 if ( newOperation == mCurrentOperation )
1309 if ( newOperation == MouseOperation::None )
1311 mClickPoint = QPoint();
1319 else if ( mClickPoint.isNull() || isATranslationRotationSequence( newOperation ) )
1321 mClickPoint = clickPoint;
1325 mCurrentOperation = newOperation;
1326 mDepthBufferIsReady =
false;
1327 mRotationCenterCalculated =
false;
1328 mDragPointCalculated =
false;
1329 mZoomPointCalculated =
false;
1331 if ( mCurrentOperation != MouseOperation::None && mCurrentOperation != MouseOperation::RotationCamera )
1333 mMousePressViewCenter = mCameraPose.
centerPoint() + mOrigin;
1337 mCameraBefore->setPosition( mCamera->position() );
1338 mCameraBefore->setViewCenter( mCamera->viewCenter() );
1339 mCameraBefore->setUpVector( mCamera->upVector() );
1340 mCameraBefore->setProjectionMatrix( mCamera->projectionMatrix() );
1341 mCameraBefore->setNearPlane( mCamera->nearPlane() );
1342 mCameraBefore->setFarPlane( mCamera->farPlane() );
1343 mCameraBefore->setAspectRatio( mCamera->aspectRatio() );
1344 mCameraBefore->setFieldOfView( mCamera->fieldOfView() );
1354 mCameraBefore->setPosition( (
QgsVector3D( mCameraBefore->position() ) - diff ).toVector3D() );
1355 mCameraBefore->setViewCenter( (
QgsVector3D( mCameraBefore->viewCenter() ) - diff ).toVector3D() );
1356 mDragPoint = (
QgsVector3D( mDragPoint ) - diff ).toVector3D();
1357 mRotationCenter = (
QgsVector3D( mRotationCenter ) - diff ).toVector3D();
1361 updateCameraFromPose();
The Qgis class provides global constants for use throughout the application.
VerticalAxisInversion
Vertical axis inversion options for 3D views.
@ Always
Always invert vertical axis movements.
@ Never
Never invert vertical axis movements.
@ WhenDragging
Invert vertical axis movements when dragging in first person modes.
NavigationMode
The navigation mode used by 3D cameras.
@ TerrainBased
The default navigation based on the terrain.
@ Walk
Uses WASD keys or arrows to navigate in walking (first person) manner.
@ GlobeTerrainBased
Navigation similar to TerrainBased, but for use with globe.
@ Globe
Scene is represented as a globe using a geocentric CRS.
@ Reverse
Reverse/inverse transform (from destination to source)
Qgs3DMapSettings * mapSettings() const
Returns the 3D map settings.
QgsAbstract3DEngine * engine() const
Returns the abstract 3D engine.
QgsTerrainEntity * terrainEntity()
Returns terrain entity (may be temporarily nullptr)
Qgis::SceneMode sceneMode() const
Returns mode of the 3D scene - whether it is represented as a globe (when using Geocentric CRS such a...
QgsRectangle extent() const
Returns the 3D scene's 2D extent in the 3D scene's CRS.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used in the 3D scene.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
QgsVector3D origin() const
Returns coordinates in map CRS at which 3D scene has origin (0,0,0).
static QQuaternion rotationFromPitchHeadingAngles(float pitchAngle, float headingAngle)
Returns rotation quaternion that performs rotation around X axis by pitchAngle, followed by rotation ...
static double decodeDepth(const QRgb &pixel)
Decodes the depth value from the pixel's color value The depth value is encoded from OpenGL side (the...
static QVector3D screenPointToWorldPos(const QPoint &screenPoint, double depth, const QSize &screenSize, Qt3DRender::QCamera *camera)
Converts the clicked mouse position to the corresponding 3D world coordinates.
virtual QSize size() const =0
Returns size of the engine's rendering area in pixels.
void navigationModeChanged(Qgis::NavigationMode mode)
Emitted when the navigation mode is changed using the hotkey ctrl + ~.
void setLookingAtMapPoint(const QgsVector3D &point, float distance, float pitch, float yaw)
Sets camera configuration like setLookingAtPoint(), but the point is given in map coordinates.
void readXml(const QDomElement &elem)
Reads camera configuration from the given DOM element.
float pitch() const
Returns pitch angle in degrees (0 = looking from the top, 90 = looking from the side).
~QgsCameraController() override
float yaw() const
Returns yaw angle in degrees.
void requestDepthBufferCapture()
Emitted to ask for the depth buffer image.
void tiltUpAroundViewCenter(float deltaPitch)
Tilt up the view by deltaPitch around the view center (camera moves)
void globeMoveCenterPoint(double latDiff, double lonDiff)
Orbits camera around the globe by the specified amount given as the difference in latitude/longitude ...
void setVerticalAxisInversion(Qgis::VerticalAxisInversion inversion)
Sets the vertical axis inversion behavior.
bool willHandleKeyEvent(QKeyEvent *event)
Returns true if the camera controller will handle the specified key event, preventing it from being i...
float distance() const
Returns distance of the camera from the point it is looking at.
void globeUpdatePitchAngle(float angleDiff)
Updates pitch angle by the specified amount given as the angular difference in degrees.
void zoomCameraAroundPivot(const QVector3D &oldCameraPosition, double zoomFactor, const QVector3D &pivotPoint)
Zooms camera by given zoom factor (>1 one means zoom in) while keeping the pivot point (given in worl...
void globeZoom(float factor)
Moves camera closer or further away from the globe.
void rotateCamera(float diffPitch, float diffYaw)
Rotates the camera on itself.
void setCameraNavigationMode(Qgis::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
void cameraChanged()
Emitted when camera has been updated.
void cameraMovementSpeedChanged(double speed)
Emitted whenever the camera movement speed is changed by the controller.
QgsCameraController(Qgs3DMapScene *scene)
Constructs the camera controller with optional parent node that will take ownership.
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates)
void setLookingAtPoint(const QgsVector3D &point, float distance, float pitch, float yaw)
Sets the complete camera configuration: the point towards it is looking (in 3D world coordinates),...
QgsVector3D lookingAtPoint() const
Returns the point in the world coordinates towards which the camera is looking.
QgsVector3D lookingAtMapPoint() const
Returns the point in the map coordinates towards which the camera is looking.
QDomElement writeXml(QDomDocument &doc) const
Writes camera configuration to 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...
void resetGlobe(float distance, double lat=0, double lon=0)
Resets view of the globe to look at a particular location given as latitude and longitude (in degrees...
void zoom(float factor)
Zoom the map by factor.
void globeUpdateHeadingAngle(float angleDiff)
Updates heading angle by the specified amount given as the angular difference in degrees.
void rotateAroundViewCenter(float deltaYaw)
Rotate clockwise the view by deltaYaw around the view center (camera moves)
void walkView(double tx, double ty, double tz)
Walks into the map by tx, ty, and tz.
void setCameraPose(const QgsCameraPose &camPose, bool force=false)
Sets camera pose.
void setOrigin(const QgsVector3D &origin)
Reacts to the shift of origin of the scene, updating camera pose and any other member variables so th...
void setCameraHeadingAngle(float angle)
Set camera heading to angle (used for rotating the view)
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
void rotateCameraAroundPivot(float newPitch, float newHeading, const QVector3D &pivotPoint)
Rotates the camera around the pivot point (in world coordinates) to the given new pitch and heading a...
void depthBufferCaptured(const QImage &depthImage)
Sets the depth buffer image used by the camera controller to calculate world position from a pixel's ...
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
void setCursorPosition(QPoint point)
Emitted when the mouse cursor position should be moved to the specified point on the map viewport.
void moveView(float tx, float ty)
Move the map by tx and ty.
float headingAngle() const
Returns heading (yaw) angle in degrees.
QgsVector3D centerPoint() const
Returns center point (towards which point the camera is looking)
float pitchAngle() const
Returns pitch angle in degrees.
void updateCameraGlobe(Qt3DRender::QCamera *camera, double lat, double lon)
Updates camera when using a globe scene.
float distanceFromCenterPoint() const
Returns distance of the camera from the center point.
void setPitchAngle(float pitch)
Sets pitch angle in degrees.
void setCenterPoint(const QgsVector3D &point)
Sets center point (towards which point the camera is looking)
void setHeadingAngle(float heading)
Sets heading (yaw) angle in degrees.
void setDistanceFromCenterPoint(float distance)
Sets distance of the camera from the center point.
void updateCamera(Qt3DRender::QCamera *camera)
Update Qt3D camera view matrix based on the pose.
QgsCoordinateReferenceSystem toGeographicCrs() const
Returns the geographic CRS associated with this CRS object.
Custom exception class for Coordinate Reference System related exceptions.
A class to represent a 2D point.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
void setX(double x)
Sets X coordinate.
void set(double x, double y, double z)
Sets vector coordinates.
void setY(double y)
Sets Y coordinate.
QWindow * window()
Returns the internal 3D window where all the rendered output is displayed.
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)