mirror of https://github.com/apache/lucene.git
LUCENE-9250: Add support for Circle2d#intersectsLine around the dateline. (#1289)
This commit is contained in:
parent
3ad9915547
commit
988ce9bff7
|
@ -208,6 +208,8 @@ Bug Fixes
|
|||
so an query for UNORDERED(foo, foo) would match a document containing 'foo'
|
||||
only once. (Alan Woodward)
|
||||
|
||||
* LUCENE-9250: Add support for Circle2d#intersectsLine around the dateline. (Ignacio Vera)
|
||||
|
||||
Other
|
||||
---------------------
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ class Circle2D implements Component2D {
|
|||
// if any of the edges intersects an the edge belongs to the shape then it cannot be within.
|
||||
// if it only intersects edges that do not belong to the shape, then it is a candidate
|
||||
// we skip edges at the dateline to support shapes crossing it
|
||||
if (intersectsLine(ax, ay, bx, by)) {
|
||||
if (calculator.intersectsLine(ax, ay, bx, by)) {
|
||||
if (ab == true) {
|
||||
return WithinRelation.NOTWITHIN;
|
||||
} else {
|
||||
|
@ -120,14 +120,14 @@ class Circle2D implements Component2D {
|
|||
}
|
||||
}
|
||||
|
||||
if (intersectsLine(bx, by, cx, cy)) {
|
||||
if (calculator.intersectsLine(bx, by, cx, cy)) {
|
||||
if (bc == true) {
|
||||
return WithinRelation.NOTWITHIN;
|
||||
} else {
|
||||
relation = WithinRelation.CANDIDATE;
|
||||
}
|
||||
}
|
||||
if (intersectsLine(cx, cy, ax, ay)) {
|
||||
if (calculator.intersectsLine(cx, cy, ax, ay)) {
|
||||
if (ca == true) {
|
||||
return WithinRelation.NOTWITHIN;
|
||||
} else {
|
||||
|
@ -162,7 +162,7 @@ class Circle2D implements Component2D {
|
|||
if (numCorners == 2) {
|
||||
return Relation.CELL_INSIDE_QUERY;
|
||||
} else if (numCorners == 0) {
|
||||
if (intersectsLine(a2x, a2y, b2x, b2y)) {
|
||||
if (calculator.intersectsLine(a2x, a2y, b2x, b2y)) {
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
}
|
||||
return Relation.CELL_OUTSIDE_QUERY;
|
||||
|
@ -181,9 +181,9 @@ class Circle2D implements Component2D {
|
|||
if (Component2D.pointInTriangle(minX, maxX, minY, maxY, calculator.geX(), calculator.getY(), ax, ay, bx, by, cx, cy) == true) {
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
}
|
||||
if (intersectsLine(ax, ay, bx, by) ||
|
||||
intersectsLine(bx, by, cx, cy) ||
|
||||
intersectsLine(cx, cy, ax, ay)) {
|
||||
if (calculator.intersectsLine(ax, ay, bx, by) ||
|
||||
calculator.intersectsLine(bx, by, cx, cy) ||
|
||||
calculator.intersectsLine(cx, cy, ax, ay)) {
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
}
|
||||
return Relation.CELL_OUTSIDE_QUERY;
|
||||
|
@ -210,14 +210,16 @@ class Circle2D implements Component2D {
|
|||
return containsCount;
|
||||
}
|
||||
|
||||
// This methods in a new helper class XYUtil?
|
||||
private boolean intersectsLine(double aX, double aY, double bX, double bY) {
|
||||
private static boolean intersectsLine(double centerX, double centerY, double aX, double aY, double bX, double bY, DistanceCalculator calculator) {
|
||||
//Algorithm based on this thread : https://stackoverflow.com/questions/3120357/get-closest-point-to-a-line
|
||||
final double[] vectorAP = new double[] {calculator.geX() - aX, calculator.getY() - aY};
|
||||
final double[] vectorAB = new double[] {bX - aX, bY - aY};
|
||||
final double vectorAPX = centerX - aX;
|
||||
final double vectorAPY = centerY - aY;
|
||||
|
||||
final double magnitudeAB = vectorAB[0] * vectorAB[0] + vectorAB[1] * vectorAB[1];
|
||||
final double dotProduct = vectorAP[0] * vectorAB[0] + vectorAP[1] * vectorAB[1];
|
||||
final double vectorABX = bX - aX;
|
||||
final double vectorABY = bY - aY;
|
||||
|
||||
final double magnitudeAB = vectorABX * vectorABX + vectorABY * vectorABY;
|
||||
final double dotProduct = vectorAPX * vectorABX + vectorAPY * vectorABY;
|
||||
|
||||
final double distance = dotProduct / magnitudeAB;
|
||||
|
||||
|
@ -225,8 +227,8 @@ class Circle2D implements Component2D {
|
|||
return false;
|
||||
}
|
||||
|
||||
final double pX = aX + vectorAB[0] * distance;
|
||||
final double pY = aY + vectorAB[1] * distance;
|
||||
final double pX = aX + vectorABX * distance;
|
||||
final double pY = aY + vectorABY * distance;
|
||||
|
||||
final double minX = StrictMath.min(aX, bX);
|
||||
final double minY = StrictMath.min(aY, bY);
|
||||
|
@ -234,31 +236,34 @@ class Circle2D implements Component2D {
|
|||
final double maxY = StrictMath.max(aY, bY);
|
||||
|
||||
if (pX >= minX && pX <= maxX && pY >= minY && pY <= maxY) {
|
||||
return contains(pX, pY);
|
||||
return calculator.contains(pX, pY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private interface DistanceCalculator {
|
||||
|
||||
Relation relate(double minX, double maxX, double minY, double maxY);
|
||||
|
||||
/** check if the point is within a distance */
|
||||
boolean contains(double x, double y);
|
||||
|
||||
/** check if the line is within a distance */
|
||||
boolean intersectsLine(double aX, double aY, double bX, double bY);
|
||||
/** Relates this calculator to the provided bounding box */
|
||||
Relation relate(double minX, double maxX, double minY, double maxY);
|
||||
/** check if the bounding box is disjoint with this calculator bounding box */
|
||||
boolean disjoint(double minX, double maxX, double minY, double maxY);
|
||||
|
||||
/** check if the bounding box is contains this calculator bounding box */
|
||||
boolean within(double minX, double maxX, double minY, double maxY);
|
||||
|
||||
/** get min X of this calculator */
|
||||
double getMinX();
|
||||
|
||||
/** get max X of this calculator */
|
||||
double getMaxX();
|
||||
|
||||
/** get min Y of this calculator */
|
||||
double getMinY();
|
||||
|
||||
/** get max Y of this calculator */
|
||||
double getMaxY();
|
||||
|
||||
/** get center X */
|
||||
double geX();
|
||||
|
||||
/** get center Y */
|
||||
double getY();
|
||||
}
|
||||
|
||||
|
@ -321,6 +326,11 @@ class Circle2D implements Component2D {
|
|||
return diffX * diffX + diffY * diffY <= radiusSquared;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean intersectsLine(double aX, double aY, double bX, double bY) {
|
||||
return Circle2D.intersectsLine(centerX, centerY, aX, aY, bX, bY, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disjoint(double minX, double maxX, double minY, double maxY) {
|
||||
return Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY);
|
||||
|
@ -390,6 +400,19 @@ class Circle2D implements Component2D {
|
|||
return SloppyMath.haversinSortKey(y, x, this.centerLat, this.centerLon) <= sortKey;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean intersectsLine(double aX, double aY, double bX, double bY) {
|
||||
if (Circle2D.intersectsLine(centerLon, centerLat, aX, aY, bX, bY, this)) {
|
||||
return true;
|
||||
}
|
||||
if (crossesDateline) {
|
||||
double newCenterLon = (centerLon > 0) ? centerLon - 360 : centerLon + 360;
|
||||
return Circle2D.intersectsLine(newCenterLon, centerLat, aX, aY, bX, bY, this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disjoint(double minX, double maxX, double minY, double maxY) {
|
||||
if (crossesDateline) {
|
||||
|
|
|
@ -60,6 +60,19 @@ public class TestCircle2D extends LuceneTestCase {
|
|||
assertEquals(Component2D.WithinRelation.NOTWITHIN, circle2D.withinTriangle(ax, ay, true, bx, by, true, cx, cy, true));
|
||||
}
|
||||
|
||||
public void testTriangleDateLineIntersects() {
|
||||
Component2D circle2D = LatLonGeometry.create(new Circle(0, 179, 222400));
|
||||
double ax = -179;
|
||||
double ay = 1;
|
||||
double bx = -179;
|
||||
double by = -1;
|
||||
double cx = -178;
|
||||
double cy = 0;
|
||||
// we just touch the edge from the dateline
|
||||
assertEquals(PointValues.Relation.CELL_CROSSES_QUERY, circle2D.relateTriangle(ax, ay, bx, by , cx, cy));
|
||||
assertEquals(Component2D.WithinRelation.NOTWITHIN, circle2D.withinTriangle(ax, ay, true, bx, by, true, cx, cy, true));
|
||||
}
|
||||
|
||||
public void testTriangleContains() {
|
||||
Component2D circle2D;
|
||||
if (random().nextBoolean()) {
|
||||
|
|
Loading…
Reference in New Issue