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

Rubberband/digitizing not working correctly with snapping after database trigger has normalized polygon with inner ring during saving #57181

Closed
2 tasks done
rnousia opened this issue Apr 18, 2024 · 5 comments
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Digitizing Related to feature digitizing map tools or functionality

Comments

@rnousia
Copy link

rnousia commented Apr 18, 2024

What is the bug or the crash?

If a polygon with inner ring is changed in the database with trigger after saving edits (e.g. due to normalization of polygon), rubberband snaps to old vertices and not to the updated ones if the inner ring is used as snapping target. This looks very confusing to the user although in some cases the actual snapping seems to work (maybe if the digitized ring was symmetrical?) and resulting feature is created as digitized.

The problem occurs only with inner rings and only if digitizing + saving is done in a specific order. So it is quite difficult to reproduce but at least the steps in the following section describe one case where this issue occurs.

snapping-issue
Here the digitized ring also seems to be incorrect (not the using the vertices snapped).

Steps to reproduce the issue

  1. Create tables with trigger that normalizes geometry before insert or update (tested with postgis database):
-- create trigger function to normalize polygons
CREATE OR REPLACE FUNCTION public.normalize_geom()
RETURNS trigger AS $$
BEGIN
  NEW.geom = ST_Normalize(NEW.geom);
  RETURN NEW;
END; $$ LANGUAGE 'plpgsql';

-- create test tables
CREATE TABLE normalized_polygons_1
(
    id bigserial NOT NULL,
    geom geometry(POLYGON, 3067),
    CONSTRAINT "PK_normalized_polygons_1" PRIMARY KEY (id)
);

CREATE TABLE normalized_polygons_2
(
    id bigserial NOT NULL,
    geom geometry(POLYGON, 3067),
    CONSTRAINT "PK_normalized_polygons_2" PRIMARY KEY (id)
);

-- create triggers
CREATE TRIGGER normalize_geom
BEFORE INSERT OR UPDATE ON normalized_polygons_1
FOR EACH ROW EXECUTE PROCEDURE public.normalize_geom();

CREATE TRIGGER normalize_geom
BEFORE INSERT OR UPDATE ON normalized_polygons_2
FOR EACH ROW EXECUTE PROCEDURE public.normalize_geom();
  1. Add layers to QGIS and digitize a polygon to both layers that are overlapping each other, like so:
initial-polygons
  1. Save edits on all layers (this is important step as the issue only happens if layer is saved before adding the inner ring)
  2. Add a ring to one of the layers and save edits (again, saving must be done at this step, otherwise everything works correctly in next step)
  3. Start adding ring to the other layer with vertex snapping on -> digitized rubberband is drawn to wrong vertices

I couldn't figure any way to reset this behaviour once it starts happening. Also, as mentioned in the steps, this only occurs if edits are saved after each step and layer is not changed before saving the first ring creation.

Versions

<style type="text/css"> p, li { white-space: pre-wrap; } </style>
QGIS version 3.36.1-Maidenhead QGIS code revision 3e58945
Qt version 5.15.13
Python version 3.12.3
GDAL/OGR version 3.8.5
PROJ version 9.4.0
EPSG Registry database version v11.004 (2024-02-24)
GEOS version 3.12.1-CAPI-1.18.1
SQLite version 3.45.1
PDAL version 2.6.3
PostgreSQL client version 16.2
SpatiaLite version 5.1.0
QWT version 6.2.0
QScintilla2 version 2.14.1
OS version Windows 10 Version 2009
       
Active Python plugins
db_manager 0.1.20
grassprovider 2.12.99
MetaSearch 0.3.6
processing 2.12.99
QGIS version 3.36.1-Maidenhead QGIS code revision [3e58945](https://github.com/qgis/QGIS/commit/3e589453) Qt version 5.15.13 Python version 3.12.3 GDAL/OGR version 3.8.5 PROJ version 9.4.0 EPSG Registry database version v11.004 (2024-02-24) GEOS version 3.12.1-CAPI-1.18.1 SQLite version 3.45.1 PDAL version 2.6.3 PostgreSQL client version 16.2 SpatiaLite version 5.1.0 QWT version 6.2.0 QScintilla2 version 2.14.1 OS version Windows 10 Version 2009

Active Python plugins
db_manager
0.1.20
grassprovider
2.12.99
MetaSearch
0.3.6
processing
2.12.99

Supported QGIS version

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

New profile

Additional context

No response

@rnousia rnousia added the Bug Either a bug report, or a bug fix. Let's hope for the latter! label Apr 18, 2024
@Joonalai
Copy link
Contributor

The bug exists on 3.34.3-Prizren as well.

@agiudiceandrea agiudiceandrea added the Digitizing Related to feature digitizing map tools or functionality label Jun 18, 2024
@uclaros
Copy link
Contributor

uclaros commented Jun 19, 2024

Is this also a #31251 duplicate?

@Djedouas
Copy link
Member

Reproduced on master 623ceab11d8

With a more simple test case, on one polygon only:

qgis_issue_57181-2024-07-29_17.08.32_srt.mp4

It seems to be related to how the vertices order is not updated in the cache, when saving after a modification action, but it is updated when saving after digitizing a new feature.

This vertex confusion stays even after digitizing other features.

A refresh via the toolbar image reorders everything.

I will investigate further into the code.

@Djedouas
Copy link
Member

After some investigations, we are on a case where QGIS can't be aware of underlying data change.

💾 When the "save layer" button is pushed, the trigger normalize_geom() changes the feature geometry, and QGIS has no clue about this, but the snapping geometry index is invalidated (as well as the independent vertex tool geometry cache).

🧠 This explains why everything works fine when not saving the layer and doing all the digitizing steps: the geometry is always in a state that QGIS knows about.

🤔 "But... the label with the geometry WKT is up-to-date right after saving, so... surly somewhere QGIS does know that the geometry has changed?"

Well... the label expression directly queries the data provider (PostgreSQL) after the save action (because of refreshing the canvas after saving a layer).
PostgreSQL will always give the expression the up-to-date WKT. But no way to know if the WKT has changed recently, in fact.

📡 Right. What now? We have a solution! Let's use PostgreSQL notification signal! With

NOTIFY qgis;

SQL statement, that we will add in our trigger that becomes

-- create trigger function to normalize polygons
CREATE OR REPLACE FUNCTION public.normalize_geom()
RETURNS trigger AS $$
BEGIN
  NEW.geom = ST_Normalize(NEW.geom);
  NOTIFY qgis;  -- tell QGIS layers listening to the notification to refresh!
  RETURN NEW;
END; $$ LANGUAGE 'plpgsql';

And configure our layers to listen to the provider notifications in the Rendering properties:

image

✅ This configuration fixes the vertex tool geometry cache and snapping index being wrong.

⚠️ The notification triggers the emission of QgsMapLayer::dataChanged() signal which completely clears the cache and index, which will be rebuilt. There is no way currently to say "only refresh the feature I was just modifying". Changing geometry under the hood by a database trigger could impact any feature.

NB: the notification can include a message: NOTIFY, 'my great message'; which can be specifically listened by the layer (for instance, to have one different signal for each layer/trigger).

image

@Djedouas
Copy link
Member

Another solution is to check the layer itself in Dependencies section of the layer properties.

In this way, every change on the layer will trigger a full refresh of the data, caches, and rubber bands.

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! Digitizing Related to feature digitizing map tools or functionality
Projects
None yet
Development

No branches or pull requests

5 participants