LUCENE-9251: Filter equal edges with different value on isEdgeFromPolygon (#1290)

Fix bug in the polygon tessellator where edges with different value on #isEdgeFromPolygon were bot filtered out properly
This commit is contained in:
Ignacio Vera 2020-03-03 07:07:34 +01:00 committed by GitHub
parent b732ce7002
commit c313365c5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 6 deletions

View File

@ -224,6 +224,9 @@ Bug Fixes
* LUCENE-9239: Circle2D#WithinTriangle detects properly if a triangle is Within distance. (Ignacio Vera) * LUCENE-9239: Circle2D#WithinTriangle detects properly if a triangle is Within distance. (Ignacio Vera)
* LUCENE-9251: Fix bug in the polygon tessellator where edges with different value on #isEdgeFromPolygon
were bot filtered out properly. (Ignacio Vera)
Other Other
--------------------- ---------------------

View File

@ -435,7 +435,6 @@ final public class Tessellator {
continue; continue;
} }
currEar = nextNode; currEar = nextNode;
// If the whole polygon has been iterated over and no more ears can be found. // If the whole polygon has been iterated over and no more ears can be found.
if (currEar == stop) { if (currEar == stop) {
switch (state) { switch (state) {
@ -915,13 +914,14 @@ final public class Tessellator {
continueIteration = false; continueIteration = false;
nextNode = node.next; nextNode = node.next;
prevNode = node.previous; prevNode = node.previous;
//We can filter points when they are the same, if not and they are co-linear we can only // we can filter points when:
//remove it if both edges have the same value in .isNextEdgeFromPolygon if (isVertexEquals(node, nextNode) || // 1. they are the same,
if (isVertexEquals(node, nextNode) || isVertexEquals(prevNode, nextNode) || // 2.- each one starts and ends in each other
(prevNode.isNextEdgeFromPolygon == node.isNextEdgeFromPolygon && (prevNode.isNextEdgeFromPolygon == node.isNextEdgeFromPolygon && // 3.- they are co-linear and both edges have the same value in .isNextEdgeFromPolygon
area(prevNode.getX(), prevNode.getY(), node.getX(), node.getY(), nextNode.getX(), nextNode.getY()) == 0)) { area(prevNode.getX(), prevNode.getY(), node.getX(), node.getY(), nextNode.getX(), nextNode.getY()) == 0)) {
// Remove the node // Remove the node
removeNode(node, prevNode.isNextEdgeFromPolygon); boolean nextEdgeFromPol = prevNode.isNextEdgeFromPolygon != node.isNextEdgeFromPolygon ? true : prevNode.isNextEdgeFromPolygon;
removeNode(node, nextEdgeFromPol);
node = end = prevNode; node = end = prevNode;
if (node == nextNode) { if (node == nextNode) {

View File

@ -561,6 +561,18 @@ public class TestTessellator extends LuceneTestCase {
checkPolygon(wkt); checkPolygon(wkt);
} }
@Nightly
public void testComplexPolygon40() throws Exception {
String wkt = GeoTestUtil.readShape("lucene-9251.wkt.gz");
Polygon polygon = (Polygon) SimpleWKTShapeParser.parse(wkt);
List<Tessellator.Triangle> tessellation = Tessellator.tessellate(polygon);
// calculate the area of big polygons have numerical error
assertEquals(area(polygon), area(tessellation), 1e-12);
for (Tessellator.Triangle t : tessellation) {
checkTriangleEdgesFromPolygon(polygon, t);
}
}
private void checkPolygon(String wkt) throws Exception { private void checkPolygon(String wkt) throws Exception {
Polygon polygon = (Polygon) SimpleWKTShapeParser.parse(wkt); Polygon polygon = (Polygon) SimpleWKTShapeParser.parse(wkt);
List<Tessellator.Triangle> tessellation = Tessellator.tessellate(polygon); List<Tessellator.Triangle> tessellation = Tessellator.tessellate(polygon);

View File

@ -16,10 +16,17 @@
*/ */
package org.apache.lucene.geo; package org.apache.lucene.geo;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.zip.GZIPInputStream;
import org.apache.lucene.util.NumericUtils; import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.SloppyMath; import org.apache.lucene.util.SloppyMath;
@ -718,4 +725,26 @@ public class GeoTestUtil {
} }
return c; return c;
} }
/** reads a shape from file */
public static String readShape(String name) throws IOException {
return Loader.LOADER.readShape(name);
}
private static class Loader {
static Loader LOADER = new Loader();
String readShape(String name) throws IOException {
InputStream is = getClass().getResourceAsStream(name);
if (is == null) {
throw new FileNotFoundException("classpath resource not found: " + name);
}
if (name.endsWith(".gz")) {
is = new GZIPInputStream(is);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
return reader.readLine();
}
}
} }