LUCENE-8171: Refactor vector constructor to support later changes, and add an ignored test for a precision issue.

This commit is contained in:
Karl Wright 2018-02-13 09:53:04 -05:00
parent 277097cd24
commit 4f351fd21b
3 changed files with 85 additions and 14 deletions

View File

@ -177,16 +177,41 @@ public class SidedPlane extends Plane implements Membership {
*/
public static SidedPlane constructNormalizedThreePointSidedPlane(final Vector insidePoint,
final Vector point1, final Vector point2, final Vector point3) {
SidedPlane rval = null;
if (rval == null) {
try {
final Vector planeNormal = new Vector(
new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z),
new Vector(point2.x - point3.x, point2.y - point3.y, point2.z - point3.z));
return new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
point1.x - point2.x, point1.y - point2.y, point1.z - point2.z,
point2.x - point3.x, point2.y - point3.y, point2.z - point3.z);
rval = new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
} catch (IllegalArgumentException e) {
return null;
}
}
if (rval == null) {
try {
final Vector planeNormal = new Vector(
point1.x - point3.x, point1.y - point3.y, point1.z - point3.z,
point3.x - point2.x, point3.y - point2.y, point3.z - point2.z);
rval = new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point3));
} catch (IllegalArgumentException e) {
}
}
if (rval == null) {
try {
final Vector planeNormal = new Vector(
point3.x - point1.x, point3.y - point1.y, point3.z - point1.z,
point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
rval = new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point1));
} catch (IllegalArgumentException e) {
}
}
return rval;
}
@Override
public boolean isWithin(double x, double y, double z) {
double evalResult = evaluate(x, y, z);

View File

@ -72,6 +72,24 @@ public class Vector {
* @param BZ is the Z value of the second
*/
public Vector(final Vector A, final double BX, final double BY, final double BZ) {
// We're really looking at two vectors and computing a perpendicular one from that.
this(A.x, A.y, A.z, BX, BY, BZ);
}
/**
* Construct a vector that is perpendicular to
* two other (non-zero) vectors. If the vectors are parallel,
* IllegalArgumentException will be thrown.
* Produces a normalized final vector.
*
* @param AX is the X value of the first
* @param AY is the Y value of the first
* @param AZ is the Z value of the first
* @param BX is the X value of the second
* @param BY is the Y value of the second
* @param BZ is the Z value of the second
*/
public Vector(final double AX, final double AY, final double AZ, final double BX, final double BY, final double BZ) {
// We're really looking at two vectors and computing a perpendicular one from that.
// We can think of this as having three points -- the origin, and two points that aren't the origin.
// Normally, we can compute the perpendicular vector this way:
@ -83,9 +101,9 @@ public class Vector {
// Gram-Schmidt process: https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
// Compute the naive perpendicular
final double thisX = A.y * BZ - A.z * BY;
final double thisY = A.z * BX - A.x * BZ;
final double thisZ = A.x * BY - A.y * BX;
final double thisX = AY * BZ - AZ * BY;
final double thisY = AZ * BX - AX * BZ;
final double thisZ = AX * BY - AY * BX;
final double magnitude = magnitude(thisX, thisY, thisZ);
if (magnitude < MINIMUM_RESOLUTION) {
@ -103,7 +121,7 @@ public class Vector {
// we need to adjust
int i = 0;
while (true) {
final double currentDotProdA = A.x * normalizeX + A.y * normalizeY + A.z * normalizeZ;
final double currentDotProdA = AX * normalizeX + AY * normalizeY + AZ * normalizeZ;
final double currentDotProdB = BX * normalizeX + BY * normalizeY + BZ * normalizeZ;
if (Math.abs(currentDotProdA) < MINIMUM_RESOLUTION && Math.abs(currentDotProdB) < MINIMUM_RESOLUTION) {
break;
@ -114,9 +132,9 @@ public class Vector {
final double currentVectorZ;
final double currentDotProd;
if (Math.abs(currentDotProdA) > Math.abs(currentDotProdB)) {
currentVectorX = A.x;
currentVectorY = A.y;
currentVectorZ = A.z;
currentVectorX = AX;
currentVectorY = AY;
currentVectorZ = AZ;
currentDotProd = currentDotProdA;
} else {
currentVectorX = BX;

View File

@ -22,6 +22,7 @@ import java.util.List;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import org.junit.Test;
import org.junit.Ignore;
/**
* Random test for planes.
@ -51,6 +52,33 @@ public class RandomPlaneTest extends RandomGeo3dShapeGenerator {
}
}
@Ignore
@Test
@Repeat(iterations = 10)
public void testPlaneThreePointsAccuracy() {
PlanetModel planetModel = randomPlanetModel();
for (int i= 0; i < 1000; i++) {
GeoPoint point1 = randomGeoPoint(planetModel);
double dist = random().nextDouble() * Math.PI - Vector.MINIMUM_ANGULAR_RESOLUTION;
double bearing = random().nextDouble() * 2 * Math.PI;
GeoPoint point2 = planetModel.surfacePointOnBearing(point1, dist, bearing );
dist = random().nextDouble() * Vector.MINIMUM_ANGULAR_RESOLUTION + Vector.MINIMUM_ANGULAR_RESOLUTION;
bearing = random().nextDouble() * 2 * Math.PI;
GeoPoint point3 = planetModel.surfacePointOnBearing(point1, dist, bearing );
GeoPoint check = randomGeoPoint(planetModel);
SidedPlane plane = SidedPlane.constructNormalizedThreePointSidedPlane(check, point1, point2, point3);
String msg = planetModel + " point 1: " + point1 + ", point 2: " + point2 + ", point 3: " + point3 + " , check: " + check;
if (plane == null) {
fail(msg);
}
assertTrue(plane.evaluate(check) + " " + msg, plane.isWithin(check));
assertTrue(plane.evaluate(point1) + " " +msg, plane.isWithin(point3));
assertTrue(plane.evaluate(point2) + " " +msg, plane.isWithin(point2));
assertTrue(plane.evaluate(point3) + " " +msg, plane.isWithin(point1));
}
}
@Test
@Repeat(iterations = 10)