LUCENE-6196: committing Karl's latest patch

https://reviews.apache.org/r/33509/ (diff #6)


git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene6196@1677205 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
David Wayne Smiley 2015-05-01 18:49:49 +00:00
parent 40daf30a83
commit c561d376bc
10 changed files with 321 additions and 93 deletions

View File

@ -187,7 +187,8 @@ public class Bounds
double testRightLongitude = rightLongitude; double testRightLongitude = rightLongitude;
if (testRightLongitude < leftLongitude) if (testRightLongitude < leftLongitude)
testRightLongitude += Math.PI * 2.0; testRightLongitude += Math.PI * 2.0;
if (testRightLongitude - leftLongitude >= Math.PI * 2.0) { // If the bound exceeds 180 degrees, we know we could have screwed up.
if (testRightLongitude - leftLongitude >= Math.PI) {
noLongitudeBound = true; noLongitudeBound = true;
leftLongitude = null; leftLongitude = null;
rightLongitude = null; rightLongitude = null;
@ -244,7 +245,7 @@ public class Bounds
double testRightLongitude = rightLongitude; double testRightLongitude = rightLongitude;
if (testRightLongitude < leftLongitude) if (testRightLongitude < leftLongitude)
testRightLongitude += Math.PI * 2.0; testRightLongitude += Math.PI * 2.0;
if (testRightLongitude - leftLongitude >= Math.PI * 2.0) { if (testRightLongitude - leftLongitude >= Math.PI) {
noLongitudeBound = true; noLongitudeBound = true;
leftLongitude = null; leftLongitude = null;
rightLongitude = null; rightLongitude = null;

View File

@ -229,7 +229,7 @@ public class GeoConvexPolygon extends GeoBaseExtendedShape implements GeoMembers
edge.recordBounds(bounds,membershipBounds); edge.recordBounds(bounds,membershipBounds);
} }
if (fullDistance >= Math.PI * 0.5) { if (fullDistance >= Math.PI) {
// We can't reliably assume that bounds did its longitude calculation right, so we force it to be unbounded. // We can't reliably assume that bounds did its longitude calculation right, so we force it to be unbounded.
bounds.noLongitudeBound(); bounds.noLongitudeBound();
} }

View File

@ -677,7 +677,7 @@ public class GeoPath extends GeoBaseExtendedShape implements GeoDistanceShape
lowerConnectingPlane.recordBounds(bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane); lowerConnectingPlane.recordBounds(bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
startCutoffPlane.recordBounds(bounds, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane); startCutoffPlane.recordBounds(bounds, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
endCutoffPlane.recordBounds(bounds, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane); endCutoffPlane.recordBounds(bounds, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
if (fullDistance >= Math.PI * 0.5) { if (fullDistance >= Math.PI) {
// Too large a segment basically means that we can confuse the Bounds object. Specifically, if our span exceeds 180 degrees // Too large a segment basically means that we can confuse the Bounds object. Specifically, if our span exceeds 180 degrees
// in longitude (which even a segment whose actual length is less than that might if it goes close to a pole). // in longitude (which even a segment whose actual length is less than that might if it goes close to a pole).
// Unfortunately, we can get arbitrarily close to the pole, so this may still not work in all cases. // Unfortunately, we can get arbitrarily close to the pole, so this may still not work in all cases.

View File

@ -38,7 +38,7 @@ public class GeoPoint extends Vector
public double arcDistance(final GeoPoint v) public double arcDistance(final GeoPoint v)
{ {
return Tools.safeAcos(evaluate(v)); return Tools.safeAcos(dotProduct(v));
} }
} }

View File

@ -27,6 +27,13 @@ public class Plane extends Vector
public final double D; public final double D;
/** Construct a plane with all four coefficients defined.
*/
public Plane(final double A, final double B, final double C, final double D) {
super(A,B,C);
this.D = D;
}
/** Construct a plane through two points and origin. /** Construct a plane through two points and origin.
*@param A is the first point (origin based). *@param A is the first point (origin based).
*@param B is the second point (origin based). *@param B is the second point (origin based).
@ -68,9 +75,8 @@ public class Plane extends Vector
*@param v is the vector. *@param v is the vector.
*@return the result of the evaluation. *@return the result of the evaluation.
*/ */
@Override
public double evaluate(final Vector v) { public double evaluate(final Vector v) {
return super.evaluate(v) + D; return dotProduct(v) + D;
} }
/** Evaluate the plane equation for a given point, as represented /** Evaluate the plane equation for a given point, as represented
@ -78,9 +84,8 @@ public class Plane extends Vector
*@param x,y,z is the vector. *@param x,y,z is the vector.
*@return the result of the evaluation. *@return the result of the evaluation.
*/ */
@Override
public double evaluate(final double x, final double y, final double z) { public double evaluate(final double x, final double y, final double z) {
return super.evaluate(x,y,z) + D; return dotProduct(x,y,z) + D;
} }
/** Evaluate the plane equation for a given point, as represented /** Evaluate the plane equation for a given point, as represented
@ -88,7 +93,6 @@ public class Plane extends Vector
*@param v is the vector. *@param v is the vector.
*@return true if the result is on the plane. *@return true if the result is on the plane.
*/ */
@Override
public boolean evaluateIsZero(final Vector v) { public boolean evaluateIsZero(final Vector v) {
return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION; return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
} }
@ -98,7 +102,6 @@ public class Plane extends Vector
*@param x,y,z is the vector. *@param x,y,z is the vector.
*@return true if the result is on the plane. *@return true if the result is on the plane.
*/ */
@Override
public boolean evaluateIsZero(final double x, final double y, final double z) { public boolean evaluateIsZero(final double x, final double y, final double z) {
return Math.abs(evaluate(x,y,z)) < MINIMUM_RESOLUTION; return Math.abs(evaluate(x,y,z)) < MINIMUM_RESOLUTION;
} }
@ -113,6 +116,159 @@ public class Plane extends Vector
return new Plane(normVect,this.D); return new Plane(normVect,this.D);
} }
/** Find points on the boundary of the intersection of a plane and the unit sphere,
* given a starting point, and ending point, and a list of proportions of the arc (e.g. 0.25, 0.5, 0.75).
* The angle between the starting point and ending point is assumed to be less than pi.
*/
public GeoPoint[] interpolate(final GeoPoint start, final GeoPoint end, final double[] proportions) {
// Steps:
// (1) Translate (x0,y0,z0) of endpoints into origin-centered place:
// x1 = x0 + D*A
// y1 = y0 + D*B
// z1 = z0 + D*C
// (2) Rotate counterclockwise in x-y:
// ra = -atan2(B,A)
// x2 = x1 cos ra - y1 sin ra
// y2 = x1 sin ra + y1 cos ra
// z2 = z1
// Faster:
// cos ra = A/sqrt(A^2+B^2+C^2)
// sin ra = -B/sqrt(A^2+B^2+C^2)
// cos (-ra) = A/sqrt(A^2+B^2+C^2)
// sin (-ra) = B/sqrt(A^2+B^2+C^2)
// (3) Rotate clockwise in x-z:
// ha = pi/2 - asin(C/sqrt(A^2+B^2+C^2))
// x3 = x2 cos ha - z2 sin ha
// y3 = y2
// z3 = x2 sin ha + z2 cos ha
// At this point, z3 should be zero.
// Faster:
// sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
// cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
// (4) Compute interpolations by getting longitudes of original points
// la = atan2(y3,x3)
// (5) Rotate new points (xN0, yN0, zN0) counter-clockwise in x-z:
// ha = -(pi - asin(C/sqrt(A^2+B^2+C^2)))
// xN1 = xN0 cos ha - zN0 sin ha
// yN1 = yN0
// zN1 = xN0 sin ha + zN0 cos ha
// (6) Rotate new points clockwise in x-y:
// ra = atan2(B,A)
// xN2 = xN1 cos ra - yN1 sin ra
// yN2 = xN1 sin ra + yN1 cos ra
// zN2 = zN1
// (7) Translate new points:
// xN3 = xN2 - D*A
// yN3 = yN2 - D*B
// zN3 = zN2 - D*C
// First, calculate the angles and their sin/cos values
double A = x;
double B = y;
double C = z;
// Translation amounts
final double transX = -D * A;
final double transY = -D * B;
final double transZ = -D * C;
double cosRA;
double sinRA;
double cosHA;
double sinHA;
double magnitude = magnitude();
if (magnitude >= MINIMUM_RESOLUTION) {
final double denom = 1.0/magnitude;
A *= denom;
B *= denom;
C *= denom;
// cos ra = A/sqrt(A^2+B^2+C^2)
// sin ra = -B/sqrt(A^2+B^2+C^2)
// cos (-ra) = A/sqrt(A^2+B^2+C^2)
// sin (-ra) = B/sqrt(A^2+B^2+C^2)
final double xyMagnitude = Math.sqrt(A*A + B*B);
if (xyMagnitude >= MINIMUM_RESOLUTION) {
final double xyDenom = 1.0/xyMagnitude;
cosRA = A * xyDenom;
sinRA = -B * xyDenom;
} else {
cosRA = 1.0;
sinRA = 0.0;
}
// sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
// cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
sinHA = xyMagnitude;
cosHA = C;
} else {
cosRA = 1.0;
sinRA = 0.0;
cosHA = 1.0;
sinHA = 0.0;
}
// Forward-translate the start and end points
final Vector modifiedStart = modify(start, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
final Vector modifiedEnd = modify(end, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
if (Math.abs(modifiedStart.z) >= MINIMUM_RESOLUTION)
throw new IllegalArgumentException("Start point was not on plane: "+modifiedStart.z);
if (Math.abs(modifiedEnd.z) >= MINIMUM_RESOLUTION)
throw new IllegalArgumentException("End point was not on plane: "+modifiedEnd.z);
// Compute the angular distance between start and end point
final double startAngle = Math.atan2(modifiedStart.y, modifiedStart.x);
final double endAngle = Math.atan2(modifiedEnd.y, modifiedEnd.x);
final double startMagnitude = Math.sqrt(modifiedStart.x * modifiedStart.x + modifiedStart.y * modifiedStart.y);
double delta;
double beginAngle;
double newEndAngle = endAngle;
while (newEndAngle < startAngle) {
newEndAngle += Math.PI * 2.0;
}
if (newEndAngle - startAngle <= Math.PI) {
delta = newEndAngle - startAngle;
beginAngle = startAngle;
} else {
double newStartAngle = startAngle;
while (newStartAngle < endAngle) {
newStartAngle += Math.PI * 2.0;
}
delta = newStartAngle - endAngle;
beginAngle = endAngle;
}
final GeoPoint[] returnValues = new GeoPoint[proportions.length];
for (int i = 0; i < returnValues.length; i++) {
final double newAngle = startAngle + proportions[i] * delta;
final double sinNewAngle = Math.sin(newAngle);
final double cosNewAngle = Math.cos(newAngle);
final Vector newVector = new Vector(cosNewAngle * startMagnitude, sinNewAngle * startMagnitude, 0.0);
returnValues[i] = reverseModify(newVector, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
}
return returnValues;
}
/** Modify a point to produce a vector in translated/rotated space.
*/
protected static Vector modify(final GeoPoint start, final double transX, final double transY, final double transZ,
final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
return start.translate(transX, transY, transZ).rotateXY(sinRA, cosRA).rotateXZ(sinHA, cosHA);
}
/** Reverse modify a point to produce a GeoPoint in normal space.
*/
protected static GeoPoint reverseModify(final Vector point, final double transX, final double transY, final double transZ,
final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
final Vector result = point.rotateXZ(-sinHA, cosHA).rotateXY(-sinRA, cosRA).translate(-transX, -transY, -transZ);
return new GeoPoint(result.x, result.y, result.z);
}
/** Find the intersection points between two planes, given a set of bounds. /** Find the intersection points between two planes, given a set of bounds.
*@param q is the plane to intersect with. *@param q is the plane to intersect with.
*@param bounds is the set of bounds. *@param bounds is the set of bounds.
@ -823,14 +979,26 @@ public class Plane extends Vector
protected boolean isNumericallyIdentical(final Plane p) { protected boolean isNumericallyIdentical(final Plane p) {
// We can get the correlation by just doing a parallel plane check. If that passes, then compute a point on the plane // We can get the correlation by just doing a parallel plane check. If that passes, then compute a point on the plane
// (using D) and see if it also on the other plane. // (using D) and see if it also on the other plane.
if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION_SQUARED) if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION)
return false; return false;
if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION_SQUARED) if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION)
return false; return false;
if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION_SQUARED) if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION)
return false; return false;
// Now, see whether the parallel planes are in fact on top of one another. // Now, see whether the parallel planes are in fact on top of one another.
// The math:
// We need a single point that fulfills:
// Ax + By + Cz + D = 0
// Pick:
// x0 = -(A * D) / (A^2 + B^2 + C^2)
// y0 = -(B * D) / (A^2 + B^2 + C^2)
// z0 = -(C * D) / (A^2 + B^2 + C^2)
// Check:
// A (x0) + B (y0) + C (z0) + D =? 0
// A (-(A * D) / (A^2 + B^2 + C^2)) + B (-(B * D) / (A^2 + B^2 + C^2)) + C (-(C * D) / (A^2 + B^2 + C^2)) + D ?= 0
// -D [ A^2 / (A^2 + B^2 + C^2) + B^2 / (A^2 + B^2 + C^2) + C^2 / (A^2 + B^2 + C^2)] + D ?= 0
// Yes.
final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z); final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z);
return evaluateIsZero(- p.x * p.D * denom, - p.y * p.D * denom, - p.z * p.D * denom); return evaluateIsZero(- p.x * p.D * denom, - p.y * p.D * denom, - p.z * p.D * denom);
} }

View File

@ -70,39 +70,21 @@ public class Vector
return new Vector(x*normFactor,y*normFactor,z*normFactor); return new Vector(x*normFactor,y*normFactor,z*normFactor);
} }
/** Evaluate a vector (dot product) and check for "zero". /** Do a dot product.
*@param v is the vector to evaluate. *@param v is the vector to multiply.
*@return true if the evaluation yielded zero.
*/
public boolean evaluateIsZero(final Vector v) {
return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
}
/** Evaluate a vector (do a dot product) snd check for "zero".
*@param x is the x value of the vector to evaluate.
*@param y is the x value of the vector to evaluate.
*@param z is the x value of the vector to evaluate.
*@return true if the evaluation yielded zero.
*/
public boolean evaluateIsZero(final double x, final double y, final double z) {
return Math.abs(evaluate(x,y,z)) < MINIMUM_RESOLUTION;
}
/** Evaluate a vector (do a dot product).
*@param v is the vector to evaluate.
*@return the result. *@return the result.
*/ */
public double evaluate(final Vector v) { public double dotProduct(final Vector v) {
return this.x * v.x + this.y * v.y + this.z * v.z; return this.x * v.x + this.y * v.y + this.z * v.z;
} }
/** Evaluate a vector (do a dot product). /** Do a dot product.
*@param x is the x value of the vector to evaluate. *@param x is the x value of the vector to multiply.
*@param y is the x value of the vector to evaluate. *@param y is the y value of the vector to multiply.
*@param z is the x value of the vector to evaluate. *@param z is the z value of the vector to multiply.
*@return the result. *@return the result.
*/ */
public double evaluate(final double x, final double y, final double z) { public double dotProduct(final double x, final double y, final double z) {
return this.x * x + this.y * y + this.z * z; return this.x * x + this.y * y + this.z * z;
} }
@ -125,6 +107,48 @@ public class Vector
return true; return true;
} }
/** Translate vector.
*/
public Vector translate(final double xOffset, final double yOffset, final double zOffset) {
return new Vector(x - xOffset, y - yOffset, z - zOffset);
}
/** Rotate vector counter-clockwise in x-y by an angle.
*/
public Vector rotateXY(final double angle) {
return rotateXY(Math.sin(angle),Math.cos(angle));
}
/** Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
*/
public Vector rotateXY(final double sinAngle, final double cosAngle) {
return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z);
}
/** Rotate vector counter-clockwise in x-z by an angle.
*/
public Vector rotateXZ(final double angle) {
return rotateXZ(Math.sin(angle),Math.cos(angle));
}
/** Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
*/
public Vector rotateXZ(final double sinAngle, final double cosAngle) {
return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle);
}
/** Rotate vector counter-clockwise in z-y by an angle.
*/
public Vector rotateZY(final double angle) {
return rotateZY(Math.sin(angle),Math.cos(angle));
}
/** Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
*/
public Vector rotateZY(final double sinAngle, final double cosAngle) {
return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle);
}
/** Compute the square of a straight-line distance to a point described by the /** Compute the square of a straight-line distance to a point described by the
* vector taken from the origin. * vector taken from the origin.
* Monotonically increasing for arc distances up to PI. * Monotonically increasing for arc distances up to PI.
@ -182,7 +206,7 @@ public class Vector
*@return the square of the normal distance. *@return the square of the normal distance.
*/ */
public double normalDistanceSquared(final Vector v) { public double normalDistanceSquared(final Vector v) {
double t = x*v.x + y*v.y + z*v.z; double t = dotProduct(v);
double deltaX = this.x * t - v.x; double deltaX = this.x * t - v.x;
double deltaY = this.y * t - v.y; double deltaY = this.y * t - v.y;
double deltaZ = this.z * t - v.z; double deltaZ = this.z * t - v.z;
@ -198,7 +222,7 @@ public class Vector
*@return the square of the normal distance. *@return the square of the normal distance.
*/ */
public double normalDistanceSquared(final double x, final double y, final double z) { public double normalDistanceSquared(final double x, final double y, final double z) {
double t = this.x*x + this.y*y + this.z*z; double t = dotProduct(x,y,z);
double deltaX = this.x * t - x; double deltaX = this.x * t - x;
double deltaY = this.y * t - y; double deltaY = this.y * t - y;
double deltaZ = this.z * t - z; double deltaZ = this.z * t - z;

View File

@ -56,39 +56,55 @@ public class Geo3dShapeRectRelationTest extends RandomizedShapeTest {
@Test @Test
public void testFailure() { public void testFailure() {
/* /*
[junit4] 1> S-R Rel: {}, Shape {}, Rectangle {} [INTERSECTS, Geo3dShape{GeoCompositeMembershipShape: {[ [junit4] 1> S-R Rel: {}, Shape {}, Rectangle {} [WITHIN, Geo3dShape{GeoCompositeMembershipShape: {[
GeoConvexPolygon: { GeoConvexPolygon: {points=[
points=[ [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
[X=0.03206699943821901, Y=-0.7556330442094724, Z=0.6542097599743943], [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
[X=-0.2848733212046893, Y=-0.9533780638748927, Z=0.09958643576296423], [X=0.8344549994139991, Y=0.216175219373972, Z=0.5069054433339593]]
[X=0.37929990916639644, Y=0.9241954620264722, Z=0.044657887053005746]]
edges={ edges={
[A=0.5484584327149066, B=-0.18956034526809354, C=-0.2458316687546487, D=0.0, side=1.0] internal? false; [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
[A=-0.13461318190686059, B=0.05049496664187115, C=0.09833758231919826, D=0.0, side=1.0] internal? false; [A=0.11536057134002048, B=0.32272431860685813, C=-0.3275328920717585, D=0.0, side=-1.0] internal? false;
[A=0.6383626665235883, B=-0.246709658095017, C=-0.31624772039338794, D=0.0, side=1.0] internal? false; }}]}}, [A=0.29740830615965186, B=-0.5854932295360462, C=-0.2398962611358763, D=0.0, side=-1.0] internal? false; }}]}},
X=0.03206699943821901, Y=-0.7556330442094724, Z=0.6542097599743943 Rect(minX=-30.0,maxX=62.0,minY=30.0,maxY=88.0)](no slf4j subst; sorry)
Rect(minX=-52.0,maxX=50.0,minY=58.0,maxY=68.0)](no slf4j subst; sorry) [junit4] FAILURE 1.85s J2 | Geo3dShapeRectRelationTest.testGeoPolygonRect <<<
[junit4] > Throwable #1: java.lang.AssertionError: Rect(minX=-30.0,maxX=62.0,minY=30.0,maxY=88.0) intersect Pt(x=82.75500168892472,y=34.2730264413182)
[junit4] > at __randomizedtesting.SeedInfo.seed([3EBD2127AF6641F7:3A64BDAC8843B64]:0)
[junit4] > at org.apache.lucene.spatial.spatial4j.RandomizedShapeTest._assertIntersect(RandomizedShapeTest.java:167)
[junit4] > at org.apache.lucene.spatial.spatial4j.RandomizedShapeTest.assertRelation(RandomizedShapeTest.java:152)
[junit4] > at org.apache.lucene.spatial.spatial4j.RectIntersectionTestHelper.testRelateWithRectangle(RectIntersectionTestHelper.java:105)
[junit4] > at org.apache.lucene.spatial.spatial4j.Geo3dShapeRectRelationTest.testGeoPolygonRect(Geo3dShapeRectRelationTest.java:219)
*/ */
final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(68 * RADIANS_PER_DEGREE, 58 * RADIANS_PER_DEGREE, -52 * RADIANS_PER_DEGREE, 50 * RADIANS_PER_DEGREE); final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(88 * RADIANS_PER_DEGREE, 30 * RADIANS_PER_DEGREE, -30 * RADIANS_PER_DEGREE, 62 * RADIANS_PER_DEGREE);
final List<GeoPoint> points = new ArrayList<GeoPoint>(); final List<GeoPoint> points = new ArrayList<GeoPoint>();
points.add(new GeoPoint(40.8597568993 * RADIANS_PER_DEGREE, -87.5699819016 * RADIANS_PER_DEGREE)); points.add(new GeoPoint(66.2465299717 * RADIANS_PER_DEGREE, -29.1786158537 * RADIANS_PER_DEGREE));
points.add(new GeoPoint(5.71535611517 * RADIANS_PER_DEGREE, -106.636363741 * RADIANS_PER_DEGREE)); points.add(new GeoPoint(43.684447915 * RADIANS_PER_DEGREE, 46.2210986329 * RADIANS_PER_DEGREE));
points.add(new GeoPoint(2.55955969779 * RADIANS_PER_DEGREE, 67.6862179901 * RADIANS_PER_DEGREE)); points.add(new GeoPoint(30.4579218227 * RADIANS_PER_DEGREE, 14.5238410082 * RADIANS_PER_DEGREE));
final GeoShape path = GeoPolygonFactory.makeGeoPolygon(points,0); final GeoShape path = GeoPolygonFactory.makeGeoPolygon(points,0);
System.err.println("Rectangle = "+rect+"; path = "+path); final GeoPoint point = new GeoPoint(34.2730264413182 * RADIANS_PER_DEGREE, 82.75500168892472 * RADIANS_PER_DEGREE);
// Edges intersect == OVERLAP. This seems reasonable... between points 2 and 3 the path could well cross. System.err.println("Rectangle = "+rect+"; path = "+path+"; point = "+point);
assertFalse(GeoArea.DISJOINT == rect.getRelationship(path));
final GeoBBox pathBounds = getBoundingBox(path); /*
// Path bounds go around the back side of the world rather than the front. The actual path goes around the front. This is I think what the problem is. [junit4] 2> Rectangle = GeoRectangle: {toplat=1.53588974175501(87.99999999999999), bottomlat=0.5235987755982988(29.999999999999996), leftlon=-0.5235987755982988(-29.999999999999996), rightlon=1.0821041362364843(62.0)};
System.err.println("Path bounds = "+pathBounds); path = GeoCompositeMembershipShape: {[GeoConvexPolygon: {points=[
assertFalse(GeoArea.DISJOINT == rect.getRelationship(pathBounds)); [X=0.3516881844340107, Y=-0.1963796619709742, Z=0.9152870857242963],
[X=0.500334318953081, Y=0.5221285432268337, Z=0.6906861469767445],
[X=0.8344549994140144, Y=0.21617521937373424, Z=0.5069054433340355]]
edges={[A=-0.6135342247748885, B=0.21504338363844255, C=0.28188192383710364, D=0.0, side=-1.0] internal? false;
[A=0.1153605713406553, B=0.32272431860660283, C=-0.3275328920724975, D=0.0, side=-1.0] internal? false;
[A=0.29740830615958036, B=-0.5854932295358584, C=-0.2398962611360862, D=0.0, side=-1.0] internal? false; }}]};
point = [X=0.10421465978661167, Y=0.8197657811637465, Z=0.5631370780889439]
*/
// Apparently the rectangle thinks the polygon is completely within it... "shape inside rectangle"
assertTrue(GeoArea.WITHIN == rect.getRelationship(path));
// Point is within path? Apparently not...
assertFalse(path.isWithin(point));
// If it is within the path, it must be within the rectangle, and similarly visa versa
assertFalse(rect.isWithin(point));
final GeoBBox rectBounds = getBoundingBox(rect);
assertFalse(GeoArea.DISJOINT == rectBounds.getRelationship(pathBounds));
} }
protected static GeoBBox getBoundingBox(final GeoShape path) { protected static GeoBBox getBoundingBox(final GeoShape path) {

View File

@ -17,13 +17,15 @@ package org.apache.lucene.spatial.spatial4j.geo3d;
* limitations under the License. * limitations under the License.
*/ */
import static org.junit.Assert.*;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class GeoBBoxTest { public class GeoBBoxTest {
protected final double DEGREES_TO_RADIANS = Math.PI/180.0; protected final double DEGREES_TO_RADIANS = Math.PI/180.0;
@ -145,11 +147,11 @@ public class GeoBBoxTest {
c = GeoBBoxFactory.makeGeoBBox(0.0,-Math.PI * 0.25, 1.0, -1.0); c = GeoBBoxFactory.makeGeoBBox(0.0,-Math.PI * 0.25, 1.0, -1.0);
b = c.getBounds(null); b = c.getBounds(null);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertFalse(b.checkNoTopLatitudeBound()); assertFalse(b.checkNoTopLatitudeBound());
assertFalse(b.checkNoBottomLatitudeBound()); assertFalse(b.checkNoBottomLatitudeBound());
assertEquals(1.0,b.getLeftLongitude(),0.000001); //assertEquals(1.0,b.getLeftLongitude(),0.000001);
assertEquals(-1.0,b.getRightLongitude(),0.000001); //assertEquals(-1.0,b.getRightLongitude(),0.000001);
assertEquals(-Math.PI * 0.25,b.getMinLatitude(),0.000001); assertEquals(-Math.PI * 0.25,b.getMinLatitude(),0.000001);
assertEquals(0.0,b.getMaxLatitude(),0.000001); assertEquals(0.0,b.getMaxLatitude(),0.000001);
@ -165,22 +167,22 @@ public class GeoBBoxTest {
c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0); c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0);
b = c.getBounds(null); b = c.getBounds(null);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoTopLatitudeBound());
assertTrue(b.checkNoBottomLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound());
assertEquals(1.0,b.getLeftLongitude(),0.000001); //assertEquals(1.0,b.getLeftLongitude(),0.000001);
assertEquals(-1.0,b.getRightLongitude(),0.000001); //assertEquals(-1.0,b.getRightLongitude(),0.000001);
// Check wide variants of rectangle and longitude slice // Check wide variants of rectangle and longitude slice
c = GeoBBoxFactory.makeGeoBBox(0.0,-Math.PI * 0.25, -Math.PI+0.1, Math.PI-0.1); c = GeoBBoxFactory.makeGeoBBox(0.0,-Math.PI * 0.25, -Math.PI+0.1, Math.PI-0.1);
b = c.getBounds(null); b = c.getBounds(null);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertFalse(b.checkNoTopLatitudeBound()); assertFalse(b.checkNoTopLatitudeBound());
assertFalse(b.checkNoBottomLatitudeBound()); assertFalse(b.checkNoBottomLatitudeBound());
assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001); //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001); //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
assertEquals(-Math.PI * 0.25,b.getMinLatitude(),0.000001); assertEquals(-Math.PI * 0.25,b.getMinLatitude(),0.000001);
assertEquals(0.0,b.getMaxLatitude(),0.000001); assertEquals(0.0,b.getMaxLatitude(),0.000001);
@ -198,11 +200,11 @@ public class GeoBBoxTest {
c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, -Math.PI+0.1, Math.PI-0.1); c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, -Math.PI+0.1, Math.PI-0.1);
b = c.getBounds(null); b = c.getBounds(null);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoTopLatitudeBound());
assertTrue(b.checkNoBottomLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound());
assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001); //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001); //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, Math.PI-0.1, -Math.PI+0.1); c = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, Math.PI-0.1, -Math.PI+0.1);
@ -243,11 +245,11 @@ public class GeoBBoxTest {
b = new Bounds(); b = new Bounds();
b = c1.getBounds(b); b = c1.getBounds(b);
b = c2.getBounds(b); b = c2.getBounds(b);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoTopLatitudeBound());
assertTrue(b.checkNoBottomLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound());
assertEquals(-Math.PI,b.getLeftLongitude(),0.000001); //assertEquals(-Math.PI,b.getLeftLongitude(),0.000001);
assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001); //assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001);
c1 = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0); c1 = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0);
c2 = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI); c2 = GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
@ -255,11 +257,11 @@ public class GeoBBoxTest {
b = new Bounds(); b = new Bounds();
b = c1.getBounds(b); b = c1.getBounds(b);
b = c2.getBounds(b); b = c2.getBounds(b);
assertFalse(b.checkNoLongitudeBound()); assertTrue(b.checkNoLongitudeBound());
assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoTopLatitudeBound());
assertTrue(b.checkNoBottomLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound());
assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001); //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001);
assertEquals(Math.PI,b.getRightLongitude(),0.000001); //assertEquals(Math.PI,b.getRightLongitude(),0.000001);
} }

View File

@ -178,6 +178,7 @@ public class GeoPathTest {
assertEquals(0.4046919,b.getRightLongitude(),0.000001); assertEquals(0.4046919,b.getRightLongitude(),0.000001);
assertEquals(-0.3999999,b.getMinLatitude(),0.000001); assertEquals(-0.3999999,b.getMinLatitude(),0.000001);
assertEquals(0.3999999,b.getMaxLatitude(),0.000001); assertEquals(0.3999999,b.getMaxLatitude(),0.000001);
} }
} }

View File

@ -43,6 +43,22 @@ public class PlaneTest {
assertTrue(p1.isNumericallyIdentical(p2)); assertTrue(p1.isNumericallyIdentical(p2));
} }
@Test
public void testInterpolation() {
// [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
// [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
final GeoPoint start = new GeoPoint(0.35168818443386646,-0.19637966197066342,0.9152870857244183);
final GeoPoint end = new GeoPoint(0.5003343189532654,0.522128543226148,0.6906861469771293);
// [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
final Plane p = new Plane(-0.6135342247741855,0.21504338363863665,0.28188192383666794,0.0);
final GeoPoint[] points = p.interpolate(start,end,new double[]{0.25,0.50,0.75});
for (GeoPoint point : points) {
assertTrue(p.evaluateIsZero(point));
}
}
} }