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 )
333 mMousePos = QPoint( mouse->x(), mouse->y() );
340 dist -= dist * factor * 0.01f;
342 updateCameraFromPose();
345 void QgsCameraController::onWheel( Qt3DInput::QWheelEvent *wheel )
347 float scaling = ( ( wheel->modifiers() & Qt::ControlModifier ) ? 0.1f : 1.0f ) / 1000.f;
349 dist -= dist * scaling * wheel->angleDelta().y();
351 updateCameraFromPose();
354 void QgsCameraController::onMousePressed( Qt3DInput::QMouseEvent *mouse )
357 mKeyboardHandler->setFocus(
true );
360 void QgsCameraController::onMouseReleased( Qt3DInput::QMouseEvent *mouse )
365 void QgsCameraController::onKeyPressed( Qt3DInput::QKeyEvent *event )
367 bool hasShift = (
event->modifiers() & Qt::ShiftModifier );
368 bool hasCtrl = (
event->modifiers() & Qt::ControlModifier );
370 int tx = 0, ty = 0, tElev = 0;
371 switch ( event->key() )
387 case Qt::Key_PageDown:
397 if ( !hasShift && !hasCtrl )
401 else if ( hasShift && !hasCtrl )
407 else if ( hasCtrl && !hasShift )
410 float diffPitch = ty;
412 rotateCamera( diffPitch, diffYaw );
413 updateCameraFromPose(
true );
420 center.
set( center.
x(), center.
y() + tElev * 10, center.
z() );
422 updateCameraFromPose(
true );
426 void QgsCameraController::onKeyReleased( Qt3DInput::QKeyEvent *event )
431 void QgsCameraController::onPickerMousePressed( Qt3DRender::QPickEvent *pick )
433 mLastPressedHeight = pick->worldIntersection().y();
442 updateCameraFromPose();
451 updateCameraFromPose();
452 qInfo() <<
"Delta yaw: " << deltaYaw;
453 qInfo() <<
"Yaw: " <<
yaw;
459 updateCameraFromPose();
466 float x = tx * dist * 0.02f;
467 float y = -ty * dist * 0.02f;
470 float t = sqrt( x * x + y * y );
471 float a = atan2( y, x ) - yaw * M_PI / 180;
472 float dx = cos( a ) * t;
473 float dy = sin( a ) * t;
476 center.
set( center.
x() + dx, center.
y(), center.
z() + dy );
478 updateCameraFromPose(
true );
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...
void setCameraHeadingAngle(float angle)
Set camera heading to angle (used for rotating the view)
float pitch() const
Returns pitch angle in degrees (0 = looking from the top, 90 = looking from the side).
void tiltUpAroundViewCenter(float deltaPitch)
Tilt up the view by deltaPitch around the view center (camera moves)
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.
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)
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 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 moveView(float tx, float ty)
Move the map by tx and ty.
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.