Skip to content

Commit e59cb5b

Browse files
committed
Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole (#15657)
1 parent 39969e5 commit e59cb5b

File tree

4 files changed

+33
-2
lines changed

4 files changed

+33
-2
lines changed

lucene/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ Bug Fixes
203203

204204
* GITHUB#14616 : Fix mis-interpretation of `maxNumBytes` in FuzzySet#createSetBasedOnMaxMemory (Greg Miller)
205205

206+
* GITHUB#15554: Fix tessellator failure by preferring the shared vertex that is the leftmost vertex of the hole
207+
(Ignacio Vera)
208+
206209
Other
207210
---------------------
208211
* GITHUB#15237: Fix SmartChinese to only deserialize dictionary data from classpath with a native array

lucene/core/src/java/org/apache/lucene/geo/Tessellator.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,25 +408,47 @@ private static boolean maybeMergeHoleWithSharedVertices(
408408
// Attempt to find a common point between the HoleNode and OuterNode.
409409
Node sharedVertex = null;
410410
Node sharedVertexConnection = null;
411+
// Track the leftmost vertex match (holeNode is the leftmost vertex of the hole)
412+
Node leftmostSharedVertex = null;
413+
Node leftmostSharedVertexConnection = null;
411414
Node next = outerNode;
412415
do {
413416
if (Rectangle.containsPoint(
414417
next.getY(), next.getX(), holeMinY, holeMaxY, holeMinX, holeMaxX)) {
415418
Node newSharedVertex = getSharedVertex(holeNode, next);
416419
if (newSharedVertex != null) {
420+
// Check if this shared vertex is the leftmost point of the hole (holeNode)
421+
if (isVertexEquals(newSharedVertex, holeNode)) {
422+
if (leftmostSharedVertex == null) {
423+
leftmostSharedVertex = newSharedVertex;
424+
leftmostSharedVertexConnection = next;
425+
} else if (newSharedVertex.equals(leftmostSharedVertex)) {
426+
// Same vertex found again via different connection
427+
leftmostSharedVertexConnection =
428+
getSharedInsideVertex(leftmostSharedVertex, leftmostSharedVertexConnection, next);
429+
}
430+
}
417431
if (sharedVertex == null) {
418432
sharedVertex = newSharedVertex;
419433
sharedVertexConnection = next;
420434
} else if (newSharedVertex.equals(sharedVertex)) {
421-
// This can only happen if this vertex has been already used for a bridge. We need to
422-
// choose the right one.
435+
// Same vertex found again via different connection.
423436
sharedVertexConnection =
424437
getSharedInsideVertex(sharedVertex, sharedVertexConnection, next);
425438
}
426439
}
427440
}
428441
next = next.next;
429442
} while (next != outerNode);
443+
444+
// The leftmost vertex of the hole is a shared vertex. Prefer this connection point if it is
445+
// from a hole that was already merged (higher idx), as this maintains proper connectivity
446+
// for chained holes.
447+
if (leftmostSharedVertex != null
448+
&& leftmostSharedVertexConnection.idx > sharedVertexConnection.idx) {
449+
splitPolygon(leftmostSharedVertexConnection, leftmostSharedVertex, true);
450+
return true;
451+
}
430452
if (sharedVertex != null) {
431453
// Split the resulting polygon.
432454
splitPolygon(sharedVertexConnection, sharedVertex, true);

lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,12 @@ public void testComplexPolygon61() throws Exception {
935935
checkMultiPolygon(polygons, 1e-11);
936936
}
937937

938+
public void testComplexPolygon62() throws Exception {
939+
String geoJson = GeoTestUtil.readShape("github-15657.geojson.gz");
940+
Polygon[] polygons = Polygon.fromGeoJSON(geoJson);
941+
checkMultiPolygon(polygons, 1e-11);
942+
}
943+
938944
private static class TestCountingMonitor implements Tessellator.Monitor {
939945
private int count = 0;
940946
private int splitsStarted = 0;
Binary file not shown.

0 commit comments

Comments
 (0)