[postgis-tickets] [SCM] PostGIS branch stable-3.1 updated. 3.1.9-16-ga4fbfec9d

git at osgeo.org git at osgeo.org
Tue Oct 10 03:10:09 PDT 2023


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, stable-3.1 has been updated
       via  a4fbfec9d507925e14add9e86c79a438c59aa2c1 (commit)
       via  dab8a55aecec70dfe5e94956ee66c313819079a9 (commit)
      from  04ec7aee9a3425b70e9da91f4cb6fd17511bf9a0 (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 a4fbfec9d507925e14add9e86c79a438c59aa2c1
Author: Sandro Santilli <strk at kbt.io>
Date:   Thu Sep 7 16:57:53 2023 +0200

    Normalize results from ST_DelaunayTriangles
    
    GEOS recent commit changed starting point of polygon rings
    ref: https://debbie.postgis.net/view/GEOS/job/GEOS_Master/1793/

diff --git a/regress/core/delaunaytriangles.sql b/regress/core/delaunaytriangles.sql
index 18589e05d..efc561029 100644
--- a/regress/core/delaunaytriangles.sql
+++ b/regress/core/delaunaytriangles.sql
@@ -1,12 +1,11 @@
--- TODO: normalize !
-SELECT 1,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9)'::geometry));
-SELECT 2,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry));
-SELECT 3,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2));
-SELECT 4,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2, 1));
-SELECT 5,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9)'::geometry, 0.0, 2));
-SELECT 6,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 0.0, 2));
-SELECT 7,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2.0, 2));
+SELECT 1,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9)'::geometry)));
+SELECT 2,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry)));
+SELECT 3,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2)));
+SELECT 4,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2, 1)));
+SELECT 5,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9)'::geometry, 0.0, 2)));
+SELECT 6,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 0.0, 2)));
+SELECT 7,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5, 6 0, 7 9, 8 9)'::geometry, 2.0, 2)));
 
 -- 3DZ
-SELECT 10,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5 3, 6 0 2, 7 9 1)'::geometry));
-SELECT 11,  ST_AsText(ST_DelaunayTriangles('MULTIPOINT(5 5 1, 6 0 2, 7 9 3)'::geometry, 0.0, 2));
+SELECT 10,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5 3, 6 0 2, 7 9 1)'::geometry)));
+SELECT 11,  ST_AsText(ST_Normalize(ST_DelaunayTriangles('MULTIPOINT(5 5 1, 6 0 2, 7 9 3)'::geometry, 0.0, 2)));
diff --git a/regress/core/delaunaytriangles_expected b/regress/core/delaunaytriangles_expected
index d3ab102bc..5b61b195c 100644
--- a/regress/core/delaunaytriangles_expected
+++ b/regress/core/delaunaytriangles_expected
@@ -1,9 +1,9 @@
-1|GEOMETRYCOLLECTION(POLYGON((5 5,6 0,7 9,5 5)))
-2|GEOMETRYCOLLECTION(POLYGON((5 5,6 0,8 9,5 5)),POLYGON((5 5,8 9,7 9,5 5)))
-3|GEOMETRYCOLLECTION(POLYGON((5 5,6 0,7 9,5 5)))
-4|MULTILINESTRING((5 5,7 9),(5 5,6 0),(6 0,7 9))
-5|TIN(((5 5,6 0,7 9,5 5)))
-6|TIN(((5 5,6 0,8 9,5 5)),((5 5,8 9,7 9,5 5)))
-7|TIN(((5 5,6 0,7 9,5 5)))
-10|GEOMETRYCOLLECTION Z (POLYGON Z ((5 5 3,6 0 2,7 9 1,5 5 3)))
-11|TIN Z (((5 5 1,6 0 2,7 9 3,5 5 1)))
+1|GEOMETRYCOLLECTION(POLYGON((5 5,7 9,6 0,5 5)))
+2|GEOMETRYCOLLECTION(POLYGON((5 5,8 9,6 0,5 5)),POLYGON((5 5,7 9,8 9,5 5)))
+3|GEOMETRYCOLLECTION(POLYGON((5 5,7 9,6 0,5 5)))
+4|MULTILINESTRING((6 0,7 9),(5 5,7 9),(5 5,6 0))
+5|GEOMETRYCOLLECTION(POLYGON((5 5,7 9,6 0,5 5)))
+6|GEOMETRYCOLLECTION(POLYGON((5 5,8 9,6 0,5 5)),POLYGON((5 5,7 9,8 9,5 5)))
+7|GEOMETRYCOLLECTION(POLYGON((5 5,7 9,6 0,5 5)))
+10|GEOMETRYCOLLECTION Z (POLYGON Z ((5 5 3,7 9 1,6 0 2,5 5 3)))
+11|GEOMETRYCOLLECTION Z (POLYGON Z ((5 5 1,7 9 3,6 0 2,5 5 1)))

commit dab8a55aecec70dfe5e94956ee66c313819079a9
Author: Sandro Santilli <strk at kbt.io>
Date:   Mon Oct 9 12:09:38 2023 +0200

    Fix robustness issue in topology face split handling
    
    Stop using interpolation to find edges to update in _lwt_AddFaceSplit.
    
    Includes regress test.
    
    References #5568 in stable-3.1 branch (3.1.10dev)

diff --git a/NEWS b/NEWS
index 66b15dfd2..021e69017 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ PostGIS 3.1.10dev
 xxxx/xx/xx
 
 * Bug Fixes *
+  - #5568, Improve robustness of topology face split handling (Sandro Santilli)
   - #5494, Fix double-upgrade with view using st_dwithin(text, ...)
            (Sandro Santilli)
   - #5450, Fix macro expansion recursion on powerpc architectures
diff --git a/liblwgeom/lwgeom_topo.c b/liblwgeom/lwgeom_topo.c
index 2b7306522..8b3690554 100644
--- a/liblwgeom/lwgeom_topo.c
+++ b/liblwgeom/lwgeom_topo.c
@@ -1888,7 +1888,12 @@ _lwt_AddFaceSplit( LWT_TOPOLOGY* topo,
   LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " split face %" LWTFMT_ELEMID " (mbr_only:%d)",
            sedge, face, mbr_only);
 
-  /* Construct a polygon using edges of the ring */
+  /*
+   * Construct a polygon using edges of the ring
+   *
+   * NOTE: this possibily includes dangling edges
+   *
+   */
   LWPOLY *shell = _lwt_MakeRingShell(topo, signed_edge_ids,
                                      num_signed_edge_ids);
   if ( ! shell ) {
@@ -2035,7 +2040,7 @@ _lwt_AddFaceSplit( LWT_TOPOLOGY* topo,
 	  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
 	  return -2;
   }
-  LWDEBUGF(1, "lwt_be_getEdgeByFace returned %d edges", numfaceedges);
+  LWDEBUGF(1, "_lwt_AddFaceSplit: lwt_be_getEdgeByFace(%d) returned %d edges", face, numfaceedges);
 
   if ( numfaceedges )
   {
@@ -2052,70 +2057,68 @@ _lwt_AddFaceSplit( LWT_TOPOLOGY* topo,
       int contains;
       POINT2D ep;
 
-      /* (2.1) skip edges whose ID is in the list of boundary edges ? */
+      /* (2.1) skip edges whose ID is in the list of boundary edges */
       for ( j=0; j<num_signed_edge_ids; ++j )
       {
-        int seid = signed_edge_ids[j];
+        int seid = signed_edge_ids[j]; /* signed ring edge id */
         if ( seid == e->edge_id )
         {
-          /* IDEA: remove entry from signed_edge_ids ? */
-          LWDEBUGF(1, "Edge %d is a forward edge of the new ring", e->edge_id);
+          /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
+          LWDEBUGF(1, "Edge %d is a known forward edge of the new ring", e->edge_id);
           forward_edges[forward_edges_count].edge_id = e->edge_id;
           forward_edges[forward_edges_count++].face_left = newface.face_id;
           found++;
-          if ( found == 2 ) break;
+          if ( found == 2 ) break; /* both edge sides are found on the ring */
         }
         else if ( -seid == e->edge_id )
         {
-          /* IDEA: remove entry from signed_edge_ids ? */
-          LWDEBUGF(1, "Edge %d is a backward edge of the new ring", e->edge_id);
+          /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
+          LWDEBUGF(1, "Edge %d is a known backward edge of the new ring", e->edge_id);
           backward_edges[backward_edges_count].edge_id = e->edge_id;
           backward_edges[backward_edges_count++].face_right = newface.face_id;
           found++;
-          if ( found == 2 ) break;
+          if ( found == 2 ) break; /* both edge sides are found on the ring */
         }
       }
       if ( found ) continue;
+      LWDEBUGF(1, "Edge %d is not a known edge of the new ring", e->edge_id);
 
-      /* We need to check only a single point
-       * (to avoid collapsed elements of the shell polygon
-       * giving false positive).
-       * The point but must not be an endpoint.
-       */
-      if ( ! _lwt_GetInteriorEdgePoint(e->geom, &ep) )
+      /* Check if the edge is now binding a different face */
+
+      if ( ! getPoint2d_p(e->geom->points, 0, &ep) )
       {
         lwfree(signed_edge_ids);
         lwpoly_free(shell);
         lwfree(forward_edges); /* contents owned by edges */
         lwfree(backward_edges); /* contents owned by edges */
         _lwt_release_edges(edges, numfaceedges);
-        lwerror("Could not find interior point for edge %d: %s",
-                e->edge_id, lwgeom_geos_errmsg);
+        lwerror("Edge %d is empty", e->edge_id);
         return -2;
       }
 
       /* IDEA: check that bounding box shortcut is taken, or use
        *       shellbox to do it here */
-      contains = ptarray_contains_point(pa, &ep) == LW_INSIDE;
-      if ( contains == 2 )
-      LWDEBUGF(1, "Edge %d %scontained in new ring", e->edge_id,
-                  (contains?"":"not "));
+      contains = ptarray_contains_point(pa, &ep);
 
-      /* (2.2) skip edges (NOT, if newface_outside) contained in shell */
+      LWDEBUGF(1, "Edge %d first point %s new ring",
+          e->edge_id, (contains == LW_INSIDE ? "inside" :
+           contains == LW_OUTSIDE ? "outside" : "on boundary of"));
+
+      /* (2.2) skip edges (NOT, if newface_outside) contained in ring */
       if ( newface_outside )
       {
-        if ( contains )
+        if ( contains != LW_OUTSIDE )
         {
-          LWDEBUGF(1, "Edge %d contained in an hole of the new face",
+          LWDEBUGF(1, "Edge %d not outside of the new ring, not updating it",
                       e->edge_id);
           continue;
         }
       }
       else
       {
-        if ( ! contains )
+        if ( contains != LW_INSIDE )
         {
-          LWDEBUGF(1, "Edge %d not contained in the face shell",
+          LWDEBUGF(1, "Edge %d not inside the new ring, not updating it",
                       e->edge_id);
           continue;
         }
diff --git a/topology/test/regress/topogeo_addlinestring.sql b/topology/test/regress/topogeo_addlinestring.sql
index 1ee15ca63..8edf9a243 100644
--- a/topology/test/regress/topogeo_addlinestring.sql
+++ b/topology/test/regress/topogeo_addlinestring.sql
@@ -467,3 +467,15 @@ SELECT 'b5234.1', count(*) FROM
 TopoGeo_addLinestring('b5234',
   'LINESTRING(10 10 3, 5 0 0.8)', 0);
 ROLLBACK;
+
+-- See https://trac.osgeo.org/postgis/ticket/5568
+BEGIN;
+SELECT NULL FROM topology.CreateTopology ('t5568');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5568','0102000000030000007A6873CA73782440DE38B01D9CEE4D40438AD46B73782440FEAF5D499CEE4D40588FC2F528782440106D5B2FB5EE4D40');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5568','010200000002000000588FC2F528782440106D5B2FB5EE4D4089058AA63E7824401D9FCAB6B0EE4D40');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5568','01020000000300000089058AA63E7824401D9FCAB6B0EE4D4040A8CCBF35782440B80E7F8CB2EE4D40588FC2F528782440106D5B2FB5EE4D40');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5568','01020000000200000089058AA63E7824401D9FCAB6B0EE4D4084CBFA5C7A7824405CC705259CEE4D40');
+SELECT 't5568', 'invalidities at start', array_agg((v)) FROM validatetopology('t5568') v;
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5568','01020000000200000084CBFA5C7A7824405CC705259CEE4D407A6873CA73782440DE38B01D9CEE4D40');
+SELECT 't5568', 'invalidities at end', array_agg(error) FROM validatetopology('t5568') v;
+ROLLBACK;
diff --git a/topology/test/regress/topogeo_addlinestring_expected b/topology/test/regress/topogeo_addlinestring_expected
index 6b68149d9..973aaf35c 100644
--- a/topology/test/regress/topogeo_addlinestring_expected
+++ b/topology/test/regress/topogeo_addlinestring_expected
@@ -222,3 +222,5 @@ b4941|inner_ring|1
 b4941|crossing_line|5
 b5234.0|1
 b5234.1|1
+t5568|invalidities at start|
+t5568|invalidities at end|

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

Summary of changes:
 NEWS                                               |  1 +
 liblwgeom/lwgeom_topo.c                            | 57 ++++++++++++----------
 regress/core/delaunaytriangles.sql                 | 19 ++++----
 regress/core/delaunaytriangles_expected            | 18 +++----
 topology/test/regress/topogeo_addlinestring.sql    | 12 +++++
 .../test/regress/topogeo_addlinestring_expected    |  2 +
 6 files changed, 63 insertions(+), 46 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list