LUCENE-9055: Fix the detection of lines crossing triangles through edge points (#1020)

This commit is contained in:
Ignacio Vera 2019-12-17 09:38:58 +01:00 committed by GitHub
parent db11e9e9a2
commit 17ef175224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 22 deletions

View File

@ -89,7 +89,9 @@ Optimizations
Bug Fixes
---------------------
(No changes)
* LUCENE-9055: Fix the detection of lines crossing triangles through edge points.
(Ignacio Vera)
Other
---------------------

View File

@ -161,7 +161,7 @@ public class EdgeTree {
/** Returns true if the triangle crosses any edge in this edge subtree */
protected boolean crossesTriangle(double minX, double maxX, double minY, double maxY,
double ax, double ay, double bx, double by, double cx, double cy) {
double ax, double ay, double bx, double by, double cx, double cy, boolean includeBoundary) {
if (minY <= max) {
double dy = y1;
double ey = y2;
@ -176,18 +176,27 @@ public class EdgeTree {
(dx > maxX && ex > maxX);
if (outside == false) {
if (lineCrossesLine(dx, dy, ex, ey, ax, ay, bx, by) ||
lineCrossesLine(dx, dy, ex, ey, bx, by, cx, cy) ||
lineCrossesLine(dx, dy, ex, ey, cx, cy, ax, ay)) {
return true;
if (includeBoundary == true) {
if (lineCrossesLineWithBoundary(dx, dy, ex, ey, ax, ay, bx, by) ||
lineCrossesLineWithBoundary(dx, dy, ex, ey, bx, by, cx, cy) ||
lineCrossesLineWithBoundary(dx, dy, ex, ey, cx, cy, ax, ay)) {
return true;
}
} else {
if (lineCrossesLine(dx, dy, ex, ey, ax, ay, bx, by) ||
lineCrossesLine(dx, dy, ex, ey, bx, by, cx, cy) ||
lineCrossesLine(dx, dy, ex, ey, cx, cy, ax, ay)) {
return true;
}
}
}
if (left != null && left.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy)) {
if (left != null && left.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy, includeBoundary)) {
return true;
}
if (right != null && maxY >= low && right.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy)) {
if (right != null && maxY >= low && right.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy, includeBoundary)) {
return true;
}
}
@ -222,18 +231,21 @@ public class EdgeTree {
(cx > maxX && dx > maxX);
if (outside == false) {
if (includeBoundary == true &&
lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, minY, maxX, minY) ||
if (includeBoundary == true) {
if (lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, minY, maxX, minY) ||
lineCrossesLineWithBoundary(cx, cy, dx, dy, maxX, minY, maxX, maxY) ||
lineCrossesLineWithBoundary(cx, cy, dx, dy, maxX, maxY, minX, maxY) ||
lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, maxY, minX, minY)) {
// include boundaries: ensures box edges that terminate on the polygon are included
return true;
} else if (lineCrossesLine(cx, cy, dx, dy, minX, minY, maxX, minY) ||
lineCrossesLine(cx, cy, dx, dy, maxX, minY, maxX, maxY) ||
lineCrossesLine(cx, cy, dx, dy, maxX, maxY, minX, maxY) ||
lineCrossesLine(cx, cy, dx, dy, minX, maxY, minX, minY)) {
return true;
// include boundaries: ensures box edges that terminate on the polygon are included
return true;
}
} else {
if (lineCrossesLine(cx, cy, dx, dy, minX, minY, maxX, minY) ||
lineCrossesLine(cx, cy, dx, dy, maxX, minY, maxX, maxY) ||
lineCrossesLine(cx, cy, dx, dy, maxX, maxY, minX, maxY) ||
lineCrossesLine(cx, cy, dx, dy, minX, maxY, minX, minY)) {
return true;
}
}
}

View File

@ -117,7 +117,7 @@ public class Polygon2D implements Component2D {
// check each corner: if < 4 && > 0 are present, its cheaper than crossesSlowly
int numCorners = numberOfCorners(minX, maxX, minY, maxY);
if (numCorners == 4) {
if (tree.crossesBox(minX, maxX, minY, maxY, false)) {
if (tree.crossesBox(minX, maxX, minY, maxY, true)) {
return Relation.CELL_CROSSES_QUERY;
}
return Relation.CELL_INSIDE_QUERY;
@ -125,7 +125,7 @@ public class Polygon2D implements Component2D {
if (Component2D.containsPoint(tree.x1, tree.y1, minX, maxX, minY, maxY)) {
return Relation.CELL_CROSSES_QUERY;
}
if (tree.crossesBox(minX, maxX, minY, maxY, false)) {
if (tree.crossesBox(minX, maxX, minY, maxY, true)) {
return Relation.CELL_CROSSES_QUERY;
}
return Relation.CELL_OUTSIDE_QUERY;
@ -255,7 +255,7 @@ public class Polygon2D implements Component2D {
// check each corner: if < 3 && > 0 are present, its cheaper than crossesSlowly
int numCorners = numberOfTriangleCorners(ax, ay, bx, by, cx, cy);
if (numCorners == 3) {
if (tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy)) {
if (tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy, false)) {
return Relation.CELL_CROSSES_QUERY;
}
return Relation.CELL_INSIDE_QUERY;
@ -263,7 +263,7 @@ public class Polygon2D implements Component2D {
if (Component2D.pointInTriangle(minX, maxX, minY, maxY, tree.x1, tree.y1, ax, ay, bx, by, cx, cy) == true) {
return Relation.CELL_CROSSES_QUERY;
}
if (tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy)) {
if (tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy, false)) {
return Relation.CELL_CROSSES_QUERY;
}
return Relation.CELL_OUTSIDE_QUERY;

View File

@ -126,7 +126,7 @@ public final class Line2D implements Component2D {
}
return Relation.CELL_OUTSIDE_QUERY;
} else if (Component2D.pointInTriangle(minX, maxX, minY, maxY, tree.x1, tree.y1, ax, ay, bx, by, cx, cy) == true ||
tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy)) {
tree.crossesTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, cy, true)) {
// indexed "triangle" is a triangle:
return Relation.CELL_CROSSES_QUERY;
}

View File

@ -659,4 +659,44 @@ public class TestLatLonShape extends LuceneTestCase {
quantizeLon(-5), quantizeLat(0));
assertEquals(PointValues.Relation.CELL_CROSSES_QUERY, r);
}
public void testLUCENE9055() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
// test polygons:
//[5, 5], [10, 6], [10, 10], [5, 10], [5, 5] ]
Polygon indexPoly1 = new Polygon(
new double[] {5d, 6d, 10d, 10d, 5d},
new double[] {5d, 10d, 10d, 5d, 5d}
);
// [ [6, 6], [9, 6], [9, 9], [6, 9], [6, 6] ]
Polygon indexPoly2 = new Polygon(
new double[] {6d, 6d, 9d, 9d, 6d},
new double[] {6d, 9d, 9d, 6d, 6d}
);
// index polygons:
Document doc;
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly1);
w.addDocument(doc);
addPolygonsToDoc(FIELDNAME, doc = new Document(), indexPoly2);
w.addDocument(doc);
w.forceMerge(1);
///// search //////
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = newSearcher(reader);
// [ [0, 0], [5, 5], [7, 7] ]
Line searchLine = new Line(new double[] {0, 5, 7}, new double[] {0, 5, 7});
Query q = LatLonShape.newLineQuery(FIELDNAME, QueryRelation.INTERSECTS, searchLine);
assertEquals(2, searcher.count(q));
IOUtils.close(w, reader, dir);
}
}