mirror of https://github.com/apache/lucene.git
LUCENE-9055: Fix the detection of lines crossing triangles through edge points (#1020)
This commit is contained in:
parent
db11e9e9a2
commit
17ef175224
|
@ -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
|
||||||
---------------------
|
---------------------
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue