QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgscameracontroller.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscameracontroller.cpp
3  --------------------------------------
4  Date : July 2017
5  Copyright : (C) 2017 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscameracontroller.h"
17 #include "qgsraycastingutils_p.h"
18 #include "qgsterrainentity_p.h"
19 #include "qgsvector3d.h"
20 #include "qgssettings.h"
21 #include "qgs3dutils.h"
22 
23 #include "qgis.h"
24 
25 #include <QDomDocument>
26 #include <Qt3DRender/QCamera>
27 #include <Qt3DRender/QObjectPicker>
28 #include <Qt3DRender/QPickEvent>
29 #include <Qt3DInput>
30 
31 #include "qgslogger.h"
32 
33 QgsCameraController::QgsCameraController( Qt3DCore::QNode *parent )
34  : Qt3DCore::QEntity( parent )
35  , mCameraBeforeRotation( new Qt3DRender::QCamera )
36  , mCameraBeforeDrag( new Qt3DRender::QCamera )
37  , mCameraBeforeZoom( new Qt3DRender::QCamera )
38  , mMouseDevice( new Qt3DInput::QMouseDevice() )
39  , mKeyboardDevice( new Qt3DInput::QKeyboardDevice() )
40  , mMouseHandler( new Qt3DInput::QMouseHandler )
41  , mKeyboardHandler( new Qt3DInput::QKeyboardHandler )
42 {
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 );
53 
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 );
60 
61  // Disable the handlers when the entity is disabled
62  connect( this, &Qt3DCore::QEntity::enabledChanged,
63  mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
64  connect( this, &Qt3DCore::QEntity::enabledChanged,
65  mKeyboardHandler, &Qt3DInput::QKeyboardHandler::setEnabled );
66 
67  mFpsNavTimer = new QTimer( this );
68  mFpsNavTimer->setInterval( 10 );
69  connect( mFpsNavTimer, &QTimer::timeout, this, &QgsCameraController::applyFlyModeKeyMovements );
70  mFpsNavTimer->start();
71 }
72 
74 {
75  if ( navigationMode == mCameraNavigationMode )
76  return;
77 
78  mCameraNavigationMode = navigationMode;
79  mIgnoreNextMouseMove = true;
80  emit navigationModeChanged( mCameraNavigationMode );
81 }
82 
83 void QgsCameraController::setCameraMovementSpeed( double movementSpeed )
84 {
85  if ( movementSpeed == mCameraMovementSpeed )
86  return;
87 
88  mCameraMovementSpeed = movementSpeed;
89  emit cameraMovementSpeedChanged( mCameraMovementSpeed );
90 }
91 
93 {
94  mVerticalAxisInversion = inversion;
95 }
96 
97 void QgsCameraController::setTerrainEntity( QgsTerrainEntity *te )
98 {
99  mTerrainEntity = te;
100  // object picker for terrain for correct map panning
101  if ( mTerrainEntity )
102  connect( te->terrainPicker(), &Qt3DRender::QObjectPicker::pressed, this, &QgsCameraController::onPickerMousePressed );
103 }
104 
105 void QgsCameraController::setCamera( Qt3DRender::QCamera *camera )
106 {
107  if ( mCamera == camera )
108  return;
109  mCamera = camera;
110 
111  mCameraPose.updateCamera( mCamera ); // initial setup
112 
113  // TODO: set camera's parent if not set already?
114  // TODO: registerDestructionHelper (?)
115  emit cameraChanged();
116 }
117 
118 void QgsCameraController::setViewport( QRect viewport )
119 {
120  if ( mViewport == viewport )
121  return;
122 
123  mViewport = viewport;
124  emit viewportChanged();
125 }
126 
127 void QgsCameraController::rotateCamera( float diffPitch, float diffYaw )
128 {
129  const float pitch = mCameraPose.pitchAngle();
130  const float yaw = mCameraPose.headingAngle();
131 
132  if ( pitch + diffPitch > 180 )
133  diffPitch = 180 - pitch; // prevent going over the head
134  if ( pitch + diffPitch < 0 )
135  diffPitch = 0 - pitch; // prevent going over the head
136 
137  // Is it always going to be love/hate relationship with quaternions???
138  // This quaternion combines two rotations:
139  // - first it undoes the previously applied rotation so we have do not have any rotation compared to world coords
140  // - then it applies new rotation
141  // (We can't just apply our euler angles difference because the camera may be already rotated)
142  const QQuaternion q = QQuaternion::fromEulerAngles( pitch + diffPitch, yaw + diffYaw, 0 ) *
143  QQuaternion::fromEulerAngles( pitch, yaw, 0 ).conjugated();
144 
145  // get camera's view vector, rotate it to get new view center
146  const QVector3D position = mCamera->position();
147  QVector3D viewCenter = mCamera->viewCenter();
148  const QVector3D viewVector = viewCenter - position;
149  const QVector3D cameraToCenter = q * viewVector;
150  viewCenter = position + cameraToCenter;
151 
152  mCameraPose.setCenterPoint( viewCenter );
153  mCameraPose.setPitchAngle( pitch + diffPitch );
154  mCameraPose.setHeadingAngle( yaw + diffYaw );
155  updateCameraFromPose();
156 }
157 
158 
160 {
161  Q_UNUSED( dt )
162 }
163 
164 void QgsCameraController::resetView( float distance )
165 {
166  setViewFromTop( 0, 0, distance );
167 }
168 
169 void QgsCameraController::setViewFromTop( float worldX, float worldY, float distance, float yaw )
170 {
171  QgsCameraPose camPose;
172  if ( mTerrainEntity )
173  camPose.setCenterPoint( QgsVector3D( worldX, mTerrainEntity->terrainElevationOffset(), worldY ) );
174  else
175  camPose.setCenterPoint( QgsVector3D( worldX, 0.0f, worldY ) );
177  camPose.setHeadingAngle( yaw );
178 
179  // a basic setup to make frustum depth range long enough that it does not cull everything
180  mCamera->setNearPlane( distance / 2 );
181  mCamera->setFarPlane( distance * 2 );
182 
183  setCameraPose( camPose );
184 }
185 
187 {
188  return mCameraPose.centerPoint();
189 }
190 
191 void QgsCameraController::setLookingAtPoint( const QgsVector3D &point, float distance, float pitch, float yaw )
192 {
193  QgsCameraPose camPose;
194  camPose.setCenterPoint( point );
196  camPose.setPitchAngle( pitch );
197  camPose.setHeadingAngle( yaw );
198  setCameraPose( camPose );
199 }
200 
202 {
203  if ( camPose == mCameraPose )
204  return;
205 
206  mCameraPose = camPose;
207 
208  if ( mCamera )
209  mCameraPose.updateCamera( mCamera );
210 
211  emit cameraChanged();
212 }
213 
214 QDomElement QgsCameraController::writeXml( QDomDocument &doc ) const
215 {
216  QDomElement elemCamera = doc.createElement( QStringLiteral( "camera" ) );
217  elemCamera.setAttribute( QStringLiteral( "x" ), mCameraPose.centerPoint().x() );
218  elemCamera.setAttribute( QStringLiteral( "y" ), mCameraPose.centerPoint().z() );
219  elemCamera.setAttribute( QStringLiteral( "elev" ), mCameraPose.centerPoint().y() );
220  elemCamera.setAttribute( QStringLiteral( "dist" ), mCameraPose.distanceFromCenterPoint() );
221  elemCamera.setAttribute( QStringLiteral( "pitch" ), mCameraPose.pitchAngle() );
222  elemCamera.setAttribute( QStringLiteral( "yaw" ), mCameraPose.headingAngle() );
223  return elemCamera;
224 }
225 
226 void QgsCameraController::readXml( const QDomElement &elem )
227 {
228  const float x = elem.attribute( QStringLiteral( "x" ) ).toFloat();
229  const float y = elem.attribute( QStringLiteral( "y" ) ).toFloat();
230  const float elev = elem.attribute( QStringLiteral( "elev" ) ).toFloat();
231  const float dist = elem.attribute( QStringLiteral( "dist" ) ).toFloat();
232  const float pitch = elem.attribute( QStringLiteral( "pitch" ) ).toFloat();
233  const float yaw = elem.attribute( QStringLiteral( "yaw" ) ).toFloat();
234  setLookingAtPoint( QgsVector3D( x, elev, y ), dist, pitch, yaw );
235 }
236 
237 double QgsCameraController::sampleDepthBuffer( const QImage &buffer, int px, int py )
238 {
239  double depth = 1;
240 
241  // Sample the neighbouring pixels for the closest point to the camera
242  for ( int x = px - 3; x <= px + 3; ++x )
243  {
244  for ( int y = py - 3; y <= py + 3; ++y )
245  {
246  if ( buffer.valid( x, y ) )
247  {
248  depth = std::min( depth, Qgs3DUtils::decodeDepth( buffer.pixel( x, y ) ) );
249  }
250  }
251  }
252 
253  if ( depth < 1 )
254  return depth;
255 
256  // Returns the average of depth values that are not 1 (void area)
257  depth = 0;
258  int samplesCount = 0;
259  for ( int x = 0; x < mDepthBufferImage.width(); ++x )
260  {
261  for ( int y = 0; y < mDepthBufferImage.height(); ++y )
262  {
263  double d = Qgs3DUtils::decodeDepth( buffer.pixel( x, y ) );
264  if ( d < 1 )
265  {
266  depth += d;
267  samplesCount += 1;
268  }
269  }
270  }
271 
272  // if the whole buffer is white, a depth cannot be computed
273  if ( samplesCount == 0 )
274  depth = 1.0;
275  else
276  depth /= samplesCount;
277 
278  return depth;
279 }
280 
281 void QgsCameraController::updateCameraFromPose()
282 {
283  if ( mCamera )
284  mCameraPose.updateCamera( mCamera );
285  emit cameraChanged();
286 }
287 
288 void QgsCameraController::moveCameraPositionBy( const QVector3D &posDiff )
289 {
290  mCameraPose.setCenterPoint( mCameraPose.centerPoint() + posDiff );
291  updateCameraFromPose();
292 }
293 
294 void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
295 {
296  mIsInZoomInState = false;
297  mCumulatedWheelY = 0;
298  switch ( mCameraNavigationMode )
299  {
301  onPositionChangedTerrainNavigation( mouse );
302  break;
303 
304  case WalkNavigation:
305  onPositionChangedFlyNavigation( mouse );
306  break;
307  }
308 }
309 
310 void QgsCameraController::onPositionChangedTerrainNavigation( Qt3DInput::QMouseEvent *mouse )
311 {
312  if ( mIgnoreNextMouseMove )
313  {
314  mIgnoreNextMouseMove = false;
315  mMousePos = QPoint( mouse->x(), mouse->y() );
316  return;
317  }
318 
319  const int dx = mouse->x() - mMousePos.x();
320  const int dy = mouse->y() - mMousePos.y();
321 
322  const bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
323  const bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
324  const bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
325  const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
326  const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
327 
328  if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
329  {
330  // rotate/tilt using mouse (camera moves as it rotates around the clicked point)
331 
332  double scale = std::max( mViewport.width(), mViewport.height() );
333  float pitchDiff = 180 * ( mouse->y() - mMiddleButtonClickPos.y() ) / scale;
334  float yawDiff = -180 * ( mouse->x() - mMiddleButtonClickPos.x() ) / scale;
335 
336  if ( !mDepthBufferIsReady )
337  return;
338 
339  if ( !mRotationCenterCalculated )
340  {
341  double depth = sampleDepthBuffer( mDepthBufferImage, mMiddleButtonClickPos.x(), mMiddleButtonClickPos.y() );
342 
343  mRotationCenter = Qgs3DUtils::screenPointToWorldPos( mMiddleButtonClickPos, depth, mViewport.size(), mCameraBeforeRotation.get() );
344 
345  mRotationDistanceFromCenter = ( mRotationCenter - mCameraBeforeRotation->position() ).length();
346 
347  emit cameraRotationCenterChanged( mRotationCenter );
348  mRotationCenterCalculated = true;
349  }
350 
351  // First transformation : Shift camera position and view center and rotate the camera
352  {
353  QVector3D shiftVector = mRotationCenter - mCamera->viewCenter();
354 
355  QVector3D newViewCenterWorld = camera()->viewCenter() + shiftVector;
356  QVector3D newCameraPosition = camera()->position() + shiftVector;
357 
358  mCameraPose.setDistanceFromCenterPoint( ( newViewCenterWorld - newCameraPosition ).length() );
359  mCameraPose.setCenterPoint( newViewCenterWorld );
360  mCameraPose.setPitchAngle( mRotationPitch + pitchDiff );
361  mCameraPose.setHeadingAngle( mRotationYaw + yawDiff );
362  updateCameraFromPose();
363  }
364 
365 
366  // Second transformation : Shift camera position back
367  {
368  QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMiddleButtonClickPos.x(), mMiddleButtonClickPos.y() ), mViewport.size(), mCamera );
369 
370  QVector3D clickedPositionWorld = ray.origin() + mRotationDistanceFromCenter * ray.direction();
371 
372  QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
373 
374  QVector3D newViewCenterWorld = camera()->viewCenter() - shiftVector;
375  QVector3D newCameraPosition = camera()->position() - shiftVector;
376 
377  mCameraPose.setDistanceFromCenterPoint( ( newViewCenterWorld - newCameraPosition ).length() );
378  mCameraPose.setCenterPoint( newViewCenterWorld );
379  updateCameraFromPose();
380  }
381  }
382  else if ( hasLeftButton && hasCtrl && !hasShift )
383  {
384  // rotate/tilt using mouse (camera stays at one position as it rotates)
385  const float diffPitch = 0.2f * dy;
386  const float diffYaw = - 0.2f * dx;
387  rotateCamera( diffPitch, diffYaw );
388  }
389  else if ( hasLeftButton && !hasShift && !hasCtrl )
390  {
391  // translation works as if one grabbed a point on the 3D viewer and dragged it
392 
393  if ( !mDepthBufferIsReady )
394  return;
395 
396  if ( !mDragPointCalculated )
397  {
398  double depth = sampleDepthBuffer( mDepthBufferImage, mDragButtonClickPos.x(), mDragButtonClickPos.y() );
399 
400  mDragDepth = depth;
401 
402  mDragPoint = Qgs3DUtils::screenPointToWorldPos( mDragButtonClickPos, mDragDepth, mViewport.size(), mCameraBeforeDrag.get() );
403  mDragPointCalculated = true;
404  }
405 
406  QVector3D cameraBeforeDragPos = mCameraBeforeDrag->position();
407 
408  QVector3D moveToPosition = Qgs3DUtils::screenPointToWorldPos( mMousePos, mDragDepth, mViewport.size(), mCameraBeforeDrag.get() );
409  QVector3D cameraBeforeToMoveToPos = ( moveToPosition - mCameraBeforeDrag->position() ).normalized();
410  QVector3D cameraBeforeToDragPointPos = ( mDragPoint - mCameraBeforeDrag->position() ).normalized();
411 
412  // Make sure the rays are not horizontal (add small y shift if it is)
413  if ( cameraBeforeToMoveToPos.y() == 0 )
414  {
415  cameraBeforeToMoveToPos.setY( 0.01 );
416  cameraBeforeToMoveToPos = cameraBeforeToMoveToPos.normalized();
417  }
418 
419  if ( cameraBeforeToDragPointPos.y() == 0 )
420  {
421  cameraBeforeToDragPointPos.setY( 0.01 );
422  cameraBeforeToDragPointPos = cameraBeforeToDragPointPos.normalized();
423  }
424 
425  double d1 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToMoveToPos.y();
426  double d2 = ( mDragPoint.y() - cameraBeforeDragPos.y() ) / cameraBeforeToDragPointPos.y();
427 
428  QVector3D from = cameraBeforeDragPos + d1 * cameraBeforeToMoveToPos;
429  QVector3D to = cameraBeforeDragPos + d2 * cameraBeforeToDragPointPos;
430 
431  QVector3D shiftVector = to - from;
432 
433  mCameraPose.setCenterPoint( mCameraBeforeDrag->viewCenter() + shiftVector );
434  updateCameraFromPose();
435  }
436  else if ( hasRightButton && !hasShift && !hasCtrl )
437  {
438  if ( !mDepthBufferIsReady )
439  return;
440 
441  if ( !mDragPointCalculated )
442  {
443  double depth = sampleDepthBuffer( mDepthBufferImage, mDragButtonClickPos.x(), mDragButtonClickPos.y() );
444 
445  mDragPoint = Qgs3DUtils::screenPointToWorldPos( mDragButtonClickPos, depth, mViewport.size(), mCameraBeforeDrag.get() );
446  mDragPointCalculated = true;
447  }
448 
449  float dist = ( mCameraBeforeDrag->position() - mDragPoint ).length();
450 
451  // Applies smoothing
452  if ( mMousePos.y() > mDragButtonClickPos.y() ) // zoom in
453  {
454  double f = ( double )( mMousePos.y() - mDragButtonClickPos.y() ) / ( double )( mViewport.height() - mDragButtonClickPos.y() );
455  f = std::max( 0.0, std::min( 1.0, f ) );
456  f = 1 - ( std::expm1( -2 * f ) ) / ( std::expm1( -2 ) );
457  dist = dist * f;
458  }
459  else // zoom out
460  {
461  double f = 1 - ( double )( mMousePos.y() ) / ( double )( mDragButtonClickPos.y() );
462  f = std::max( 0.0, std::min( 1.0, f ) );
463  f = ( std::expm1( 2 * f ) ) / ( std::expm1( 2 ) );
464  dist = dist + 2 * dist * f;
465  }
466 
467  // First transformation : Shift camera position and view center and rotate the camera
468  {
469  QVector3D shiftVector = mDragPoint - mCamera->viewCenter();
470 
471  QVector3D newViewCenterWorld = camera()->viewCenter() + shiftVector;
472 
473  mCameraPose.setDistanceFromCenterPoint( dist );
474  mCameraPose.setCenterPoint( newViewCenterWorld );
475  updateCameraFromPose();
476  }
477 
478  // Second transformation : Shift camera position back
479  {
480  QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mDragButtonClickPos.x(), mDragButtonClickPos.y() ), mViewport.size(), mCamera );
481  QVector3D clickedPositionWorld = ray.origin() + dist * ray.direction();
482 
483  QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
484 
485  QVector3D newViewCenterWorld = camera()->viewCenter() - shiftVector;
486  QVector3D newCameraPosition = camera()->position() - shiftVector;
487 
488  mCameraPose.setDistanceFromCenterPoint( ( newViewCenterWorld - newCameraPosition ).length() );
489  mCameraPose.setCenterPoint( newViewCenterWorld );
490  updateCameraFromPose();
491  }
492  }
493 
494  mMousePos = QPoint( mouse->x(), mouse->y() );
495 }
496 
497 void QgsCameraController::zoom( float factor )
498 {
499  // zoom in/out
500  float dist = mCameraPose.distanceFromCenterPoint();
501  dist -= dist * factor * 0.01f;
502  mCameraPose.setDistanceFromCenterPoint( dist );
503  updateCameraFromPose();
504 }
505 
506 void QgsCameraController::handleTerrainNavigationWheelZoom()
507 {
508  if ( !mDepthBufferIsReady )
509  return;
510 
511  if ( !mZoomPointCalculated )
512  {
513  double depth = sampleDepthBuffer( mDepthBufferImage, mMousePos.x(), mMousePos.y() );
514 
515  mZoomPoint = Qgs3DUtils::screenPointToWorldPos( mMousePos, depth, mViewport.size(), mCameraBeforeZoom.get() );
516  mZoomPointCalculated = true;
517  }
518 
519  float f = mCumulatedWheelY / ( 120.0 * 24.0 );
520 
521  double dist = ( mZoomPoint - mCameraBeforeZoom->position() ).length();
522  dist -= dist * f;
523 
524  // First transformation : Shift camera position and view center and rotate the camera
525  {
526  QVector3D shiftVector = mZoomPoint - mCamera->viewCenter();
527 
528  QVector3D newViewCenterWorld = camera()->viewCenter() + shiftVector;
529 
530  mCameraPose.setDistanceFromCenterPoint( dist );
531  mCameraPose.setCenterPoint( newViewCenterWorld );
532  updateCameraFromPose();
533  }
534 
535  // Second transformation : Shift camera position back
536  {
537  QgsRay3D ray = Qgs3DUtils::rayFromScreenPoint( QPoint( mMousePos.x(), mMousePos.y() ), mViewport.size(), mCamera );
538  QVector3D clickedPositionWorld = ray.origin() + dist * ray.direction();
539 
540  QVector3D shiftVector = clickedPositionWorld - mCamera->viewCenter();
541 
542  QVector3D newViewCenterWorld = camera()->viewCenter() - shiftVector;
543  QVector3D newCameraPosition = camera()->position() - shiftVector;
544 
545  mCameraPose.setDistanceFromCenterPoint( ( newViewCenterWorld - newCameraPosition ).length() );
546  mCameraPose.setCenterPoint( newViewCenterWorld );
547  updateCameraFromPose();
548  }
549  mIsInZoomInState = false;
550  mCumulatedWheelY = 0;
551 }
552 
553 void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
554 {
555  switch ( mCameraNavigationMode )
556  {
558  {
559  const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.1f : 1.0f ) / 1000.f;
560  setCameraMovementSpeed( mCameraMovementSpeed + mCameraMovementSpeed * scaling * wheel->angleDelta().y() );
561  break;
562  }
563 
565  {
566 
567  const float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) != 0 ? 0.5f : 5.f );
568 
569  // Apparently angleDelta needs to be accumulated
570  // see: https://doc.qt.io/qt-5/qwheelevent.html#angleDelta
571  mCumulatedWheelY += scaling * wheel->angleDelta().y();
572 
573  if ( !mIsInZoomInState )
574  {
575  mCameraPose.updateCamera( mCameraBeforeZoom.get() );
576 
577  mCameraBeforeZoom->setProjectionMatrix( mCamera->projectionMatrix() );
578  mCameraBeforeZoom->setNearPlane( mCamera->nearPlane() );
579  mCameraBeforeZoom->setFarPlane( mCamera->farPlane() );
580  mCameraBeforeZoom->setAspectRatio( mCamera->aspectRatio() );
581  mCameraBeforeZoom->setFieldOfView( mCamera->fieldOfView() );
582 
583  mZoomPointCalculated = false;
584  mIsInZoomInState = true;
585  mDepthBufferIsReady = false;
587  }
588  else
589  handleTerrainNavigationWheelZoom();
590 
591  break;
592  }
593  }
594 }
595 
596 void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
597 {
598  mKeyboardHandler->setFocus( true );
599  if ( mouse->button() == Qt3DInput::QMouseEvent::LeftButton || mouse->button() == Qt3DInput::QMouseEvent::RightButton )
600  {
601  mMousePos = QPoint( mouse->x(), mouse->y() );
602  mDragButtonClickPos = QPoint( mouse->x(), mouse->y() );
603  mPressedButton = mouse->button();
604  mMousePressed = true;
605 
606  if ( mCaptureFpsMouseMovements )
607  mIgnoreNextMouseMove = true;
608 
609  mCameraPose.updateCamera( mCameraBeforeDrag.get() );
610 
611  mCameraBeforeDrag->setProjectionMatrix( mCamera->projectionMatrix() );
612  mCameraBeforeDrag->setNearPlane( mCamera->nearPlane() );
613  mCameraBeforeDrag->setFarPlane( mCamera->farPlane() );
614  mCameraBeforeDrag->setAspectRatio( mCamera->aspectRatio() );
615  mCameraBeforeDrag->setFieldOfView( mCamera->fieldOfView() );
616 
617  mDepthBufferIsReady = false;
618  mDragPointCalculated = false;
619 
621  }
622 
623  if ( mouse->button() == Qt3DInput::QMouseEvent::MiddleButton || ( ( mouse->modifiers() & Qt::ShiftModifier ) != 0 && mouse->button() == Qt3DInput::QMouseEvent::LeftButton ) )
624  {
625  mMousePos = QPoint( mouse->x(), mouse->y() );
626  mMiddleButtonClickPos = QPoint( mouse->x(), mouse->y() );
627  mPressedButton = mouse->button();
628  mMousePressed = true;
629  if ( mCaptureFpsMouseMovements )
630  mIgnoreNextMouseMove = true;
631  mDepthBufferIsReady = false;
632  mRotationCenterCalculated = false;
633 
634  mRotationPitch = mCameraPose.pitchAngle();
635  mRotationYaw = mCameraPose.headingAngle();
636 
637  mCameraPose.updateCamera( mCameraBeforeRotation.get() );
638 
639  mCameraBeforeRotation->setProjectionMatrix( mCamera->projectionMatrix() );
640  mCameraBeforeRotation->setNearPlane( mCamera->nearPlane() );
641  mCameraBeforeRotation->setFarPlane( mCamera->farPlane() );
642  mCameraBeforeRotation->setAspectRatio( mCamera->aspectRatio() );
643  mCameraBeforeRotation->setFieldOfView( mCamera->fieldOfView() );
644 
646  }
647 }
648 
649 void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
650 {
651  Q_UNUSED( mouse )
652  mPressedButton = Qt3DInput::QMouseEvent::NoButton;
653  mMousePressed = false;
654 
655  mDragPointCalculated = false;
656  mRotationCenterCalculated = false;
657 }
658 
659 void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
660 {
661  if ( event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_QuoteLeft )
662  {
663  // switch navigation mode
664  switch ( mCameraNavigationMode )
665  {
666  case NavigationMode::WalkNavigation:
667  setCameraNavigationMode( NavigationMode::TerrainBasedNavigation );
668  break;
669  case NavigationMode::TerrainBasedNavigation:
670  setCameraNavigationMode( NavigationMode::WalkNavigation );
671  break;
672  }
673  return;
674  }
675 
676  switch ( mCameraNavigationMode )
677  {
678  case WalkNavigation:
679  {
680  onKeyPressedFlyNavigation( event );
681  break;
682  }
683 
685  {
686  onKeyPressedTerrainNavigation( event );
687  break;
688  }
689  }
690 }
691 
692 void QgsCameraController::onKeyPressedTerrainNavigation( Qt3DInput::QKeyEvent *event )
693 {
694  const bool hasShift = ( event->modifiers() & Qt::ShiftModifier );
695  const bool hasCtrl = ( event->modifiers() & Qt::ControlModifier );
696 
697  int tx = 0, ty = 0, tElev = 0;
698  switch ( event->key() )
699  {
700  case Qt::Key_Left:
701  tx -= 1;
702  break;
703  case Qt::Key_Right:
704  tx += 1;
705  break;
706 
707  case Qt::Key_Up:
708  ty += 1;
709  break;
710  case Qt::Key_Down:
711  ty -= 1;
712  break;
713 
714  case Qt::Key_PageDown:
715  tElev -= 1;
716  break;
717  case Qt::Key_PageUp:
718  tElev += 1;
719  break;
720  }
721 
722  if ( tx || ty )
723  {
724  if ( !hasShift && !hasCtrl )
725  {
726  moveView( tx, ty );
727  }
728  else if ( hasShift && !hasCtrl )
729  {
730  // rotate/tilt using keyboard (camera moves as it rotates around its view center)
733  }
734  else if ( hasCtrl && !hasShift )
735  {
736  // rotate/tilt using keyboard (camera stays at one position as it rotates)
737  const float diffPitch = ty; // down key = rotating camera down
738  const float diffYaw = -tx; // right key = rotating camera to the right
739  rotateCamera( diffPitch, diffYaw );
740  }
741  }
742 
743  if ( tElev )
744  {
745  QgsVector3D center = mCameraPose.centerPoint();
746  center.set( center.x(), center.y() + tElev * 10, center.z() );
747  mCameraPose.setCenterPoint( center );
748  updateCameraFromPose();
749  }
750 }
751 
752 void QgsCameraController::onKeyPressedFlyNavigation( Qt3DInput::QKeyEvent *event )
753 {
754  switch ( event->key() )
755  {
756  case Qt::Key_QuoteLeft:
757  {
758  // toggle mouse lock mode
759  mCaptureFpsMouseMovements = !mCaptureFpsMouseMovements;
760  mIgnoreNextMouseMove = true;
761  if ( mCaptureFpsMouseMovements )
762  {
763  qApp->setOverrideCursor( QCursor( Qt::BlankCursor ) );
764  }
765  else
766  {
767  qApp->restoreOverrideCursor();
768  }
769  return;
770  }
771 
772  case Qt::Key_Escape:
773  {
774  // always exit mouse lock mode
775  if ( mCaptureFpsMouseMovements )
776  {
777  mCaptureFpsMouseMovements = false;
778  mIgnoreNextMouseMove = true;
779  qApp->restoreOverrideCursor();
780  return;
781  }
782  break;
783  }
784 
785  default:
786  break;
787  }
788 
789  if ( event->isAutoRepeat() )
790  return;
791 
792  mDepressedKeys.insert( event->key() );
793 }
794 
795 void QgsCameraController::applyFlyModeKeyMovements()
796 {
797  const QVector3D cameraUp = mCamera->upVector().normalized();
798  const QVector3D cameraFront = ( QVector3D( mCameraPose.centerPoint().x(), mCameraPose.centerPoint().y(), mCameraPose.centerPoint().z() ) - mCamera->position() ).normalized();
799  const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
800 
801  QVector3D cameraPosDiff( 0.0f, 0.0f, 0.0f );
802 
803  // shift = "run", ctrl = "slow walk"
804  const bool shiftPressed = mDepressedKeys.contains( Qt::Key_Shift );
805  const bool ctrlPressed = mDepressedKeys.contains( Qt::Key_Control );
806 
807  const double movementSpeed = mCameraMovementSpeed * ( shiftPressed ? 2 : 1 ) * ( ctrlPressed ? 0.1 : 1 );
808 
809  bool changed = false;
810  if ( mDepressedKeys.contains( Qt::Key_Left ) || mDepressedKeys.contains( Qt::Key_A ) )
811  {
812  changed = true;
813  cameraPosDiff += movementSpeed * cameraLeft;
814  }
815 
816  if ( mDepressedKeys.contains( Qt::Key_Right ) || mDepressedKeys.contains( Qt::Key_D ) )
817  {
818  changed = true;
819  cameraPosDiff += - movementSpeed * cameraLeft;
820  }
821 
822  if ( mDepressedKeys.contains( Qt::Key_Up ) || mDepressedKeys.contains( Qt::Key_W ) )
823  {
824  changed = true;
825  cameraPosDiff += movementSpeed * cameraFront;
826  }
827 
828  if ( mDepressedKeys.contains( Qt::Key_Down ) || mDepressedKeys.contains( Qt::Key_S ) )
829  {
830  changed = true;
831  cameraPosDiff += - movementSpeed * cameraFront;
832  }
833 
834  // note -- vertical axis movements are slower by default then horizontal ones, as GIS projects
835  // tend to have much more limited elevation range vs ground range
836  static constexpr double ELEVATION_MOVEMENT_SCALE = 0.5;
837  if ( mDepressedKeys.contains( Qt::Key_PageUp ) || mDepressedKeys.contains( Qt::Key_E ) )
838  {
839  changed = true;
840  cameraPosDiff += ELEVATION_MOVEMENT_SCALE * movementSpeed * QVector3D( 0.0f, 1.0f, 0.0f );
841  }
842 
843  if ( mDepressedKeys.contains( Qt::Key_PageDown ) || mDepressedKeys.contains( Qt::Key_Q ) )
844  {
845  changed = true;
846  cameraPosDiff += ELEVATION_MOVEMENT_SCALE * - movementSpeed * QVector3D( 0.0f, 1.0f, 0.0f );
847  }
848 
849  if ( changed )
850  moveCameraPositionBy( cameraPosDiff );
851 }
852 
853 void QgsCameraController::onPositionChangedFlyNavigation( Qt3DInput::QMouseEvent *mouse )
854 {
855  const bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
856  const bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
857 
858  const double dx = mCaptureFpsMouseMovements ? QCursor::pos().x() - mMousePos.x() : mouse->x() - mMousePos.x();
859  const double dy = mCaptureFpsMouseMovements ? QCursor::pos().y() - mMousePos.y() : mouse->y() - mMousePos.y();
860  mMousePos = mCaptureFpsMouseMovements ? QCursor::pos() : QPoint( mouse->x(), mouse->y() );
861 
862  if ( mIgnoreNextMouseMove )
863  {
864  mIgnoreNextMouseMove = false;
865  return;
866  }
867 
868  if ( hasMiddleButton )
869  {
870  // middle button drag = pan camera in place (strafe)
871  const QVector3D cameraUp = mCamera->upVector().normalized();
872  const QVector3D cameraFront = ( QVector3D( mCameraPose.centerPoint().x(), mCameraPose.centerPoint().y(), mCameraPose.centerPoint().z() ) - mCamera->position() ).normalized();
873  const QVector3D cameraLeft = QVector3D::crossProduct( cameraUp, cameraFront );
874  const QVector3D cameraPosDiff = -dx * cameraLeft - dy * cameraUp;
875  moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 10.0 );
876  }
877  else if ( hasRightButton )
878  {
879  // right button drag = camera dolly
880  const QVector3D cameraFront = ( QVector3D( mCameraPose.centerPoint().x(), mCameraPose.centerPoint().y(), mCameraPose.centerPoint().z() ) - mCamera->position() ).normalized();
881  const QVector3D cameraPosDiff = dy * cameraFront;
882  moveCameraPositionBy( mCameraMovementSpeed * cameraPosDiff / 5.0 );
883  }
884  else
885  {
886  if ( mCaptureFpsMouseMovements )
887  {
888  float diffPitch = -0.2f * dy;
889  switch ( mVerticalAxisInversion )
890  {
891  case Always:
892  diffPitch *= -1;
893  break;
894 
895  case WhenDragging:
896  case Never:
897  break;
898  }
899 
900  const float diffYaw = - 0.2f * dx;
901  rotateCamera( diffPitch, diffYaw );
902  }
903  else if ( mouse->buttons() & Qt::LeftButton )
904  {
905  float diffPitch = -0.2f * dy;
906  switch ( mVerticalAxisInversion )
907  {
908  case Always:
909  case WhenDragging:
910  diffPitch *= -1;
911  break;
912 
913  case Never:
914  break;
915  }
916  const float diffYaw = - 0.2f * dx;
917  rotateCamera( diffPitch, diffYaw );
918  }
919  }
920 
921  if ( mCaptureFpsMouseMovements )
922  {
923  mIgnoreNextMouseMove = true;
924 
925  // reset cursor back to center of map widget
926  emit setCursorPosition( QPoint( mViewport.width() / 2, mViewport.height() / 2 ) );
927  }
928 }
929 
930 void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
931 {
932  if ( event->isAutoRepeat() )
933  return;
934 
935  mDepressedKeys.remove( event->key() );
936 }
937 
938 void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
939 {
940  mLastPressedHeight = pick->worldIntersection().y();
941 }
942 
943 
945 {
946  // Tilt up the view by deltaPitch around the view center (camera moves)
947  float pitch = mCameraPose.pitchAngle();
948  pitch -= deltaPitch; // down key = moving camera toward terrain
949  mCameraPose.setPitchAngle( pitch );
950  updateCameraFromPose();
951 }
952 
954 {
955  // Rotate clockwise the view by deltaYaw around the view center (camera moves)
956  float yaw = mCameraPose.headingAngle();
957  yaw -= deltaYaw; // right key = moving camera clockwise
958  mCameraPose.setHeadingAngle( yaw );
959  updateCameraFromPose();
960 }
961 
963 {
964  mCameraPose.setHeadingAngle( angle );
965  updateCameraFromPose();
966 }
967 
968 void QgsCameraController::moveView( float tx, float ty )
969 {
970  const float yaw = mCameraPose.headingAngle();
971  const float dist = mCameraPose.distanceFromCenterPoint();
972  const float x = tx * dist * 0.02f;
973  const float y = -ty * dist * 0.02f;
974 
975  // moving with keyboard - take into account yaw of camera
976  const float t = sqrt( x * x + y * y );
977  const float a = atan2( y, x ) - yaw * M_PI / 180;
978  const float dx = cos( a ) * t;
979  const float dy = sin( a ) * t;
980 
981  QgsVector3D center = mCameraPose.centerPoint();
982  center.set( center.x() + dx, center.y(), center.z() + dy );
983  mCameraPose.setCenterPoint( center );
984  updateCameraFromPose();
985 }
986 
988 {
989  if ( event->key() == Qt::Key_QuoteLeft )
990  return true;
991 
992  switch ( mCameraNavigationMode )
993  {
994  case WalkNavigation:
995  {
996  switch ( event->key() )
997  {
998  case Qt::Key_Left:
999  case Qt::Key_A:
1000  case Qt::Key_Right:
1001  case Qt::Key_D:
1002  case Qt::Key_Up:
1003  case Qt::Key_W:
1004  case Qt::Key_Down:
1005  case Qt::Key_S:
1006  case Qt::Key_PageUp:
1007  case Qt::Key_E:
1008  case Qt::Key_PageDown:
1009  case Qt::Key_Q:
1010  return true;
1011 
1012  case Qt::Key_Escape:
1013  if ( mCaptureFpsMouseMovements )
1014  return true;
1015  break;
1016 
1017  default:
1018  break;
1019  }
1020  break;
1021  }
1022 
1024  {
1025  switch ( event->key() )
1026  {
1027  case Qt::Key_Left:
1028  case Qt::Key_Right:
1029  case Qt::Key_PageUp:
1030  case Qt::Key_PageDown:
1031  return true;
1032 
1033  default:
1034  break;
1035  }
1036  break;
1037  }
1038  }
1039  return false;
1040 }
1041 
1042 void QgsCameraController::depthBufferCaptured( const QImage &depthImage )
1043 {
1044  mDepthBufferImage = depthImage;
1045  mDepthBufferIsReady = true;
1046 
1047  if ( mIsInZoomInState )
1048  handleTerrainNavigationWheelZoom();
1049 }
QgsCameraController::Always
@ Always
Always invert vertical axis movements.
Definition: qgscameracontroller.h:81
QgsCameraController::yaw
float yaw() const
Returns yaw angle in degrees.
Definition: qgscameracontroller.h:186
QgsCameraController::lookingAtPoint
QgsVector3D lookingAtPoint() const
Returns the point in the world coordinates towards which the camera is looking.
Definition: qgscameracontroller.cpp:186
QgsCameraPose::centerPoint
QgsVector3D centerPoint() const
Returns center point (towards which point the camera is looking)
Definition: qgscamerapose.h:51
QgsCameraController::Never
@ Never
Never invert vertical axis movements.
Definition: qgscameracontroller.h:79
QgsCameraController::readXml
void readXml(const QDomElement &elem)
Reads camera configuration from the given DOM element.
Definition: qgscameracontroller.cpp:226
QgsCameraController::resetView
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates)
Definition: qgscameracontroller.cpp:164
QgsVector3D::y
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:64
QgsVector3D
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition: qgsvector3d.h:31
QgsCameraController::WalkNavigation
@ WalkNavigation
Uses WASD keys or arrows to navigate in walking (first person) manner.
Definition: qgscameracontroller.h:72
QgsCameraController::writeXml
QDomElement writeXml(QDomDocument &doc) const
Writes camera configuration to the given DOM element.
Definition: qgscameracontroller.cpp:214
QgsCameraController::cameraMovementSpeedChanged
void cameraMovementSpeedChanged(double speed)
Emitted whenever the camera movement speed is changed by the controller.
QgsCameraController::frameTriggered
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
Definition: qgscameracontroller.cpp:159
qgis.h
QgsCameraPose::distanceFromCenterPoint
float distanceFromCenterPoint() const
Returns distance of the camera from the center point.
Definition: qgscamerapose.h:56
QgsCameraController::pitch
float pitch() const
Returns pitch angle in degrees (0 = looking from the top, 90 = looking from the side).
Definition: qgscameracontroller.h:179
QgsVector3D::set
void set(double x, double y, double z)
Sets vector coordinates.
Definition: qgsvector3d.h:69
QgsCameraPose::setHeadingAngle
void setHeadingAngle(float heading)
Sets heading (yaw) angle in degrees.
Definition: qgscamerapose.h:68
QgsCameraController::tiltUpAroundViewCenter
void tiltUpAroundViewCenter(float deltaPitch)
Tilt up the view by deltaPitch around the view center (camera moves)
Definition: qgscameracontroller.cpp:944
QgsCameraController::rotateAroundViewCenter
void rotateAroundViewCenter(float deltaYaw)
Rotate clockwise the view by deltaYaw around the view center (camera moves)
Definition: qgscameracontroller.cpp:953
QgsCameraController::VerticalAxisInversion
VerticalAxisInversion
Vertical axis inversion options.
Definition: qgscameracontroller.h:77
QgsCameraController::setVerticalAxisInversion
void setVerticalAxisInversion(QgsCameraController::VerticalAxisInversion inversion)
Sets the vertical axis inversion behavior.
Definition: qgscameracontroller.cpp:92
Qgs3DUtils::rayFromScreenPoint
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.
Definition: qgs3dutils.cpp:681
QgsCameraPose::pitchAngle
float pitchAngle() const
Returns pitch angle in degrees.
Definition: qgscamerapose.h:61
QgsCameraController::navigationModeChanged
void navigationModeChanged(QgsCameraController::NavigationMode mode)
Emitted when the navigation mode is changed using the hotkey ctrl + ~.
QgsCameraPose::headingAngle
float headingAngle() const
Returns heading (yaw) angle in degrees.
Definition: qgscamerapose.h:66
QgsCameraController::QgsCameraController
QgsCameraController(Qt3DCore::QNode *parent=nullptr)
Constructs the camera controller with optional parent node that will take ownership.
Definition: qgscameracontroller.cpp:33
QgsCameraPose::updateCamera
void updateCamera(Qt3DRender::QCamera *camera)
Update Qt3D camera view matrix based on the pose.
Definition: qgscamerapose.cpp:70
Qgs3DUtils::screenPointToWorldPos
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.
Definition: qgs3dutils.cpp:707
QgsCameraController::zoom
void zoom(float factor)
Zoom the map by factor.
Definition: qgscameracontroller.cpp:497
QgsRay3D
A representation of a ray in 3D.
Definition: qgsray3d.h:30
QgsCameraController::setCameraPose
void setCameraPose(const QgsCameraPose &camPose)
Sets camera pose.
Definition: qgscameracontroller.cpp:201
QgsVector3D::z
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:66
QgsCameraController::camera
Qt3DRender::QCamera camera
Definition: qgscameracontroller.h:64
qgs3dutils.h
QgsCameraController::moveView
void moveView(float tx, float ty)
Move the map by tx and ty.
Definition: qgscameracontroller.cpp:968
Qt3DInput
Definition: qgscameracontroller.h:27
QgsCameraController::requestDepthBufferCapture
void requestDepthBufferCapture()
Emitted to ask for the depth buffer image.
Qt3DCore
Definition: qgsabstract3drenderer.h:30
Qt3DRender
Definition: qgs3dmapscene.h:28
QgsCameraController::viewportChanged
void viewportChanged()
Emitted when viewport rectangle has been updated.
QgsCameraController::viewport
QRect viewport
Definition: qgscameracontroller.h:65
QgsCameraController::setCamera
void setCamera(Qt3DRender::QCamera *camera)
Assigns camera that should be controlled by this class. Called internally from 3D scene.
Definition: qgscameracontroller.cpp:105
QgsRay3D::origin
QVector3D origin() const
Returns the origin of the ray.
Definition: qgsray3d.h:57
QgsCameraController::setCameraMovementSpeed
void setCameraMovementSpeed(double movementSpeed)
Sets the camera movement speed.
Definition: qgscameracontroller.cpp:83
qgscameracontroller.h
QgsCameraController::setCursorPosition
void setCursorPosition(QPoint point)
Emitted when the mouse cursor position should be moved to the specified point on the map viewport.
QgsCameraController::setTerrainEntity
void setTerrainEntity(QgsTerrainEntity *te)
Connects to object picker attached to terrain entity.
Definition: qgscameracontroller.cpp:97
QgsCameraController::setLookingAtPoint
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),...
Definition: qgscameracontroller.cpp:191
QgsCameraPose
Class that encapsulates camera pose in a 3D scene.
Definition: qgscamerapose.h:46
QgsCameraController::cameraRotationCenterChanged
void cameraRotationCenterChanged(QVector3D position)
Emitted when the camera rotation center changes.
qgsterrainentity_p.h
QgsCameraController::setViewport
void setViewport(QRect viewport)
Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates.
Definition: qgscameracontroller.cpp:118
qgsvector3d.h
Qgs3DUtils::decodeDepth
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...
Definition: qgs3dutils.h:230
QgsCameraController::depthBufferCaptured
void depthBufferCaptured(const QImage &depthImage)
Sets the depth buffer image used by the camera controller to calculate world position from a pixel's ...
Definition: qgscameracontroller.cpp:1042
qgssettings.h
QgsCameraController::setCameraHeadingAngle
void setCameraHeadingAngle(float angle)
Set camera heading to angle (used for rotating the view)
Definition: qgscameracontroller.cpp:962
QgsCameraController::setCameraNavigationMode
void setCameraNavigationMode(QgsCameraController::NavigationMode navigationMode)
Sets the navigation mode used by the camera controller.
Definition: qgscameracontroller.cpp:73
QgsCameraController::WhenDragging
@ WhenDragging
Invert vertical axis movements when dragging in first person modes.
Definition: qgscameracontroller.h:80
QgsCameraController::distance
float distance() const
Returns distance of the camera from the point it is looking at.
Definition: qgscameracontroller.h:172
QgsCameraPose::setPitchAngle
void setPitchAngle(float pitch)
Sets pitch angle in degrees.
Definition: qgscamerapose.cpp:60
qgslogger.h
QgsCameraPose::setDistanceFromCenterPoint
void setDistanceFromCenterPoint(float distance)
Sets distance of the camera from the center point.
Definition: qgscamerapose.cpp:55
QgsCameraController::cameraChanged
void cameraChanged()
Emitted when camera has been updated.
qgsraycastingutils_p.h
MathUtils::angle
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)
Definition: MathUtils.cpp:786
QgsVector3D::x
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:62
QgsRay3D::direction
QVector3D direction() const
Returns the direction of the ray see setDirection()
Definition: qgsray3d.h:63
QgsCameraPose::setCenterPoint
void setCenterPoint(const QgsVector3D &point)
Sets center point (towards which point the camera is looking)
Definition: qgscamerapose.cpp:46
QgsCameraController::NavigationMode
NavigationMode
The navigation mode used by the camera.
Definition: qgscameracontroller.h:69
QgsCameraController::setViewFromTop
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...
Definition: qgscameracontroller.cpp:169
QgsCameraController::TerrainBasedNavigation
@ TerrainBasedNavigation
The default navigation based on the terrain.
Definition: qgscameracontroller.h:71
QgsCameraController::willHandleKeyEvent
bool willHandleKeyEvent(QKeyEvent *event)
Returns true if the camera controller will handle the specified key event, preventing it from being i...
Definition: qgscameracontroller.cpp:987