Skip to content

Commit 2da7058

Browse files
committedSep 19, 2018
Fix search tolerance when doing identification in 3D map view
Until now the identification from 3D map view used tolerance based on the current view of the main 2D map canvas - that was giving often unexpected results if the 2D map canvas had significantly different zoom level from the 3D map view.
1 parent e3f63d8 commit 2da7058

File tree

8 files changed

+91
-4
lines changed

8 files changed

+91
-4
lines changed
 

‎python/gui/auto_generated/qgsmaptoolidentify.sip.in

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,31 @@ Call the right method depending on layer type
161161
QMap< QString, QString > derivedAttributesForPoint( const QgsPoint &point );
162162
%Docstring
163163
Returns derived attributes map for a clicked point in map coordinates. May be 2D or 3D point.
164+
%End
165+
166+
void setCanvasPropertiesOverrides( double searchRadiusMapUnits );
167+
%Docstring
168+
Overrides some map canvas properties inside the map tool for the upcoming identify requests.
169+
170+
This is useful when the identification is triggered by some other piece of GUI like a 3D map view
171+
and some properties like search radius need to be adjusted so that identification returns correct
172+
results. Currently only search radius may be overridden.
173+
174+
When the custom identification has finished, restoreCanvasPropertiesOverrides() should
175+
be called to erase any overrides.
176+
177+
.. seealso:: :py:func:`restoreCanvasProperties`
178+
179+
.. versionadded:: 3.4
180+
%End
181+
182+
void restoreCanvasPropertiesOverrides();
183+
%Docstring
184+
Clears canvas properties overrides previously set with setCanvasPropertiesOverrides()
185+
186+
.. seealso:: :py:func:`setCanvasPropertiesOverrides`
187+
188+
.. versionadded:: 3.4
164189
%End
165190

166191
};

‎src/3d/qgs3dmapscene.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ void Qgs3DMapScene::unregisterPickHandler( Qgs3DMapScenePickHandler *pickHandler
210210
}
211211
}
212212

213+
float Qgs3DMapScene::worldSpaceError( float epsilon, float distance )
214+
{
215+
Qt3DRender::QCamera *camera = mCameraController->camera();
216+
float fov = camera->fieldOfView();
217+
QRect rect = mCameraController->viewport();
218+
float screenSizePx = std::max( rect.width(), rect.height() ); // TODO: is this correct?
219+
220+
// in qgschunkedentity_p.cpp there is inverse calculation (world space error to screen space error)
221+
// with explanation of the math.
222+
float frustumWidthAtDistance = 2 * distance * tan( fov / 2 );
223+
float err = frustumWidthAtDistance * epsilon / screenSizePx;
224+
return err;
225+
}
226+
213227
QgsChunkedEntity::SceneState _sceneState( QgsCameraController *cameraController )
214228
{
215229
Qt3DRender::QCamera *camera = cameraController->camera();

‎src/3d/qgs3dmapscene.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ class _3D_EXPORT Qgs3DMapScene : public Qt3DCore::QEntity
8383
//! Unregisters previously registered pick handler. Pick handler is not deleted. Also removes object picker components from 3D entities.
8484
void unregisterPickHandler( Qgs3DMapScenePickHandler *pickHandler );
8585

86+
/**
87+
* Given screen error (in pixels) and distance from camera (in 3D world coordinates), this function
88+
* estimates the error in world space. Takes into account camera's field of view and the screen (3D view) size.
89+
*/
90+
float worldSpaceError( float epsilon, float distance );
91+
8692
signals:
8793
//! Emitted when the current terrain entity is replaced by a new one
8894
void terrainEntityChanged();

‎src/app/3d/qgs3dmaptoolidentify.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,16 @@ void Qgs3DMapToolIdentify::onTerrainPicked( Qt3DRender::QPickEvent *event )
9696

9797
QgsGeometry geom = QgsGeometry::fromPointXY( QgsPointXY( mapCoords.x(), mapCoords.y() ) );
9898

99+
// estimate search radius
100+
Qgs3DMapScene *scene = mCanvas->scene();
101+
double searchRadiusMM = QgsMapTool::searchRadiusMM();
102+
double pixelsPerMM = mCanvas->logicalDpiX() / 25.4;
103+
double searchRadiusPx = searchRadiusMM * pixelsPerMM;
104+
double searchRadiusMapUnits = scene->worldSpaceError( searchRadiusPx, event->distance() );
105+
99106
QgsMapToolIdentifyAction *identifyTool2D = QgisApp::instance()->identifyMapTool();
100107

101-
identifyTool2D->identifyAndShowResults( geom );
108+
identifyTool2D->identifyAndShowResults( geom, searchRadiusMapUnits );
102109
}
103110

104111
void Qgs3DMapToolIdentify::onTerrainEntityChanged()

‎src/app/qgsmaptoolidentifyaction.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,11 @@ void QgsMapToolIdentifyAction::deactivate()
212212
QgsMapToolIdentify::deactivate();
213213
}
214214

215-
void QgsMapToolIdentifyAction::identifyAndShowResults( const QgsGeometry &geom )
215+
void QgsMapToolIdentifyAction::identifyAndShowResults( const QgsGeometry &geom, double searchRadiusMapUnits )
216216
{
217+
setCanvasPropertiesOverrides( searchRadiusMapUnits );
217218
mSelectionHandler->setSelectedGeometry( geom );
219+
restoreCanvasPropertiesOverrides();
218220
}
219221

220222
void QgsMapToolIdentifyAction::clearResults()

‎src/app/qgsmaptoolidentifyaction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class APP_EXPORT QgsMapToolIdentifyAction : public QgsMapToolIdentify
6262
void deactivate() override;
6363

6464
//! Triggers map identification of at the given location and outputs results in GUI
65-
void identifyAndShowResults( const QgsGeometry &geom );
65+
void identifyAndShowResults( const QgsGeometry &geom, double searchRadiusMapUnits );
6666
//! Clears any previous results from the GUI
6767
void clearResults();
6868
//! Looks up feature by its ID and outputs the result in GUI

‎src/gui/qgsmaptoolidentify.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( const Qg
179179
return results;
180180
}
181181

182+
void QgsMapToolIdentify::setCanvasPropertiesOverrides( double searchRadiusMapUnits )
183+
{
184+
mOverrideCanvasSearchRadius = searchRadiusMapUnits;
185+
}
186+
187+
void QgsMapToolIdentify::restoreCanvasPropertiesOverrides()
188+
{
189+
mOverrideCanvasSearchRadius = -1;
190+
}
191+
182192
void QgsMapToolIdentify::activate()
183193
{
184194
QgsMapTool::activate();
@@ -270,7 +280,7 @@ bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::Identify
270280
QgsRectangle r;
271281
if ( isSingleClick )
272282
{
273-
double sr = searchRadiusMU( mCanvas );
283+
double sr = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
274284
r = toLayerCoordinates( layer, QgsRectangle( point.x() - sr, point.y() - sr, point.x() + sr, point.y() + sr ) );
275285
}
276286
else

‎src/gui/qgsmaptoolidentify.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,27 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
168168
//! Returns derived attributes map for a clicked point in map coordinates. May be 2D or 3D point.
169169
QMap< QString, QString > derivedAttributesForPoint( const QgsPoint &point );
170170

171+
/**
172+
* Overrides some map canvas properties inside the map tool for the upcoming identify requests.
173+
*
174+
* This is useful when the identification is triggered by some other piece of GUI like a 3D map view
175+
* and some properties like search radius need to be adjusted so that identification returns correct
176+
* results. Currently only search radius may be overridden.
177+
*
178+
* When the custom identification has finished, restoreCanvasPropertiesOverrides() should
179+
* be called to erase any overrides.
180+
* \see restoreCanvasProperties()
181+
* \since QGIS 3.4
182+
*/
183+
void setCanvasPropertiesOverrides( double searchRadiusMapUnits );
184+
185+
/**
186+
* Clears canvas properties overrides previously set with setCanvasPropertiesOverrides()
187+
* \see setCanvasPropertiesOverrides()
188+
* \since QGIS 3.4
189+
*/
190+
void restoreCanvasPropertiesOverrides();
191+
171192
private:
172193

173194
bool identifyLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMapLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType = AllLayers );
@@ -238,6 +259,8 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
238259
QgsRectangle mLastExtent;
239260

240261
int mCoordinatePrecision;
262+
263+
double mOverrideCanvasSearchRadius = -1;
241264
};
242265

243266
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsMapToolIdentify::LayerType )

0 commit comments

Comments
 (0)
Please sign in to comment.