Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix algorithm that chooses the bridge between a polygon and a hole #11988

Merged
merged 4 commits into from Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion lucene/CHANGES.txt
Expand Up @@ -125,7 +125,7 @@ API Changes

* GITHUB#11962: VectorValues#cost() now delegates to VectorValues#size().
(Adrien Grand)

* GITHUB#11984: Improved TimeLimitBulkScorer to check the timeout at exponantial rate.
(Costin Leau)

Expand Down Expand Up @@ -183,6 +183,9 @@ Bug Fixes
so that subsequent passage merges don't mean that we return too few passages in
total. (Alan Woodward, Dawid Weiss)

* GITHUB#11986: Fix algorithm that chooses the bridge between a polygon and a hole when there is
common vertex. (Ignacio Vera)

Optimizations
---------------------
* GITHUB#11738: Optimize MultiTermQueryConstantScoreWrapper when a term is present that matches all
Expand Down
47 changes: 13 additions & 34 deletions lucene/core/src/java/org/apache/lucene/geo/Tessellator.java
Expand Up @@ -435,42 +435,21 @@ private static final Node fetchHoleBridge(final Node holeNode, final Node outerN
final double my = connection.getY();
double tanMin = Double.POSITIVE_INFINITY;
double tan;
p = connection.next;
{
while (p != stop) {
if (hx >= p.getX()
&& p.getX() >= mx
&& hx != p.getX()
&& pointInEar(
p.getX(), p.getY(), hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy)) {
tan = Math.abs(hy - p.getY()) / (hx - p.getX()); // tangential
if (isVertexEquals(p, connection) && isLocallyInside(p, holeNode)) {
// make sure we are not crossing the polygon. This might happen when several holes have
// a bridge to the same polygon vertex
// and this vertex has different vertex.
boolean crosses =
GeoUtils.lineCrossesLine(
p.getX(),
p.getY(),
holeNode.getX(),
holeNode.getY(),
connection.next.getX(),
connection.next.getY(),
connection.previous.getX(),
connection.previous.getY());
if (crosses == false) {
connection = p;
tanMin = tan;
}
} else if ((tan < tanMin || (tan == tanMin && p.getX() > connection.getX()))
&& isLocallyInside(p, holeNode)) {
connection = p;
tanMin = tan;
}
p = connection;
do {
if (hx >= p.getX()
&& p.getX() >= mx
&& hx != p.getX()
&& pointInEar(p.getX(), p.getY(), hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy)) {
tan = Math.abs(hy - p.getY()) / (hx - p.getX()); // tangential
if ((tan < tanMin || (tan == tanMin && p.getX() > connection.getX()))
&& isLocallyInside(p, holeNode)) {
connection = p;
tanMin = tan;
}
p = p.next;
}
}
p = p.next;
} while (p != stop);
return connection;
}

Expand Down
26 changes: 25 additions & 1 deletion lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java
Expand Up @@ -845,7 +845,7 @@ public void testComplexPolygon50_WithMonitor() throws Exception {
Polygon polygon = polygons[0];
TestCountingMonitor monitor = new TestCountingMonitor();
Tessellator.tessellate(polygon, true, monitor);
assertThat("Expected many monitor calls", monitor.count, greaterThan(400));
assertThat("Expected many monitor calls", monitor.count, greaterThan(390));
assertThat("Expected specific number of splits", monitor.splitsStarted, equalTo(3));
assertThat(
"Expected splits to start and end", monitor.splitsStarted, equalTo(monitor.splitsEnded));
Expand Down Expand Up @@ -891,6 +891,30 @@ public void testComplexPolygon52() throws Exception {
ex.getMessage());
}

public void testComplexPolygon53() throws Exception {
String geoJson = GeoTestUtil.readShape("github-11986-1.geojson.gz");
Polygon[] polygons = Polygon.fromGeoJSON(geoJson);
for (Polygon polygon : polygons) {
List<Tessellator.Triangle> tessellation = Tessellator.tessellate(polygon, true);
assertEquals(area(polygon), area(tessellation), 0.0);
for (Tessellator.Triangle t : tessellation) {
checkTriangleEdgesFromPolygon(polygon, t);
}
}
}

public void testComplexPolygon54() throws Exception {
String geoJson = GeoTestUtil.readShape("github-11986-2.geojson.gz");
Polygon[] polygons = Polygon.fromGeoJSON(geoJson);
for (Polygon polygon : polygons) {
List<Tessellator.Triangle> tessellation = Tessellator.tessellate(polygon, true);
assertEquals(area(polygon), area(tessellation), 0.0);
for (Tessellator.Triangle t : tessellation) {
checkTriangleEdgesFromPolygon(polygon, t);
}
}
}

private static class TestCountingMonitor implements Tessellator.Monitor {
private int count = 0;
private int splitsStarted = 0;
Expand Down
Binary file not shown.
Binary file not shown.