[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