[SCM] PostGIS branch master updated. 3.7.0alpha1-86-g63345d444

git at osgeo.org git at osgeo.org
Thu Jul 9 03:46:13 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, master has been updated
       via  63345d444bdb865524444eb0f4a4189a0890cf0a (commit)
       via  09f9558ae04577e6277b3c1c30cbb8921ea58a71 (commit)
       via  9c931e6fcdcf78a5d605a0d445b4a51564f78ff5 (commit)
       via  ca3323d8c748dd806bab188028bb61c5f67b39af (commit)
      from  ec3216f2897fa8dccf7db5750e38653f9b012261 (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 63345d444bdb865524444eb0f4a4189a0890cf0a
Merge: ec3216f28 09f9558ae
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Thu Jul 9 14:11:48 2026 +0400

    Merge pull request #1160 from Komzpa/codex/ci-wrapx-collection-output
    
    Stabilize GEOS main linework handling


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

    Keep manual examples stable across GEOS linework merging
    
    Use disjoint lines in the ST_Union array example and avoid a vertex
    inside a straight shared stretch in the ST_SharedPaths examples, so
    the documented outputs are identical across GEOS versions. Document
    that ST_SharedPaths segmentation may vary with the GEOS version.

diff --git a/doc/reference_overlay.xml b/doc/reference_overlay.xml
index 64a20bbf2..8e96c75bf 100644
--- a/doc/reference_overlay.xml
+++ b/doc/reference_overlay.xml
@@ -1056,9 +1056,9 @@ FROM (
 <para>This example unions an array of linestrings.</para>
 <programlisting>SELECT ST_AsText(ST_Union(ARRAY[
     ST_GeomFromText('LINESTRING(1 2, 3 4)'),
-    ST_GeomFromText('LINESTRING(3 4, 4 5)')
+    ST_GeomFromText('LINESTRING(4 5, 5 6)')
 ])) As wktunion;</programlisting>
-<screen>MULTILINESTRING((1 2,3 4),(3 4,4 5))</screen>
+<screen>MULTILINESTRING((1 2,3 4),(4 5,5 6))</screen>
       </refsection>
       <refsection>
         <title>See Also</title>
diff --git a/doc/reference_processing.xml b/doc/reference_processing.xml
index 72e46b615..ffa35213f 100644
--- a/doc/reference_processing.xml
+++ b/doc/reference_processing.xml
@@ -2596,6 +2596,8 @@ FROM (SELECT ST_Polygonize(geom_4269) AS polycoll
       </refsection>
       <refsection>
         <title>Examples: Finding shared paths</title>
+        <para>Adjacent shared path segments may be returned as separate or merged LineStrings
+          depending on the GEOS version.</para>
         <informaltable>
           <tgroup cols="1">
             <tbody>
@@ -2622,11 +2624,11 @@ FROM (SELECT ST_Polygonize(geom_4269) AS polycoll
                   <programlisting>
  SELECT ST_AsText(ST_SharedPaths(ST_GeomFromText('MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),
        (51 150,101 150,76 175,51 150))'),
-    ST_GeomFromText('LINESTRING(151 100,126 156.25,126 125,90 161, 76 175)')
+    ST_GeomFromText('LINESTRING(151 100,126 156.25,126 125,101 150, 76 175)')
     )
   )</programlisting>
 <screen>GEOMETRYCOLLECTION(MULTILINESTRING((126 156.25,126 125),
- (101 150,90 161),(90 161,76 175)),MULTILINESTRING EMPTY)</screen>
+ (101 150,76 175)),MULTILINESTRING EMPTY)</screen>
             </para>
             </entry>
         </row>
@@ -2636,13 +2638,13 @@ FROM (SELECT ST_Polygonize(geom_4269) AS polycoll
 <lineannotation>
 same example but linestring orientation flipped
 </lineannotation>
-SELECT ST_AsText(ST_SharedPaths(ST_GeomFromText('LINESTRING(76 175,90 161,126 125,126 156.25,151 100)'),
+SELECT ST_AsText(ST_SharedPaths(ST_GeomFromText('LINESTRING(76 175,101 150,126 125,126 156.25,151 100)'),
    ST_GeomFromText('MULTILINESTRING((26 125,26 200,126 200,126 125,26 125),
        (51 150,101 150,76 175,51 150))')
     )
   )</programlisting>
 <screen>GEOMETRYCOLLECTION(MULTILINESTRING EMPTY,
-MULTILINESTRING((76 175,90 161),(90 161,101 150),(126 125,126 156.25)))</screen>
+MULTILINESTRING((76 175,101 150),(126 125,126 156.25)))</screen>
             </para>
             </entry>
         </row>

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

    Fix GEOS version parser in wrapx regression
    
    A stray ']' made the regexp never match, so the GEOS >= 3.15
    expected outputs were never selected.

diff --git a/regress/core/wrapx.sql b/regress/core/wrapx.sql
index 321958d52..b35504961 100644
--- a/regress/core/wrapx.sql
+++ b/regress/core/wrapx.sql
@@ -15,7 +15,7 @@ $$ LANGUAGE 'plpgsql';
 CREATE OR REPLACE FUNCTION geos_version()
 RETURNS integer AS $$
     SELECT (matches[1]::integer * 100) + matches[2]::integer
-    FROM regexp_match(postgis_geos_version(), E'^([0-9]+)]\\.([0-9]+)') AS matches;
+    FROM regexp_match(postgis_geos_version(), E'^([0-9]+)\\.([0-9]+)') AS matches;
 $$ LANGUAGE 'sql' IMMUTABLE;
 
 

commit ca3323d8c748dd806bab188028bb61c5f67b39af
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

diff --git a/NEWS b/NEWS
index 4fa4d414c..d101510e3 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
 
 * Bug Fixes *
 
+ - GH-1160, [topology] Preserve overlay intersection boundaries when
+          noding lines with GEOS main (Darafei Praliaskouski)
  - #6093, Fix SQL generation on ppc64el when NURBS comments are
           preprocessed with AltiVec vector macros (Darafei Praliaskouski)
  - #6094, [upgrade] Avoid legacy string literal warnings in downgrade checks
diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index b119d5dae..a8d00c108 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -7379,6 +7379,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, int maxNewEdges)
@@ -7386,7 +7437,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;
@@ -7601,6 +7652,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
@@ -7691,6 +7745,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 5946ceec0..1f67b7198 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 5035a8654..957ed5f3c 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 +
 doc/reference_overlay.xml                          |  4 +-
 doc/reference_processing.xml                       | 10 +--
 liblwgeom/topo/lwgeom_topo.c                       | 75 +++++++++++++++++++++-
 regress/core/wrapx.sql                             |  2 +-
 topology/test/regress/topogeo_addlinestring.sql    |  4 +-
 .../test/regress/topogeo_addlinestring_expected    |  8 +--
 7 files changed, 89 insertions(+), 16 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list