mirror of https://github.com/apache/lucene.git
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:
parent
40daf30a83
commit
c561d376bc
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue