-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Fix topological slowness with spatial filtering #60130
Conversation
I have to apologize for this PR is not being completely ready yet (tests are not fixed), but it is crucial to get the discussion started as soon as possible since we really need this to the 3.40.3 release. Could you @troopa81 please take a look at this already at this stage if possible? |
The original reason why whole geometries were added instead of just snapped points is based on this comment by @uclaros. I propose that for those specific use cases separate feature requests could be made if really needed. For our application wit over 150 editable layers, topological digitizing is extremely slow at this current stage. |
🪟 Windows buildsDownload Windows builds of this PR for testing. 🪟 Windows Qt6 buildsDownload Windows Qt6 builds of this PR for testing. |
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.
Adding only snapped points instead of whole geometries in add feature tool
That would mean a regression compare to 3.38.
In the issue you are editing 200 layers at the same time. I'm wondering if it's reasonable? Should user not select only the layer consistent between them (those for which you want to test and add topo points) and edit only them instead ?
src/app/vertextool/qgsvertextool.cpp
Outdated
@@ -2200,7 +2200,7 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato | |||
|
|||
applyEditsToLayers( edits ); | |||
|
|||
if ( QgsProject::instance()->topologicalEditing() ) | |||
if ( QgsProject::instance()->topologicalEditing() && mapPointMatch->layer() ) |
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.
Not looping every layer in vertex tool if there are no snapped points
But what if we drag some segment or set of points and there is no snap, we still have to try to add topo points for other vertex
I don't think this is the proper way to resolve your issue, as relying on snapped points is inadequate for topological integrity, as discussed on the linked comment. |
Unfortunately, all the layers have to be editable at the same time to ensure the topological integrity of the database. I know that reverting already implemented functionality is not optimal, but it has caused a huge performance downgrade compared to the 3.34 tree. What do you think, could another solution be to add method |
Like @uclaros already pointed out, I think that relying on only snapped point is not enough. I'm wondering if:
But I'm afraid that these 2 modifications are complicated enough to not make it to 3.40.3 (or even being backported) |
Not sure to understand this comment. We call addTopologicalPoints on every new/modified points regarding of the different action that have been done before. We add no more no less than what we need, no? |
After investigating more what really takes the time here, it appears that starting and ending edit commands takes the most of the time. It can be bypassed by checking intersection beforehand. I'll do some more investigating with this approach, but it looks promising and it does not revert any existing functionality. |
880505a
to
d25082a
Compare
I changed the whole fix to just check bbox intersection with What do you guys think about the new approach? Could this be backported? |
@troopa81 Should I add a little threshold to the bounding box like in
We also noticed that it is suboptimal to call
|
That would mean the request would be executed twice when there are points to be added. I understand you want to avoid beginEditCommand but why this call took so long ? |
It is not just one FeatureRequest that is being made. It is number of vertices times number of layers in the project. Here is a gif from my issue data showing that adding feature consisting of four vertex creates 800 featureRequests, ie. 4 * 200 requests. The code here is without the suggested change, just with added logging. If we can get the number of requests down to 1 for each layer that has no data near the feature, I would say it is a remarkable optimization. |
With GPKG data (issue data) edit command took the longest time (5-6ms). As I tested with PostGIS data with latencies (Toxiproxy is good tool for container latency simulation btw), requests took the longest time but by reducing those down to typically 1 per layer, the suggested change is still a big improvement. |
Core of the issue is not necessarily the absolute amount of layers etc. but the total UX when considering latency etc. and the issue would appear at much lower layer counts in some cases. Its much easier for the user to keep all layers editable when doing topological stuff, since that would be worse to miss the topological points on a shared segment of 3 features, if there was for example 1 of those 3 layers on that shared segment in a not editable state? And when you have like even 20-50 layers editable, the issue starts to appear, but its a perfectly valid use case for now, since there is no easy way to on demand toggle editability of a group of layers you want to make topological edits to and also ensuring all the layers for example on a shared segment are actually editable when making the change. |
For vertex tool this change would increase the amount of feature requests made only by the amount of layers actually intersected with the vertex: for layers not intersected only the initial request is made, and for layers intersected For 100 layers with 5 intersected by the vertex what is now 100 feature requests becomes 105. Of course for 3 editable and 3 intersected its 6 now, but maybe that is not an issue for now and can be optimized separately to become 3 again? For add feature tool this would reduce the amount of feature requests made by (the amount of layers not intersected * (new feature vertices - 1)), and increase by the amount of layers intersected: for layers not intersected only the initial request is made but looping each vertex is skipped, and for layers intersected the logic stays as is with the added initial request. There could be further improvement to the (currently convinience) methods accepting QgsGeometry or QgsPointSequence to do a single feature request with all the vertices or also make use of the initial feature request as well to reduce it as well to the total layer count? For 100 layers with 5 intersected by a new feature with 100 vertices what is now 10000 feature requests would become 595, and similarly 20/5/1000 would change from 20000 to 5015. Like above, worst case with point feature intersecting all layers it would be doubled for now. Maybe there is one downside: bringing the layer precision & topological point search distance logic to this code as well, since it seems asimilarly buffered search on the initial request might be needed? Maybe that could be a separate method in edit utils, for example |
If we decide to go that way (filter out layer for which geometry doesn't intersect at all adding an extra request before calling addTopologicalPoint(Point) ) it should be done in addTopologicalPoints(QgsPointSequence/QgsGeometry) as a matter of consistency for all map tool. I think that it would have been way better to use snapping cache QgsPointLocator that could have give you this information really fast without accessing data. I'm not a big fan on adding extra request but if it can spares a lot more, that's maybe worthy What do you think @uclaros ? |
I did some benchmark testing with two different datasets that are available here as download. I hope this clarifies the issue we are having and how this improvement (filter before edit command) improves it. There is most likely a better solution that will turn both tools much more performant, but this change is lightweight enough to be backported and still provides good performance benefit. Datasets:
Feature being digitized is a line with 4 vertex. It does not intersect with other features.
I will also add this threshold growing asap as an private method for both tools with |
The total amount is correct, but it is called more often than actually needed. I mean on each click we immediately add the points while we could be collecting the clicks and do the call once at the end (on rightclick, esc etc).
Wouldn't this require snapping to be enabled for the candidate layer? We want this to work even when snapping is altogether disabled and users are adding specific coordinates using other means (cad dock widget, layer precision etc)
Me neither, requests can be very costly for remote connections.
Do you think that would make sense? |
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 tend to agree on the proposed approach. It adds an extra request but spares many more in most of the scenarios.
Like I said before, I would have prefer that we try to use snapping cache, but I'm still willing to merge as is (minus the review comments).
@uclaros Don't you see any reason not to ?
Yes, but we could use it when we have it and fallback when we don't. Or we could just build it as we need it.
Yes, I had something alike in mind when I was asking to move the actual logic inside addTopologicalPoints. @Joonalai Do you think it's doable? |
1848553
to
72c3004
Compare
It is doable at some point and it makes a perfect sense. However, as that would require a lot of changes in the code and would thus become impossible to backport, I must ask could this change be merged and backported as is and could the improved workflow then be added as an additional PR later on?
I understand that, but this change lowers the amount of requests in most cases as @komima explained. |
Changing the behaviour seems a bit more complex, and would probably be a feature, not a bugfix? Even then without other changes we would hit the same issue as with add-new-feature tool, where the current
Since the It seems moving the edit command logic is a much much larger task and it would affect all the locations where |
I agree that modifying addTopologicalPoints the way you propose @uclaros would require to modify all the callee to, at least, remove the begin/EndEditCommand. I'm also concerned of plugins that could also use addTopologicalPoints and doesn't expect it to call begin/EndEditCommand. It's maybe not that bad, but it would change their command stack. It seems to me that the proposed approach is less prone to generate new issues and would improve things for 3.40 while we try to improve it even more later on. |
@troopa81 is there anything I could do to help this get merged? |
72c3004
to
5cc1d16
Compare
Could a backport label be added for automated backport PR after merge? |
Done |
OK, let's merge this as workaround then! |
Description
This PR fixes #60124 by:
Backport needed for 3.40.