From e06554ad408a60dc37eb77c0aeeff542e506f1a5 Mon Sep 17 00:00:00 2001 From: Karl Wright Date: Fri, 30 Mar 2018 08:36:47 -0400 Subject: [PATCH] LUCENE-8227: Widen plane envelopes a small amount to allow for some imprecision when intersecting inner and outer edges. --- .../apache/lucene/spatial3d/geom/Plane.java | 4 +- .../lucene/spatial3d/TestGeo3DPoint.java | 1 - .../lucene/spatial3d/geom/GeoPolygonTest.java | 73 +++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java index e40fb271d03..5ecee287508 100755 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java @@ -23,6 +23,8 @@ package org.apache.lucene.spatial3d.geom; * @lucene.experimental */ public class Plane extends Vector { + /** For plane envelopes, we need a small distance that can't lead to numerical confusion. */ + public final static double MINIMUM_PLANE_OFFSET = MINIMUM_RESOLUTION * 1.5; /** An array with no points in it */ public final static GeoPoint[] NO_POINTS = new GeoPoint[0]; /** An array with no bounds in it */ @@ -114,7 +116,7 @@ public class Plane extends Vector { * or false in the negative direction. */ public Plane(final Plane basePlane, final boolean above) { - this(basePlane.x, basePlane.y, basePlane.z, above?Math.nextUp(basePlane.D + MINIMUM_RESOLUTION):Math.nextDown(basePlane.D - MINIMUM_RESOLUTION)); + this(basePlane.x, basePlane.y, basePlane.z, above?Math.nextUp(basePlane.D + MINIMUM_PLANE_OFFSET):Math.nextDown(basePlane.D - MINIMUM_PLANE_OFFSET)); } /** Construct the most accurate normalized plane through an x-y point and including the Z axis. diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java index 5d58d5ebe1f..861e26ea0a1 100644 --- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java @@ -188,7 +188,6 @@ public class TestGeo3DPoint extends LuceneTestCase { } /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */ - @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/LUCENE-8227") public void testGeo3DRelations() throws Exception { int numDocs = atLeast(1000); diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java index 65659b3accd..11e44afd49a 100755 --- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java @@ -1257,4 +1257,77 @@ shape: } + /* + [junit4] 1> doc=754 is contained by shape but is outside the returned XYZBounds + [junit4] 1> unquantized=[lat=2.4043303687704734E-204, lon=3.1342447995980507([X=-1.0010918284309325, Y=0.007356008974104805, Z=2.4070204634028112E-204])] + [junit4] 1> quantized=[X=-1.0010918285430614, Y=0.007356008812298254, Z=2.3309121299774915E-10] + + [junit4] 1> doc=3728 is contained by shape but is outside the returned XYZBounds + [junit4] 1> unquantized=[lat=2.4457272005608357E-47, lon=-3.1404077424936307([X=-1.001118151199965, Y=-0.0011862365610909341, Z=2.448463612203698E-47])] + [junit4] 1> quantized=[X=-1.0011181510675629, Y=-0.001186236379718708, Z=2.3309121299774915E-10] + + [junit4] 1> shape=GeoComplexPolygon: {planetmodel=PlanetModel.WGS84, number of shapes=1, address=7969cab3, + testPoint=[X=-0.07416172733314662, Y=0.5686488061136892, Z=0.8178445379402641], testPointInSet=true, shapes={ { + [lat=-1.5707963267948966, lon=-1.0755217966112058([X=2.903696886845155E-17, Y=-5.375400029710238E-17, Z=-0.997762292022105])], + [lat=-1.327365682666958, lon=-2.9674513704178316([X=-0.23690293696956322, Y=-0.04167672037374933, Z=-0.9685334156912658])], + [lat=0.32288591161895097, lon=3.141592653589793([X=-0.9490627533610154, Y=1.1622666630935417E-16, Z=0.3175519551883462])], + [lat=0.0, lon=0.0([X=1.0011188539924791, Y=0.0, Z=0.0])], + [lat=0.2839194570254642, lon=-1.2434404554202965([X=0.30893121415043073, Y=-0.9097632721627391, Z=0.2803596238536593])]}} + */ + @Test + public void testLUCENE8227_case2() { + List points = new ArrayList<>(); + points.add(new GeoPoint(PlanetModel.WGS84, -1.5707963267948966, -1.0755217966112058)); + points.add(new GeoPoint(PlanetModel.WGS84, -1.327365682666958, -2.9674513704178316)); + points.add(new GeoPoint(PlanetModel.WGS84, 0.32288591161895097, 3.141592653589793)); + points.add(new GeoPoint(PlanetModel.WGS84, 0.0, 0.0)); + points.add(new GeoPoint(PlanetModel.WGS84, 0.2839194570254642, -1.2434404554202965)); + GeoPolygonFactory.PolygonDescription pd = new GeoPolygonFactory.PolygonDescription(points); + + for (int i = 0; i < points.size(); i++) { + System.out.println("Point "+i+": "+points.get(i)); + } + + final GeoPoint unquantized = new GeoPoint(PlanetModel.WGS84, 2.4457272005608357E-47, -3.1404077424936307); + final GeoPoint quantized = new GeoPoint(-1.0011181510675629, -0.001186236379718708, 2.3309121299774915E-10); + + // Is the north pole in set, or out of set? + final GeoPoint northPole = new GeoPoint(PlanetModel.WGS84, Math.PI * 0.5, 0.0); + final GeoPoint negativeX = new GeoPoint(PlanetModel.WGS84, 0.0, Math.PI); + final GeoPoint negativeY = new GeoPoint(PlanetModel.WGS84, 0.0, -Math.PI * 0.5); + final GeoPoint positiveY = new GeoPoint(PlanetModel.WGS84, 0.0, Math.PI * 0.5); + final GeoPoint testPoint = new GeoPoint(-0.07416172733314662, 0.5686488061136892, 0.8178445379402641); + + // Construct a standard polygon first to see what that does. This winds up being a large polygon under the covers. + GeoPolygon standard = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, pd); + + System.out.println("Shape = "+standard); + + // This should be true, by inspection, but is false. That's the cause for the failure. + assertTrue(standard.isWithin(negativeX)); + System.out.println("Negative x pole in set? "+standard.isWithin(negativeX)); + + System.out.println("Test point in set? "+standard.isWithin(testPoint)); + assertTrue(standard.isWithin(testPoint)); + + // This is in-set because it's on an edge + System.out.println("North pole in set? "+standard.isWithin(northPole)); + assertTrue(standard.isWithin(northPole)); + + // This is in-set + System.out.println("Plus-Y pole in set? "+standard.isWithin(positiveY)); + assertTrue(standard.isWithin(positiveY)); + + + final XYZBounds standardBounds = new XYZBounds(); + standard.getBounds(standardBounds); + System.out.println("Bounds = "+standardBounds); + final XYZSolid standardSolid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, standardBounds); + + // If within shape, should be within bounds + assertTrue(standard.isWithin(unquantized)?standardSolid.isWithin(unquantized):true); + assertTrue(standard.isWithin(quantized)?standardSolid.isWithin(quantized):true); + + } + }