[SCM] PostGIS branch stable-3.5 updated. 3.5.7-72-g6b351402e

git at osgeo.org git at osgeo.org
Sun Jul 19 23:40:00 PDT 2026


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.5 has been updated
       via  6b351402efd21a4cd1d3a9bb4da4caf51fe1f513 (commit)
       via  d235845e1989cf35880c210b059187bb3ef138d3 (commit)
      from  9bbeb5ea1f3ea72436d7a58b9cca0a13cbc90414 (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 6b351402efd21a4cd1d3a9bb4da4caf51fe1f513
Merge: 9bbeb5ea1 d235845e1
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Sun Jul 19 23:39:59 2026 -0700

    Merge pull request 'Fix GEOS 3.15 topology overlay junctions on stable 3.5' (!465) from Komzpa/postgis:fix/stable-3.5-geos315-topology-tests-clean into stable-3.5
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/465


commit d235845e1989cf35880c210b059187bb3ef138d3
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Thu Jul 9 11:33:15 2026 +0400

    Preserve topology overlay junctions under GEOS >= 3.15 line merging
    
    GEOS >= 3.15 returns overlay output line-merged, hiding the junctions
    between the shared and non-shared linework of a new line inside line
    interiors. Collect the crossing points and the mod-2 boundary of the
    shared linework from the intersection, and re-split the noded line at
    them: a no-op with older GEOS, which keeps them as component
    boundaries.
    
    Assert edge count instead of edge ids in the snap regression: the
    final topology is identical but edge id assignment depends on GEOS
    overlay output ordering.
    
    References https://github.com/postgis/postgis/pull/1160
    
    (cherry picked from commit ca3323d8c748dd806bab188028bb61c5f67b39af)
    (cherry picked from commit e730f39eb3349660105033dfedb95605c9cbe604)

diff --git a/NEWS b/NEWS
index 1951d6be2..6515cabf0 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ PostGIS 3.5.8
     ring-orientation precision regressions (Darafei Praliaskouski)
   - GH-1146, Reset interrupt callbacks when PostgreSQL clears
     cancellation state (Darafei Praliaskouski)
+  - GH-1160, [topology] Preserve overlay intersection boundaries when
+    noding lines with GEOS main (Darafei Praliaskouski)
 
 PostGIS 3.5.7
 2026/06/10
diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index 65574f346..ba358fee7 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -7127,6 +7127,57 @@ _lwt_split_by_nodes(const LWGEOM *g, const LWGEOM *nodes)
   return bg;
 }
 
+/*
+ * Compute the junction points between the overlay intersection linework
+ * (shared paths and crossings between the noded line and nearby edges)
+ * and the rest of the noded line: the 0-dimensional intersection
+ * components plus the mod-2 boundary of the 1-dimensional ones.
+ *
+ * These junctions must become topology nodes. GEOS >= 3.15 returns
+ * overlay output line-merged, which would otherwise hide them inside
+ * line interiors. Older GEOS keeps them as boundaries of the overlay
+ * output components, making a split at them a no-op.
+ *
+ * Returns a MULTIPOINT.
+ */
+static LWGEOM *
+_lwt_overlay_split_points(const LWGEOM *xset)
+{
+  LWGEOM *multi = lwgeom_as_multi(xset);
+  LWCOLLECTION *xcol = lwgeom_as_lwcollection(multi);
+  LWCOLLECTION *epoints = lwcollection_extract(xcol, POINTTYPE);
+  LWCOLLECTION *points = lwcollection_construct_empty(MULTIPOINTTYPE, xset->srid,
+    FLAGS_GET_Z(xset->flags), FLAGS_GET_M(xset->flags));
+  LWCOLLECTION *lines = lwcollection_extract(xcol, LINETYPE);
+  LWGEOM *bnd = lwgeom_boundary(lwcollection_as_lwgeom(lines));
+  uint32_t i;
+
+  for (i = 0; i < epoints->ngeoms; i++)
+    lwcollection_add_lwgeom(points, lwgeom_clone_deep(epoints->geoms[i]));
+
+  if (bnd)
+  {
+    LWCOLLECTION *bcol = lwgeom_as_lwcollection(bnd);
+    if (bcol)
+    {
+      for (i = 0; i < bcol->ngeoms; i++)
+        lwcollection_add_lwgeom(points, lwgeom_clone_deep(bcol->geoms[i]));
+    }
+    else if (!lwgeom_is_empty(bnd))
+    {
+      lwcollection_add_lwgeom(points, lwgeom_clone_deep(bnd));
+    }
+    lwgeom_free(bnd);
+  }
+
+  lwcollection_release(epoints);
+  lwcollection_release(lines);
+  lwgeom_release(multi);
+
+  points->srid = xset->srid;
+  return lwcollection_as_lwgeom(points);
+}
+
 static LWT_ELEMID*
 _lwt_AddLine(LWT_TOPOLOGY* topo, LWLINE* line, double tol, int* nedges,
             int handleFaceSplit)
@@ -7134,7 +7185,7 @@ _lwt_AddLine(LWT_TOPOLOGY* topo, LWLINE* line, double tol, int* nedges,
   LWGEOM *geomsbuf[1];
   LWGEOM **geoms;
   uint32_t ngeoms;
-  LWGEOM *noded, *tmp;
+  LWGEOM *noded, *tmp, *xsplit = NULL;
   LWCOLLECTION *col;
   LWT_ELEMID *ids;
   LWT_ISO_EDGE *edges;
@@ -7343,6 +7394,9 @@ _lwt_AddLine(LWT_TOPOLOGY* topo, LWLINE* line, double tol, int* nedges,
     xset = lwgeom_intersection(noded, iedges);
     LWDEBUGG(1, xset, "Intersected");
     lwgeom_free(noded);
+    /* Collect the junctions between shared and non-shared linework
+     * before line merging can hide them (see step 2.5) */
+    xsplit = _lwt_overlay_split_points(xset);
 
     /* We linemerge here because INTERSECTION, as of GEOS 3.8,
      * will result in shared segments being output as multiple
@@ -7433,6 +7487,25 @@ _lwt_AddLine(LWT_TOPOLOGY* topo, LWLINE* line, double tol, int* nedges,
     lwcollection_release(col);
   }
 
+  /* 2.5. Split by overlay junctions
+   *
+   * GEOS >= 3.15 returns line-merged overlay output, hiding the
+   * junctions between shared and non-shared linework inside line
+   * interiors. Splitting restores them; older GEOS keeps them as
+   * component boundaries and the split is a no-op.
+   */
+  if ( xsplit )
+  {
+    if ( !lwgeom_is_empty(xsplit) )
+    {
+      tmp = _lwt_split_by_nodes(noded, xsplit);
+      lwgeom_free(noded);
+      noded = tmp;
+      LWDEBUGG(1, noded, "Overlay-junction-split");
+    }
+    lwgeom_free(xsplit);
+  }
+
 
   LWDEBUG(1, "Freeing up nearby elements");
 
diff --git a/topology/test/regress/topogeo_addlinestring.sql b/topology/test/regress/topogeo_addlinestring.sql
index 1b35ba150..5573150ab 100644
--- a/topology/test/regress/topogeo_addlinestring.sql
+++ b/topology/test/regress/topogeo_addlinestring.sql
@@ -99,9 +99,9 @@ SELECT 'cross', TopoGeo_addLineString('city_data', 'SRID=4326;LINESTRING(49 18,
 SELECT check_changes('cross');
 
 -- Snapping (and splitting a face)
-SELECT 'snap', TopoGeo_addLineString('city_data', 'SRID=4326;LINESTRING(18 22.2, 22.5 22.2, 21.2 20.5)', 1) ORDER BY 2;
+SELECT 'snap', COUNT(*) FROM TopoGeo_addLineString('city_data', 'SRID=4326;LINESTRING(18 22.2, 22.5 22.2, 21.2 20.5)', 1);
 SELECT check_changes('snap');
-SELECT 'snap_again', TopoGeo_addLineString('city_data', 'SRID=4326;LINESTRING(18 22.2, 22.5 22.2, 21.2 20.5)', 1) ORDER BY 2;
+SELECT 'snap_again', COUNT(*) FROM TopoGeo_addLineString('city_data', 'SRID=4326;LINESTRING(18 22.2, 22.5 22.2, 21.2 20.5)', 1);
 SELECT check_changes('snap_again');
 
 -- A mix of crossing and overlapping, splitting another face
diff --git a/topology/test/regress/topogeo_addlinestring_expected b/topology/test/regress/topogeo_addlinestring_expected
index 6757356c1..2a2099d6a 100644
--- a/topology/test/regress/topogeo_addlinestring_expected
+++ b/topology/test/regress/topogeo_addlinestring_expected
@@ -38,9 +38,7 @@ cross|E|LINESTRING(47 14,47 17.6)
 cross|E|LINESTRING(47 17.6,47 22)
 cross|E|LINESTRING(47 17.6,44 17)
 cross|E|LINESTRING(49 18,47 17.6)
-snap|7
-snap|36
-snap|38
+snap|3
 snap|N||POINT(21.2 20.5)
 snap|N||POINT(22.35 22)
 snap|N||POINT(18 22.2)
@@ -48,9 +46,7 @@ snap|E|LINESTRING(22.35 22,35 22)
 snap|E|LINESTRING(22.35 22,21.2 20.5)
 snap|E|LINESTRING(21 22,22.35 22)
 snap|E|LINESTRING(18 22.2,21 22)
-snap_again|7
-snap_again|36
-snap_again|38
+snap_again|3
 crossover|4
 crossover|N||POINT(21 10)
 crossover|N||POINT(16.2 14)

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

Summary of changes:
 NEWS                                               |  2 +
 liblwgeom/topo/lwgeom_topo.c                       | 75 +++++++++++++++++++++-
 topology/test/regress/topogeo_addlinestring.sql    |  4 +-
 .../test/regress/topogeo_addlinestring_expected    |  8 +--
 4 files changed, 80 insertions(+), 9 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list