Skip to content

Commit a170dcb

Browse files
committedOct 13, 2017
Fix dragging 3D view with mouse when camera is far
Before, when looking at a greater area (e.g. spanning 200km or more), dragging 3D view with left mouse button would not work at all. Only when zoomed in more it would start working again. This was cause by unproject() method in Qt having tolerance against division by zero very high. Lowering the tolerance by few magnitudes fixed the problem (1e-5 to 1e-10)
1 parent b740a89 commit a170dcb

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed
 

‎src/3d/qgscameracontroller.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "qgscameracontroller.h"
1717

18+
#include "qgis.h"
19+
1820
#include <Qt3DRender/QObjectPicker>
1921
#include <Qt3DRender/QPickEvent>
2022

@@ -161,6 +163,28 @@ void QgsCameraController::setCameraData( float x, float y, float dist, float pit
161163
}
162164

163165

166+
static QVector3D unproject( const QVector3D &v, const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport )
167+
{
168+
// Reimplementation of QVector3D::unproject() - see qtbase/src/gui/math3d/qvector3d.cpp
169+
// The only difference is that the original implementation uses tolerance 1e-5
170+
// (see qFuzzyIsNull()) as a protection against division by zero. For us it is however
171+
// common to get lower values (e.g. as low as 1e-8 when zoomed out to the whole Earth with web mercator).
172+
173+
QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
174+
175+
QVector4D tmp( v, 1.0f );
176+
tmp.setX( ( tmp.x() - float( viewport.x() ) ) / float( viewport.width() ) );
177+
tmp.setY( ( tmp.y() - float( viewport.y() ) ) / float( viewport.height() ) );
178+
tmp = tmp * 2.0f - QVector4D( 1.0f, 1.0f, 1.0f, 1.0f );
179+
180+
QVector4D obj = inverse * tmp;
181+
if ( qgsDoubleNear( obj.w(), 0, 1e-10 ) )
182+
obj.setW( 1.0f );
183+
obj /= obj.w();
184+
return obj.toVector3D();
185+
}
186+
187+
164188
float find_x_on_line( float x0, float y0, float x1, float y1, float y )
165189
{
166190
float d_x = x1 - x0;
@@ -172,8 +196,8 @@ float find_x_on_line( float x0, float y0, float x1, float y1, float y )
172196
QPointF screen_point_to_point_on_plane( const QPointF &pt, const QRect &viewport, Qt3DRender::QCamera *camera, float y )
173197
{
174198
// get two points of the ray
175-
QVector3D l0 = QVector3D( pt.x(), viewport.height() - pt.y(), 0 ).unproject( camera->viewMatrix(), camera->projectionMatrix(), viewport );
176-
QVector3D l1 = QVector3D( pt.x(), viewport.height() - pt.y(), 1 ).unproject( camera->viewMatrix(), camera->projectionMatrix(), viewport );
199+
QVector3D l0 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 0 ), camera->viewMatrix(), camera->projectionMatrix(), viewport );
200+
QVector3D l1 = unproject( QVector3D( pt.x(), viewport.height() - pt.y(), 1 ), camera->viewMatrix(), camera->projectionMatrix(), viewport );
177201

178202
QVector3D p0( 0, y, 0 ); // a point on the plane
179203
QVector3D n( 0, 1, 0 ); // normal of the plane

0 commit comments

Comments
 (0)
Please sign in to comment.