From c561d376bc48a8d5870a27699c6576ac6b630944 Mon Sep 17 00:00:00 2001 From: David Wayne Smiley Date: Fri, 1 May 2015 18:49:49 +0000 Subject: [PATCH] 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 --- .../spatial/spatial4j/geo3d/Bounds.java | 5 +- .../spatial4j/geo3d/GeoConvexPolygon.java | 2 +- .../spatial/spatial4j/geo3d/GeoPath.java | 2 +- .../spatial/spatial4j/geo3d/GeoPoint.java | 2 +- .../lucene/spatial/spatial4j/geo3d/Plane.java | 188 +++++++++++++++++- .../spatial/spatial4j/geo3d/Vector.java | 82 +++++--- .../spatial4j/Geo3dShapeRectRelationTest.java | 70 ++++--- .../spatial/spatial4j/geo3d/GeoBBoxTest.java | 44 ++-- .../spatial/spatial4j/geo3d/GeoPathTest.java | 1 + .../spatial/spatial4j/geo3d/PlaneTest.java | 18 +- 10 files changed, 321 insertions(+), 93 deletions(-) diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Bounds.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Bounds.java index 79e8ef56e4d..23778f19fa1 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Bounds.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Bounds.java @@ -187,7 +187,8 @@ public class Bounds double testRightLongitude = rightLongitude; if (testRightLongitude < leftLongitude) 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; leftLongitude = null; rightLongitude = null; @@ -244,7 +245,7 @@ public class Bounds double testRightLongitude = rightLongitude; if (testRightLongitude < leftLongitude) testRightLongitude += Math.PI * 2.0; - if (testRightLongitude - leftLongitude >= Math.PI * 2.0) { + if (testRightLongitude - leftLongitude >= Math.PI) { noLongitudeBound = true; leftLongitude = null; rightLongitude = null; diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java index 30bb0ff7162..20575b52071 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java @@ -229,7 +229,7 @@ public class GeoConvexPolygon extends GeoBaseExtendedShape implements GeoMembers 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. bounds.noLongitudeBound(); } diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java index ecf4febfe18..05614b96b43 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java @@ -677,7 +677,7 @@ public class GeoPath extends GeoBaseExtendedShape implements GeoDistanceShape lowerConnectingPlane.recordBounds(bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane); startCutoffPlane.recordBounds(bounds, endCutoffPlane, 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 // 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. diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java index 9d83a8d47a1..29f35a22b7f 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java @@ -38,7 +38,7 @@ public class GeoPoint extends Vector public double arcDistance(final GeoPoint v) { - return Tools.safeAcos(evaluate(v)); + return Tools.safeAcos(dotProduct(v)); } } diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java index ce07c6f8233..5d63e312d35 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java @@ -27,6 +27,13 @@ public class Plane extends Vector 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. *@param A is the first 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. *@return the result of the evaluation. */ - @Override 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 @@ -78,9 +84,8 @@ public class Plane extends Vector *@param x,y,z is the vector. *@return the result of the evaluation. */ - @Override 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 @@ -88,7 +93,6 @@ public class Plane extends Vector *@param v is the vector. *@return true if the result is on the plane. */ - @Override public boolean evaluateIsZero(final Vector v) { return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION; } @@ -98,7 +102,6 @@ public class Plane extends Vector *@param x,y,z is the vector. *@return true if the result is on the plane. */ - @Override public boolean evaluateIsZero(final double x, final double y, final double z) { return Math.abs(evaluate(x,y,z)) < MINIMUM_RESOLUTION; } @@ -113,6 +116,159 @@ public class Plane extends Vector 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. *@param q is the plane to intersect with. *@param bounds is the set of bounds. @@ -823,14 +979,26 @@ public class Plane extends Vector 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 // (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; - 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; - 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; - // 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); return evaluateIsZero(- p.x * p.D * denom, - p.y * p.D * denom, - p.z * p.D * denom); } diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java index 3e71390fdaa..4a658b40426 100755 --- a/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java +++ b/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java @@ -70,42 +70,24 @@ public class Vector return new Vector(x*normFactor,y*normFactor,z*normFactor); } - /** Evaluate a vector (dot product) and check for "zero". - *@param v is the vector to evaluate. - *@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. + /** Do a dot product. + *@param v is the vector to multiply. *@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; } - /** Evaluate a vector (do a dot product). - *@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. + /** Do a dot product. + *@param x is the x value of the vector to multiply. + *@param y is the y value of the vector to multiply. + *@param z is the z value of the vector to multiply. *@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; } - + /** Determine if this vector, taken from the origin, * describes a point within a set of planes. *@param bounds is the first part of the set of planes. @@ -125,6 +107,48 @@ public class Vector 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 * vector taken from the origin. * Monotonically increasing for arc distances up to PI. @@ -182,7 +206,7 @@ public class Vector *@return the square of the normal distance. */ 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 deltaY = this.y * t - v.y; double deltaZ = this.z * t - v.z; @@ -198,7 +222,7 @@ public class Vector *@return the square of the normal distance. */ 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 deltaY = this.y * t - y; double deltaZ = this.z * t - z; diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTest.java b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTest.java index 8119d124e13..08dd46423a7 100644 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTest.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTest.java @@ -56,39 +56,55 @@ public class Geo3dShapeRectRelationTest extends RandomizedShapeTest { @Test public void testFailure() { /* - [junit4] 1> S-R Rel: {}, Shape {}, Rectangle {} [INTERSECTS, Geo3dShape{GeoCompositeMembershipShape: {[ - GeoConvexPolygon: { - points=[ - [X=0.03206699943821901, Y=-0.7556330442094724, Z=0.6542097599743943], - [X=-0.2848733212046893, Y=-0.9533780638748927, Z=0.09958643576296423], - [X=0.37929990916639644, Y=0.9241954620264722, Z=0.044657887053005746]] - edges={ - [A=0.5484584327149066, B=-0.18956034526809354, C=-0.2458316687546487, 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.6383626665235883, B=-0.246709658095017, C=-0.31624772039338794, D=0.0, side=1.0] internal? false; }}]}}, - X=0.03206699943821901, Y=-0.7556330442094724, Z=0.6542097599743943 - Rect(minX=-52.0,maxX=50.0,minY=58.0,maxY=68.0)](no slf4j subst; sorry) - + [junit4] 1> S-R Rel: {}, Shape {}, Rectangle {} [WITHIN, Geo3dShape{GeoCompositeMembershipShape: {[ + GeoConvexPolygon: {points=[ + [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183], + [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293], + [X=0.8344549994139991, Y=0.216175219373972, Z=0.5069054433339593]] + edges={ + [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, 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.29740830615965186, B=-0.5854932295360462, C=-0.2398962611358763, D=0.0, side=-1.0] internal? false; }}]}}, + Rect(minX=-30.0,maxX=62.0,minY=30.0,maxY=88.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 points = new ArrayList(); - points.add(new GeoPoint(40.8597568993 * RADIANS_PER_DEGREE, -87.5699819016 * RADIANS_PER_DEGREE)); - points.add(new GeoPoint(5.71535611517 * RADIANS_PER_DEGREE, -106.636363741 * RADIANS_PER_DEGREE)); - points.add(new GeoPoint(2.55955969779 * RADIANS_PER_DEGREE, 67.6862179901 * RADIANS_PER_DEGREE)); + points.add(new GeoPoint(66.2465299717 * RADIANS_PER_DEGREE, -29.1786158537 * RADIANS_PER_DEGREE)); + points.add(new GeoPoint(43.684447915 * RADIANS_PER_DEGREE, 46.2210986329 * 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 GeoPoint point = new GeoPoint(34.2730264413182 * RADIANS_PER_DEGREE, 82.75500168892472 * RADIANS_PER_DEGREE); - System.err.println("Rectangle = "+rect+"; path = "+path); + System.err.println("Rectangle = "+rect+"; path = "+path+"; point = "+point); - // Edges intersect == OVERLAP. This seems reasonable... between points 2 and 3 the path could well cross. - assertFalse(GeoArea.DISJOINT == rect.getRelationship(path)); + /* + [junit4] 2> Rectangle = GeoRectangle: {toplat=1.53588974175501(87.99999999999999), bottomlat=0.5235987755982988(29.999999999999996), leftlon=-0.5235987755982988(-29.999999999999996), rightlon=1.0821041362364843(62.0)}; + path = GeoCompositeMembershipShape: {[GeoConvexPolygon: {points=[ + [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 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. - System.err.println("Path bounds = "+pathBounds); - assertFalse(GeoArea.DISJOINT == rect.getRelationship(pathBounds)); - - final GeoBBox rectBounds = getBoundingBox(rect); - assertFalse(GeoArea.DISJOINT == rectBounds.getRelationship(pathBounds)); } protected static GeoBBox getBoundingBox(final GeoShape path) { diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxTest.java b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxTest.java index c1801f50641..bb3e6648a78 100755 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxTest.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxTest.java @@ -17,13 +17,15 @@ package org.apache.lucene.spatial.spatial4j.geo3d; * limitations under the License. */ -import static org.junit.Assert.*; - -import java.util.List; import java.util.ArrayList; +import java.util.List; 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 { 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); b = c.getBounds(null); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertFalse(b.checkNoTopLatitudeBound()); assertFalse(b.checkNoBottomLatitudeBound()); - assertEquals(1.0,b.getLeftLongitude(),0.000001); - assertEquals(-1.0,b.getRightLongitude(),0.000001); + //assertEquals(1.0,b.getLeftLongitude(),0.000001); + //assertEquals(-1.0,b.getRightLongitude(),0.000001); assertEquals(-Math.PI * 0.25,b.getMinLatitude(),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); b = c.getBounds(null); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound()); - assertEquals(1.0,b.getLeftLongitude(),0.000001); - assertEquals(-1.0,b.getRightLongitude(),0.000001); + //assertEquals(1.0,b.getLeftLongitude(),0.000001); + //assertEquals(-1.0,b.getRightLongitude(),0.000001); // 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); b = c.getBounds(null); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertFalse(b.checkNoTopLatitudeBound()); assertFalse(b.checkNoBottomLatitudeBound()); - assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001); - assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001); + //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001); + //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001); assertEquals(-Math.PI * 0.25,b.getMinLatitude(),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); b = c.getBounds(null); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound()); - assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001); - assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001); + //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),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); @@ -243,11 +245,11 @@ public class GeoBBoxTest { b = new Bounds(); b = c1.getBounds(b); b = c2.getBounds(b); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound()); - assertEquals(-Math.PI,b.getLeftLongitude(),0.000001); - assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001); + //assertEquals(-Math.PI,b.getLeftLongitude(),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); 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 = c1.getBounds(b); b = c2.getBounds(b); - assertFalse(b.checkNoLongitudeBound()); + assertTrue(b.checkNoLongitudeBound()); assertTrue(b.checkNoTopLatitudeBound()); assertTrue(b.checkNoBottomLatitudeBound()); - assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001); - assertEquals(Math.PI,b.getRightLongitude(),0.000001); + //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001); + //assertEquals(Math.PI,b.getRightLongitude(),0.000001); } diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPathTest.java b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPathTest.java index 2909d4e7e0e..691295118d5 100755 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPathTest.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPathTest.java @@ -178,6 +178,7 @@ public class GeoPathTest { assertEquals(0.4046919,b.getRightLongitude(),0.000001); assertEquals(-0.3999999,b.getMinLatitude(),0.000001); assertEquals(0.3999999,b.getMaxLatitude(),0.000001); + } } diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/PlaneTest.java b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/PlaneTest.java index 4f4057f35eb..89a70032ed7 100644 --- a/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/PlaneTest.java +++ b/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/geo3d/PlaneTest.java @@ -42,7 +42,23 @@ public class PlaneTest { final Plane p2 = new Plane(v2,0.2*constant); 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)); + } + } }