[SCM] PostGIS branch stable-3.4 updated. 3.4.3-8-g639f030bb
git at osgeo.org
git at osgeo.org
Thu Oct 3 01:17:21 PDT 2024
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.4 has been updated
via 639f030bbead6727228399db0ac044a011be5f61 (commit)
from 0758764f4c7ff03e8d425201d5260be8fc698a41 (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 639f030bbead6727228399db0ac044a011be5f61
Author: Sandro Santilli <strk at kbt.io>
Date: Wed Oct 2 17:02:56 2024 +0200
Check that ST_ChangeEdgeGeom doesn't change winding of rings
References #5787 in 3.4 branch (3.4.4dev)
diff --git a/NEWS b/NEWS
index 722b42246..94e9826d3 100644
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,9 @@ PostGIS 3.4.4dev
- Quote-protect output paths of pgtopo_export (Sandro Santilli)
- #5785, [raster] ST_MapAlgebra segfaults when expression references
- a supernumerary rast argument (Dian M Fay)
+ a supernumerary rast argument (Dian M Fay)
+ - #5787, Check that ST_ChangeEdgeGeom doesn't change winding of rings
+ (Sandro Santilli)
* Enhancements *
diff --git a/liblwgeom/lwgeom_topo.c b/liblwgeom/lwgeom_topo.c
index 6648bb525..5d8c0e609 100644
--- a/liblwgeom/lwgeom_topo.c
+++ b/liblwgeom/lwgeom_topo.c
@@ -1522,7 +1522,7 @@ _lwt_InitEdgeEndByLine(edgeend *fee, edgeend *lee, LWLINE *edge,
/*
* Find the first edges encountered going clockwise and counterclockwise
* around a node, starting from the given azimuth, and take
- * note of the face on the both sides.
+ * note of the face on both sides.
*
* @param topo the topology to act upon
* @param node the identifier of the node to analyze
@@ -3267,6 +3267,7 @@ lwt_ChangeEdgeGeom(LWT_TOPOLOGY* topo, LWT_ELEMID edge_id, LWLINE *geom)
POINT2D p1, p2, pt;
uint64_t i;
int isclosed = 0;
+ int leftRingIsCCW = -1;
/* curve must be simple */
if ( ! lwgeom_is_simple(lwline_as_lwgeom(geom)) )
@@ -3452,6 +3453,61 @@ lwt_ChangeEdgeGeom(LWT_TOPOLOGY* topo, LWT_ELEMID edge_id, LWLINE *geom)
span_pre.nextCW, span_pre.nextCCW,
epan_pre.nextCW, epan_pre.nextCCW);
+ /* If the same edge is both on CW and CCW direction on both start
+ * and end points we need to verify winding of the left and right
+ * rings to verify we didn't twist.
+ * See https://trac.osgeo.org/postgis/ticket/5787
+ *
+ * NOTE: this could probably replace the "isclosed" test.
+ *
+ * NOTE: if either start or end node had different CW and CCW
+ * edges a twist would be cought in the previous check.
+ */
+ if ( ! isclosed &&
+ oldedge->face_left != oldedge->face_right &&
+ span_pre.nextCW == span_pre.nextCCW &&
+ epan_pre.nextCW == epan_pre.nextCCW )
+ {{
+ uint64_t num_signed_edge_ids;
+ LWT_ELEMID *signed_edge_ids;
+ LWPOLY *shell;
+
+ lwnotice("Twist check before");
+ signed_edge_ids = lwt_be_getRingEdges(topo, edge_id, &num_signed_edge_ids, 0);
+ /* Get winding of left face ring */
+ if (!signed_edge_ids)
+ {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+ LWDEBUGF(1, "getRingEdges returned %d edges", num_signed_edge_ids);
+
+ shell = _lwt_MakeRingShell(topo, signed_edge_ids, num_signed_edge_ids);
+ if ( ! shell ) {
+ lwfree( signed_edge_ids );
+ /* ring_edges should be NULL */
+ lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ const POINTARRAY *pa = shell->rings[0];
+ if ( ! ptarray_is_closed_2d(pa) )
+ {
+ lwpoly_free(shell);
+ lwfree( signed_edge_ids );
+ lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
+ " is geometrically not-closed", edge_id);
+ return -1;
+ }
+
+ leftRingIsCCW = ptarray_isccw(pa);
+ lwpoly_free(shell);
+ lwfree( signed_edge_ids );
+
+ lwnotice("Ring of edge %" LWTFMT_ELEMID " is %sclockwise", edge_id, leftRingIsCCW ? "counter" : "");
+ }}
+
+
/* update edge geometry */
newedge.edge_id = edge_id;
newedge.geom = geom;
@@ -3511,6 +3567,55 @@ lwt_ChangeEdgeGeom(LWT_TOPOLOGY* topo, LWT_ELEMID edge_id, LWLINE *geom)
return -1;
}}
+ /* Check winding of left face ring did not change */
+ if ( leftRingIsCCW != -1 )
+ {{
+ uint64_t num_signed_edge_ids;
+ LWT_ELEMID *signed_edge_ids;
+ LWPOLY *shell;
+ int isCCW;
+
+ lwnotice("Twist check after");
+ signed_edge_ids = lwt_be_getRingEdges(topo, edge_id, &num_signed_edge_ids, 0);
+ /* Get winding of left face ring */
+ if (!signed_edge_ids)
+ {
+ //PGTOPO_BE_ERRORF("no ring edges for edge %" LWTFMT_ELEMID, sedge);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+ LWDEBUGF(1, "getRingEdges returned %d edges", num_signed_edge_ids);
+
+ shell = _lwt_MakeRingShell(topo, signed_edge_ids, num_signed_edge_ids);
+ if ( ! shell ) {
+ lwfree( signed_edge_ids );
+ /* ring_edges should be NULL */
+ lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ const POINTARRAY *pa = shell->rings[0];
+ if ( ! ptarray_is_closed_2d(pa) )
+ {
+ lwpoly_free(shell);
+ lwfree( signed_edge_ids );
+ lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
+ " is geometrically not-closed", edge_id);
+ return -1;
+ }
+
+ isCCW = ptarray_isccw(pa);
+ lwpoly_free(shell);
+ lwfree( signed_edge_ids );
+
+ if ( isCCW != leftRingIsCCW )
+ {
+ _lwt_release_edges(oldedge, 1);
+ lwerror("Edge ring changes winding");
+ return -1;
+ }
+ }}
+
/*
-- Update faces MBR of left and right faces
-- TODO: think about ways to optimize this part, like see if
diff --git a/topology/test/regress/st_changeedgegeom.sql b/topology/test/regress/st_changeedgegeom.sql
index 7f2605e4e..769157a5f 100644
--- a/topology/test/regress/st_changeedgegeom.sql
+++ b/topology/test/regress/st_changeedgegeom.sql
@@ -186,3 +186,11 @@ AND NOT ST_Equals(
)
);
SELECT NULL FROM topology.DropTopology('t5709');
+
+-- See https://trac.osgeo.org/postgis/ticket/5787
+SELECT NULL FROM topology.CreateTopology('t5787');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5787', 'LINESTRING(0 0, 5 5, 10 0)');
+SELECT NULL FROM topology.TopoGeo_addLinestring('t5787', 'LINESTRING(0 0, 10 0)');
+SELECT '#5787', 'unexpected success' FROM topology.ST_ChangeEdgeGeom('t5787', 1, 'LINESTRING(0 0, 5 -5, 10 0)');
+SELECT '#5787', 'unexpected invalidity', * FROM topology.ValidateTopology('t5787');
+SELECT NULL FROM topology.DropTopology('t5787');
diff --git a/topology/test/regress/st_changeedgegeom_expected b/topology/test/regress/st_changeedgegeom_expected
index f2bc4fb95..bfb094b73 100644
--- a/topology/test/regress/st_changeedgegeom_expected
+++ b/topology/test/regress/st_changeedgegeom_expected
@@ -37,3 +37,4 @@ T13.3|26
ERROR: Edge motion collision at POINT(-1.1697 47.7825)
Topology 'city_data' dropped
t5709|edge|1
+ERROR: Edge ring changes winding
-----------------------------------------------------------------------
Summary of changes:
NEWS | 4 +-
liblwgeom/lwgeom_topo.c | 107 ++++++++++++++++++++++-
topology/test/regress/st_changeedgegeom.sql | 8 ++
topology/test/regress/st_changeedgegeom_expected | 1 +
4 files changed, 118 insertions(+), 2 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list