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

This commit is contained in:
Ignacio Vera 2022-12-13 10:16:53 +01:00 committed by GitHub
parent 486003833f
commit ef5766aa81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 36 deletions

View File

@ -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)
@ -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

View File

@ -435,42 +435,21 @@ public final class Tessellator {
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;
}

View File

@ -845,7 +845,7 @@ public class TestTessellator extends LuceneTestCase {
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));
@ -891,6 +891,30 @@ public class TestTessellator extends LuceneTestCase {
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;