mirror of https://github.com/apache/lucene.git
LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic (#2059)
This commit is contained in:
parent
a5d0654a24
commit
44be9f903d
|
@ -253,6 +253,9 @@ Bug Fixes
|
||||||
* LUCENE-9581: Japanese tokenizer should discard the compound token instead of disabling the decomposition
|
* LUCENE-9581: Japanese tokenizer should discard the compound token instead of disabling the decomposition
|
||||||
of long tokens when discardCompoundToken is activated. (Jim Ferenczi)
|
of long tokens when discardCompoundToken is activated. (Jim Ferenczi)
|
||||||
|
|
||||||
|
* LUCENE-9595: Make Component2D#withinPoint implementations consistent with ShapeQuery logic.
|
||||||
|
(Ignacio Vera)
|
||||||
|
|
||||||
Other
|
Other
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,8 @@ final class LatLonShapeBoundingBoxQuery extends ShapeQuery {
|
||||||
|
|
||||||
switch (scratchTriangle.type) {
|
switch (scratchTriangle.type) {
|
||||||
case POINT: {
|
case POINT: {
|
||||||
return Component2D.WithinRelation.DISJOINT;
|
return encodedRectangle.contains(scratchTriangle.aX, scratchTriangle.aY)
|
||||||
|
? Component2D.WithinRelation.NOTWITHIN : Component2D.WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
case LINE: {
|
case LINE: {
|
||||||
return encodedRectangle.withinLine(scratchTriangle.aX, scratchTriangle.aY, scratchTriangle.ab,
|
return encodedRectangle.withinLine(scratchTriangle.aX, scratchTriangle.aY, scratchTriangle.ab,
|
||||||
|
|
|
@ -110,7 +110,7 @@ class Circle2D implements Component2D {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinPoint(double x, double y) {
|
public WithinRelation withinPoint(double x, double y) {
|
||||||
return WithinRelation.DISJOINT;
|
return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -129,13 +129,15 @@ final class Line2D implements Component2D {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinPoint(double x, double y) {
|
public WithinRelation withinPoint(double x, double y) {
|
||||||
return WithinRelation.DISJOINT;
|
return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
|
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
|
||||||
double aX, double aY, boolean ab, double bX, double bY) {
|
double aX, double aY, boolean ab, double bX, double bY) {
|
||||||
// can be improved?
|
if (ab && intersectsLine(minX, maxX, minY, maxY, aX, aY, bX, bY)) {
|
||||||
|
return WithinRelation.NOTWITHIN;
|
||||||
|
}
|
||||||
return WithinRelation.DISJOINT;
|
return WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ final class Polygon2D implements Component2D {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinPoint(double x, double y) {
|
public WithinRelation withinPoint(double x, double y) {
|
||||||
return WithinRelation.DISJOINT;
|
return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -118,13 +118,13 @@ final class Rectangle2D implements Component2D {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinPoint(double x, double y) {
|
public WithinRelation withinPoint(double x, double y) {
|
||||||
return WithinRelation.DISJOINT;
|
return contains(x, y) ? WithinRelation.NOTWITHIN : WithinRelation.DISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
|
public WithinRelation withinLine(double minX, double maxX, double minY, double maxY,
|
||||||
double aX, double aY, boolean ab, double bX, double bY) {
|
double aX, double aY, boolean ab, double bX, double bY) {
|
||||||
if (ab == true && Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY) ==false &&
|
if (ab == true && Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY) == false &&
|
||||||
edgesIntersect(aX, aY, bX, bY)) {
|
edgesIntersect(aX, aY, bX, bY)) {
|
||||||
return WithinRelation.NOTWITHIN;
|
return WithinRelation.NOTWITHIN;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.geo.GeoUtils;
|
||||||
import org.apache.lucene.geo.LatLonGeometry;
|
import org.apache.lucene.geo.LatLonGeometry;
|
||||||
import org.apache.lucene.geo.Line;
|
import org.apache.lucene.geo.Line;
|
||||||
import org.apache.lucene.geo.Polygon;
|
import org.apache.lucene.geo.Polygon;
|
||||||
|
import org.apache.lucene.geo.Rectangle;
|
||||||
import org.apache.lucene.geo.Tessellator;
|
import org.apache.lucene.geo.Tessellator;
|
||||||
import org.apache.lucene.index.DirectoryReader;
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
import org.apache.lucene.index.IndexReader;
|
import org.apache.lucene.index.IndexReader;
|
||||||
|
@ -827,4 +828,49 @@ public class TestLatLonShape extends LuceneTestCase {
|
||||||
|
|
||||||
IOUtils.close(r, dir);
|
IOUtils.close(r, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testContainsIndexedGeometryCollection() throws Exception {
|
||||||
|
Directory dir = newDirectory();
|
||||||
|
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
|
||||||
|
Polygon polygon = new Polygon(new double[] {-64, -64, 64, 64, -64}, new double[] {-132, 132, 132, -132, -132});
|
||||||
|
Field[] polygonFields = LatLonShape.createIndexableFields(FIELDNAME, polygon);
|
||||||
|
// POINT(5, 5) inside the indexed polygon
|
||||||
|
Field[] pointFields = LatLonShape.createIndexableFields(FIELDNAME, 5, 5);
|
||||||
|
int numDocs = random().nextInt(1000);
|
||||||
|
// index the same multi geometry many times
|
||||||
|
for (int i = 0; i < numDocs; i++) {
|
||||||
|
Document doc = new Document();
|
||||||
|
for (Field f : polygonFields) {
|
||||||
|
doc.add(f);
|
||||||
|
}
|
||||||
|
for(int j = 0; j < 10; j++) {
|
||||||
|
for (Field f : pointFields) {
|
||||||
|
doc.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.addDocument(doc);
|
||||||
|
}
|
||||||
|
w.forceMerge(1);
|
||||||
|
|
||||||
|
///// search //////
|
||||||
|
IndexReader reader = w.getReader();
|
||||||
|
w.close();
|
||||||
|
IndexSearcher searcher = newSearcher(reader);
|
||||||
|
// Contains is only true if the query geometry is inside a geometry and does not intersect with any other geometry
|
||||||
|
// belonging to the same document. In this case the query geometry contains the indexed polygon but the point is
|
||||||
|
// inside the query as well, hence the result is 0.
|
||||||
|
Polygon polygonQuery = new Polygon(new double[] {4, 4, 6, 6, 4}, new double[] {4, 6, 6, 4, 4});
|
||||||
|
Query query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, polygonQuery);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
Rectangle rectangle = new Rectangle(4.0, 6.0, 4.0, 6.0);
|
||||||
|
query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, rectangle);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
Circle circle = new Circle(5, 5, 10000);
|
||||||
|
query = LatLonShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
IOUtils.close(w, reader, dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,6 +202,51 @@ public class TestXYShape extends LuceneTestCase {
|
||||||
IOUtils.close(r, dir);
|
IOUtils.close(r, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testContainsIndexedGeometryCollection() throws Exception {
|
||||||
|
Directory dir = newDirectory();
|
||||||
|
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
|
||||||
|
XYPolygon polygon = new XYPolygon(new float[] {-132, 132, 132, -132, -132}, new float[] {-64, -64, 64, 64, -64});
|
||||||
|
Field[] polygonFields = XYShape.createIndexableFields(FIELDNAME, polygon);
|
||||||
|
// POINT(5, 5) inside the indexed polygon
|
||||||
|
Field[] pointFields = XYShape.createIndexableFields(FIELDNAME, 5, 5);
|
||||||
|
int numDocs = random().nextInt(1000);
|
||||||
|
// index the same multi geometry many times
|
||||||
|
for (int i = 0; i < numDocs; i++) {
|
||||||
|
Document doc = new Document();
|
||||||
|
for (Field f : polygonFields) {
|
||||||
|
doc.add(f);
|
||||||
|
}
|
||||||
|
for(int j = 0; j < 10; j++) {
|
||||||
|
for (Field f : pointFields) {
|
||||||
|
doc.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.addDocument(doc);
|
||||||
|
}
|
||||||
|
w.forceMerge(1);
|
||||||
|
|
||||||
|
///// search //////
|
||||||
|
IndexReader reader = w.getReader();
|
||||||
|
w.close();
|
||||||
|
IndexSearcher searcher = newSearcher(reader);
|
||||||
|
// Contains is only true if the query geometry is inside a geometry and does not intersect with any other geometry
|
||||||
|
// belonging to the same document. In this case the query geometry contains the indexed polygon but the point is
|
||||||
|
// inside the query as well, hence the result is 0.
|
||||||
|
XYPolygon polygonQuery = new XYPolygon(new float[] {4, 6, 6, 4, 4}, new float[] {4, 4, 6, 6, 4});
|
||||||
|
Query query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, polygonQuery);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
XYRectangle rectangle = new XYRectangle(4, 6, 4, 6);
|
||||||
|
query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, rectangle);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
XYCircle circle = new XYCircle(5, 5, 1);
|
||||||
|
query = XYShape.newGeometryQuery(FIELDNAME, QueryRelation.CONTAINS, circle);
|
||||||
|
assertEquals(0, searcher.count(query));
|
||||||
|
|
||||||
|
IOUtils.close(w, reader, dir);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean areBoxDisjoint(XYRectangle r1, XYRectangle r2) {
|
private static boolean areBoxDisjoint(XYRectangle r1, XYRectangle r2) {
|
||||||
return ( r1.minX <= r2.minX && r1.minY <= r2.minY && r1.maxX >= r2.maxX && r1.maxY >= r2.maxY);
|
return ( r1.minX <= r2.minX && r1.minY <= r2.minY && r1.maxX >= r2.maxX && r1.maxY >= r2.maxY);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue