You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by iv...@apache.org on 2026/02/02 17:06:37 UTC
(lucene) branch branch_10x updated: Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole (#15657)
This is an automated email from the ASF dual-hosted git repository.
ivera pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git
The following commit(s) were added to refs/heads/branch_10x by this push:
new e59cb5bca5d Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole (#15657)
e59cb5bca5d is described below
commit e59cb5bca5dcb1653355eb028de767af8ae7f322
Author: Ignacio Vera <iv...@apache.org>
AuthorDate: Mon Feb 2 17:05:33 2026 +0000
Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole (#15657)
---
lucene/CHANGES.txt | 3 +++
.../java/org/apache/lucene/geo/Tessellator.java | 26 +++++++++++++++++++--
.../org/apache/lucene/geo/TestTessellator.java | 6 +++++
.../lucene/tests/geo/github-15657.geojson.gz | Bin 0 -> 1394 bytes
4 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index fa7f9acb523..9567cfd39de 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -203,6 +203,9 @@ Bug Fixes
* GITHUB#14616 : Fix mis-interpretation of `maxNumBytes` in FuzzySet#createSetBasedOnMaxMemory (Greg Miller)
+* GITHUB#15554: Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole
+ (Ignacio Vera)
+
Other
---------------------
* GITHUB#15237: Fix SmartChinese to only deserialize dictionary data from classpath with a native array
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java b/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java
index 697bcdce5ba..03fca6b005e 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java
@@ -408,18 +408,31 @@ public final class Tessellator {
// Attempt to find a common point between the HoleNode and OuterNode.
Node sharedVertex = null;
Node sharedVertexConnection = null;
+ // Track the leftmost vertex match (holeNode is the leftmost vertex of the hole)
+ Node leftmostSharedVertex = null;
+ Node leftmostSharedVertexConnection = null;
Node next = outerNode;
do {
if (Rectangle.containsPoint(
next.getY(), next.getX(), holeMinY, holeMaxY, holeMinX, holeMaxX)) {
Node newSharedVertex = getSharedVertex(holeNode, next);
if (newSharedVertex != null) {
+ // Check if this shared vertex is the leftmost point of the hole (holeNode)
+ if (isVertexEquals(newSharedVertex, holeNode)) {
+ if (leftmostSharedVertex == null) {
+ leftmostSharedVertex = newSharedVertex;
+ leftmostSharedVertexConnection = next;
+ } else if (newSharedVertex.equals(leftmostSharedVertex)) {
+ // Same vertex found again via different connection
+ leftmostSharedVertexConnection =
+ getSharedInsideVertex(leftmostSharedVertex, leftmostSharedVertexConnection, next);
+ }
+ }
if (sharedVertex == null) {
sharedVertex = newSharedVertex;
sharedVertexConnection = next;
} else if (newSharedVertex.equals(sharedVertex)) {
- // This can only happen if this vertex has been already used for a bridge. We need to
- // choose the right one.
+ // Same vertex found again via different connection.
sharedVertexConnection =
getSharedInsideVertex(sharedVertex, sharedVertexConnection, next);
}
@@ -427,6 +440,15 @@ public final class Tessellator {
}
next = next.next;
} while (next != outerNode);
+
+ // The leftmost vertex of the hole is a shared vertex. Prefer this connection point if it is
+ // from a hole that was already merged (higher idx), as this maintains proper connectivity
+ // for chained holes.
+ if (leftmostSharedVertex != null
+ && leftmostSharedVertexConnection.idx > sharedVertexConnection.idx) {
+ splitPolygon(leftmostSharedVertexConnection, leftmostSharedVertex, true);
+ return true;
+ }
if (sharedVertex != null) {
// Split the resulting polygon.
splitPolygon(sharedVertexConnection, sharedVertex, true);
diff --git a/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java b/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java
index b24dee3485f..33e8480dcdf 100644
--- a/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java
+++ b/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java
@@ -935,6 +935,12 @@ public class TestTessellator extends LuceneTestCase {
checkMultiPolygon(polygons, 1e-11);
}
+ public void testComplexPolygon62() throws Exception {
+ String geoJson = GeoTestUtil.readShape("github-15657.geojson.gz");
+ Polygon[] polygons = Polygon.fromGeoJSON(geoJson);
+ checkMultiPolygon(polygons, 1e-11);
+ }
+
private static class TestCountingMonitor implements Tessellator.Monitor {
private int count = 0;
private int splitsStarted = 0;
diff --git a/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-15657.geojson.gz b/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-15657.geojson.gz
new file mode 100644
index 00000000000..399f71063b0
Binary files /dev/null and b/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-15657.geojson.gz differ