mirror of https://github.com/apache/lucene.git
committing Karl's latest LUCENE-6196-fixes.patch
https://issues.apache.org/jira/secure/attachment/12725741/LUCENE-6196-fixes.patch WIP; tests fail git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene6196@1674049 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
400c39bac7
commit
b2c273fa7a
|
@ -221,4 +221,11 @@ public class GeoCircle extends GeoBaseExtendedShape implements GeoDistanceShape,
|
|||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Circle: center = ");
|
||||
sb.append(center).append(" radius = ").append(cutoffAngle);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,8 +129,14 @@ public class GeoConvexPolygon extends GeoBaseExtendedShape implements GeoMembers
|
|||
|
||||
// Let's be sure that our interior point is really inside
|
||||
for (SidedPlane sp : edges) {
|
||||
if (!sp.isWithin(interiorPoint))
|
||||
throw new IllegalArgumentException("Interior point logic failed to produce an interior point");
|
||||
if (!sp.isWithin(interiorPoint)) {
|
||||
StringBuilder sb = new StringBuilder("Interior point logic failed to produce an interior point. Vertices: ");
|
||||
for (GeoPoint p : points) {
|
||||
sb.append(p).append(" ");
|
||||
}
|
||||
sb.append(". Interior point: ").append(interiorPoint);
|
||||
throw new IllegalArgumentException(sb.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,11 @@ public class GeoDegenerateHorizontalLine implements GeoBBox
|
|||
this.RHC = new GeoPoint(sinLatitude,sinRightLon,cosLatitude,cosRightLon);
|
||||
|
||||
this.plane = new Plane(sinLatitude);
|
||||
|
||||
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
double sinMiddleLon = Math.sin(middleLon);
|
||||
double cosMiddleLon = Math.cos(middleLon);
|
||||
|
|
|
@ -43,12 +43,13 @@ public class GeoLatitudeZone implements GeoBBox
|
|||
Vector topPoint = new Vector(0.0,0.0,sinTopLat);
|
||||
Vector bottomPoint = new Vector(0.0,0.0,sinBottomLat);
|
||||
|
||||
this.topPlane = new SidedPlane(bottomPoint,sinTopLat);
|
||||
this.bottomPlane = new SidedPlane(topPoint,sinBottomLat);
|
||||
|
||||
// Compute an interior point. Pick one whose lat is between top and bottom.
|
||||
double sinMiddleLat = (topLat + bottomLat) * 0.5;
|
||||
double middleLat = (topLat + bottomLat) * 0.5;
|
||||
double sinMiddleLat = Math.sin(middleLat);
|
||||
interiorPoint = new GeoPoint(Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat),0.0,sinMiddleLat);
|
||||
|
||||
this.topPlane = new SidedPlane(interiorPoint,sinTopLat);
|
||||
this.bottomPlane = new SidedPlane(interiorPoint,sinBottomLat);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,10 +118,6 @@ public class GeoLatitudeZone implements GeoBBox
|
|||
|
||||
@Override
|
||||
public int getRelationship(GeoShape path) {
|
||||
// First observation: The only way you can draw a path that
|
||||
// contains this area is to have an unbounded path that circles the globe.
|
||||
// So we will never return CONTAINS.
|
||||
|
||||
// Second, the shortcut of seeing whether endpoints are in/out is not going to
|
||||
// work with no area endpoints. So we rely entirely on intersections.
|
||||
|
||||
|
@ -128,6 +125,9 @@ public class GeoLatitudeZone implements GeoBBox
|
|||
path.intersects(bottomPlane,topPlane))
|
||||
return OVERLAPS;
|
||||
|
||||
if (path.isWithin(interiorPoint))
|
||||
return CONTAINS;
|
||||
|
||||
if (isWithin(path.getInteriorPoint()))
|
||||
return WITHIN;
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ public class GeoLongitudeSlice implements GeoBBox
|
|||
double sinRightLon = Math.sin(rightLon);
|
||||
double cosRightLon = Math.cos(rightLon);
|
||||
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
centerPoint = new GeoPoint(0.0,middleLon);
|
||||
|
||||
|
@ -134,22 +138,19 @@ public class GeoLongitudeSlice implements GeoBBox
|
|||
|
||||
@Override
|
||||
public int getRelationship(GeoShape path) {
|
||||
// It's possible to contain this area. The way we do this is to
|
||||
// see whether the shape contains both the north and south poles. If it does,
|
||||
// we make the assumption that it contains the entire shape (which is
|
||||
// a convenient approximation that, at worst, increases our computation).
|
||||
if (path.isWithin(0.0,0.0,Math.PI * 0.5) &&
|
||||
path.isWithin(0.0,0.0,-Math.PI * 0.5))
|
||||
return CONTAINS;
|
||||
|
||||
// Next, look for intersections.
|
||||
if (path.intersects(leftPlane,rightPlane) ||
|
||||
path.intersects(rightPlane,leftPlane))
|
||||
path.intersects(rightPlane,leftPlane)) {
|
||||
return OVERLAPS;
|
||||
}
|
||||
|
||||
if (isWithin(path.getInteriorPoint()))
|
||||
if (isWithin(path.getInteriorPoint())) {
|
||||
return WITHIN;
|
||||
}
|
||||
|
||||
if (path.isWithin(centerPoint)) {
|
||||
return CONTAINS;
|
||||
}
|
||||
|
||||
return DISJOINT;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,11 @@ public class GeoPath extends GeoBaseExtendedShape implements GeoDistanceShape
|
|||
points.add(se);
|
||||
}
|
||||
|
||||
public void done() {
|
||||
if (points.size() == 0)
|
||||
throw new IllegalArgumentException("Path must have at least one point");
|
||||
}
|
||||
|
||||
/** Compute an estimate of "distance" to the GeoPoint.
|
||||
* A return value of Double.MAX_VALUE should be returned for
|
||||
* points outside of the shape.
|
||||
|
|
|
@ -96,6 +96,11 @@ public class GeoPolygonFactory
|
|||
// Handle exclusion
|
||||
recursionList.add(newPoint);
|
||||
recursionList.add(currentList.get(currentList.size()-1));
|
||||
if (recursionList.size() == pointsList.size()) {
|
||||
// We are trying to recurse with a list the same size as the one we started with.
|
||||
// Clearly, the polygon cannot be constructed
|
||||
throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
|
||||
}
|
||||
// We want the other side for the recursion
|
||||
SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
|
||||
rval.addShape(buildPolygonShape(recursionList,recursionList.size()-2,recursionList.size()-1,otherSideNewBoundary));
|
||||
|
@ -115,6 +120,11 @@ public class GeoPolygonFactory
|
|||
// The last step back to the start point had a recursion, so take care of that before we complete our work
|
||||
recursionList.add(currentList.get(0));
|
||||
recursionList.add(currentList.get(currentList.size()-1));
|
||||
if (recursionList.size() == pointsList.size()) {
|
||||
// We are trying to recurse with a list the same size as the one we started with.
|
||||
// Clearly, the polygon cannot be constructed
|
||||
throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
|
||||
}
|
||||
// Construct a sided plane based on these two points, and the previous point
|
||||
SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size()-2),currentList.get(0),currentList.get(currentList.size()-1));
|
||||
// We want the other side for the recursion
|
||||
|
|
|
@ -86,6 +86,10 @@ public class GeoRectangle implements GeoBBox
|
|||
double middleLat = (topLat + bottomLat) * 0.5;
|
||||
double sinMiddleLat = Math.sin(middleLat);
|
||||
cosMiddleLat = Math.cos(middleLat);
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
double sinMiddleLon = Math.sin(middleLon);
|
||||
double cosMiddleLon = Math.cos(middleLon);
|
||||
|
@ -181,29 +185,6 @@ public class GeoRectangle implements GeoBBox
|
|||
|
||||
@Override
|
||||
public int getRelationship(GeoShape path) {
|
||||
// There are many cases here. I'll go through them in order
|
||||
boolean ulhcWithin = path.isWithin(ULHC);
|
||||
boolean urhcWithin = path.isWithin(URHC);
|
||||
boolean lrhcWithin = path.isWithin(LRHC);
|
||||
boolean llhcWithin = path.isWithin(LLHC);
|
||||
|
||||
// If there are some that are in, and some that are out, we've got overlap. Otherwise, things are different.
|
||||
if (ulhcWithin && urhcWithin && lrhcWithin && llhcWithin) {
|
||||
// It's not precisely correct, but at this point we CHOOSE to claim that the entire rectangle is within the path.
|
||||
// This in practice will mean that we generate more geotokens than are strictly needed, but otherwise this case
|
||||
// would be expensive to disentangle.
|
||||
return CONTAINS;
|
||||
}
|
||||
|
||||
if (ulhcWithin || urhcWithin || lrhcWithin || llhcWithin) {
|
||||
// Some are in, some are out: definite overlap
|
||||
return OVERLAPS;
|
||||
}
|
||||
|
||||
// All rectangle endpoints are outside the path. The three possible cases are WITHIN, OVERLAPS, and DISJOINT.
|
||||
// The only way to distinguish between them is to look at whether any of the four rectangle sides intersect
|
||||
// the path edges. If there is no intersection, AND any path point is within the rectangle, THEN return WITHIN.
|
||||
|
||||
if (path.intersects(topPlane,bottomPlane,leftPlane,rightPlane) ||
|
||||
path.intersects(bottomPlane,topPlane,leftPlane,rightPlane) ||
|
||||
path.intersects(leftPlane,topPlane,bottomPlane,rightPlane) ||
|
||||
|
@ -213,6 +194,9 @@ public class GeoRectangle implements GeoBBox
|
|||
if (isWithin(path.getInteriorPoint()))
|
||||
return WITHIN;
|
||||
|
||||
if (path.isWithin(centerPoint))
|
||||
return CONTAINS;
|
||||
|
||||
return DISJOINT;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,11 @@ public class GeoWideDegenerateHorizontalLine implements GeoBBox
|
|||
this.RHC = new GeoPoint(sinLatitude,sinRightLon,cosLatitude,cosRightLon);
|
||||
|
||||
this.plane = new Plane(sinLatitude);
|
||||
|
||||
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
double sinMiddleLon = Math.sin(middleLon);
|
||||
double cosMiddleLon = Math.cos(middleLon);
|
||||
|
|
|
@ -54,7 +54,11 @@ public class GeoWideLongitudeSlice implements GeoBBox
|
|||
double cosLeftLon = Math.cos(leftLon);
|
||||
double sinRightLon = Math.sin(rightLon);
|
||||
double cosRightLon = Math.cos(rightLon);
|
||||
|
||||
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
centerPoint = new GeoPoint(0.0,middleLon);
|
||||
|
||||
|
@ -136,15 +140,6 @@ public class GeoWideLongitudeSlice implements GeoBBox
|
|||
|
||||
@Override
|
||||
public int getRelationship(GeoShape path) {
|
||||
// It's possible to contain this area. The way we do this is to
|
||||
// see whether the shape contains both the north and south poles. If it does,
|
||||
// we make the assumption that it contains the entire shape (which is
|
||||
// a convenient approximation that, at worst, increases our computation).
|
||||
if (path.isWithin(0.0,0.0,Math.PI * 0.5) &&
|
||||
path.isWithin(0.0,0.0,-Math.PI * 0.5))
|
||||
return CONTAINS;
|
||||
|
||||
// Next, look for intersections. No bounds because it is a wide variant.
|
||||
if (path.intersects(leftPlane) ||
|
||||
path.intersects(rightPlane))
|
||||
return OVERLAPS;
|
||||
|
@ -152,6 +147,9 @@ public class GeoWideLongitudeSlice implements GeoBBox
|
|||
if (isWithin(path.getInteriorPoint()))
|
||||
return WITHIN;
|
||||
|
||||
if (path.isWithin(centerPoint))
|
||||
return CONTAINS;
|
||||
|
||||
return DISJOINT;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,10 @@ public class GeoWideRectangle implements GeoBBox
|
|||
double middleLat = (topLat + bottomLat) * 0.5;
|
||||
double sinMiddleLat = Math.sin(middleLat);
|
||||
cosMiddleLat = Math.cos(middleLat);
|
||||
// Normalize
|
||||
while (leftLon > rightLon) {
|
||||
rightLon += Math.PI * 2.0;
|
||||
}
|
||||
double middleLon = (leftLon + rightLon) * 0.5;
|
||||
double sinMiddleLon = Math.sin(middleLon);
|
||||
double cosMiddleLon = Math.cos(middleLon);
|
||||
|
@ -187,29 +191,6 @@ public class GeoWideRectangle implements GeoBBox
|
|||
|
||||
@Override
|
||||
public int getRelationship(GeoShape path) {
|
||||
// There are many cases here. I'll go through them in order
|
||||
boolean ulhcWithin = path.isWithin(ULHC);
|
||||
boolean urhcWithin = path.isWithin(URHC);
|
||||
boolean lrhcWithin = path.isWithin(LRHC);
|
||||
boolean llhcWithin = path.isWithin(LLHC);
|
||||
|
||||
// If there are some that are in, and some that are out, we've got overlap. Otherwise, things are different.
|
||||
if (ulhcWithin && urhcWithin && lrhcWithin && llhcWithin) {
|
||||
// It's not precisely correct, but at this point we CHOOSE to claim that the entire rectangle is within the path.
|
||||
// This in practice will mean that we generate more geotokens than are strictly needed, but otherwise this case
|
||||
// would be expensive to disentangle.
|
||||
return CONTAINS;
|
||||
}
|
||||
|
||||
if (ulhcWithin || urhcWithin || lrhcWithin || llhcWithin) {
|
||||
// Some are in, some are out: definite overlap
|
||||
return OVERLAPS;
|
||||
}
|
||||
|
||||
// All rectangle endpoints are outside the path. The three possible cases are WITHIN, OVERLAPS, and DISJOINT.
|
||||
// The only way to distinguish between them is to look at whether any of the four rectangle sides intersect
|
||||
// the path edges. If there is no intersection, AND any path point is within the rectangle, THEN return WITHIN.
|
||||
|
||||
if (path.intersects(topPlane,bottomPlane,eitherBound) ||
|
||||
path.intersects(bottomPlane,topPlane,eitherBound) ||
|
||||
path.intersects(leftPlane,topPlane,bottomPlane) ||
|
||||
|
@ -219,6 +200,9 @@ public class GeoWideRectangle implements GeoBBox
|
|||
if (isWithin(path.getInteriorPoint()))
|
||||
return WITHIN;
|
||||
|
||||
if (path.isWithin(centerPoint))
|
||||
return CONTAINS;
|
||||
|
||||
return DISJOINT;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ import org.apache.lucene.spatial.spatial4j.Geo3dShape;
|
|||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoPoint;
|
||||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoPolygonFactory;
|
||||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoShape;
|
||||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoCircle;
|
||||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoPath;
|
||||
import org.apache.lucene.spatial.spatial4j.geo3d.GeoBBoxFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.spatial4j.core.distance.DistanceUtils.DEGREES_TO_RADIANS;
|
||||
|
@ -91,6 +94,14 @@ public class Geo3dRptTest extends RandomSpatialOpStrategyTestCase {
|
|||
|
||||
@Test
|
||||
public void testTriangleDisjointRect() throws IOException {
|
||||
setupStrategy();
|
||||
Rectangle rect = ctx.makeRectangle(-180, 180, 77, 84);
|
||||
Shape triangle = makeTriangle(-149, 35, 88, -11, -27, -18);
|
||||
assertTrue(rect.relate(triangle).intersects()); //unsure if this is correct or not but passes
|
||||
//if they intersect, then the following rect cell can be "within" the triangle
|
||||
final Rectangle cellRect = ctx.makeRectangle(-180, -168.75, 73.125, 78.75);
|
||||
assert cellRect.relate(rect).intersects();
|
||||
//assertTrue(cellRect.relate(triangle) != SpatialRelation.WITHIN);
|
||||
}
|
||||
|
||||
private Shape makeTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
|
||||
|
@ -110,17 +121,85 @@ public class Geo3dRptTest extends RandomSpatialOpStrategyTestCase {
|
|||
|
||||
@Override
|
||||
protected Shape randomQueryShape() {
|
||||
//random triangle
|
||||
final List<GeoPoint> geoPoints = new ArrayList<>();
|
||||
while (geoPoints.size() < 3) {
|
||||
final Point point = randomPoint();
|
||||
final GeoPoint gPt = new GeoPoint(point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS);
|
||||
if (geoPoints.contains(gPt) == false) {
|
||||
geoPoints.add(gPt);
|
||||
final int shapeType = random().nextInt(4);
|
||||
switch (shapeType) {
|
||||
case 0: {
|
||||
// Polygons
|
||||
final int vertexCount = random().nextInt(3) + 3;
|
||||
while (true) {
|
||||
final List<GeoPoint> geoPoints = new ArrayList<>();
|
||||
while (geoPoints.size() < vertexCount) {
|
||||
final Point point = randomPoint();
|
||||
final GeoPoint gPt = new GeoPoint(point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS);
|
||||
geoPoints.add(gPt);
|
||||
}
|
||||
final int convexPointIndex = random().nextInt(vertexCount); //If we get this wrong, hopefully we get IllegalArgumentException
|
||||
try {
|
||||
final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(geoPoints, convexPointIndex);
|
||||
return new Geo3dShape(shape, ctx);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
|
||||
// the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 1: {
|
||||
// Circles
|
||||
while (true) {
|
||||
final int circleRadius = random().nextInt(180);
|
||||
final Point point = randomPoint();
|
||||
try {
|
||||
final GeoShape shape = new GeoCircle(point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS,
|
||||
circleRadius * DEGREES_TO_RADIANS);
|
||||
return new Geo3dShape(shape, ctx);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
|
||||
// the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 2: {
|
||||
// Rectangles
|
||||
while (true) {
|
||||
final Point ulhcPoint = randomPoint();
|
||||
final Point lrhcPoint = randomPoint();
|
||||
try {
|
||||
final GeoShape shape = GeoBBoxFactory.makeGeoBBox(ulhcPoint.getY() * DEGREES_TO_RADIANS,
|
||||
lrhcPoint.getY() * DEGREES_TO_RADIANS,
|
||||
ulhcPoint.getX() * DEGREES_TO_RADIANS,
|
||||
lrhcPoint.getX() * DEGREES_TO_RADIANS);
|
||||
return new Geo3dShape(shape, ctx);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
|
||||
// the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3: {
|
||||
// Paths
|
||||
final int pointCount = random().nextInt(5) + 1;
|
||||
final double width = random().nextInt(90) * DEGREES_TO_RADIANS;
|
||||
while (true) {
|
||||
try {
|
||||
final GeoPath path = new GeoPath(width);
|
||||
for (int i = 0; i < pointCount; i++) {
|
||||
final Point nextPoint = randomPoint();
|
||||
path.addPoint(nextPoint.getY() * DEGREES_TO_RADIANS, nextPoint.getX() * DEGREES_TO_RADIANS);
|
||||
}
|
||||
path.done();
|
||||
return new Geo3dShape(path, ctx);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This is what happens when we create a shape that is invalid. Although it is conceivable that there are cases where
|
||||
// the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected shape type");
|
||||
}
|
||||
final int convexPointIndex = random().nextInt(3);
|
||||
final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(geoPoints, convexPointIndex);
|
||||
return new Geo3dShape(shape, ctx);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue