[postgis-tickets] [SCM] PostGIS branch main updated. 3.1.0rc1-285-g8b0ecf6

git at osgeo.org git at osgeo.org
Thu Jul 8 04:15:03 PDT 2021


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, main has been updated
       via  8b0ecf66da15b39093f36b6be84b5f84817d5bac (commit)
      from  cde6f3d524dcbcd7e30c53bed8949c5ddde8dc7a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8b0ecf66da15b39093f36b6be84b5f84817d5bac
Author: Sandro Santilli <strk at kbt.io>
Date:   Wed Jul 7 18:02:49 2021 +0200

    Implement side labeling check in ValidateTopology
    
    Closes #4944
    Includes regress test catching new error (swapped side-labels)
    Updates test expectances as we're now getting more errors.

diff --git a/NEWS b/NEWS
index b199ead..e15db67 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ PostGIS 3.2.0
   - #4933, topology.GetFaceByPoint will not work with topologies having invalid edge linking.
 
  * Enhancements *
+  - #4944, Side-location conflict check in ValidateTopology (Sandro Santilli)
   - #3042, ValidateTopology check for edge linking (Sandro Santilli)
   - #3276, ValidateTopology check for face's mbr (Sandro Santilli)
   - #4936, Bounding box limited ValidateTopology (Sandro Santilli)
diff --git a/topology/sql/manage/ValidateTopology.sql.in b/topology/sql/manage/ValidateTopology.sql.in
index e22eff1..375cd29 100644
--- a/topology/sql/manage/ValidateTopology.sql.in
+++ b/topology/sql/manage/ValidateTopology.sql.in
@@ -62,6 +62,166 @@ END;
 $BODY$
 LANGUAGE 'plpgsql' IMMUTABLE STRICT;
 
+-- NOTE: assumes search_path was set before calling this function
+CREATE OR REPLACE FUNCTION topology._ValidateTopologySideLabeling(bbox geometry DEFAULT NULL)
+RETURNS SETOF topology.ValidateTopology_ReturnType
+AS --{
+$BODY$
+DECLARE
+  retrec topology.ValidateTopology_ReturnType;
+  nextEdge INT;
+  rec RECORD;
+  affected_rows integer;
+BEGIN
+  RAISE DEBUG 'Gathering edges for side faces labeling';
+
+  -- NOTE: this check relies on correct edge linking,
+  --       if those are not correct the results
+  --       of this check do not make much sense.
+
+  -- Pick all edges ending on any node in the bbox
+  -- Those are the only edges we want to consider
+  CREATE TEMP TABLE side_label_check_edge AS
+  WITH edges_to_check AS (
+    SELECT DISTINCT e.edge_id
+    FROM edge_data e, node n
+    WHERE (
+      bbox IS NULL
+      OR n.geom && bbox
+    )
+    AND (
+      e.start_node = n.node_id
+      OR e.end_node = n.node_id
+    )
+  )
+  SELECT edge_id FROM edges_to_check
+    UNION
+  SELECT -edge_id FROM edges_to_check
+  ;
+
+  CREATE INDEX ON side_label_check_edge (edge_id); -- DROP ?
+
+  RAISE DEBUG 'Checking edge side faces labeling';
+
+  -- Find all rings that can be formed on both sides
+  -- of selected edges
+  affected_rows := 0;
+  LOOP --{
+    -- Fetch next unvisited edge
+    SELECT edge_id
+    FROM pg_temp.side_label_check_edge
+    LIMIT 1
+    INTO nextEdge;
+
+    IF nextEdge IS NULL THEN
+      EXIT; -- exit loop if no more unvisited edges found
+    END IF;
+
+    affected_rows := affected_rows + 1;
+
+    -- Gather side faces for the ring formed on nextEdge
+    -- NOTE: if edge linking is bogus the following query
+    --       won't make much sense
+    BEGIN
+
+      WITH RECURSIVE
+      edgering AS (
+        SELECT
+          nextEdge as signed_edge_id,
+          edge_id,
+          next_left_edge,
+          next_right_edge,
+          CASE WHEN nextEdge > 0 THEN
+            left_face
+          ELSE
+            right_face
+          END as side_face
+        FROM edge_data
+        WHERE edge_id = abs(nextEdge)
+          UNION
+        SELECT
+          CASE WHEN p.signed_edge_id < 0
+          THEN
+            p.next_right_edge
+          ELSE
+            p.next_left_edge
+          END, -- signed_edge_id
+          e.edge_id,
+          e.next_left_edge,
+          e.next_right_edge,
+          CASE WHEN p.signed_edge_id < 0
+          THEN
+            CASE WHEN p.next_right_edge > 0
+            THEN
+              e.left_face
+            ELSE
+              e.right_face
+            END
+          ELSE
+            CASE WHEN p.next_left_edge > 0
+            THEN
+              e.left_face
+            ELSE
+              e.right_face
+            END
+          END -- side_face
+        FROM edge_data e, edgering p
+        WHERE
+          e.edge_id = CASE
+            WHEN p.signed_edge_id < 0 THEN
+              abs(p.next_right_edge)
+            ELSE
+              abs(p.next_left_edge)
+            END
+      )
+      SELECT
+        array_agg(signed_edge_id) edges,
+        array_agg(DISTINCT side_face) side_faces
+      FROM edgering
+      INTO rec;
+
+      RAISE DEBUG 'Ring % - edges:[%], faces:[%]',
+        nextEdge,
+        array_to_string(rec.edges, ','),
+        array_to_string(rec.side_faces, ',')
+      ;
+
+      -- Check that there's a single face advertised
+      IF array_upper(rec.side_faces,1) != 1
+      THEN
+        RAISE DEBUG 'Side faces found on ring %: %', nextEdge, rec.side_faces;
+        retrec.error = 'Edgering side location conflict';
+        retrec.id1 = nextEdge;
+        retrec.id2 = NULL;
+        RETURN NEXT retrec;
+      END IF;
+    EXCEPTION WHEN OTHERS THEN
+        retrec.error = SQLERRM;
+        retrec.id1 = nextEdge;
+        retrec.id2 = NULL;
+        RETURN NEXT retrec;
+        -- Make sure this edge will be marked as visited
+        SELECT ARRAY[nextEdge] as edges INTO rec;
+    END;
+
+    -- TODO: Check that a single face is ever used
+    --       for each distinct CCW ring (shell)
+    -- NOTE: multiple CW rings (holes) can exist for a given face
+
+    DELETE FROM pg_temp.side_label_check_edge
+    WHERE edge_id = ANY (rec.edges);
+
+  END LOOP; --}
+
+  RAISE DEBUG 'Completed checking % rings for side faces labeling', affected_rows;
+
+  DROP TABLE pg_temp.side_label_check_edge;
+
+
+END;
+$BODY$ --}
+LANGUAGE 'plpgsql' VOLATILE;
+
 --{
 --  ValidateTopology(toponame, [bbox])
 --
@@ -364,7 +524,7 @@ BEGIN
   -- NOTE: this check relies on correct start_node and end_node
   --       for edges, if those are not correct the results
   --       of this check do not make much sense.
-  FOR rec IN
+  FOR rec IN --{
       WITH
       nodes AS (
         SELECT node_id
@@ -415,7 +575,7 @@ BEGIN
       )
       SELECT * FROM sequenced_edge_star
       ORDER BY node_id, seq
-  LOOP --{
+  LOOP --}{
     IF last_node_id IS NULL OR last_node_id != rec.node_id
     THEN --{
       IF last_node_id IS NOT NULL
@@ -436,7 +596,7 @@ BEGIN
       --RAISE DEBUG 'Analyzing edge star around node %', rec.node_id;
       last_node_id = rec.node_id;
       last_node_first_edge = rec;
-    ELSE --{
+    ELSE --}{
       -- Check that this edge (CW from last one) is correctly linked
       retrec := topology._CheckEdgeLinking(
         rec.edge_id,
@@ -451,7 +611,7 @@ BEGIN
     END IF; --}
     last_node_prev_edge = rec;
   END LOOP; --}
-  IF last_node_id IS NOT NULL THEN
+  IF last_node_id IS NOT NULL THEN --{
     --RAISE DEBUG 'Out of loop: last_node_id: %', last_node_id;
     --RAISE DEBUG 'Out of loop: last_node_first_edge edge_id:% next_left_edge:%', last_node_first_edge.edge_id, last_node_first_edge.next_left_edge;
     --RAISE DEBUG 'Out of loop: last_node_prev_edge edge_id:% next_left_edge:%', last_node_prev_edge.edge_id, last_node_prev_edge.next_left_edge;
@@ -468,8 +628,13 @@ BEGIN
       RETURN NEXT retrec;
     END IF;
     --RAISE DEBUG 'Finished analisys of edge star around node % (out of loop)', last_node_id;
-  END IF;
+  END IF; --}
+
+  --- Edge side-labeling check -------------------------------------------{
+
+  RETURN QUERY SELECT * FROM topology._ValidateTopologySideLabeling(bbox);
 
+  --- Edge side-labeling check -------------------------------------------}
 
 
   -- Now create a temporary table to construct all face geometries
diff --git a/topology/test/regress/legacy_invalid_expected b/topology/test/regress/legacy_invalid_expected
index c1e3b5c..d4431b3 100644
--- a/topology/test/regress/legacy_invalid_expected
+++ b/topology/test/regress/legacy_invalid_expected
@@ -1,4 +1,10 @@
 t
+Edgering side location conflict|-33|
+Edgering side location conflict|-32|
+Edgering side location conflict|-29|
+Edgering side location conflict|29|
+Edgering side location conflict|32|
+Edgering side location conflict|33|
 coincident nodes|1|23
 edge crosses edge|2|28
 edge crosses edge|2|29
diff --git a/topology/test/regress/validatetopology.sql b/topology/test/regress/validatetopology.sql
index 33a8b27..cfccf39 100644
--- a/topology/test/regress/validatetopology.sql
+++ b/topology/test/regress/validatetopology.sql
@@ -118,11 +118,16 @@ SELECT '#4830.5', '---', null, null ORDER BY 1,2,3,4;
 ROLLBACK;
 SELECT null from ( select topology.DropTopology('t') ) as dt;
 
+-------------------------------------------------------------
+-- Following tests will use the city_data topology as a base
+-------------------------------------------------------------
+
+\i ../load_topology.sql
+SELECT 'unexpected_city_data_invalidities', * FROM ValidateTopology('city_data');
+
 -- Test correctness of edge linking
 -- See https://trac.osgeo.org/postgis/ticket/3042
-\i ../load_topology.sql
 --set client_min_messages to NOTICE;
-SELECT '#3042.0', * FROM ValidateTopology('city_data');
 BEGIN;
 -- Break edge linking for all edges around node 14
 UPDATE city_data.edge_data SET next_left_edge = -next_left_edge where edge_id in (9,10,20);
@@ -136,5 +141,17 @@ where edge_id in (3,25);
 set client_min_messages to WARNING;
 SELECT '#3042.1', * FROM ValidateTopology('city_data');
 ROLLBACK;
+
+-- Test correctness of side-labeling
+-- See https://trac.osgeo.org/postgis/ticket/4944
+BEGIN;
+-- Swap side-label of face-binding edge
+UPDATE city_data.edge_data
+  SET left_face = right_face, right_face = left_face
+  WHERE edge_id = 19;
+--set client_min_messages to DEBUG;
+SELECT '#4944', * FROM ValidateTopology('city_data');
+ROLLBACK;
+
 SELECT NULL FROM topology.DropTopology('city_data');
 
diff --git a/topology/test/regress/validatetopology_expected b/topology/test/regress/validatetopology_expected
index b164c91..7c7e792 100644
--- a/topology/test/regress/validatetopology_expected
+++ b/topology/test/regress/validatetopology_expected
@@ -9,15 +9,19 @@
 #3233.3|not-isolated node has not-null containing_face|1|
 #4830.0|---||
 #4830.1|---||
+#4830.1|Edgering side location conflict|3|
 #4830.1|edge not covered by both its side faces|4|
 #4830.1|edge not covered by both its side faces|6|
 #4830.2|---||
+#4830.2|Edgering side location conflict|3|
 #4830.2|edge not covered by both its side faces|4|
 #4830.2|edge not covered by both its side faces|6|
 #4830.3|---||
+#4830.3|Edgering side location conflict|-7|
 #4830.3|edge not covered by both its side faces|7|
 #4830.3|edge not covered by both its side faces|8|
 #4830.4|---||
+#4830.4|Edgering side location conflict|-7|
 #4830.4|edge not covered by both its side faces|7|
 #4830.4|edge not covered by both its side faces|8|
 #4830.5|---||
@@ -30,3 +34,13 @@
 #3042.1|invalid next_left_edge|9|19
 #3042.1|invalid next_right_edge|25|25
 #3042.1|invalid next_left_edge|25|-25
+#3042.1|Edgering side location conflict|19|
+#3042.1|Edgering side location conflict|13|
+#3042.1|Edgering side location conflict|-22|
+#3042.1|Edgering side location conflict|-7|
+#3042.1|Edgering side location conflict|-10|
+#3042.1|Edgering side location conflict|-3|
+#3042.1|Edgering side location conflict|-9|
+#3042.1|Edgering side location conflict|-20|
+#4944|Edgering side location conflict|19|
+#4944|Edgering side location conflict|-19|

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                            |   1 +
 topology/sql/manage/ValidateTopology.sql.in     | 175 +++++++++++++++++++++++-
 topology/test/regress/legacy_invalid_expected   |   6 +
 topology/test/regress/validatetopology.sql      |  21 ++-
 topology/test/regress/validatetopology_expected |  14 ++
 5 files changed, 210 insertions(+), 7 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list