25 #include <QDomDocument>
26 #include <Qt3DRender/QCamera>
27 #include <Qt3DRender/QObjectPicker>
28 #include <Qt3DRender/QPickEvent>
35 , mCameraBeforeRotation( new
Qt3DRender::QCamera )
38 , mMouseDevice( new
Qt3DInput::QMouseDevice() )
39 , mKeyboardDevice( new
Qt3DInput::QKeyboardDevice() )
40 , mMouseHandler( new
Qt3DInput::QMouseHandler )
41 , mKeyboardHandler( new
Qt3DInput::QKeyboardHandler )
43 mMouseHandler->setSourceDevice( mMouseDevice );
44 connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
45 this, &QgsCameraController::onPositionChanged );
46 connect( mMouseHandler, &Qt3DInput::QMouseHandler::wheel,
47 this, &QgsCameraController::onWheel );
48 connect( mMouseHandler, &Qt3DInput::QMouseHandler::pressed,
49 this, &QgsCameraController::onMousePressed );
50 connect( mMouseHandler, &Qt3DInput::QMouseHandler::released,
51 this, &QgsCameraController::onMouseReleased );
52 addComponent( mMouseHandler );
54 mKeyboardHandler->setSourceDevice( mKeyboardDevice );
55 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::pressed,
56 this, &QgsCameraController::onKeyPressed );
57 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::released,
58 this, &QgsCameraController::onKeyReleased );
59 addComponent( mKeyboardHandler );
62 connect(
this, &Qt3DCore::QEntity::enabledChanged,
63 mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
64 connect(
this, &Qt3DCore::QEntity::enabledChanged,
65 mKeyboardHandler, &Qt3DInput::QMouseHandler::setEnabled );
67 mFpsNavTimer =
new QTimer(
this );
68 mFpsNavTimer->setInterval( 10 );
69 connect( mFpsNavTimer, &QTimer::timeout,
this, &QgsCameraController::applyFlyModeKeyMovements );
70 mFpsNavTimer->start();
75 if ( navigationMode == mCameraNavigationMode )
78 mCameraNavigationMode = navigationMode;
79 mIgnoreNextMouseMove =
true;
84 if ( movementSpeed == mCameraMovementSpeed )
87 mCameraMovementSpeed = movementSpeed;
93 mVerticalAxisInversion = inversion;
100 if ( mTerrainEntity )
101 connect( te->terrainPicker(), &Qt3DRender::QObjectPicker::pressed,
this, &QgsCameraController::onPickerMousePressed );
127 static QVector3D unproject( QVector3D v,
const QMatrix4x4 &modelView,
const QMatrix4x4 &projection, QRect viewport )
134 const QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
136 QVector4D tmp( v, 1.0f );
137 tmp.setX( ( tmp.x() -
float( viewport.x() ) ) /
float( viewport.width() ) );
138 tmp.setY( ( tmp.y() -
float( viewport.y() ) ) /
float( viewport.height() ) );
139 tmp = tmp * 2.0f - QVector4D( 1.0f, 1.0f, 1.0f, 1.0f );
141 QVector4D obj = inverse * tmp;
145 return obj.toVector3D();
151 const float d_x = x1 - x0;
152 const float d_y = y1 - y0;
153 const float k = ( y - y0 ) / d_y;
160 const QVector3D l0 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 0 ), camera->viewMatrix(), camera->projectionMatrix(), viewport );
161 const QVector3D l1 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 1 ), camera->viewMatrix(), camera->projectionMatrix(), viewport );
163 const QVector3D p0( 0, y, 0 );
164 const QVector3D n( 0, 1, 0 );
165 const QVector3D l = l1 - l0;
166 const float d = QVector3D::dotProduct( p0 - l0, n ) / QVector3D::dotProduct( l, n );
167 const QVector3D p = d * l + l0;
169 return QPointF( p.x(), p.z() );
173 void QgsCameraController::rotateCamera(
float diffPitch,
float diffYaw )
178 if (
pitch + diffPitch > 180 )
179 diffPitch = 180 -
pitch;
180 if (
pitch + diffPitch < 0 )
181 diffPitch = 0 -
pitch;
188 const QQuaternion q = QQuaternion::fromEulerAngles(
pitch + diffPitch,
yaw + diffYaw, 0 ) *
189 QQuaternion::fromEulerAngles(
pitch,
yaw, 0 ).conjugated();
192 const QVector3D position = mCamera->position();
193 QVector3D viewCenter = mCamera->viewCenter();
194 const QVector3D viewVector = viewCenter - position;
195 const QVector3D cameraToCenter = q * viewVector;
196 viewCenter = position + cameraToCenter;
217 if ( mTerrainEntity )
225 mCamera->setNearPlane(
distance / 2 );
226 mCamera->setFarPlane(
distance * 2 );
248 if ( camPose == mCameraPose )
251 mCameraPose = camPose;
261 QDomElement elemCamera = doc.createElement( QStringLiteral(
"camera" ) );
262 elemCamera.setAttribute( QStringLiteral(
"x" ), mCameraPose.
centerPoint().
x() );
263 elemCamera.setAttribute( QStringLiteral(
"y" ), mCameraPose.
centerPoint().
z() );
264 elemCamera.setAttribute( QStringLiteral(
"elev" ), mCameraPose.
centerPoint().
y() );
266 elemCamera.setAttribute( QStringLiteral(
"pitch" ), mCameraPose.
pitchAngle() );
267 elemCamera.setAttribute( QStringLiteral(
"yaw" ), mCameraPose.
headingAngle() );
273 const float x = elem.attribute( QStringLiteral(
"x" ) ).toFloat();
274 const float y = elem.attribute( QStringLiteral(
"y" ) ).toFloat();
275 const float elev = elem.attribute( QStringLiteral(
"elev" ) ).toFloat();
276 const float dist = elem.attribute( QStringLiteral(
"dist" ) ).toFloat();
277 const float pitch = elem.attribute( QStringLiteral(
"pitch" ) ).toFloat();
278 const float yaw = elem.attribute( QStringLiteral(
"yaw" ) ).toFloat();
282 double QgsCameraController::cameraCenterElevation()
287 qWarning() <<
"camera position got NaN!";
293 if ( mCamera && mTerrainEntity )
297 QVector3D intersectionPoint;
298 QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForCameraCenter( mCamera );
299 if ( mTerrainEntity->rayIntersection( ray, intersectionPoint ) )
300 res = intersectionPoint.y();
302 res = mTerrainEntity->terrainElevationOffset();
305 if ( mCamera && !mTerrainEntity )
311 double QgsCameraController::sampleDepthBuffer(
const QImage &buffer,
int px,
int py )
316 for (
int x = px - 3; x <= px + 3; ++x )
318 for (
int y = py - 3; y <= py + 3; ++y )
320 if ( buffer.valid( x, y ) )
332 int samplesCount = 0;
333 for (
int x = 0; x < mDepthBufferImage.width(); ++x )
335 for (
int y = 0; y < mDepthBufferImage.height(); ++y )
347 if ( samplesCount == 0 )
350 depth /= samplesCount;
355 void QgsCameraController::updateCameraFromPose()
361 qWarning() <<
"camera position got NaN!";
377 void QgsCameraController::moveCameraPositionBy(
const QVector3D &posDiff )
395 void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
397 mIsInZoomInState =
false;
398 mCumulatedWheelY = 0;
399 switch ( mCameraNavigationMode )
402 onPositionChangedTerrainNavigation( mouse );
406 onPositionChangedFlyNavigation( mouse );
411 void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseEvent *mouse )
413 if ( mIgnoreNextMouseMove )
415 mIgnoreNextMouseMove =
false;
416 mMousePos = QPoint( mouse->x(), mouse->y() );
420 const int dx = mouse->x() - mMousePos.x();
421 const int dy = mouse->y() - mMousePos.y();
423 const bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
424 const bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
425 const bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
426 const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
427 const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
429 if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
433 double scale = std::max( mViewport.width(), mViewport.height() );
434 float pitchDiff = 180 * ( mouse->y() - mMiddleButtonClickPos.y() ) / scale;
435 float yawDiff = -180 * ( mouse->x() - mMiddleButtonClickPos.x() ) / scale;
437 if ( !mDepthBufferIsReady )
440 if ( !mRotationCenterCalculated )
442 double depth = sampleDepthBuffer( mDepthBufferImage, mMiddleButtonClickPos.x(), mMiddleButtonClickPos.y() );
446 mRotationDistanceFromCenter = ( mRotationCenter - mCameraBeforeRotation->position() ).length();
449 mRotationCenterCalculated =
true;
454 QVector3D shiftVector = mRotationCenter - mCamera->viewCenter();
456 QVector3D newViewCenterWorld =
camera()->viewCenter() + shiftVector;
457 QVector3D newCameraPosition =
camera()->position() + shiftVector;
463 updateCameraFromPose();
471 QVector3D clickedPositionWorld = ray.
origin() + mRotationDistanceFromCenter * ray.
direction();
473 QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
475 QVector3D newViewCenterWorld =
camera()->viewCenter() - shiftVector;
476 QVector3D newCameraPosition =
camera()->position() - shiftVector;
480 updateCameraFromPose();
483 else if ( hasLeftButton && hasCtrl && !hasShift )
486 const float diffPitch = 0.2f * dy;
487 const float diffYaw = - 0.2f * dx;
488 rotateCamera( diffPitch, diffYaw );
490 else if ( hasLeftButton && !hasShift && !hasCtrl )
494 if ( !mDepthBufferIsReady )
497 if ( !mDragPointCalculated )
499 double depth = sampleDepthBuffer( mDepthBufferImage, mDragButtonClickPos.x(), mDragButtonClickPos.y() );
504 mDragPointCalculated =
true;
507 QVector3D cameraBeforeDragPos = mCameraBeforeDrag->position();
510 QVector3D cameraBeforeToMoveToPos = ( moveToPosition - mCameraBeforeDrag->position() ).normalized();
511 QVector3D cameraBeforeToDragPointPos = ( mDragPoint - mCameraBeforeDrag->position() ).normalized();
514 if ( cameraBeforeToMoveToPos.y() == 0 )
516 cameraBeforeToMoveToPos.setY( 0.01 );
517 cameraBeforeToMoveToPos = cameraBeforeToMoveToPos.normalized();
520 if ( cameraBeforeToDragPointPos.y() == 0 )
522 cameraBeforeToDragPointPos.setY( 0.01 );
523 cameraBeforeToDragPointPos = cameraBeforeToDragPointPos.normalized();
526 double d1 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToMoveToPos.y();
527 double d2 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToDragPointPos.y();
529 QVector3D from = cameraBeforeDragPos + d1 * cameraBeforeToMoveToPos;
530 QVector3D to = cameraBeforeDragPos + d2 * cameraBeforeToDragPointPos;
532 QVector3D shiftVector = to - from;
534 mCameraPose.
setCenterPoint( mCameraBeforeDrag->viewCenter() + shiftVector );
535 updateCameraFromPose();
537 else if ( hasRightButton && !hasShift && !hasCtrl )
539 if ( !mDepthBufferIsReady )
542 if ( !mDragPointCalculated )
544 double depth = sampleDepthBuffer( mDepthBufferImage, mDragButtonClickPos.x(), mDragButtonClickPos.y() );
547 mDragPointCalculated =
true;
550 float dist = ( mCameraBeforeDrag->position() - mDragPoint ).length();
553 if ( mMousePos.y() > mDragButtonClickPos.y() )
555 double f = ( double )( mMousePos.y() - mDragButtonClickPos.y() ) / (
double )( mViewport.height() - mDragButtonClickPos.y() );
556 f = std::max( 0.0, std::min( 1.0, f ) );
557 f = 1 - ( std::exp( -2 * f ) - 1 ) / ( std::exp( -2 ) - 1 );
562 double f = 1 - ( double )( mMousePos.y() ) / (
double )( mDragButtonClickPos.y() );
563 f = std::max( 0.0, std::min( 1.0, f ) );
564 f = ( std::exp( 2 * f ) - 1 ) / ( std::exp( 2 ) - 1 );
565 dist = dist + 2 * dist * f;
570 QVector3D shiftVector = mDragPoint - mCamera->viewCenter();
572 QVector3D newViewCenterWorld =
camera()->viewCenter() + shiftVector;
576 updateCameraFromPose();
582 QVector3D clickedPositionWorld = ray.
origin() + dist * ray.
direction();
584 QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
586 QVector3D newViewCenterWorld =
camera()->viewCenter() - shiftVector;
587 QVector3D newCameraPosition =
camera()->position() - shiftVector;
591 updateCameraFromPose();
595 mMousePos = QPoint( mouse->x(), mouse->y() );
596 updateCameraFromPose();
603 dist -= dist * factor * 0.01f;
605 updateCameraFromPose();
608 void QgsCameraController::handleTerrainNavigationWheelZoom()
610 if ( !mDepthBufferIsReady )
613 if ( !mZoomPointCalculated )
615 double depth = sampleDepthBuffer( mDepthBufferImage, mMousePos.x(), mMousePos.y() );
618 mZoomPointCalculated =
true;
621 float f = mCumulatedWheelY / ( 120.0 * 24.0 );
623 double dist = ( mZoomPoint - mCameraBeforeZoom->position() ).length();
628 QVector3D shiftVector = mZoomPoint - mCamera->viewCenter();
630 QVector3D newViewCenterWorld =
camera()->viewCenter() + shiftVector;
634 updateCameraFromPose();
640 QVector3D clickedPositionWorld = ray.
origin() + dist * ray.
direction();
642 QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
644 QVector3D newViewCenterWorld =
camera()->viewCenter() - shiftVector;
645 QVector3D newCameraPosition =
camera()->position() - shiftVector;
649 updateCameraFromPose();
653 void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
655 switch ( mCameraNavigationMode )
659 const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.1f : 1.0f ) / 1000.f;
660 setCameraMovementSpeed( mCameraMovementSpeed + mCameraMovementSpeed * scaling * wheel->angleDelta().y() );
667 const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.5f : 5.f );
671 mCumulatedWheelY += scaling * wheel->angleDelta().y();
673 if ( !mIsInZoomInState )
677 mCameraBeforeZoom->setProjectionMatrix( mCamera->projectionMatrix() );
678 mCameraBeforeZoom->setNearPlane( mCamera->nearPlane() );
679 mCameraBeforeZoom->setFarPlane( mCamera->farPlane() );
680 mCameraBeforeZoom->setAspectRatio( mCamera->aspectRatio() );
681 mCameraBeforeZoom->setFieldOfView( mCamera->fieldOfView() );
683 mZoomPointCalculated =
false;
684 mIsInZoomInState =
true;
685 mDepthBufferIsReady =
false;
689 handleTerrainNavigationWheelZoom();
696 void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
698 mKeyboardHandler->setFocus(
true );
699 if ( mouse->button() == Qt3DInput::QMouseEvent::LeftButton || mouse->button() == Qt3DInput::QMouseEvent::RightButton )
701 mMousePos = QPoint( mouse->x(), mouse->y() );
702 mDragButtonClickPos = QPoint( mouse->x(), mouse->y() );
703 mPressedButton = mouse->button();
704 mMousePressed =
true;
706 if ( mCaptureFpsMouseMovements )
707 mIgnoreNextMouseMove =
true;
711 mCameraBeforeDrag->setProjectionMatrix( mCamera->projectionMatrix() );
712 mCameraBeforeDrag->setNearPlane( mCamera->nearPlane() );
713 mCameraBeforeDrag->setFarPlane( mCamera->farPlane() );
714 mCameraBeforeDrag->setAspectRatio( mCamera->aspectRatio() );
715 mCameraBeforeDrag->setFieldOfView( mCamera->fieldOfView() );
717 mDepthBufferIsReady =
false;
718 mDragPointCalculated =
false;
723 if ( mouse->button() == Qt3DInput::QMouseEvent::MiddleButton || ( ( mouse->modifiers() & Qt::ShiftModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) )
725 mMousePos = QPoint( mouse->x(), mouse->y() );
726 mMiddleButtonClickPos = QPoint( mouse->x(), mouse->y() );
727 mPressedButton = mouse->button();
728 mMousePressed =
true;
729 if ( mCaptureFpsMouseMovements )
730 mIgnoreNextMouseMove =
true;
731 mDepthBufferIsReady =
false;
732 mRotationCenterCalculated =
false;
737 mCameraPose.
updateCamera( mCameraBeforeRotation.get() );
739 mCameraBeforeRotation->setProjectionMatrix( mCamera->projectionMatrix() );
740 mCameraBeforeRotation->setNearPlane( mCamera->nearPlane() );
741 mCameraBeforeRotation->setFarPlane( mCamera->farPlane() );
742 mCameraBeforeRotation->setAspectRatio( mCamera->aspectRatio() );
743 mCameraBeforeRotation->setFieldOfView( mCamera->fieldOfView() );
749 void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
752 mPressedButton = Qt3DInput::QMouseEvent::NoButton;
753 mMousePressed =
false;
755 mDragPointCalculated =
false;
756 mRotationCenterCalculated =
false;
759 void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
761 if ( event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_QuoteLeft )
764 switch ( mCameraNavigationMode )
766 case NavigationMode::WalkNavigation:
769 case NavigationMode::TerrainBasedNavigation:
777 switch ( mCameraNavigationMode )
781 onKeyPressedFlyNavigation( event );
787 onKeyPressedTerrainNavigation( event );
793 void QgsCameraController::onKeyPressedTerrainNavigation( Qt3DInput::QKeyEvent *event )
795 const bool hasShift = (
event->modifiers() & Qt::ShiftModifier );
796 const bool hasCtrl = (
event->modifiers() & Qt::ControlModifier );
798 int tx = 0, ty = 0, tElev = 0;
799 switch ( event->key() )
815 case Qt::Key_PageDown:
825 if ( !hasShift && !hasCtrl )
829 else if ( hasShift && !hasCtrl )
835 else if ( hasCtrl && !hasShift )
838 const float diffPitch = ty;
839 const float diffYaw = -tx;
840 rotateCamera( diffPitch, diffYaw );
841 updateCameraFromPose();
848 center.
set( center.
x(), center.
y() + tElev * 10, center.
z() );
850 updateCameraFromPose();
854 void QgsCameraController::onKeyPressedFlyNavigation( Qt3DInput::QKeyEvent *event )
856 switch ( event->key() )
858 case Qt::Key_QuoteLeft:
861 mCaptureFpsMouseMovements = !mCaptureFpsMouseMovements;
862 mIgnoreNextMouseMove =
true;
863 if ( mCaptureFpsMouseMovements )
865 qApp->setOverrideCursor( QCursor( Qt::BlankCursor ) );
869 qApp->restoreOverrideCursor();
877 if ( mCaptureFpsMouseMovements )
879 mCaptureFpsMouseMovements =
false;
880 mIgnoreNextMouseMove =
true;
881 qApp->restoreOverrideCursor();
891 if ( event->isAutoRepeat() )
894 mDepressedKeys.insert( event->key() );
897 void QgsCameraController::applyFlyModeKeyMovements()
899 const QVector3D cameraUp = mCamera->upVector().normalized();
901 const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
903 QVector3D cameraPosDiff( 0.0f, 0.0f, 0.0f );
906 const bool shiftPressed = mDepressedKeys.contains( Qt::Key_Shift );
907 const bool ctrlPressed = mDepressedKeys.contains( Qt::Key_Control );
909 const double movementSpeed = mCameraMovementSpeed * ( shiftPressed ? 2 : 1 ) * ( ctrlPressed ? 0.1 : 1 );
911 bool changed =
false;
912 if ( mDepressedKeys.contains( Qt::Key_Left ) || mDepressedKeys.contains( Qt::Key_A ) )
915 cameraPosDiff += movementSpeed * cameraLeft;
918 if ( mDepressedKeys.contains( Qt::Key_Right ) || mDepressedKeys.contains( Qt::Key_D ) )
921 cameraPosDiff += - movementSpeed * cameraLeft;
924 if ( mDepressedKeys.contains( Qt::Key_Up ) || mDepressedKeys.contains( Qt::Key_W ) )
927 cameraPosDiff += movementSpeed * cameraFront;
930 if ( mDepressedKeys.contains( Qt::Key_Down ) || mDepressedKeys.contains( Qt::Key_S ) )
933 cameraPosDiff += - movementSpeed * cameraFront;
938 static constexpr
double ELEVATION_MOVEMENT_SCALE = 0.5;
939 if ( mDepressedKeys.contains( Qt::Key_PageUp ) || mDepressedKeys.contains( Qt::Key_E ) )
942 cameraPosDiff += ELEVATION_MOVEMENT_SCALE * movementSpeed * QVector3D( 0.0f, 1.0f, 0.0f );
945 if ( mDepressedKeys.contains( Qt::Key_PageDown ) || mDepressedKeys.contains( Qt::Key_Q ) )
948 cameraPosDiff += ELEVATION_MOVEMENT_SCALE * - movementSpeed * QVector3D( 0.0f, 1.0f, 0.0f );
952 moveCameraPositionBy( cameraPosDiff );
955 void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent *mouse )
957 const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
958 const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
960 const double dx = mCaptureFpsMouseMovements ? QCursor::pos().x() - mMousePos.x() : mouse->x() - mMousePos.x();
961 const double dy = mCaptureFpsMouseMovements ? QCursor::pos().y() - mMousePos.y() : mouse->y() - mMousePos.y();
962 mMousePos = mCaptureFpsMouseMovements ? QCursor::pos() : QPoint( mouse->x(), mouse->y() );
964 if ( mIgnoreNextMouseMove )
966 mIgnoreNextMouseMove =
false;
970 if ( hasMiddleButton )
973 const QVector3D cameraUp = mCamera->upVector().normalized();
975 const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
976 const QVector3D cameraPosDiff = -dx * cameraLeft - dy * cameraUp;
977 moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 10.0 );
979 else if ( hasRightButton )
983 const QVector3D cameraPosDiff = dy * cameraFront;
984 moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 5.0 );
988 if ( mCaptureFpsMouseMovements )
990 float diffPitch = -0.2f * dy;
991 switch ( mVerticalAxisInversion )
1002 const float diffYaw = - 0.2f * dx;
1003 rotateCamera( diffPitch, diffYaw );
1004 updateCameraFromPose();
1006 else if ( mouse->buttons() & Qt::LeftButton )
1008 float diffPitch = -0.2f * dy;
1009 switch ( mVerticalAxisInversion )
1019 const float diffYaw = - 0.2f * dx;
1020 rotateCamera( diffPitch, diffYaw );
1021 updateCameraFromPose();
1025 if ( mCaptureFpsMouseMovements )
1027 mIgnoreNextMouseMove =
true;
1030 emit
setCursorPosition( QPoint( mViewport.width() / 2, mViewport.height() / 2 ) );
1034 void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
1036 if ( event->isAutoRepeat() )
1039 mDepressedKeys.remove( event->key() );
1042 void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
1044 mLastPressedHeight = pick->worldIntersection().y();
1052 pitch -= deltaPitch;
1054 updateCameraFromPose();
1063 updateCameraFromPose();
1069 updateCameraFromPose();
1076 const float x = tx * dist * 0.02f;
1077 const float y = -ty * dist * 0.02f;
1080 const float t = sqrt( x * x + y * y );
1081 const float a = atan2( y, x ) -
yaw * M_PI / 180;
1082 const float dx = cos( a ) * t;
1083 const float dy = sin( a ) * t;
1086 center.
set( center.
x() + dx, center.
y(), center.
z() + dy );
1088 updateCameraFromPose();
1093 if ( event->key() == Qt::Key_QuoteLeft )
1096 switch ( mCameraNavigationMode )
1100 switch ( event->key() )
1110 case Qt::Key_PageUp:
1112 case Qt::Key_PageDown:
1116 case Qt::Key_Escape:
1117 if ( mCaptureFpsMouseMovements )
1129 switch ( event->key() )
1133 case Qt::Key_PageUp:
1134 case Qt::Key_PageDown:
1148 mDepthBufferImage = depthImage;
1149 mDepthBufferIsReady =
true;
1151 if ( mIsInZoomInState )
1152 handleTerrainNavigationWheelZoom();
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.
static QgsRay3D rayFromScreenPoint(const QPoint &point, const QSize &windowSize, Qt3DRender::QCamera *camera)
Convert from clicked point on the screen to a ray in world coordinates.
void setViewport(QRect viewport)
Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse 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).
float yaw() const
Returns yaw angle in degrees.
void requestDepthBufferCapture()
Emitted to ask for the depth buffer image.
void setCameraNavigationMode(QgsCameraController::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
void tiltUpAroundViewCenter(float deltaPitch)
Tilt up the view by deltaPitch around the view center (camera moves)
bool willHandleKeyEvent(QKeyEvent *event)
Returns true if the camera controller will handle the specified key event, preventing it from being i...
void navigationModeHotKeyPressed(QgsCameraController::NavigationMode mode)
Emitted when the navigation mode is changed using the hotkey ctrl + ~.
Qt3DRender::QCamera * camera
void setVerticalAxisInversion(QgsCameraController::VerticalAxisInversion inversion)
Sets the vertical axis inversion behavior.
float distance() const
Returns distance of the camera from the point it is looking at.
void setCamera(Qt3DRender::QCamera *camera)
Assigns camera that should be controlled by this class. Called internally from 3D scene.
VerticalAxisInversion
Vertical axis inversion options.
@ WhenDragging
Invert vertical axis movements when dragging in first person modes.
@ Always
Always invert vertical axis movements.
@ Never
Never invert vertical axis movements.
void cameraChanged()
Emitted when camera has been updated.
void cameraMovementSpeedChanged(double speed)
Emitted whenever the camera movement speed is changed by the controller.
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.
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...
NavigationMode
The navigation mode used by the camera.
@ WalkNavigation
Uses WASD keys or arrows to navigate in walking (first person) manner.
@ TerrainBasedNavigation
The default navigation based on the terrain.
void zoom(float factor)
Zoom the map by factor.
void setTerrainEntity(QgsTerrainEntity *te)
Connects to object picker attached to terrain entity.
void rotateAroundViewCenter(float deltaYaw)
Rotate clockwise the view by deltaYaw around the view center (camera moves)
QgsCameraController(Qt3DCore::QNode *parent=nullptr)
Constructs the camera controller with optional parent node that will take ownership.
void setCameraHeadingAngle(float angle)
Set camera heading to angle (used for rotating the view)
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
void setCameraPose(const QgsCameraPose &camPose)
Sets camera pose.
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 viewportChanged()
Emitted when viewport rectangle has been updated.
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.
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.
A representation of a ray in 3D.
QVector3D origin() const
Returns the origin of the ray.
QVector3D direction() const
Returns the direction of the ray see setDirection()
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
void set(double x, double y, double z)
Sets vector coordinates.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QPointF screen_point_to_point_on_plane(QPointF pt, QRect viewport, Qt3DRender::QCamera *camera, float y)
float find_x_on_line(float x0, float y0, float x1, float y1, float y)