[SCM] PostGIS branch stable-3.6 updated. 3.6.4-76-g17f256038

git at osgeo.org git at osgeo.org
Sun Jul 19 23:40:48 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.6 has been updated
       via  17f2560386892694ff7dadbdb00de62811938c98 (commit)
       via  d27e0a1be498e64ed337b371a4ad263bc31c3d3b (commit)
      from  5c0b2776b11cbe3a5d9889d5caf941e58004f09d (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 17f2560386892694ff7dadbdb00de62811938c98
Merge: 5c0b2776b d27e0a1be
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Sun Jul 19 23:40:46 2026 -0700

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


commit d27e0a1be498e64ed337b371a4ad263bc31c3d3b
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 30cf3d57228c29c56fec68ef63e3dc5b8621fb66)

diff --git a/NEWS b/NEWS
index ef3cfab6a..e98e0e104 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,8 @@ PostGIS 3.6.5
           grid size exceeds their extent (Darafei Praliaskouski)
 - #6094, [upgrade] Avoid legacy string literal warnings in downgrade checks
   with standard_conforming_strings off (Darafei Praliaskouski)
+- GH-1160, [topology] Preserve overlay intersection boundaries when
+  noding lines with GEOS main (Darafei Praliaskouski)
 
 
 PostGIS 3.6.4
diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index dbb0085c5..3e5f5b1ee 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -7110,6 +7110,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)
@@ -7117,7 +7168,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;
@@ -7326,6 +7377,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
@@ -7416,6 +7470,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