LUCENE-7642: Take the slightly more cautious approach of introducing a plane method for functional identicality.

This commit is contained in:
Karl Wright 2018-03-31 11:42:32 -04:00
parent dc9c60322a
commit b4a83fffbd
2 changed files with 39 additions and 3 deletions

View File

@ -1239,7 +1239,7 @@ public class GeoPolygonFactory {
final Edge newLastEdge = edgeBuffer.getNext(lastEdge);
// Planes that are almost identical cannot be properly handled by the standard polygon logic. Detect this case and, if found,
// give up on the tiling -- we'll need to create a large poly instead.
if (lastEdge.plane.isNumericallyIdentical(newLastEdge.plane) /*isNearlyIdentical(lastEdge.plane, newLastEdge.plane) */) {
if (lastEdge.plane.isFunctionallyIdentical(newLastEdge.plane)) {
throw new TileException("Two adjacent edge planes are effectively parallel despite filtering; give up on tiling");
}
if (Plane.arePointsCoplanar(lastEdge.startPoint, lastEdge.endPoint, newLastEdge.endPoint)) {

View File

@ -2344,6 +2344,43 @@ public class Plane extends Vector {
}
}
/**
* Returns true if this plane and the other plane are functionally identical within the margin of error.
* Functionally identical means that the planes are so close to parallel that many aspects of planar math,
* like intersections, no longer have answers to within the required precision.
* @param p is the plane to compare against.
* @return true if the planes are functionally identical.
*/
public boolean isFunctionallyIdentical(final Plane p) {
// We can get the correlation by just doing a parallel plane check. That's basically finding
// out if the magnitude of the cross-product is "zero".
final double cross1 = this.y * p.z - this.z * p.y;
final double cross2 = this.z * p.x - this.x * p.z;
final double cross3 = this.x * p.y - this.y * p.x;
//System.out.println("cross product magnitude = "+(cross1 * cross1 + cross2 * cross2 + cross3 * cross3));
// Should be MINIMUM_RESOLUTION_SQUARED, but that gives us planes that are *almost* parallel, and those are problematic too,
// so we have a tighter constraint on parallelism in this method.
if (cross1 * cross1 + cross2 * cross2 + cross3 * cross3 >= MINIMUM_RESOLUTION) {
return false;
}
// 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);
}
/**
* Returns true if this plane and the other plane are identical within the margin of error.
* @param p is the plane to compare against.
@ -2356,8 +2393,7 @@ public class Plane extends Vector {
final double cross2 = this.z * p.x - this.x * p.z;
final double cross3 = this.x * p.y - this.y * p.x;
//System.out.println("cross product magnitude = "+(cross1 * cross1 + cross2 * cross2 + cross3 * cross3));
// Technically should be MINIMUM_RESOLUTION_SQUARED, but that gives us planes that are *almost* parallel, and those are problematic too
if (cross1 * cross1 + cross2 * cross2 + cross3 * cross3 >= MINIMUM_RESOLUTION) {
if (cross1 * cross1 + cross2 * cross2 + cross3 * cross3 >= MINIMUM_RESOLUTION_SQUARED) {
return false;
}
/* Old method