Skip to content
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

Vertex tool and snapping stop working when layers are removed and added to the project multiple times #59530

Open
2 tasks done
Joonalai opened this issue Nov 20, 2024 · 0 comments
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter!

Comments

@Joonalai
Copy link
Contributor

Joonalai commented Nov 20, 2024

What is the bug or the crash?

Snapping and vertex tool stop working when layers are removed and added again back to the project. Sometimes this happens after the first time and sometimes after numerous times. Only way to recover from this is to restart QGIS.

snapping_stops_working

Steps to reproduce the issue

It was incredibly difficult to reproduce the bug reliably but finally after hours of trying I managed to do that with a little bit of scripting. I prepared a snapping.zip that includes snapping.gpkg with two layers and python script snapping.py with this content:

from pathlib import Path
from typing import cast

from qgis.core import (
    Qgis,
    QgsPointXY,
    QgsProject,
    QgsSnappingConfig,
    QgsSnappingUtils,
    QgsVectorLayer,
)
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import QCoreApplication
from qgis.utils import iface as utils_iface

GPKG_PATH = Path(__file__).parent / "snapping.gpkg"

LAYER_NAMES = ["area1", "area2"]

SHAPES = ["Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))", "Polygon ((2 0, 3 0, 3 1, 2 1, 2 0))"]


iface = cast(QgisInterface, utils_iface)


def set_snapping_mode_to_all_layers():
    snapping_config = QgsSnappingConfig(QgsProject.instance().snappingConfig())
    snapping_config.setMode(Qgis.SnappingMode.AllLayers)
    snapping_config.setEnabled(True)
    QgsProject.instance().setSnappingConfig(snapping_config)


def check_if_location_snapping_is_working_for_layers() -> bool:
    for layer in QgsProject.instance().mapLayers().values():
        works = _check_if_location_snapping_is_working_for_layer(layer)
        if not works:
            return False
    return True


def snapping_still_works() -> bool:
    """
    For users to be able to observe the bug,
    the snapping should not be working initially
    """
    if not check_if_location_snapping_is_working_for_layers():
        layer = next(
            layer.name()
            for layer in QgsProject.instance().mapLayers().values()
            if layer.isEditable()
        )
        print(f"Snapping is not working for {layer}")
        return False

    for i in range(100):
        print(f"Sub-iteration {i}")
        _add_layers()
        if not check_if_location_snapping_is_working_for_layers():
            return True
        _remove_layers()
        _process_events()

    return True


def _check_if_location_snapping_is_working_for_layer(layer: QgsVectorLayer) -> bool:
    layer.startEditing()
    iface.setActiveLayer(layer)
    geom = next(iter(layer.getFeatures())).geometry()
    vertex = next(iter(geom.vertices()))
    utils: QgsSnappingUtils = iface.mapCanvas().snappingUtils()
    utils.setMapSettings(iface.mapCanvas().snappingUtils().mapSettings())
    utils.setCurrentLayer(layer)

    point = QgsPointXY(vertex.x(), vertex.y())
    match = utils.snapToMap(point, relaxed=False)
    if not match.isValid():
        # Leave the layer in edit mode to make it easy to observe manually
        return False
    layer.rollBack()
    return True


def _add_layers():
    for layer_name in LAYER_NAMES:
        layer = QgsVectorLayer(
            f"{GPKG_PATH!s}|layername={layer_name}", layer_name, "ogr"
        )
        QgsProject.instance().addMapLayer(layer)


def _remove_layers():
    QgsProject.instance().removeAllMapLayers()


def _process_events():
    QCoreApplication.processEvents()


def test_reproduce_snapping_bug():
    set_snapping_mode_to_all_layers()
    for i in range(20):
        print(f"Iteration {i}")
        snapping_working = snapping_still_works()
        if not snapping_working:
            return
        _process_events()
    print("Could not reproduce the bug...")
  1. Download and extract snapping.zip
  2. Open QGIS
  3. Open and run snapping.py in QGIS Python console
  4. Run test_reproduce_snapping_bug() in python console
  5. Observe how snapping nor vertex tool are no longer working with the layer mentioned in the console

I sincerely ask not to put a "Python Console" label in this issue since this is merely a way to reproduce the bug reliably.

Versions

QGIS version3.40.0-Bratislava
QGIS code branchRelease 3.40
 
Libraries
Qt version5.15.15
Python version3.12.7
GDAL/OGR version3.10.0
PROJ version9.5.0
EPSG Registry database versionv11.016 (2024-08-31)
GEOS version3.12.2-CAPI-1.18.2 (Compiled)
3.13.0-CAPI-1.19.0 (Running)
SQLite version3.46.1
PDAL version2.8.0
PostgreSQL client version16.3
SpatiaLite version5.1.0
QWT version6.3.0
QScintilla2 version2.14.1
OS versionEndeavourOS
 
Active Python plugins
db_manager0.1.20
MetaSearch0.3.6
processing2.12.99
grassprovider2.12.99

And also with 3.41.0-Master

Supported QGIS version

  • I'm running a supported QGIS version according to the roadmap.

New profile

Additional context

I tested with QGIS debugging and it seems that the bug lies in this line:

mRTree->intersectsWithQuery( rect2region( rect ), visitor );
For some reason when the snapping is halted, it never goes here
void visitData( const IData &d ) override
and thus the match is never valid.

@Joonalai Joonalai added the Bug Either a bug report, or a bug fix. Let's hope for the latter! label Nov 20, 2024
@Joonalai Joonalai changed the title Snapping stops working when layers are removed and added to the project multiple times Vertex tool and snapping stop working when layers are removed and added to the project multiple times Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter!
Projects
None yet
Development

No branches or pull requests

1 participant