24#include <QDomDocument> 
   25#include <Qt3DRender/QCamera> 
   33  , mCamera( scene->engine()->camera() )
 
   34  , mCameraBeforeRotation( new 
Qt3DRender::QCamera )
 
   37  , mMouseHandler( new 
Qt3DInput::QMouseHandler )
 
   38  , mKeyboardHandler( new 
Qt3DInput::QKeyboardHandler )
 
   40  mMouseHandler->setSourceDevice( 
new Qt3DInput::QMouseDevice() );
 
   41  connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
 
   42           this, &QgsCameraController::onPositionChanged );
 
   43  connect( mMouseHandler, &Qt3DInput::QMouseHandler::wheel,
 
   44           this, &QgsCameraController::onWheel );
 
   45  connect( mMouseHandler, &Qt3DInput::QMouseHandler::pressed,
 
   46           this, &QgsCameraController::onMousePressed );
 
   47  connect( mMouseHandler, &Qt3DInput::QMouseHandler::released,
 
   48           this, &QgsCameraController::onMouseReleased );
 
   49  addComponent( mMouseHandler );
 
   51  mKeyboardHandler->setSourceDevice( 
new Qt3DInput::QKeyboardDevice() );
 
   52  connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::pressed,
 
   53           this, &QgsCameraController::onKeyPressed );
 
   54  connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::released,
 
   55           this, &QgsCameraController::onKeyReleased );
 
   56  addComponent( mKeyboardHandler );
 
   59  connect( 
this, &Qt3DCore::QEntity::enabledChanged,
 
   60           mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
 
   61  connect( 
this, &Qt3DCore::QEntity::enabledChanged,
 
   62           mKeyboardHandler, &Qt3DInput::QKeyboardHandler::setEnabled );
 
   64  mFpsNavTimer = 
new QTimer( 
this );
 
   65  mFpsNavTimer->setInterval( 10 );
 
   66  connect( mFpsNavTimer, &QTimer::timeout, 
this, &QgsCameraController::applyFlyModeKeyMovements );
 
   67  mFpsNavTimer->start();
 
   72QWindow *QgsCameraController::window()
 const 
   75  return windowEngine ? windowEngine->
window() : 
nullptr;
 
   80  if ( navigationMode == mCameraNavigationMode )
 
   83  mCameraNavigationMode = navigationMode;
 
   84  mIgnoreNextMouseMove = 
true;
 
   90  if ( movementSpeed == mCameraMovementSpeed )
 
   93  mCameraMovementSpeed = movementSpeed;
 
   99  mVerticalAxisInversion = inversion;
 
  107  if ( 
pitch + diffPitch > 180 )
 
  108    diffPitch = 180 - 
pitch;  
 
  109  if ( 
pitch + diffPitch < 0 )
 
  110    diffPitch = 0 - 
pitch;   
 
  117  const QQuaternion q = QQuaternion::fromEulerAngles( 
pitch + diffPitch, 
yaw + diffYaw, 0 ) *
 
  118                        QQuaternion::fromEulerAngles( 
pitch, 
yaw, 0 ).conjugated();
 
  121  const QVector3D position = mCamera->position();
 
  122  QVector3D viewCenter = mCamera->viewCenter();
 
  123  const QVector3D viewVector = viewCenter - position;
 
  124  const QVector3D cameraToCenter = q * viewVector;
 
  125  viewCenter = position + cameraToCenter;
 
  130  updateCameraFromPose();
 
  156  mCamera->setNearPlane( 
distance / 2 );
 
  157  mCamera->setFarPlane( 
distance * 2 );
 
  179  if ( camPose == mCameraPose )
 
  182  mCameraPose = camPose;
 
  192  QDomElement elemCamera = doc.createElement( QStringLiteral( 
"camera" ) );
 
  193  elemCamera.setAttribute( QStringLiteral( 
"x" ), mCameraPose.
centerPoint().
x() );
 
  194  elemCamera.setAttribute( QStringLiteral( 
"y" ), mCameraPose.
centerPoint().
z() );
 
  195  elemCamera.setAttribute( QStringLiteral( 
"elev" ), mCameraPose.
centerPoint().
y() );
 
  197  elemCamera.setAttribute( QStringLiteral( 
"pitch" ), mCameraPose.
pitchAngle() );
 
  198  elemCamera.setAttribute( QStringLiteral( 
"yaw" ), mCameraPose.
headingAngle() );
 
  204  const float x = elem.attribute( QStringLiteral( 
"x" ) ).toFloat();
 
  205  const float y = elem.attribute( QStringLiteral( 
"y" ) ).toFloat();
 
  206  const float elev = elem.attribute( QStringLiteral( 
"elev" ) ).toFloat();
 
  207  const float dist = elem.attribute( QStringLiteral( 
"dist" ) ).toFloat();
 
  208  const float pitch = elem.attribute( QStringLiteral( 
"pitch" ) ).toFloat();
 
  209  const float yaw = elem.attribute( QStringLiteral( 
"yaw" ) ).toFloat();
 
  213double QgsCameraController::sampleDepthBuffer( 
const QImage &buffer, 
int px, 
int py )
 
  218  for ( 
int x = px - 3; x <= px + 3; ++x )
 
  220    for ( 
int y = py - 3; y <= py + 3; ++y )
 
  222      if ( buffer.valid( x, y ) )
 
  234  int samplesCount = 0;
 
  235  for ( 
int x = 0; x < buffer.width(); ++x )
 
  237    for ( 
int y = 0; y < buffer.height(); ++y )
 
  249  if ( samplesCount == 0 )
 
  252    depth /= samplesCount;
 
  257void QgsCameraController::updateCameraFromPose()
 
  264void QgsCameraController::moveCameraPositionBy( 
const QVector3D &posDiff )
 
  267  updateCameraFromPose();
 
  270void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
 
  272  switch ( mCameraNavigationMode )
 
  275      onPositionChangedTerrainNavigation( mouse );
 
  279      onPositionChangedFlyNavigation( mouse );
 
  284bool QgsCameraController::screenPointToWorldPos( QPoint position, Qt3DRender::QCamera *cameraBefore, 
double &depth, QVector3D &worldPosition )
 
  286  depth = sampleDepthBuffer( mDepthBufferImage, position.x(), position.y() );
 
  287  if ( !std::isfinite( depth ) )
 
  289    QgsDebugMsgLevel( QStringLiteral( 
"screenPointToWorldPos: depth is NaN or Inf. This should not happen." ), 2 );
 
  295    if ( !std::isfinite( worldPosition.x() ) || !std::isfinite( worldPosition.y() ) || !std::isfinite( worldPosition.z() ) )
 
  297      QgsDebugMsgLevel( QStringLiteral( 
"screenPointToWorldPos: position is NaN or Inf. This should not happen." ), 2 );
 
  307void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseEvent *mouse )
 
  309  if ( mIgnoreNextMouseMove )
 
  311    mIgnoreNextMouseMove = 
false;
 
  312    mMousePos = QPoint( mouse->x(), mouse->y() );
 
  316  const int dx = mouse->x() - mMousePos.x();
 
  317  const int dy = mouse->y() - mMousePos.y();
 
  319  const bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
 
  320  const bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
 
  321  const bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
 
  322  const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
 
  323  const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
 
  325  if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
 
  330    float pitchDiff = 180 * ( mouse->y() - mMiddleButtonClickPos.y() ) / scale;
 
  331    float yawDiff = -180 * ( mouse->x() - mMiddleButtonClickPos.x() ) / scale;
 
  333    if ( !mDepthBufferIsReady )
 
  336    if ( !mRotationCenterCalculated )
 
  339      QVector3D worldPosition;
 
  340      if ( screenPointToWorldPos( mMiddleButtonClickPos, mCameraBeforeRotation.get(), depth, worldPosition ) )
 
  342        mRotationCenter = worldPosition;
 
  343        mRotationDistanceFromCenter = ( mRotationCenter - mCameraBeforeRotation->position() ).length();
 
  345        mRotationCenterCalculated = 
true;
 
  351      QVector3D shiftVector = mRotationCenter - mCamera->viewCenter();
 
  353      QVector3D newViewCenterWorld = 
camera()->viewCenter() + shiftVector;
 
  354      QVector3D newCameraPosition = 
camera()->position() + shiftVector;
 
  360      updateCameraFromPose();
 
  368      QVector3D clickedPositionWorld = ray.
origin() + mRotationDistanceFromCenter * ray.
direction();
 
  370      QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
 
  372      QVector3D newViewCenterWorld = 
camera()->viewCenter() - shiftVector;
 
  373      QVector3D newCameraPosition = 
camera()->position() - shiftVector;
 
  377      updateCameraFromPose();
 
  380  else if ( hasLeftButton && hasCtrl && !hasShift )
 
  383    const float diffPitch = 0.2f * dy;
 
  384    const float diffYaw = - 0.2f * dx;
 
  387  else if ( hasLeftButton && !hasShift && !hasCtrl )
 
  391    if ( !mDepthBufferIsReady )
 
  394    if ( !mDragPointCalculated )
 
  397      QVector3D worldPosition;
 
  398      if ( screenPointToWorldPos( mDragButtonClickPos, mCameraBeforeDrag.get(), depth, worldPosition ) )
 
  401        mDragPoint = worldPosition;
 
  402        mDragPointCalculated = 
true;
 
  407    QVector3D cameraBeforeDragPos = mCameraBeforeDrag->position();
 
  410    QVector3D cameraBeforeToMoveToPos = ( moveToPosition - mCameraBeforeDrag->position() ).normalized();
 
  411    QVector3D cameraBeforeToDragPointPos = ( mDragPoint - mCameraBeforeDrag->position() ).normalized();
 
  414    if ( cameraBeforeToMoveToPos.y() == 0 )
 
  416      cameraBeforeToMoveToPos.setY( 0.01 );
 
  417      cameraBeforeToMoveToPos = cameraBeforeToMoveToPos.normalized();
 
  420    if ( cameraBeforeToDragPointPos.y() == 0 )
 
  422      cameraBeforeToDragPointPos.setY( 0.01 );
 
  423      cameraBeforeToDragPointPos = cameraBeforeToDragPointPos.normalized();
 
  426    double d1 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToMoveToPos.y();
 
  427    double d2 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToDragPointPos.y();
 
  429    QVector3D from = cameraBeforeDragPos + d1 * cameraBeforeToMoveToPos;
 
  430    QVector3D to = cameraBeforeDragPos + d2 * cameraBeforeToDragPointPos;
 
  432    QVector3D shiftVector = to - from;
 
  434    mCameraPose.
setCenterPoint( mCameraBeforeDrag->viewCenter() + shiftVector );
 
  435    updateCameraFromPose();
 
  437  else if ( hasLeftButton && hasShift && hasCtrl )
 
  441    double tElev = mMousePos.y() - mouse->y();
 
  442    center.
set( center.
x(), center.
y() + tElev * 0.5, center.
z() );
 
  444    updateCameraFromPose();
 
  446  else if ( hasRightButton && !hasShift && !hasCtrl )
 
  448    if ( !mDepthBufferIsReady )
 
  451    if ( !mDragPointCalculated )
 
  454      QVector3D worldPosition;
 
  455      if ( screenPointToWorldPos( mDragButtonClickPos, mCameraBeforeDrag.get(), depth, worldPosition ) )
 
  457        mDragPoint = worldPosition;
 
  458        mDragPointCalculated = 
true;
 
  462    float dist = ( mCameraBeforeDrag->position() - mDragPoint ).length();
 
  465    int screenHeight = mScene->
engine()->
size().height();
 
  466    QWindow *win = window();
 
  469      yOffset = win->mapToGlobal( QPoint( 0, 0 ) ).y();
 
  470      screenHeight = win->screen()->size().height();
 
  474    if ( mMousePos.y() > mDragButtonClickPos.y() ) 
 
  476      double f = ( double )( mMousePos.y() - mDragButtonClickPos.y() ) / ( 
double )( screenHeight - mDragButtonClickPos.y() - yOffset );
 
  477      f = std::max( 0.0, std::min( 1.0, f ) );
 
  478      f = 1 - ( std::expm1( -2 * f ) ) / ( std::expm1( -2 ) );
 
  483      double f = 1 - ( double )( mMousePos.y() + yOffset ) / ( 
double )( mDragButtonClickPos.y() + yOffset );
 
  484      f = std::max( 0.0, std::min( 1.0, f ) );
 
  485      f = ( std::expm1( 2 * f ) ) / ( std::expm1( 2 ) );
 
  486      dist = dist + 2 * dist * f;
 
  491      QVector3D shiftVector = mDragPoint - mCamera->viewCenter();
 
  493      QVector3D newViewCenterWorld = 
camera()->viewCenter() + shiftVector;
 
  497      updateCameraFromPose();
 
  503      QVector3D clickedPositionWorld = ray.
origin() + dist * ray.
direction();
 
  505      QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
 
  507      QVector3D newViewCenterWorld = 
camera()->viewCenter() - shiftVector;
 
  508      QVector3D newCameraPosition = 
camera()->position() - shiftVector;
 
  512      updateCameraFromPose();
 
  516  mMousePos = QPoint( mouse->x(), mouse->y() );
 
  523  dist -= dist * factor * 0.01f;
 
  525  updateCameraFromPose();
 
  528void QgsCameraController::handleTerrainNavigationWheelZoom()
 
  530  if ( !mDepthBufferIsReady )
 
  533  if ( !mZoomPointCalculated )
 
  536    QVector3D worldPosition;
 
  537    if ( screenPointToWorldPos( mMousePos, mCameraBeforeZoom.get(), depth, worldPosition ) )
 
  539      mZoomPoint = worldPosition;
 
  540      mZoomPointCalculated = 
true;
 
  544  float f = mCumulatedWheelY / ( 120.0 * 24.0 );
 
  546  double dist = ( mZoomPoint - mCameraBeforeZoom->position() ).length();
 
  551    QVector3D shiftVector = mZoomPoint - mCamera->viewCenter();
 
  553    QVector3D newViewCenterWorld = 
camera()->viewCenter() + shiftVector;
 
  557    updateCameraFromPose();
 
  563    QVector3D clickedPositionWorld = ray.
origin() + dist * ray.
direction();
 
  565    QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
 
  567    QVector3D newViewCenterWorld = 
camera()->viewCenter() - shiftVector;
 
  568    QVector3D newCameraPosition = 
camera()->position() - shiftVector;
 
  572    updateCameraFromPose();
 
  574  mIsInZoomInState = 
false;
 
  575  mCumulatedWheelY = 0;
 
  578void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
 
  580  switch ( mCameraNavigationMode )
 
  584      const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.1f : 1.0f ) / 1000.f;
 
  585      setCameraMovementSpeed( mCameraMovementSpeed + mCameraMovementSpeed * scaling * wheel->angleDelta().y() );
 
  592      const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.5f : 5.f );
 
  596      mCumulatedWheelY += scaling * wheel->angleDelta().y();
 
  598      if ( !mIsInZoomInState )
 
  602        mCameraBeforeZoom->setProjectionMatrix( mCamera->projectionMatrix() );
 
  603        mCameraBeforeZoom->setNearPlane( mCamera->nearPlane() );
 
  604        mCameraBeforeZoom->setFarPlane( mCamera->farPlane() );
 
  605        mCameraBeforeZoom->setAspectRatio( mCamera->aspectRatio() );
 
  606        mCameraBeforeZoom->setFieldOfView( mCamera->fieldOfView() );
 
  608        mZoomPointCalculated = 
false;
 
  609        mIsInZoomInState = 
true;
 
  610        mDepthBufferIsReady = 
false;
 
  614        handleTerrainNavigationWheelZoom();
 
  621void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
 
  623  mKeyboardHandler->setFocus( 
true );
 
  624  if ( mouse->button() == Qt3DInput::QMouseEvent::LeftButton || mouse->button() == Qt3DInput::QMouseEvent::RightButton )
 
  626    mMousePos = QPoint( mouse->x(), mouse->y() );
 
  627    mDragButtonClickPos = QPoint( mouse->x(), mouse->y() );
 
  628    mPressedButton = mouse->button();
 
  629    mMousePressed = 
true;
 
  631    if ( mCaptureFpsMouseMovements )
 
  632      mIgnoreNextMouseMove = 
true;
 
  636    mCameraBeforeDrag->setProjectionMatrix( mCamera->projectionMatrix() );
 
  637    mCameraBeforeDrag->setNearPlane( mCamera->nearPlane() );
 
  638    mCameraBeforeDrag->setFarPlane( mCamera->farPlane() );
 
  639    mCameraBeforeDrag->setAspectRatio( mCamera->aspectRatio() );
 
  640    mCameraBeforeDrag->setFieldOfView( mCamera->fieldOfView() );
 
  642    mDepthBufferIsReady = 
false;
 
  643    mDragPointCalculated = 
false;
 
  648  if ( mouse->button() == Qt3DInput::QMouseEvent::MiddleButton || ( ( mouse->modifiers() & Qt::ShiftModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) )
 
  650    mMousePos = QPoint( mouse->x(), mouse->y() );
 
  651    mMiddleButtonClickPos = QPoint( mouse->x(), mouse->y() );
 
  652    mPressedButton = mouse->button();
 
  653    mMousePressed = 
true;
 
  654    if ( mCaptureFpsMouseMovements )
 
  655      mIgnoreNextMouseMove = 
true;
 
  656    mDepthBufferIsReady = 
false;
 
  657    mRotationCenterCalculated = 
false;
 
  662    mCameraPose.
updateCamera( mCameraBeforeRotation.get() );
 
  664    mCameraBeforeRotation->setProjectionMatrix( mCamera->projectionMatrix() );
 
  665    mCameraBeforeRotation->setNearPlane( mCamera->nearPlane() );
 
  666    mCameraBeforeRotation->setFarPlane( mCamera->farPlane() );
 
  667    mCameraBeforeRotation->setAspectRatio( mCamera->aspectRatio() );
 
  668    mCameraBeforeRotation->setFieldOfView( mCamera->fieldOfView() );
 
  674void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
 
  677  mPressedButton = Qt3DInput::QMouseEvent::NoButton;
 
  678  mMousePressed = 
false;
 
  680  mDragPointCalculated = 
false;
 
  681  mRotationCenterCalculated = 
false;
 
  684void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
 
  686  if ( event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_QuoteLeft )
 
  689    switch ( mCameraNavigationMode )
 
  701  switch ( mCameraNavigationMode )
 
  705      onKeyPressedFlyNavigation( event );
 
  711      onKeyPressedTerrainNavigation( event );
 
  717void QgsCameraController::onKeyPressedTerrainNavigation( Qt3DInput::QKeyEvent *event )
 
  719  const bool hasShift = ( 
event->modifiers() & Qt::ShiftModifier );
 
  720  const bool hasCtrl = ( 
event->modifiers() & Qt::ControlModifier );
 
  722  int tx = 0, ty = 0, tElev = 0;
 
  723  switch ( event->key() )
 
  739    case Qt::Key_PageDown:
 
  749    if ( !hasShift && !hasCtrl )
 
  753    else if ( hasShift && !hasCtrl )
 
  759    else if ( hasCtrl && !hasShift )
 
  762      const float diffPitch = ty;   
 
  763      const float diffYaw = -tx;    
 
  771    center.
set( center.
x(), center.
y() + tElev * 10, center.
z() );
 
  773    updateCameraFromPose();
 
  777void QgsCameraController::onKeyPressedFlyNavigation( Qt3DInput::QKeyEvent *event )
 
  779  switch ( event->key() )
 
  781    case Qt::Key_QuoteLeft:
 
  784      mCaptureFpsMouseMovements = !mCaptureFpsMouseMovements;
 
  785      mIgnoreNextMouseMove = 
true;
 
  786      if ( mCaptureFpsMouseMovements )
 
  788        qApp->setOverrideCursor( QCursor( Qt::BlankCursor ) );
 
  792        qApp->restoreOverrideCursor();
 
  800      if ( mCaptureFpsMouseMovements )
 
  802        mCaptureFpsMouseMovements = 
false;
 
  803        mIgnoreNextMouseMove = 
true;
 
  804        qApp->restoreOverrideCursor();
 
  814  if ( event->isAutoRepeat() )
 
  817  mDepressedKeys.insert( event->key() );
 
  822  const QVector3D cameraUp = mCamera->upVector().normalized();
 
  824  const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
 
  826  QVector3D cameraPosDiff( 0.0f, 0.0f, 0.0f );
 
  830    cameraPosDiff += tx * cameraFront;
 
  834    cameraPosDiff += ty * cameraLeft;
 
  838    cameraPosDiff += tz * QVector3D( 0.0f, 1.0f, 0.0f );
 
  841  moveCameraPositionBy( cameraPosDiff );
 
  844void QgsCameraController::applyFlyModeKeyMovements()
 
  847  const bool shiftPressed = mDepressedKeys.contains( Qt::Key_Shift );
 
  848  const bool ctrlPressed = mDepressedKeys.contains( Qt::Key_Control );
 
  850  const double movementSpeed = mCameraMovementSpeed * ( shiftPressed ? 2 : 1 ) * ( ctrlPressed ? 0.1 : 1 );
 
  852  bool changed = 
false;
 
  856  if ( mDepressedKeys.contains( Qt::Key_Left ) || mDepressedKeys.contains( Qt::Key_A ) )
 
  862  if ( mDepressedKeys.contains( Qt::Key_Right ) || mDepressedKeys.contains( Qt::Key_D ) )
 
  868  if ( mDepressedKeys.contains( Qt::Key_Up ) || mDepressedKeys.contains( Qt::Key_W ) )
 
  874  if ( mDepressedKeys.contains( Qt::Key_Down ) || mDepressedKeys.contains( Qt::Key_S ) )
 
  882  static constexpr double ELEVATION_MOVEMENT_SCALE = 0.5;
 
  883  if ( mDepressedKeys.contains( Qt::Key_PageUp ) || mDepressedKeys.contains( Qt::Key_E ) )
 
  886    z += ELEVATION_MOVEMENT_SCALE * movementSpeed;
 
  889  if ( mDepressedKeys.contains( Qt::Key_PageDown ) || mDepressedKeys.contains( Qt::Key_Q ) )
 
  892    z -= ELEVATION_MOVEMENT_SCALE * movementSpeed;
 
  899void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent *mouse )
 
  901  const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
 
  902  const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
 
  904  const double dx = mCaptureFpsMouseMovements ? QCursor::pos().x() - mMousePos.x() : mouse->x() - mMousePos.x();
 
  905  const double dy = mCaptureFpsMouseMovements ? QCursor::pos().y() - mMousePos.y() : mouse->y() - mMousePos.y();
 
  906  mMousePos = mCaptureFpsMouseMovements ? QCursor::pos() : QPoint( mouse->x(), mouse->y() );
 
  908  if ( mIgnoreNextMouseMove )
 
  910    mIgnoreNextMouseMove = 
false;
 
  914  if ( hasMiddleButton )
 
  917    const QVector3D cameraUp = mCamera->upVector().normalized();
 
  919    const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
 
  920    const QVector3D cameraPosDiff = -dx * cameraLeft - dy * cameraUp;
 
  921    moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 10.0 );
 
  923  else if ( hasRightButton )
 
  927    const QVector3D cameraPosDiff = dy * cameraFront;
 
  928    moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 5.0 );
 
  932    if ( mCaptureFpsMouseMovements )
 
  934      float diffPitch = -0.2f * dy;
 
  935      switch ( mVerticalAxisInversion )
 
  946      const float diffYaw = - 0.2f * dx;
 
  949    else if ( mouse->buttons() & Qt::LeftButton )
 
  951      float diffPitch = -0.2f * dy;
 
  952      switch ( mVerticalAxisInversion )
 
  962      const float diffYaw = - 0.2f * dx;
 
  967  if ( mCaptureFpsMouseMovements )
 
  969    mIgnoreNextMouseMove = 
true;
 
  976void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
 
  978  if ( event->isAutoRepeat() )
 
  981  mDepressedKeys.remove( event->key() );
 
  990  updateCameraFromPose();
 
  999  updateCameraFromPose();
 
 1005  updateCameraFromPose();
 
 1012  const float x = tx * dist * 0.02f;
 
 1013  const float y = -ty * dist * 0.02f;
 
 1016  const float t = sqrt( x * x + y * y );
 
 1017  const float a = atan2( y, x ) - 
yaw * M_PI / 180;
 
 1018  const float dx = cos( a ) * t;
 
 1019  const float dy = sin( a ) * t;
 
 1022  center.
set( center.
x() + dx, center.
y(), center.
z() + dy );
 
 1024  updateCameraFromPose();
 
 1029  if ( event->key() == Qt::Key_QuoteLeft )
 
 1032  switch ( mCameraNavigationMode )
 
 1036      switch ( event->key() )
 
 1046        case Qt::Key_PageUp:
 
 1048        case Qt::Key_PageDown:
 
 1052        case Qt::Key_Escape:
 
 1053          if ( mCaptureFpsMouseMovements )
 
 1065      switch ( event->key() )
 
 1069        case Qt::Key_PageUp:
 
 1070        case Qt::Key_PageDown:
 
 1084  mDepthBufferImage = depthImage;
 
 1085  mDepthBufferIsReady = 
true;
 
 1087  if ( mIsInZoomInState )
 
 1088    handleTerrainNavigationWheelZoom();
 
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.
 
QgsAbstract3DEngine * engine()
Returns the abstract 3D engine.
 
QgsTerrainEntity * terrainEntity()
Returns terrain entity (may be temporarily nullptr)
 
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.
 
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 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).
 
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
 
~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 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 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.
 
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 zoom(float factor)
Zoom the map by factor.
 
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 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 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.
 
QWindow * window()
Returns the internal 3D window where all the rendered output is displayed.
 
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)
 
#define QgsDebugMsgLevel(str, level)