LUCENE-10514: Component2D#Within methods should return NOTWITHIN for triangles within the query geometry (#809)

This commit brings makes sure we always return NOTWITHIN for fully contained triangles in 
Component2D#within* methods
This commit is contained in:
Ignacio Vera 2022-04-20 16:30:29 +02:00 committed by GitHub
parent 15ecf3c27f
commit 4c133f435d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 20 deletions

View File

@ -485,8 +485,11 @@ final class LatLonShapeBoundingBoxQuery extends SpatialQuery {
}
/** Returns the Within relation to the provided triangle */
Component2D.WithinRelation withinLine(int ax, int ay, boolean ab, int bx, int by) {
if (ab == true && edgeIntersectsBox(ax, ay, bx, by, minX, maxX, minY, maxY) == true) {
Component2D.WithinRelation withinLine(int aX, int aY, boolean ab, int bX, int bY) {
if (contains(aX, aY) || contains(bX, bY)) {
return Component2D.WithinRelation.NOTWITHIN;
}
if (ab == true && edgeIntersectsBox(aX, aY, bX, bY, minX, maxX, minY, maxY) == true) {
return Component2D.WithinRelation.NOTWITHIN;
}
return Component2D.WithinRelation.DISJOINT;

View File

@ -159,6 +159,9 @@ class Circle2D implements Component2D {
if (calculator.disjoint(minX, maxX, minY, maxY)) {
return WithinRelation.DISJOINT;
}
if (contains(aX, aY) || contains(bX, bY)) {
return WithinRelation.NOTWITHIN;
}
if (ab == true && calculator.intersectsLine(aX, aY, bX, bY)) {
return WithinRelation.NOTWITHIN;
}

View File

@ -257,10 +257,13 @@ final class Polygon2D implements Component2D {
boolean ab,
double bX,
double bY) {
if (ab == true
&& Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY)
== false
&& tree.crossesLine(minX, maxX, minY, maxY, aX, aY, bX, bY, true)) {
if (Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY)) {
return WithinRelation.DISJOINT;
}
if (contains(aX, aY) || contains(bX, bY)) {
return WithinRelation.NOTWITHIN;
}
if (ab == true && tree.crossesLine(minX, maxX, minY, maxY, aX, aY, bX, bY, true)) {
return WithinRelation.NOTWITHIN;
}
return WithinRelation.DISJOINT;

View File

@ -164,10 +164,13 @@ final class Rectangle2D implements Component2D {
boolean ab,
double bX,
double bY) {
if (ab == true
&& Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY)
== false
&& edgesIntersect(aX, aY, bX, bY)) {
if (Component2D.disjoint(this.minX, this.maxX, this.minY, this.maxY, minX, maxX, minY, maxY)) {
return WithinRelation.DISJOINT;
}
if (contains(aX, aY) || contains(bX, bY)) {
return WithinRelation.NOTWITHIN;
}
if (ab == true && edgesIntersect(aX, aY, bX, bY)) {
return WithinRelation.NOTWITHIN;
}
return WithinRelation.DISJOINT;

View File

@ -22,6 +22,7 @@ import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude;
import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude;
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
import java.io.IOException;
import org.apache.lucene.document.ShapeField.QueryRelation;
import org.apache.lucene.geo.Circle;
import org.apache.lucene.geo.Component2D;
@ -915,24 +916,52 @@ public class TestLatLonShape extends LuceneTestCase {
IOUtils.close(r, dir);
}
public void testContainsIndexedGeometryCollection() throws Exception {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
public void testContainsGeometryCollectionIntersectsPoint() throws Exception {
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);
doTestContainsGeometryCollectionIntersects(
LatLonShape.createIndexableFields(FIELDNAME, polygon),
// point inside the indexed polygon
LatLonShape.createIndexableFields(FIELDNAME, 5, 5));
}
public void testContainsGeometryCollectionIntersectsLine() throws Exception {
Polygon polygon =
new Polygon(
new double[] {-64, -64, 64, 64, -64}, new double[] {-132, 132, 132, -132, -132});
Line line = new Line(new double[] {5, 5.1}, new double[] {5, 5.1});
doTestContainsGeometryCollectionIntersects(
LatLonShape.createIndexableFields(FIELDNAME, polygon),
// Line inside the polygon
LatLonShape.createIndexableFields(FIELDNAME, line));
}
public void testContainsGeometryCollectionIntersectsPolygon() throws Exception {
Polygon polygon =
new Polygon(
new double[] {-64, -64, 64, 64, -64}, new double[] {-132, 132, 132, -132, -132});
Polygon polygonInside =
new Polygon(new double[] {5, 5, 5.1, 5.1, 5}, new double[] {5, 5.1, 5.1, 5, 5});
doTestContainsGeometryCollectionIntersects(
LatLonShape.createIndexableFields(FIELDNAME, polygon),
// this polygon is inside the other polygon
LatLonShape.createIndexableFields(FIELDNAME, polygonInside));
}
private void doTestContainsGeometryCollectionIntersects(
Field[] containsFields, Field[] intersectsField) throws IOException {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
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) {
for (Field f : containsFields) {
doc.add(f);
}
for (int j = 0; j < 10; j++) {
for (Field f : pointFields) {
for (Field f : intersectsField) {
doc.add(f);
}
}
@ -946,8 +975,8 @@ public class TestLatLonShape extends LuceneTestCase {
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
// belonging to the same document. In this case the query geometry contains the indexed fields
// but the intersectsFields are
// 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);