23 #include <QDomDocument> 24 #include <Qt3DRender/QCamera> 25 #include <Qt3DRender/QObjectPicker> 26 #include <Qt3DRender/QPickEvent> 32 , mMouseDevice( new
Qt3DInput::QMouseDevice() )
33 , mKeyboardDevice( new
Qt3DInput::QKeyboardDevice() )
34 , mMouseHandler( new
Qt3DInput::QMouseHandler )
35 , mKeyboardHandler( new
Qt3DInput::QKeyboardHandler )
38 mMouseHandler->setSourceDevice( mMouseDevice );
39 connect( mMouseHandler, &Qt3DInput::QMouseHandler::positionChanged,
40 this, &QgsCameraController::onPositionChanged );
41 connect( mMouseHandler, &Qt3DInput::QMouseHandler::wheel,
42 this, &QgsCameraController::onWheel );
43 connect( mMouseHandler, &Qt3DInput::QMouseHandler::pressed,
44 this, &QgsCameraController::onMousePressed );
45 connect( mMouseHandler, &Qt3DInput::QMouseHandler::released,
46 this, &QgsCameraController::onMouseReleased );
47 addComponent( mMouseHandler );
49 mKeyboardHandler->setSourceDevice( mKeyboardDevice );
50 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::pressed,
51 this, &QgsCameraController::onKeyPressed );
52 connect( mKeyboardHandler, &Qt3DInput::QKeyboardHandler::released,
53 this, &QgsCameraController::onKeyReleased );
54 addComponent( mKeyboardHandler );
57 connect(
this, &Qt3DCore::QEntity::enabledChanged,
58 mMouseHandler, &Qt3DInput::QMouseHandler::setEnabled );
59 connect(
this, &Qt3DCore::QEntity::enabledChanged,
60 mKeyboardHandler, &Qt3DInput::QMouseHandler::setEnabled );
68 connect( te->terrainPicker(), &Qt3DRender::QObjectPicker::pressed,
this, &QgsCameraController::onPickerMousePressed );
73 if ( mCamera == camera )
86 if ( mViewport == viewport )
94 static QVector3D unproject( QVector3D v,
const QMatrix4x4 &modelView,
const QMatrix4x4 &projection, QRect
viewport )
101 QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
103 QVector4D tmp( v, 1.0f );
104 tmp.setX( ( tmp.x() - float( viewport.x() ) ) / float( viewport.width() ) );
105 tmp.setY( ( tmp.y() - float( viewport.y() ) ) / float( viewport.height() ) );
106 tmp = tmp * 2.0f - QVector4D( 1.0f, 1.0f, 1.0f, 1.0f );
108 QVector4D obj = inverse * tmp;
112 return obj.toVector3D();
120 float k = ( y - y0 ) / d_y;
127 QVector3D l0 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 0 ), camera->viewMatrix(), camera->projectionMatrix(),
viewport );
128 QVector3D l1 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 1 ), camera->viewMatrix(), camera->projectionMatrix(),
viewport );
130 QVector3D p0( 0, y, 0 );
131 QVector3D n( 0, 1, 0 );
132 QVector3D l = l1 - l0;
133 float d = QVector3D::dotProduct( p0 - l0, n ) / QVector3D::dotProduct( l, n );
134 QVector3D p = d * l + l0;
136 return QPointF( p.x(), p.z() );
140 void QgsCameraController::rotateCamera(
float diffPitch,
float diffYaw )
145 if ( pitch + diffPitch > 180 )
146 diffPitch = 180 -
pitch;
147 if ( pitch + diffPitch < 0 )
148 diffPitch = 0 -
pitch;
155 QQuaternion q = QQuaternion::fromEulerAngles( pitch + diffPitch, yaw + diffYaw, 0 ) *
156 QQuaternion::fromEulerAngles( pitch, yaw, 0 ).conjugated();
159 QVector3D position = mCamera->position();
160 QVector3D viewCenter = mCamera->viewCenter();
161 QVector3D viewVector = viewCenter - position;
162 QVector3D cameraToCenter = q * viewVector;
163 viewCenter = position + cameraToCenter;
189 mCamera->setNearPlane( distance / 2 );
190 mCamera->setFarPlane( distance * 2 );
212 if ( camPose == mCameraPose )
215 mCameraPose = camPose;
225 QDomElement elemCamera = doc.createElement( QStringLiteral(
"camera" ) );
226 elemCamera.setAttribute( QStringLiteral(
"x" ), mCameraPose.
centerPoint().
x() );
227 elemCamera.setAttribute( QStringLiteral(
"y" ), mCameraPose.
centerPoint().
z() );
228 elemCamera.setAttribute( QStringLiteral(
"elev" ), mCameraPose.
centerPoint().
y() );
230 elemCamera.setAttribute( QStringLiteral(
"pitch" ), mCameraPose.
pitchAngle() );
231 elemCamera.setAttribute( QStringLiteral(
"yaw" ), mCameraPose.
headingAngle() );
237 float x = elem.attribute( QStringLiteral(
"x" ) ).toFloat();
238 float y = elem.attribute( QStringLiteral(
"y" ) ).toFloat();
239 float elev = elem.attribute( QStringLiteral(
"elev" ) ).toFloat();
240 float dist = elem.attribute( QStringLiteral(
"dist" ) ).toFloat();
241 float pitch = elem.attribute( QStringLiteral(
"pitch" ) ).toFloat();
242 float yaw = elem.attribute( QStringLiteral(
"yaw" ) ).toFloat();
246 void QgsCameraController::updateCameraFromPose(
bool centerPointChanged )
251 qDebug() <<
"camera position got NaN!";
265 if ( mCamera && mTerrainEntity && centerPointChanged )
269 QVector3D intersectionPoint;
270 QgsRayCastingUtils::Ray3D ray = QgsRayCastingUtils::rayForCameraCenter( mCamera );
271 if ( mTerrainEntity->rayIntersection( ray, intersectionPoint ) )
273 float dist = ( intersectionPoint - mCamera->position() ).length();
283 void QgsCameraController::onPositionChanged( Qt3DInput::QMouseEvent *mouse )
285 int dx = mouse->x() - mMousePos.x();
286 int dy = mouse->y() - mMousePos.y();
288 bool hasShift = ( mouse->modifiers() & Qt::ShiftModifier );
289 bool hasCtrl = ( mouse->modifiers() & Qt::ControlModifier );
290 bool hasLeftButton = ( mouse->buttons() & Qt::LeftButton );
291 bool hasMiddleButton = ( mouse->buttons() & Qt::MiddleButton );
292 bool hasRightButton = ( mouse->buttons() & Qt::RightButton );
294 if ( ( hasLeftButton && hasShift && !hasCtrl ) || ( hasMiddleButton && !hasShift && !hasCtrl ) )
303 updateCameraFromPose();
305 else if ( hasLeftButton && hasCtrl && !hasShift )
308 float diffPitch = 0.2f * dy;
309 float diffYaw = 0.2f * -dx / 2;
310 rotateCamera( diffPitch, diffYaw );
311 updateCameraFromPose(
true );
313 else if ( hasLeftButton && !hasShift && !hasCtrl )
319 float z = mLastPressedHeight;
324 center.
set( center.
x() - ( p2.x() - p1.x() ), center.
y(), center.
z() - ( p2.y() - p1.y() ) );
326 updateCameraFromPose(
true );
328 else if ( hasRightButton && !hasShift && !hasCtrl )
332 dist -= dist * dy * 0.01f;
334 updateCameraFromPose();
337 mMousePos = QPoint( mouse->x(), mouse->y() );
340 void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
342 float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) ? 0.1f : 1.0f ) / 1000.f;
344 dist -= dist * scaling * wheel->angleDelta().y();
346 updateCameraFromPose();
349 void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
352 mKeyboardHandler->setFocus(
true );
355 void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
360 void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
362 bool hasShift = (
event->modifiers() & Qt::ShiftModifier );
363 bool hasCtrl = (
event->modifiers() & Qt::ControlModifier );
365 int tx = 0, ty = 0, tElev = 0;
366 switch ( event->key() )
382 case Qt::Key_PageDown:
392 if ( !hasShift && !hasCtrl )
396 float x = tx * dist * 0.02f;
397 float y = -ty * dist * 0.02f;
400 float t = sqrt( x * x + y * y );
401 float a = atan2( y, x ) - yaw * M_PI / 180;
402 float dx = cos( a ) * t;
403 float dy = sin( a ) * t;
406 center.
set( center.
x() + dx, center.
y(), center.
z() + dy );
408 updateCameraFromPose(
true );
410 else if ( hasShift && !hasCtrl )
419 updateCameraFromPose();
421 else if ( hasCtrl && !hasShift )
424 float diffPitch = ty;
426 rotateCamera( diffPitch, diffYaw );
427 updateCameraFromPose(
true );
434 center.
set( center.
x(), center.
y() + tElev * 10, center.
z() );
436 updateCameraFromPose(
true );
440 void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
445 void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
447 mLastPressedHeight = pick->worldIntersection().y();
3 Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double preci...
void cameraChanged()
Emitted when camera has been updated.
QgsCameraController(Qt3DCore::QNode *parent=nullptr)
Constructs the camera controller with optional parent node that will take ownership.
Qt3DRender::QCamera * camera() const
Returns camera that is being controlled.
void frameTriggered(float dt)
Called internally from 3D scene when a new frame is generated. Updates camera according to keyboard/m...
float pitch() const
Returns pitch angle in degrees (0 = looking from the top, 90 = looking from the side).
void setViewport(QRect viewport)
Sets viewport rectangle. Called internally from 3D canvas. Allows conversion of mouse coordinates...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QgsVector3D centerPoint() const
Returns center point (towards which point the camera is looking)
QRect viewport() const
Returns viewport rectangle.
void resetView(float distance)
Move camera back to the initial position (looking down towards origin of world's coordinates) ...
double y() const
Returns Y coordinate.
void set(double x, double y, double z)
Sets vector coordinates.
3 Class that encapsulates camera pose in a 3D scene.
float yaw() const
Returns yaw angle in degrees.
double z() const
Returns Z coordinate.
float find_x_on_line(float x0, float y0, float x1, float y1, float y)
void viewportChanged()
Emitted when viewport rectangle has been updated.
void setPitchAngle(float pitch)
Sets pitch angle in degrees.
float distanceFromCenterPoint() const
Returns distance of the camera from the center point.
void readXml(const QDomElement &elem)
Reads camera configuration from the given DOM element.
float headingAngle() const
Returns heading (yaw) angle in degrees.
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...
QDomElement writeXml(QDomDocument &doc) const
Writes camera configuration to the given DOM element.
void setCamera(Qt3DRender::QCamera *camera)
Assigns camera that should be controlled by this class. Called internally from 3D scene...
void updateCamera(Qt3DRender::QCamera *camera)
Update Qt3D camera view matrix based on the pose.
QgsVector3D lookingAtPoint() const
Returns the point in the world coordinates towards which the camera is looking.
void setHeadingAngle(float heading)
Sets heading (yaw) angle in degrees.
QPointF screen_point_to_point_on_plane(QPointF pt, QRect viewport, Qt3DRender::QCamera *camera, float y)
void setCenterPoint(const QgsVector3D &point)
Sets center point (towards which point the camera is looking)
float pitchAngle() const
Returns pitch angle in degrees.
void setDistanceFromCenterPoint(float distance)
Sets distance of the camera from the center point.
void setTerrainEntity(QgsTerrainEntity *te)
Connects to object picker attached to terrain entity.
void setCameraPose(const QgsCameraPose &camPose)
Sets camera pose.
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)...
float distance() const
Returns distance of the camera from the point it is looking at.
double x() const
Returns X coordinate.