QGIS API Documentation 3.43.0-Master (3ee7834ace6)
qgscamerapose.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscamerapose.cpp
3 --------------------------------------
4 Date : July 2018
5 Copyright : (C) 2018 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 "qgscamerapose.h"
17
18#include "qgs3dutils.h"
19
20#include <Qt3DRender/QCamera>
21
22#include <QDomDocument>
23
24QDomElement QgsCameraPose::writeXml( QDomDocument &doc ) const
25{
26 QDomElement elemCamera = doc.createElement( QStringLiteral( "camera-pose" ) );
27 elemCamera.setAttribute( QStringLiteral( "x" ), mCenterPoint.x() );
28 elemCamera.setAttribute( QStringLiteral( "y" ), mCenterPoint.y() );
29 elemCamera.setAttribute( QStringLiteral( "z" ), mCenterPoint.z() );
30 elemCamera.setAttribute( QStringLiteral( "dist" ), mDistanceFromCenterPoint );
31 elemCamera.setAttribute( QStringLiteral( "pitch" ), mPitchAngle );
32 elemCamera.setAttribute( QStringLiteral( "heading" ), mHeadingAngle );
33 return elemCamera;
34}
35
36void QgsCameraPose::readXml( const QDomElement &elem )
37{
38 const double x = elem.attribute( QStringLiteral( "x" ) ).toDouble();
39 const double y = elem.attribute( QStringLiteral( "y" ) ).toDouble();
40 const double z = elem.attribute( QStringLiteral( "z" ) ).toDouble();
41 mCenterPoint = QgsVector3D( x, y, z );
42
43 mDistanceFromCenterPoint = elem.attribute( QStringLiteral( "dist" ) ).toFloat();
44 mPitchAngle = elem.attribute( QStringLiteral( "pitch" ) ).toFloat();
45 mHeadingAngle = elem.attribute( QStringLiteral( "heading" ) ).toFloat();
46}
47
49{
50 // something went horribly wrong. Prevent further errors
51 if ( std::isnan( point.x() ) || std::isnan( point.y() ) || std::isnan( point.z() ) )
52 qWarning() << "Not updating camera position: it cannot be NaN!";
53 else
54 mCenterPoint = point;
55}
56
58{
59 mDistanceFromCenterPoint = std::max( distance, 10.0f );
60}
61
63{
64 // prevent going over the head
65 mPitchAngle = std::clamp( pitch, 0.0f, 180.0f );
66}
67
68void QgsCameraPose::updateCamera( Qt3DRender::QCamera *camera )
69{
70 // first rotate by pitch angle around X axis, then by heading angle around Z axis
71 QQuaternion q = Qgs3DUtils::rotationFromPitchHeadingAngles( mPitchAngle, mHeadingAngle );
72 QVector3D cameraToCenter = q * QVector3D( 0, 0, -mDistanceFromCenterPoint );
73 camera->setUpVector( q * QVector3D( 0, 1, 0 ) );
74 camera->setPosition( mCenterPoint.toVector3D() - cameraToCenter );
75 camera->setViewCenter( mCenterPoint.toVector3D() );
76}
77
78void QgsCameraPose::updateCameraGlobe( Qt3DRender::QCamera *camera, double lat, double lon )
79{
80 // how the camera setup works:
81 // - we are using ECEF coordinates (https://en.wikipedia.org/wiki/Earth-centered,_Earth-fixed_coordinate_system)
82 // - point (0,0,0) is in the center of reference ellipsoid
83 // - X and Y axes define equator plane
84 // - X axis grows towards the prime meridian (zero longitude)
85 // - Y axis grows towards 90 degrees of longitude
86 // - Z axis grows towards the north pole
87
88 QVector3D viewCenter = mCenterPoint.toVector3D();
89
90 // rotate camera so that it is looking towards the tangent plane to ellipsoid at given
91 // lat/lon coordinates
92 QQuaternion qLatLon = QQuaternion::fromAxisAndAngle( QVector3D( 0, 0, 1 ), static_cast<float>( lon ) ) * QQuaternion::fromAxisAndAngle( QVector3D( 0, -1, 0 ), static_cast<float>( lat ) );
93
94 // rotate camera using the pitch and heading angles
95 QQuaternion qPitchHeading = QQuaternion::fromAxisAndAngle( QVector3D( 1, 0, 0 ), mHeadingAngle ) * QQuaternion::fromAxisAndAngle( QVector3D( 0, 1, 0 ), mPitchAngle );
96
97 // combine the two rotations (the order is important: pitch/heading is applied first)
98 QQuaternion q = qLatLon * qPitchHeading;
99
100 QVector3D cameraToCenter = ( q * QVector3D( -1, 0, 0 ) ) * mDistanceFromCenterPoint;
101 camera->setUpVector( q * QVector3D( 0, 0, 1 ) );
102 camera->setPosition( viewCenter - cameraToCenter );
103 camera->setViewCenter( viewCenter );
104}
static QQuaternion rotationFromPitchHeadingAngles(float pitchAngle, float headingAngle)
Returns rotation quaternion that performs rotation around X axis by pitchAngle, followed by rotation ...
void updateCameraGlobe(Qt3DRender::QCamera *camera, double lat, double lon)
Updates camera when using a globe scene.
void setPitchAngle(float pitch)
Sets pitch angle in degrees.
QDomElement writeXml(QDomDocument &doc) const
Writes configuration to a new DOM element and returns it.
void setCenterPoint(const QgsVector3D &point)
Sets center point (towards which point the camera is looking)
void readXml(const QDomElement &elem)
Reads configuration from a DOM element previously written using writeXml()
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.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition qgsvector3d.h:31
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:50
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:52
QVector3D toVector3D() const
Converts the current object to QVector3D.
double x() const
Returns X coordinate.
Definition qgsvector3d.h:48