-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP][BUGFIX][FEATURE][NEEDS-DOCS] Disable snapping on invisible features #6657
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I don't think this approach will work - it's triggering a complete iteration through the layer (not just features in the view) for every candidate match -- it's going to be way too expensive to do.
I can't talk from a user point of view, but I feel that snapping should't be related with the fact that the layer is rendered or not (you may thing to snapToGrid, where grid is not a layer and nor is rendered). |
Agreed with both Nyall (performance) and Luigi (configuration): in my opinion the default behavior should be that all features are considered by QgsSnappingUtils (if not, we are breaking the API!), and there should be a flag whether to consider just visible features which would be turned on in QgsMapCanvasSnappingUtils. |
From a user point of view it is very confusing that invisible features (that aren't displayed for whatever reason) are acting as snap features. I don't agree with Luigi that it is a "feature". |
Is this only for snapping or does it cover Trace tool too? |
To avoid confusion, here is how it should work IMHO:
From user's point of view, in map canvas he/she only gets snapping to visible features. I don't think this needs to be configurable anywhere in the GUI... snapping to invisible features does not make much sense. From developer's point of view, the spatial queries in QgsSnappingUtils work on all features, with extra option to use just visible features if needed. This class may be used in various analytical algorithms, so by default the behavior should not be affected by renderer configuration. |
@wonder-sk thanks - agreed. |
Thanks for your comments, I was still on it :) . Thanks @wonder-sk |
Something to keep in mind while reworking this is that renderer->filter() isn't comprehensive -- it's just a way to partially limit the features requested for the renderer. Instead you need to check willRenderFeature instead. |
@nyalldawson
Return always true. |
That should work - maybe the map settings isn't correctly constructed? Check how the identify/select tools operate - they do a similar thing. |
Even with the spatial filter this is still going to be very slow. You need to avoid all feature requests when checking a match, because even a feature request for a single matching feature is expensive. |
A couple of other tips:
|
Thanks @nyalldawson willRenderFeature works, I have adapted identify tools. |
@nyalldawson Maybe, I have founded a bug with willRenderFeature. Some cases works, some returns always true. I have made a reproductible example here with a video. Any idea? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some small details...Otherwise, it's a long awaited BUGFIX....not a feature ;) ...
@@ -53,7 +53,7 @@ class CORE_EXPORT QgsSnappingUtils : public QObject | |||
public: | |||
|
|||
//! Constructor for QgsSnappingUtils | |||
QgsSnappingUtils( QObject *parent SIP_TRANSFERTHIS = nullptr ); | |||
QgsSnappingUtils( QObject *parent SIP_TRANSFERTHIS = nullptr, bool enableSnappingForInvisibleFeature = true ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to keep the set method only to set the option (i.e. remove it) or if we keep it in the constructor, can we use an enum instead of a bool then?
* | ||
* \since QGIS 3.2 | ||
*/ | ||
void setEnableSnappingForInvisibleFeature( bool enableIt ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/enableIt/enable/
|
||
#include <QApplication> | ||
#include <QProgressDialog> | ||
|
||
QgsMapCanvasSnappingUtils::QgsMapCanvasSnappingUtils( QgsMapCanvas *canvas, QObject *parent ) | ||
: QgsSnappingUtils( parent ) | ||
: QgsSnappingUtils( parent, QgsSettings().value( QStringLiteral( "/qgis/digitizing/snap_invisible_feature" ), false ).toBool() ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using an enum would be nicer here since you could use
QgsSettings().enumValue( QStringLiteral( "/qgis/digitizing/snap_invisible_feature" ), DoNotSnapOnInvisible );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate to keep throwing up issues here - but this code NEEDS to be fast and anything which potentially impacts the speed of snapping is a no-go for me. Fetching features one-at-a-time from a provider is very inefficient, so that needs to be reworked.
When that's addressed it also needs unit tests before it's merge-able.
@@ -970,6 +970,7 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOpti | |||
|
|||
mSnappingMarkerColorButton->setColor( mSettings->value( QStringLiteral( "/qgis/digitizing/snap_color" ), QColor( Qt::magenta ) ).value<QColor>() ); | |||
mSnappingTooltipsCheckbox->setChecked( mSettings->value( QStringLiteral( "/qgis/digitizing/snap_tooltip" ), false ).toBool() ); | |||
mEnableSnappingOnInvisibleFeatureCheckbox->setChecked( mSettings->value( QStringLiteral( "/qgis/digitizing/snap_invisible_feature" ), false ).toBool() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add this new setting to resources/qgis_global_settings.ini
if ( candidateMatch.layer() ) | ||
{ | ||
bool filter = false; | ||
QgsRenderContext context( QgsRenderContext::fromMapSettings( mapSettings ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please move this up from _isMatchAVisibleLayer so that the render context and renderer is only constructed once per layer per snap? startRender is expensive so this is also a performance killer.
filter = renderer->capabilities() & QgsFeatureRenderer::Filter; | ||
} | ||
|
||
QgsFeature feat = candidateMatch.layer()->getFeature( candidateMatch.featureId() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be a performance killer too - can you find a way to avoid fetching individual features and instead do a single feature fetch for the whole canvas extent at once?
I am just thinking of another approach: what about saving the info along when building the index. Then, if a layer gets its symbology edited, you update the index (just the visible boolean flag). @wonder-sk does it make sense? |
@nyalldawson @3nids I was also thinking about something like that. |
@lbartoletti I think this issue is fixed in this PR: #6679. Can you give it a try and let me know if you have some time? Thanks! |
Agreed with @nyalldawson and @3nids - the checks whether features will be rendered should be IMHO done when building the index, it would be otherwise too slow. |
Description
Bug founded by QWAT Team. Fixes #16838.
Solution: Filter on layer rendered.
New option to enable it or not:
![option](https://user-images.githubusercontent.com/7521540/37758076-3f44dd00-2daf-11e8-84c5-8811457a2aa7.png)
Screenshot for a normal case:
![normal](https://user-images.githubusercontent.com/7521540/37758121-5cd30db0-2daf-11e8-99ab-bd9945e5fa29.png)
When this bug/feature is enabled:
![option_enabled](https://user-images.githubusercontent.com/7521540/37758139-66bc6e8e-2daf-11e8-9fc7-6ce7fd861eea.png)
Checklist
fixes #11111
in the commit message next to the description[FEATURE]
in the commit message[needs-docs]
in the commit message and containt sufficient information in the commit message to be documentedscripts/prepare-commit.sh
script before each commit