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 Bug Fixes
--------------------- ---------------------
(No changes)
* LUCENE-9055: Fix the detection of lines crossing triangles through edge points.
(Ignacio Vera)
Other Other
--------------------- ---------------------

View File

@ -161,7 +161,7 @@ public class EdgeTree {
/** Returns true if the triangle crosses any edge in this edge subtree */ /** Returns true if the triangle crosses any edge in this edge subtree */
protected boolean crossesTriangle(double minX, double maxX, double minY, double maxY, 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) { if (minY <= max) {
double dy = y1; double dy = y1;
double ey = y2; double ey = y2;
@ -176,18 +176,27 @@ public class EdgeTree {
(dx > maxX && ex > maxX); (dx > maxX && ex > maxX);
if (outside == false) { if (outside == false) {
if (lineCrossesLine(dx, dy, ex, ey, ax, ay, bx, by) || if (includeBoundary == true) {
lineCrossesLine(dx, dy, ex, ey, bx, by, cx, cy) || if (lineCrossesLineWithBoundary(dx, dy, ex, ey, ax, ay, bx, by) ||
lineCrossesLine(dx, dy, ex, ey, cx, cy, ax, ay)) { lineCrossesLineWithBoundary(dx, dy, ex, ey, bx, by, cx, cy) ||
return true; 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; 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; return true;
} }
} }
@ -222,18 +231,21 @@ public class EdgeTree {
(cx > maxX && dx > maxX); (cx > maxX && dx > maxX);
if (outside == false) { if (outside == false) {
if (includeBoundary == true && if (includeBoundary == true) {
lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, minY, maxX, minY) || 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, minY, maxX, maxY) ||
lineCrossesLineWithBoundary(cx, cy, dx, dy, maxX, maxY, minX, maxY) || lineCrossesLineWithBoundary(cx, cy, dx, dy, maxX, maxY, minX, maxY) ||
lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, maxY, minX, minY)) { lineCrossesLineWithBoundary(cx, cy, dx, dy, minX, maxY, minX, minY)) {
// include boundaries: ensures box edges that terminate on the polygon are included // include boundaries: ensures box edges that terminate on the polygon are included
return true; return true;
} else if (lineCrossesLine(cx, cy, dx, dy, minX, minY, maxX, minY) || }
lineCrossesLine(cx, cy, dx, dy, maxX, minY, maxX, maxY) || } else {
lineCrossesLine(cx, cy, dx, dy, maxX, maxY, minX, maxY) || if (lineCrossesLine(cx, cy, dx, dy, minX, minY, maxX, minY) ||
lineCrossesLine(cx, cy, dx, dy, minX, maxY, minX, minY)) { lineCrossesLine(cx, cy, dx, dy, maxX, minY, maxX, maxY) ||
return true; 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 // check each corner: if < 4 && > 0 are present, its cheaper than crossesSlowly
int numCorners = numberOfCorners(minX, maxX, minY, maxY); int numCorners = numberOfCorners(minX, maxX, minY, maxY);
if (numCorners == 4) { 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_CROSSES_QUERY;
} }
return Relation.CELL_INSIDE_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)) { if (Component2D.containsPoint(tree.x1, tree.y1, minX, maxX, minY, maxY)) {
return Relation.CELL_CROSSES_QUERY; 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_CROSSES_QUERY;
} }
return Relation.CELL_OUTSIDE_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 // check each corner: if < 3 && > 0 are present, its cheaper than crossesSlowly
int numCorners = numberOfTriangleCorners(ax, ay, bx, by, cx, cy); int numCorners = numberOfTriangleCorners(ax, ay, bx, by, cx, cy);
if (numCorners == 3) { 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_CROSSES_QUERY;
} }
return Relation.CELL_INSIDE_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) { if (Component2D.pointInTriangle(minX, maxX, minY, maxY, tree.x1, tree.y1, ax, ay, bx, by, cx, cy) == true) {
return Relation.CELL_CROSSES_QUERY; 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_CROSSES_QUERY;
} }
return Relation.CELL_OUTSIDE_QUERY; return Relation.CELL_OUTSIDE_QUERY;

View File

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

View File

@ -659,4 +659,44 @@ public class TestLatLonShape extends LuceneTestCase {
quantizeLon(-5), quantizeLat(0)); quantizeLon(-5), quantizeLat(0));
assertEquals(PointValues.Relation.CELL_CROSSES_QUERY, r); 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);
}
} }