You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2016/03/01 18:07:02 UTC

[19/50] [abbrv] lucene-solr git commit: LUCENE-7015: Refactor spatial module to spatial-extras

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/serialized/SerializedStrategyTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/serialized/SerializedStrategyTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/serialized/SerializedStrategyTest.java
new file mode 100644
index 0000000..bed8339
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/serialized/SerializedStrategyTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.serialized;
+
+import java.io.IOException;
+
+import com.spatial4j.core.context.SpatialContext;
+import org.apache.lucene.spatial.SpatialMatchConcern;
+import org.apache.lucene.spatial.StrategyTestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SerializedStrategyTest extends StrategyTestCase {
+
+  @Before
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    this.ctx = SpatialContext.GEO;
+    this.strategy = new SerializedDVStrategy(ctx, "serialized");
+  }
+
+  @Override
+  protected boolean needsDocValues() {
+    return (strategy instanceof SerializedDVStrategy);
+  }
+
+  @Test
+  public void testBasicOperaions() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_SIMPLE_BBOX);
+
+    executeQueries(SpatialMatchConcern.EXACT, QTEST_Simple_Queries_BBox);
+  }
+
+  @Test
+  public void testStatesBBox() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_STATES_BBOX);
+
+    executeQueries(SpatialMatchConcern.FILTER, QTEST_States_IsWithin_BBox);
+    executeQueries(SpatialMatchConcern.FILTER, QTEST_States_Intersects_BBox);
+  }
+
+  @Test
+  public void testCitiesIntersectsBBox() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_WORLD_CITIES_POINTS);
+
+    executeQueries(SpatialMatchConcern.FILTER, QTEST_Cities_Intersects_BBox);
+  }
+
+  //sorting is tested in DistanceStrategyTest
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dRptTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dRptTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dRptTest.java
new file mode 100644
index 0000000..8040a35
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dRptTest.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.carrotsearch.randomizedtesting.annotations.Repeat;
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Rectangle;
+import com.spatial4j.core.shape.Shape;
+import org.apache.lucene.spatial.composite.CompositeSpatialStrategy;
+import org.apache.lucene.spatial.prefix.RandomSpatialOpStrategyTestCase;
+import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
+import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
+import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
+import org.apache.lucene.spatial.query.SpatialOperation;
+import org.apache.lucene.spatial.serialized.SerializedDVStrategy;
+import org.apache.lucene.geo3d.GeoBBoxFactory;
+import org.apache.lucene.geo3d.GeoStandardCircle;
+import org.apache.lucene.geo3d.GeoPath;
+import org.apache.lucene.geo3d.GeoPoint;
+import org.apache.lucene.geo3d.GeoPolygonFactory;
+import org.apache.lucene.geo3d.GeoShape;
+import org.apache.lucene.geo3d.PlanetModel;
+import org.junit.Test;
+
+import static com.spatial4j.core.distance.DistanceUtils.DEGREES_TO_RADIANS;
+
+public class Geo3dRptTest extends RandomSpatialOpStrategyTestCase {
+
+  private SpatialPrefixTree grid;
+  private RecursivePrefixTreeStrategy rptStrategy;
+  {
+    this.ctx = SpatialContext.GEO;
+  }
+
+  private void setupGeohashGrid() {
+    this.grid = new GeohashPrefixTree(ctx, 2);//A fairly shallow grid
+    this.rptStrategy = newRPT();
+  }
+
+  protected RecursivePrefixTreeStrategy newRPT() {
+    final RecursivePrefixTreeStrategy rpt = new RecursivePrefixTreeStrategy(this.grid,
+        getClass().getSimpleName() + "_rpt");
+    rpt.setDistErrPct(0.10);//not too many cells
+    return rpt;
+  }
+
+  @Override
+  protected boolean needsDocValues() {
+    return true;//due to SerializedDVStrategy
+  }
+
+  private void setupStrategy() {
+    //setup
+    setupGeohashGrid();
+
+    SerializedDVStrategy serializedDVStrategy = new SerializedDVStrategy(ctx, getClass().getSimpleName() + "_sdv");
+    this.strategy = new CompositeSpatialStrategy("composite_" + getClass().getSimpleName(),
+        rptStrategy, serializedDVStrategy);
+  }
+
+  @Test
+  public void testFailure1() throws IOException {
+    setupStrategy();
+    final List<GeoPoint> points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, 18 * DEGREES_TO_RADIANS, -27 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -57 * DEGREES_TO_RADIANS, 146 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 14 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -15 * DEGREES_TO_RADIANS, 153 * DEGREES_TO_RADIANS));
+
+    final Shape triangle = new Geo3dShape(GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points,0),ctx);
+    final Rectangle rect = ctx.makeRectangle(-49, -45, 73, 86);
+    testOperation(rect,SpatialOperation.Intersects,triangle, false);
+  }
+
+  @Test
+  public void testFailureLucene6535() throws IOException {
+    setupStrategy();
+
+    final List<GeoPoint> points = new ArrayList<>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, 18 * DEGREES_TO_RADIANS, -27 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -57 * DEGREES_TO_RADIANS, 146 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 14 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -15 * DEGREES_TO_RADIANS, 153 * DEGREES_TO_RADIANS));
+    final GeoPath path = new GeoPath(PlanetModel.SPHERE, 29 * DEGREES_TO_RADIANS);
+    path.addPoint(55.0 * DEGREES_TO_RADIANS, -26.0 * DEGREES_TO_RADIANS);
+    path.addPoint(-90.0 * DEGREES_TO_RADIANS, 0.0);
+    path.addPoint(54.0 * DEGREES_TO_RADIANS, 165.0 * DEGREES_TO_RADIANS);
+    path.addPoint(-90.0 * DEGREES_TO_RADIANS, 0.0);
+    path.done();
+    final Shape shape = new Geo3dShape(path,ctx);
+    final Rectangle rect = ctx.makeRectangle(131, 143, 39, 54);
+    testOperation(rect,SpatialOperation.Intersects,shape,true);
+  }
+
+  @Test
+  @Repeat(iterations = 10)
+  public void testOperations() throws IOException {
+    setupStrategy();
+
+    testOperationRandomShapes(SpatialOperation.Intersects);
+  }
+
+  private Shape makeTriangle(double x1, double y1, double x2, double y2, double x3, double y3) {
+    final List<GeoPoint> geoPoints = new ArrayList<>();
+    geoPoints.add(new GeoPoint(PlanetModel.SPHERE, y1 * DEGREES_TO_RADIANS, x1 * DEGREES_TO_RADIANS));
+    geoPoints.add(new GeoPoint(PlanetModel.SPHERE, y2 * DEGREES_TO_RADIANS, x2 * DEGREES_TO_RADIANS));
+    geoPoints.add(new GeoPoint(PlanetModel.SPHERE, y3 * DEGREES_TO_RADIANS, x3 * DEGREES_TO_RADIANS));
+    final int convexPointIndex = 0;
+    final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, geoPoints, convexPointIndex);
+    return new Geo3dShape(shape, ctx);
+  }
+
+  @Override
+  protected Shape randomIndexedShape() {
+    return randomRectangle();
+  }
+
+  @Override
+  protected Shape randomQueryShape() {
+    final int shapeType = random().nextInt(4);
+    switch (shapeType) {
+    case 0: {
+        // Polygons
+        final int vertexCount = random().nextInt(3) + 3;
+        while (true) {
+          final List<GeoPoint> geoPoints = new ArrayList<>();
+          while (geoPoints.size() < vertexCount) {
+            final Point point = randomPoint();
+            final GeoPoint gPt = new GeoPoint(PlanetModel.SPHERE, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS);
+            geoPoints.add(gPt);
+          }
+          final int convexPointIndex = random().nextInt(vertexCount);       //If we get this wrong, hopefully we get IllegalArgumentException
+          try {
+            final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, geoPoints, convexPointIndex);
+            return new Geo3dShape(shape, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+    case 1: {
+        // Circles
+        while (true) {
+          final int circleRadius = random().nextInt(179) + 1;
+          final Point point = randomPoint();
+          try {
+            final GeoShape shape = new GeoStandardCircle(PlanetModel.SPHERE, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS,
+              circleRadius * DEGREES_TO_RADIANS);
+            return new Geo3dShape(shape, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+    case 2: {
+        // Rectangles
+        while (true) {
+          Point ulhcPoint = randomPoint();
+          Point lrhcPoint = randomPoint();
+          if (ulhcPoint.getY() < lrhcPoint.getY()) {
+            //swap
+            Point temp = ulhcPoint;
+            ulhcPoint = lrhcPoint;
+            lrhcPoint = temp;
+          }
+          try {
+            final GeoShape shape = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, ulhcPoint.getY() * DEGREES_TO_RADIANS,
+              lrhcPoint.getY() * DEGREES_TO_RADIANS,
+              ulhcPoint.getX() * DEGREES_TO_RADIANS,
+              lrhcPoint.getX() * DEGREES_TO_RADIANS);
+            //System.err.println("Trial rectangle shape: "+shape);
+            return new Geo3dShape(shape, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+    case 3: {
+        // Paths
+        final int pointCount = random().nextInt(5) + 1;
+        final double width = (random().nextInt(89)+1) * DEGREES_TO_RADIANS;
+        while (true) {
+          try {
+            final GeoPath path = new GeoPath(PlanetModel.SPHERE, width);
+            for (int i = 0; i < pointCount; i++) {
+              final Point nextPoint = randomPoint();
+              path.addPoint(nextPoint.getY() * DEGREES_TO_RADIANS, nextPoint.getX() * DEGREES_TO_RADIANS);
+            }
+            path.done();
+            return new Geo3dShape(path, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+    default:
+      throw new IllegalStateException("Unexpected shape type");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
new file mode 100644
index 0000000..58b520d
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeRectRelationTestCase.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.spatial4j.core.TestLog;
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.distance.DistanceUtils;
+import com.spatial4j.core.shape.Circle;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.RectIntersectionTestHelper;
+import org.apache.lucene.geo3d.LatLonBounds;
+import org.apache.lucene.geo3d.GeoBBox;
+import org.apache.lucene.geo3d.GeoBBoxFactory;
+import org.apache.lucene.geo3d.GeoStandardCircle;
+import org.apache.lucene.geo3d.GeoPath;
+import org.apache.lucene.geo3d.GeoPoint;
+import org.apache.lucene.geo3d.GeoPolygonFactory;
+import org.apache.lucene.geo3d.GeoShape;
+import org.apache.lucene.geo3d.PlanetModel;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static com.spatial4j.core.distance.DistanceUtils.DEGREES_TO_RADIANS;
+
+public abstract class Geo3dShapeRectRelationTestCase extends RandomizedShapeTestCase {
+  protected final static double RADIANS_PER_DEGREE = Math.PI/180.0;
+
+  @Rule
+  public final TestLog testLog = TestLog.instance;
+
+  protected final PlanetModel planetModel;
+
+  public Geo3dShapeRectRelationTestCase(PlanetModel planetModel) {
+    super(SpatialContext.GEO);
+    this.planetModel = planetModel;
+  }
+
+  protected GeoBBox getBoundingBox(final GeoShape path) {
+    LatLonBounds bounds = new LatLonBounds();
+    path.getBounds(bounds);
+
+    double leftLon;
+    double rightLon;
+    if (bounds.checkNoLongitudeBound()) {
+      leftLon = -Math.PI;
+      rightLon = Math.PI;
+    } else {
+      leftLon = bounds.getLeftLongitude().doubleValue();
+      rightLon = bounds.getRightLongitude().doubleValue();
+    }
+    double minLat;
+    if (bounds.checkNoBottomLatitudeBound()) {
+      minLat = -Math.PI * 0.5;
+    } else {
+      minLat = bounds.getMinLatitude().doubleValue();
+    }
+    double maxLat;
+    if (bounds.checkNoTopLatitudeBound()) {
+      maxLat = Math.PI * 0.5;
+    } else {
+      maxLat = bounds.getMaxLatitude().doubleValue();
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, maxLat, minLat, leftLon, rightLon);
+  }
+
+  abstract class Geo3dRectIntersectionTestHelper extends RectIntersectionTestHelper<Geo3dShape> {
+
+    public Geo3dRectIntersectionTestHelper(SpatialContext ctx) {
+      super(ctx);
+    }
+
+    //20 times each -- should be plenty
+
+    protected int getContainsMinimum(int laps) {
+      return 20;
+    }
+
+    protected int getIntersectsMinimum(int laps) {
+      return 20;
+    }
+
+    // producing "within" cases in Geo3D based on our random shapes doesn't happen often. It'd be nice to increase this.
+    protected int getWithinMinimum(int laps) {
+      return 2;
+    }
+
+    protected int getDisjointMinimum(int laps) {
+      return 20;
+    }
+
+    protected int getBoundingMinimum(int laps) {
+      return 20;
+    }
+  }
+
+  @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
+  @Test
+  public void testGeoCircleRect() {
+    new Geo3dRectIntersectionTestHelper(ctx) {
+
+      @Override
+      protected Geo3dShape generateRandomShape(Point nearP) {
+        final int circleRadius = 180 - random().nextInt(180);//no 0-radius
+        final Point point = nearP;
+        final GeoShape shape = new GeoStandardCircle(planetModel, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS,
+            circleRadius * DEGREES_TO_RADIANS);
+        return new Geo3dShape(planetModel, shape, ctx);
+      }
+
+      @Override
+      protected Point randomPointInEmptyShape(Geo3dShape shape) {
+        GeoPoint geoPoint = ((GeoStandardCircle)shape.shape).getCenter();
+        return geoPointToSpatial4jPoint(geoPoint);
+      }
+
+    }.testRelateWithRectangle();
+  }
+
+  @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
+  @Test
+  public void testGeoBBoxRect() {
+    new Geo3dRectIntersectionTestHelper(ctx) {
+
+      @Override
+      protected boolean isRandomShapeRectangular() {
+        return true;
+      }
+
+      @Override
+      protected Geo3dShape generateRandomShape(Point nearP) {
+        // (ignoring nearP)
+        Point ulhcPoint = randomPoint();
+        Point lrhcPoint = randomPoint();
+        if (ulhcPoint.getY() < lrhcPoint.getY()) {
+          //swap
+          Point temp = ulhcPoint;
+          ulhcPoint = lrhcPoint;
+          lrhcPoint = temp;
+        }
+        final GeoShape shape = GeoBBoxFactory.makeGeoBBox(planetModel, ulhcPoint.getY() * DEGREES_TO_RADIANS,
+            lrhcPoint.getY() * DEGREES_TO_RADIANS,
+            ulhcPoint.getX() * DEGREES_TO_RADIANS,
+            lrhcPoint.getX() * DEGREES_TO_RADIANS);
+        return new Geo3dShape(planetModel, shape, ctx);
+      }
+
+      @Override
+      protected Point randomPointInEmptyShape(Geo3dShape shape) {
+        return shape.getBoundingBox().getCenter();
+      }
+    }.testRelateWithRectangle();
+  }
+
+  @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
+  @Test
+  public void testGeoPolygonRect() {
+    new Geo3dRectIntersectionTestHelper(ctx) {
+
+      @Override
+      protected Geo3dShape generateRandomShape(Point nearP) {
+        final Point centerPoint = randomPoint();
+        final int maxDistance = random().nextInt(160) + 20;
+        final Circle pointZone = ctx.makeCircle(centerPoint, maxDistance);
+        final int vertexCount = random().nextInt(3) + 3;
+        while (true) {
+          final List<GeoPoint> geoPoints = new ArrayList<>();
+          while (geoPoints.size() < vertexCount) {
+            final Point point = randomPointIn(pointZone);
+            final GeoPoint gPt = new GeoPoint(planetModel, point.getY() * DEGREES_TO_RADIANS, point.getX() * DEGREES_TO_RADIANS);
+            geoPoints.add(gPt);
+          }
+          final int convexPointIndex = random().nextInt(vertexCount); //If we get this wrong, hopefully we get IllegalArgumentException
+          try {
+            final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
+            return new Geo3dShape(planetModel, shape, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+
+      @Override
+      protected Point randomPointInEmptyShape(Geo3dShape shape) {
+        throw new IllegalStateException("unexpected; need to finish test code");
+      }
+
+      @Override
+      protected int getWithinMinimum(int laps) {
+        // Long/thin so lets just find 1.
+        return 1;
+      }
+
+    }.testRelateWithRectangle();
+  }
+
+  @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/LUCENE-6867")
+  @Test
+  public void testGeoPathRect() {
+    new Geo3dRectIntersectionTestHelper(ctx) {
+
+      @Override
+      protected Geo3dShape generateRandomShape(Point nearP) {
+        final Point centerPoint = randomPoint();
+        final int maxDistance = random().nextInt(160) + 20;
+        final Circle pointZone = ctx.makeCircle(centerPoint, maxDistance);
+        final int pointCount = random().nextInt(5) + 1;
+        final double width = (random().nextInt(89)+1) * DEGREES_TO_RADIANS;
+        while (true) {
+          try {
+            final GeoPath path = new GeoPath(planetModel, width);
+            for (int i = 0; i < pointCount; i++) {
+              final Point nextPoint = randomPointIn(pointZone);
+              path.addPoint(nextPoint.getY() * DEGREES_TO_RADIANS, nextPoint.getX() * DEGREES_TO_RADIANS);
+            }
+            path.done();
+            return new Geo3dShape(planetModel, path, ctx);
+          } catch (IllegalArgumentException e) {
+            // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
+            // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
+            continue;
+          }
+        }
+      }
+
+      @Override
+      protected Point randomPointInEmptyShape(Geo3dShape shape) {
+        throw new IllegalStateException("unexpected; need to finish test code");
+      }
+
+      @Override
+      protected int getWithinMinimum(int laps) {
+        // Long/thin so lets just find 1.
+        return 1;
+      }
+
+    }.testRelateWithRectangle();
+  }
+
+  private Point geoPointToSpatial4jPoint(GeoPoint geoPoint) {
+    return ctx.makePoint(geoPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES,
+        geoPoint.getLongitude() * DistanceUtils.RADIANS_TO_DEGREES);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
new file mode 100644
index 0000000..aac0a0a
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeSphereModelRectRelationTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.spatial4j.core.shape.Rectangle;
+import org.apache.lucene.geo3d.GeoArea;
+import org.apache.lucene.geo3d.GeoBBox;
+import org.apache.lucene.geo3d.GeoBBoxFactory;
+import org.apache.lucene.geo3d.GeoStandardCircle;
+import org.apache.lucene.geo3d.GeoPoint;
+import org.apache.lucene.geo3d.GeoPolygonFactory;
+import org.apache.lucene.geo3d.GeoShape;
+import org.apache.lucene.geo3d.PlanetModel;
+import org.junit.Test;
+
+public class Geo3dShapeSphereModelRectRelationTest extends Geo3dShapeRectRelationTestCase {
+
+  public Geo3dShapeSphereModelRectRelationTest() {
+    super(PlanetModel.SPHERE);
+  }
+
+  @Test
+  public void testFailure1() {
+    final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(planetModel, 88 * RADIANS_PER_DEGREE, 30 * RADIANS_PER_DEGREE, -30 * RADIANS_PER_DEGREE, 62 * RADIANS_PER_DEGREE);
+    final List<GeoPoint> points = new ArrayList<>();
+    points.add(new GeoPoint(planetModel, 66.2465299717 * RADIANS_PER_DEGREE, -29.1786158537 * RADIANS_PER_DEGREE));
+    points.add(new GeoPoint(planetModel, 43.684447915 * RADIANS_PER_DEGREE, 46.2210986329 * RADIANS_PER_DEGREE));
+    points.add(new GeoPoint(planetModel, 30.4579218227 * RADIANS_PER_DEGREE, 14.5238410082 * RADIANS_PER_DEGREE));
+    final GeoShape path = GeoPolygonFactory.makeGeoPolygon(planetModel, points,0);
+
+    final GeoPoint point = new GeoPoint(planetModel, 34.2730264413182 * RADIANS_PER_DEGREE, 82.75500168892472 * RADIANS_PER_DEGREE);
+
+    // 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));
+
+  }
+
+  @Test
+  public void testFailure2_LUCENE6475() {
+    GeoShape geo3dCircle = new GeoStandardCircle(planetModel, 1.6282053147165243E-4 * RADIANS_PER_DEGREE,
+        -70.1600629789353 * RADIANS_PER_DEGREE, 86 * RADIANS_PER_DEGREE);
+    Geo3dShape geo3dShape = new Geo3dShape(planetModel, geo3dCircle, ctx);
+    Rectangle rect = ctx.makeRectangle(-118, -114, -2.0, 32.0);
+    assertTrue(geo3dShape.relate(rect).intersects());
+    // thus the bounding box must intersect too
+    assertTrue(geo3dShape.getBoundingBox().relate(rect).intersects());
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
new file mode 100644
index 0000000..3b026c3
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import org.apache.lucene.geo3d.GeoArea;
+import org.apache.lucene.geo3d.GeoBBox;
+import org.apache.lucene.geo3d.GeoBBoxFactory;
+import org.apache.lucene.geo3d.GeoCircle;
+import org.apache.lucene.geo3d.GeoStandardCircle;
+import org.apache.lucene.geo3d.GeoPath;
+import org.apache.lucene.geo3d.GeoPoint;
+import org.apache.lucene.geo3d.PlanetModel;
+import org.junit.Test;
+
+public class Geo3dShapeWGS84ModelRectRelationTest extends Geo3dShapeRectRelationTestCase {
+
+  public Geo3dShapeWGS84ModelRectRelationTest() {
+    super(PlanetModel.WGS84);
+  }
+
+  @Test
+  public void testFailure1() {
+    final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(planetModel, 90 * RADIANS_PER_DEGREE, 74 * RADIANS_PER_DEGREE,
+        40 * RADIANS_PER_DEGREE, 60 * RADIANS_PER_DEGREE);
+    final GeoPath path = new GeoPath(planetModel, 4 * RADIANS_PER_DEGREE);
+    path.addPoint(84.4987594274 * RADIANS_PER_DEGREE, -22.8345484402 * RADIANS_PER_DEGREE);
+    path.done();
+    assertTrue(GeoArea.DISJOINT == rect.getRelationship(path));
+    // This is what the test failure claimed...
+    //assertTrue(GeoArea.CONTAINS == rect.getRelationship(path));
+    //final GeoBBox bbox = getBoundingBox(path);
+    //assertFalse(GeoArea.DISJOINT == rect.getRelationship(bbox));
+  }
+
+  @Test
+  public void testFailure2() {
+    final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(planetModel, -74 * RADIANS_PER_DEGREE, -90 * RADIANS_PER_DEGREE,
+        0 * RADIANS_PER_DEGREE, 26 * RADIANS_PER_DEGREE);
+    final GeoCircle circle = new GeoStandardCircle(planetModel, -87.3647352103 * RADIANS_PER_DEGREE, 52.3769709972 * RADIANS_PER_DEGREE, 1 * RADIANS_PER_DEGREE);
+    assertTrue(GeoArea.DISJOINT == rect.getRelationship(circle));
+    // This is what the test failure claimed...
+    //assertTrue(GeoArea.CONTAINS == rect.getRelationship(circle));
+    //final GeoBBox bbox = getBoundingBox(circle);
+    //assertFalse(GeoArea.DISJOINT == rect.getRelationship(bbox));
+  }
+
+  @Test
+  public void testFailure3() {
+    /*
+   [junit4]   1> S-R Rel: {}, Shape {}, Rectangle {}    lap# {} [CONTAINS, Geo3dShape{planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
+    points={[[X=0.12097657665150223, Y=-0.6754177666095532, Z=0.7265376136709238], [X=-0.3837892785614207, Y=0.4258049113530899, Z=0.8180007850434892]]}}},
+    Rect(minX=4.0,maxX=36.0,minY=16.0,maxY=16.0), 6981](no slf4j subst; sorry)
+   [junit4] FAILURE 0.59s | Geo3dWGS84ShapeRectRelationTest.testGeoPathRect <<<
+   [junit4]    > Throwable #1: java.lang.AssertionError: Geo3dShape{planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
+    points={[[X=0.12097657665150223, Y=-0.6754177666095532, Z=0.7265376136709238], [X=-0.3837892785614207, Y=0.4258049113530899, Z=0.8180007850434892]]}}} intersect Pt(x=23.81626064835212,y=16.0)
+   [junit4]    >  at __randomizedtesting.SeedInfo.seed([2595268DA3F13FEA:6CC30D8C83453E5D]:0)
+   [junit4]    >  at org.apache.lucene.spatial.spatial4j.RandomizedShapeTestCase._assertIntersect(RandomizedShapeTestCase.java:168)
+   [junit4]    >  at org.apache.lucene.spatial.spatial4j.RandomizedShapeTestCase.assertRelation(RandomizedShapeTestCase.java:153)
+   [junit4]    >  at org.apache.lucene.spatial.spatial4j.RectIntersectionTestHelper.testRelateWithRectangle(RectIntersectionTestHelper.java:128)
+   [junit4]    >  at org.apache.lucene.spatial.spatial4j.Geo3dWGS84ShapeRectRelationTest.testGeoPathRect(Geo3dWGS84ShapeRectRelationTest.java:265)
+  */
+    final GeoBBox rect = GeoBBoxFactory.makeGeoBBox(planetModel, 16 * RADIANS_PER_DEGREE, 16 * RADIANS_PER_DEGREE, 4 * RADIANS_PER_DEGREE, 36 * RADIANS_PER_DEGREE);
+    final GeoPoint pt = new GeoPoint(planetModel, 16 * RADIANS_PER_DEGREE, 23.81626064835212 * RADIANS_PER_DEGREE);
+    final GeoPath path = new GeoPath(planetModel, 88 * RADIANS_PER_DEGREE);
+    path.addPoint(46.6369060853 * RADIANS_PER_DEGREE, -79.8452213228 * RADIANS_PER_DEGREE);
+    path.addPoint(54.9779334519 * RADIANS_PER_DEGREE, 132.029177424 * RADIANS_PER_DEGREE);
+    path.done();
+    System.out.println("rect=" + rect);
+    // Rectangle is within path (this is wrong; it's on the other side.  Should be OVERLAPS)
+    assertTrue(GeoArea.OVERLAPS == rect.getRelationship(path));
+    // Rectangle contains point
+    //assertTrue(rect.isWithin(pt));
+    // Path contains point (THIS FAILS)
+    //assertTrue(path.isWithin(pt));
+    // What happens: (1) The center point of the horizontal line is within the path, in fact within a radius of one of the endpoints.
+    // (2) The point mentioned is NOT inside either SegmentEndpoint.
+    // (3) The point mentioned is NOT inside the path segment, either.  (I think it should be...)
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/RandomizedShapeTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/RandomizedShapeTestCase.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/RandomizedShapeTestCase.java
new file mode 100644
index 0000000..40d1b24
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/RandomizedShapeTestCase.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j;
+
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.distance.DistanceUtils;
+import com.spatial4j.core.shape.Circle;
+import com.spatial4j.core.shape.Point;
+import com.spatial4j.core.shape.Rectangle;
+import com.spatial4j.core.shape.Shape;
+import com.spatial4j.core.shape.SpatialRelation;
+import com.spatial4j.core.shape.impl.Range;
+
+import static com.spatial4j.core.shape.SpatialRelation.CONTAINS;
+import static com.spatial4j.core.shape.SpatialRelation.WITHIN;
+
+import org.apache.lucene.util.LuceneTestCase;
+
+import static com.carrotsearch.randomizedtesting.RandomizedTest.*;
+
+/**
+ * A base test class with utility methods to help test shapes.
+ * Extends from RandomizedTest.
+ */
+public abstract class RandomizedShapeTestCase extends LuceneTestCase {
+
+  protected static final double EPS = 10e-9;
+
+  protected SpatialContext ctx;//needs to be set ASAP
+
+  /** Used to reduce the space of numbers to increase the likelihood that
+   * random numbers become equivalent, and thus trigger different code paths.
+   * Also makes some random shapes easier to manually examine.
+   */
+  protected final double DIVISIBLE = 2;// even coordinates; (not always used)
+
+  protected RandomizedShapeTestCase() {
+  }
+
+  public RandomizedShapeTestCase(SpatialContext ctx) {
+    this.ctx = ctx;
+  }
+
+  @SuppressWarnings("unchecked")
+  public static void checkShapesImplementEquals( Class<?>[] classes ) {
+    for( Class<?> clazz : classes ) {
+      try {
+        clazz.getDeclaredMethod( "equals", Object.class );
+      } catch (Exception e) {
+        fail("Shape needs to define 'equals' : " + clazz.getName());
+      }
+      try {
+        clazz.getDeclaredMethod( "hashCode" );
+      } catch (Exception e) {
+        fail("Shape needs to define 'hashCode' : " + clazz.getName());
+      }
+    }
+  }
+
+  //These few norm methods normalize the arguments for creating a shape to
+  // account for the dateline. Some tests loop past the dateline or have offsets
+  // that go past it and it's easier to have them coded that way and correct for
+  // it here.  These norm methods should be used when needed, not frivolously.
+
+  protected double normX(double x) {
+    return ctx.isGeo() ? DistanceUtils.normLonDEG(x) : x;
+  }
+
+  protected double normY(double y) {
+    return ctx.isGeo() ? DistanceUtils.normLatDEG(y) : y;
+  }
+
+  protected Rectangle makeNormRect(double minX, double maxX, double minY, double maxY) {
+    if (ctx.isGeo()) {
+      if (Math.abs(maxX - minX) >= 360) {
+        minX = -180;
+        maxX = 180;
+      } else {
+        minX = DistanceUtils.normLonDEG(minX);
+        maxX = DistanceUtils.normLonDEG(maxX);
+      }
+
+    } else {
+      if (maxX < minX) {
+        double t = minX;
+        minX = maxX;
+        maxX = t;
+      }
+      minX = boundX(minX, ctx.getWorldBounds());
+      maxX = boundX(maxX, ctx.getWorldBounds());
+    }
+    if (maxY < minY) {
+      double t = minY;
+      minY = maxY;
+      maxY = t;
+    }
+    minY = boundY(minY, ctx.getWorldBounds());
+    maxY = boundY(maxY, ctx.getWorldBounds());
+    return ctx.makeRectangle(minX, maxX, minY, maxY);
+  }
+
+  public static double divisible(double v, double divisible) {
+    return (int) (Math.round(v / divisible) * divisible);
+  }
+
+  protected double divisible(double v) {
+    return divisible(v, DIVISIBLE);
+  }
+
+  /** reset()'s p, and confines to world bounds. Might not be divisible if
+   * the world bound isn't divisible too.
+   */
+  protected Point divisible(Point p) {
+    Rectangle bounds = ctx.getWorldBounds();
+    double newX = boundX( divisible(p.getX()), bounds );
+    double newY = boundY( divisible(p.getY()), bounds );
+    p.reset(newX, newY);
+    return p;
+  }
+
+  static double boundX(double i, Rectangle bounds) {
+    return bound(i, bounds.getMinX(), bounds.getMaxX());
+  }
+
+  static double boundY(double i, Rectangle bounds) {
+    return bound(i, bounds.getMinY(), bounds.getMaxY());
+  }
+
+  static double bound(double i, double min, double max) {
+    if (i < min) return min;
+    if (i > max) return max;
+    return i;
+  }
+
+  protected void assertRelation(SpatialRelation expected, Shape a, Shape b) {
+    assertRelation(null, expected, a, b);
+  }
+
+  protected void assertRelation(String msg, SpatialRelation expected, Shape a, Shape b) {
+    _assertIntersect(msg, expected, a, b);
+    //check flipped a & b w/ transpose(), while we're at it
+    _assertIntersect(msg, expected.transpose(), b, a);
+  }
+
+  private void _assertIntersect(String msg, SpatialRelation expected, Shape a, Shape b) {
+    SpatialRelation sect = a.relate(b);
+    if (sect == expected)
+      return;
+    msg = ((msg == null) ? "" : msg+"\r") + a +" intersect "+b;
+    if (expected == WITHIN || expected == CONTAINS) {
+      if (a.getClass().equals(b.getClass())) // they are the same shape type
+        assertEquals(msg,a,b);
+      else {
+        //they are effectively points or lines that are the same location
+        assertTrue(msg,!a.hasArea());
+        assertTrue(msg,!b.hasArea());
+
+        Rectangle aBBox = a.getBoundingBox();
+        Rectangle bBBox = b.getBoundingBox();
+        if (aBBox.getHeight() == 0 && bBBox.getHeight() == 0
+            && (aBBox.getMaxY() == 90 && bBBox.getMaxY() == 90
+            || aBBox.getMinY() == -90 && bBBox.getMinY() == -90))
+          ;//== a point at the pole
+        else
+          assertEquals(msg, aBBox, bBBox);
+      }
+    } else {
+      assertEquals(msg,expected,sect);//always fails
+    }
+  }
+
+  protected void assertEqualsRatio(String msg, double expected, double actual) {
+    double delta = Math.abs(actual - expected);
+    double base = Math.min(actual, expected);
+    double deltaRatio = base==0 ? delta : Math.min(delta,delta / base);
+    assertEquals(msg,0,deltaRatio, EPS);
+  }
+
+  protected int randomIntBetweenDivisible(int start, int end) {
+    return randomIntBetweenDivisible(start, end, (int)DIVISIBLE);
+  }
+  /** Returns a random integer between [start, end]. Integers between must be divisible by the 3rd argument. */
+  protected int randomIntBetweenDivisible(int start, int end, int divisible) {
+    // DWS: I tested this
+    int divisStart = (int) Math.ceil( (start+1) / (double)divisible );
+    int divisEnd = (int) Math.floor( (end-1) / (double)divisible );
+    int divisRange = Math.max(0,divisEnd - divisStart + 1);
+    int r = randomInt(1 + divisRange);//remember that '0' is counted
+    if (r == 0)
+      return start;
+    if (r == 1)
+      return end;
+    return (r-2 + divisStart)*divisible;
+  }
+
+  protected Rectangle randomRectangle(Point nearP) {
+    Rectangle bounds = ctx.getWorldBounds();
+    if (nearP == null)
+      nearP = randomPointIn(bounds);
+
+    Range xRange = randomRange(rarely() ? 0 : nearP.getX(), Range.xRange(bounds, ctx));
+    Range yRange = randomRange(rarely() ? 0 : nearP.getY(), Range.yRange(bounds, ctx));
+
+    return makeNormRect(
+        divisible(xRange.getMin()),
+        divisible(xRange.getMax()),
+        divisible(yRange.getMin()),
+        divisible(yRange.getMax()) );
+  }
+
+  private Range randomRange(double near, Range bounds) {
+    double mid = near + randomGaussian() * bounds.getWidth() / 6;
+    double width = Math.abs(randomGaussian()) * bounds.getWidth() / 6;//1/3rd
+    return new Range(mid - width / 2, mid + width / 2);
+  }
+
+  private double randomGaussianZeroTo(double max) {
+    if (max == 0)
+      return max;
+    assert max > 0;
+    double r;
+    do {
+      r = Math.abs(randomGaussian()) * (max * 0.50);
+    } while (r > max);
+    return r;
+  }
+
+  protected Rectangle randomRectangle(int divisible) {
+    double rX = randomIntBetweenDivisible(-180, 180, divisible);
+    double rW = randomIntBetweenDivisible(0, 360, divisible);
+    double rY1 = randomIntBetweenDivisible(-90, 90, divisible);
+    double rY2 = randomIntBetweenDivisible(-90, 90, divisible);
+    double rYmin = Math.min(rY1,rY2);
+    double rYmax = Math.max(rY1,rY2);
+    if (rW > 0 && rX == 180)
+      rX = -180;
+    return makeNormRect(rX, rX + rW, rYmin, rYmax);
+  }
+
+  protected Point randomPoint() {
+    return randomPointIn(ctx.getWorldBounds());
+  }
+
+  protected Point randomPointIn(Circle c) {
+    double d = c.getRadius() * randomDouble();
+    double angleDEG = 360 * randomDouble();
+    Point p = ctx.getDistCalc().pointOnBearing(c.getCenter(), d, angleDEG, ctx, null);
+    assertEquals(CONTAINS,c.relate(p));
+    return p;
+  }
+
+  protected Point randomPointIn(Rectangle r) {
+    double x = r.getMinX() + randomDouble()*r.getWidth();
+    double y = r.getMinY() + randomDouble()*r.getHeight();
+    x = normX(x);
+    y = normY(y);
+    Point p = ctx.makePoint(x,y);
+    assertEquals(CONTAINS,r.relate(p));
+    return p;
+  }
+
+  protected Point randomPointInOrNull(Shape shape) {
+    if (!shape.hasArea())// or try the center?
+      throw new UnsupportedOperationException("Need area to define shape!");
+    Rectangle bbox = shape.getBoundingBox();
+    for (int i = 0; i < 1000; i++) {
+      Point p = randomPointIn(bbox);
+      if (shape.relate(p).intersects()) {
+        return p;
+      }
+    }
+    return null;//tried too many times and failed
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java
new file mode 100644
index 0000000..1d559da
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.spatial4j.geo3d;
+
+import org.apache.lucene.geo3d.GeoPoint;
+import org.apache.lucene.geo3d.PlanetModel;
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+import com.spatial4j.core.distance.DistanceUtils;
+
+import static com.carrotsearch.randomizedtesting.RandomizedTest.randomFloat;
+
+/**
+ * Test basic GeoPoint functionality.
+ */
+public class GeoPointTest extends LuceneTestCase {
+
+  @Test
+  public void testConversion() {
+    testPointRoundTrip(PlanetModel.SPHERE, 90 * DistanceUtils.DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.SPHERE, -90 * DistanceUtils.DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, 90 * DistanceUtils.DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, -90 * DistanceUtils.DEGREES_TO_RADIANS, 0, 1e-6);
+
+    final int times = atLeast(100);
+    for (int i = 0; i < times; i++) {
+      final double pLat = (randomFloat() * 180.0 - 90.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      final double pLon = (randomFloat() * 360.0 - 180.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      testPointRoundTrip(PlanetModel.SPHERE, pLat, pLon, 1e-6);//1e-6 since there's a square root in there (Karl says)
+      testPointRoundTrip(PlanetModel.WGS84, pLat, pLon, 1e-6);
+    }
+  }
+
+  protected void testPointRoundTrip(PlanetModel planetModel, double pLat, double pLon, double epsilon) {
+    final GeoPoint p1 = new GeoPoint(planetModel, pLat, pLon);
+    // In order to force the reverse conversion, we have to construct a geopoint from just x,y,z
+    final GeoPoint p2 = new GeoPoint(p1.x, p1.y, p1.z);
+    // Now, construct the final point based on getLatitude() and getLongitude()
+    final GeoPoint p3 = new GeoPoint(planetModel, p2.getLatitude(), p2.getLongitude());
+    double dist = p1.arcDistance(p3);
+    assertEquals(0, dist, epsilon);
+  }
+
+  @Test
+  public void testSurfaceDistance() {
+    final int times = atLeast(100);
+    for (int i = 0; i < times; i++) {
+      final double p1Lat = (randomFloat() * 180.0 - 90.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      final double p1Lon = (randomFloat() * 360.0 - 180.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      final double p2Lat = (randomFloat() * 180.0 - 90.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      final double p2Lon = (randomFloat() * 360.0 - 180.0) * DistanceUtils.DEGREES_TO_RADIANS;
+      final GeoPoint p1 = new GeoPoint(PlanetModel.SPHERE, p1Lat, p1Lon);
+      final GeoPoint p2 = new GeoPoint(PlanetModel.SPHERE, p2Lat, p2Lon);
+      final double arcDistance = p1.arcDistance(p2);
+      // Compute ellipsoid distance; it should agree for a sphere
+      final double surfaceDistance = PlanetModel.SPHERE.surfaceDistance(p1,p2);
+      assertEquals(arcDistance, surfaceDistance, 1e-6);
+    }
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBadLatLon() {
+    new GeoPoint(PlanetModel.SPHERE, 50.0, 32.2);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial-extras/src/test/org/apache/lucene/spatial/vector/TestPointVectorStrategy.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/vector/TestPointVectorStrategy.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/vector/TestPointVectorStrategy.java
new file mode 100644
index 0000000..d62a0a8
--- /dev/null
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/vector/TestPointVectorStrategy.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lucene.spatial.vector;
+
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.shape.Circle;
+import com.spatial4j.core.shape.Point;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.spatial.SpatialMatchConcern;
+import org.apache.lucene.spatial.StrategyTestCase;
+import org.apache.lucene.spatial.query.SpatialArgs;
+import org.apache.lucene.spatial.query.SpatialOperation;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class TestPointVectorStrategy extends StrategyTestCase {
+
+  @Before
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    this.ctx = SpatialContext.GEO;
+    this.strategy = new PointVectorStrategy(ctx, getClass().getSimpleName());
+  }
+
+  @Test
+  public void testCircleShapeSupport() {
+    Circle circle = ctx.makeCircle(ctx.makePoint(0, 0), 10);
+    SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle);
+    Query query = this.strategy.makeQuery(args);
+
+    assertNotNull(query);
+  }
+
+  @Test(expected = UnsupportedOperationException.class)
+  public void testInvalidQueryShape() {
+    Point point = ctx.makePoint(0, 0);
+    SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, point);
+    this.strategy.makeQuery(args);
+  }
+
+  @Test
+  public void testCitiesIntersectsBBox() throws IOException {
+    getAddAndVerifyIndexedDocuments(DATA_WORLD_CITIES_POINTS);
+    executeQueries(SpatialMatchConcern.FILTER, QTEST_Cities_Intersects_BBox);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial/build.xml
----------------------------------------------------------------------
diff --git a/lucene/spatial/build.xml b/lucene/spatial/build.xml
index 4c348ee..08ab178 100644
--- a/lucene/spatial/build.xml
+++ b/lucene/spatial/build.xml
@@ -24,34 +24,4 @@
 
   <import file="../module-build.xml"/>
 
-  <path id="spatialjar">
-     <fileset dir="lib"/>
-  </path>
-
-  <path id="classpath">
-    <path refid="base.classpath"/>
-    <path refid="spatialjar"/>
-    <pathelement path="${queries.jar}" />
-    <pathelement path="${misc.jar}" />
-    <pathelement path="${spatial3d.jar}" />
-  </path>
-
-  <path id="test.classpath">
-    <path refid="test.base.classpath" />
-    <path refid="spatialjar"/>
-    <pathelement path="src/test-files" />
-  </path>
-
-  <target name="compile-core" depends="jar-queries,jar-misc,jar-spatial3d,common.compile-core" />
-
-  <target name="javadocs" depends="javadocs-queries,javadocs-misc,javadocs-spatial3d,compile-core,check-javadocs-uptodate"
-          unless="javadocs-uptodate-${name}">
-    <invoke-module-javadoc>
-      <links>
-        <link href="../queries"/>
-        <link href="../misc"/>
-        <link href="../spatial3d"/>
-      </links>
-    </invoke-module-javadoc>
-  </target>
 </project>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial/ivy.xml
----------------------------------------------------------------------
diff --git a/lucene/spatial/ivy.xml b/lucene/spatial/ivy.xml
index 1625bfd..a427271 100644
--- a/lucene/spatial/ivy.xml
+++ b/lucene/spatial/ivy.xml
@@ -18,19 +18,4 @@
 -->
 <ivy-module version="2.0"  xmlns:maven="http://ant.apache.org/ivy/maven">
   <info organisation="org.apache.lucene" module="spatial"/>
-  <configurations defaultconfmapping="compile->master;test->master">
-    <conf name="compile" transitive="false"/>
-    <conf name="test" transitive="false"/>
-  </configurations>
-  <dependencies>
-    <dependency org="com.spatial4j" name="spatial4j" rev="${/com.spatial4j/spatial4j}" conf="compile"/>
-
-    <dependency org="com.spatial4j" name="spatial4j" rev="${/com.spatial4j/spatial4j}" conf="test">
-      <artifact name="spatial4j" type="test" ext="jar" maven:classifier="tests" />
-    </dependency>
-
-    <dependency org="org.slf4j" name="slf4j-api" rev="${/org.slf4j/slf4j-api}" conf="test"/>
-
-    <exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
-  </dependencies>
 </ivy-module>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java b/lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java
deleted file mode 100644
index f433c11..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/SpatialStrategy.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.spatial;
-
-import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.shape.Point;
-import com.spatial4j.core.shape.Rectangle;
-import com.spatial4j.core.shape.Shape;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.valuesource.ReciprocalFloatFunction;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.spatial.query.SpatialArgs;
-
-/**
- * The SpatialStrategy encapsulates an approach to indexing and searching based
- * on shapes.
- * <p>
- * Different implementations will support different features. A strategy should
- * document these common elements:
- * <ul>
- *   <li>Can it index more than one shape per field?</li>
- *   <li>What types of shapes can be indexed?</li>
- *   <li>What types of query shapes can be used?</li>
- *   <li>What types of query operations are supported?
- *   This might vary per shape.</li>
- *   <li>Does it use some type of cache?  When?
- * </ul>
- * If a strategy only supports certain shapes at index or query time, then in
- * general it will throw an exception if given an incompatible one.  It will not
- * be coerced into compatibility.
- * <p>
- * Note that a SpatialStrategy is not involved with the Lucene stored field
- * values of shapes, which is immaterial to indexing and search.
- * <p>
- * Thread-safe.
- * <p>
- * This API is marked as experimental, however it is quite stable.
- *
- * @lucene.experimental
- */
-public abstract class SpatialStrategy {
-
-  protected final SpatialContext ctx;
-  private final String fieldName;
-
-  /**
-   * Constructs the spatial strategy with its mandatory arguments.
-   */
-  public SpatialStrategy(SpatialContext ctx, String fieldName) {
-    if (ctx == null)
-      throw new IllegalArgumentException("ctx is required");
-    this.ctx = ctx;
-    if (fieldName == null || fieldName.length() == 0)
-      throw new IllegalArgumentException("fieldName is required");
-    this.fieldName = fieldName;
-  }
-
-  public SpatialContext getSpatialContext() {
-    return ctx;
-  }
-
-  /**
-   * The name of the field or the prefix of them if there are multiple
-   * fields needed internally.
-   * @return Not null.
-   */
-  public String getFieldName() {
-    return fieldName;
-  }
-
-  /**
-   * Returns the IndexableField(s) from the {@code shape} that are to be
-   * added to the {@link org.apache.lucene.document.Document}.  These fields
-   * are expected to be marked as indexed and not stored.
-   * <p>
-   * Note: If you want to <i>store</i> the shape as a string for retrieval in
-   * search results, you could add it like this:
-   * <pre>document.add(new StoredField(fieldName,ctx.toString(shape)));</pre>
-   * The particular string representation used doesn't matter to the Strategy
-   * since it doesn't use it.
-   *
-   * @return Not null nor will it have null elements.
-   * @throws UnsupportedOperationException if given a shape incompatible with the strategy
-   */
-  public abstract Field[] createIndexableFields(Shape shape);
-
-  /**
-   * See {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point, double)} called with
-   * a multiplier of 1.0 (i.e. units of degrees).
-   */
-  public ValueSource makeDistanceValueSource(Point queryPoint) {
-    return makeDistanceValueSource(queryPoint, 1.0);
-  }
-
-  /**
-   * Make a ValueSource returning the distance between the center of the
-   * indexed shape and {@code queryPoint}.  If there are multiple indexed shapes
-   * then the closest one is chosen. The result is multiplied by {@code multiplier}, which
-   * conveniently is used to get the desired units.
-   */
-  public abstract ValueSource makeDistanceValueSource(Point queryPoint, double multiplier);
-
-  /**
-   * Make a Query based principally on {@link org.apache.lucene.spatial.query.SpatialOperation}
-   * and {@link Shape} from the supplied {@code args}.  It should be constant scoring of 1.
-   *
-   * @throws UnsupportedOperationException If the strategy does not support the shape in {@code args}
-   * @throws org.apache.lucene.spatial.query.UnsupportedSpatialOperation If the strategy does not support the {@link
-   * org.apache.lucene.spatial.query.SpatialOperation} in {@code args}.
-   */
-  public abstract Query makeQuery(SpatialArgs args);
-
-  /**
-   * Returns a ValueSource with values ranging from 1 to 0, depending inversely
-   * on the distance from {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point,double)}.
-   * The formula is {@code c/(d + c)} where 'd' is the distance and 'c' is
-   * one tenth the distance to the farthest edge from the center. Thus the
-   * scores will be 1 for indexed points at the center of the query shape and as
-   * low as ~0.1 at its furthest edges.
-   */
-  public final ValueSource makeRecipDistanceValueSource(Shape queryShape) {
-    Rectangle bbox = queryShape.getBoundingBox();
-    double diagonalDist = ctx.getDistCalc().distance(
-        ctx.makePoint(bbox.getMinX(), bbox.getMinY()), bbox.getMaxX(), bbox.getMaxY());
-    double distToEdge = diagonalDist * 0.5;
-    float c = (float)distToEdge * 0.1f;//one tenth
-    return new ReciprocalFloatFunction(makeDistanceValueSource(queryShape.getCenter(), 1.0), 1f, c, c);
-  }
-
-  @Override
-  public String toString() {
-    return getClass().getSimpleName()+" field:"+fieldName+" ctx="+ctx;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxOverlapRatioValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxOverlapRatioValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxOverlapRatioValueSource.java
deleted file mode 100644
index 9d0afe1..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxOverlapRatioValueSource.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.spatial.bbox;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.search.Explanation;
-
-import com.spatial4j.core.shape.Rectangle;
-
-/**
- * The algorithm is implemented as envelope on envelope (rect on rect) overlays rather than
- * complex polygon on complex polygon overlays.
- * <p>
- * Spatial relevance scoring algorithm:
- * <DL>
- *   <DT>queryArea</DT> <DD>the area of the input query envelope</DD>
- *   <DT>targetArea</DT> <DD>the area of the target envelope (per Lucene document)</DD>
- *   <DT>intersectionArea</DT> <DD>the area of the intersection between the query and target envelopes</DD>
- *   <DT>queryTargetProportion</DT> <DD>A 0-1 factor that divides the score proportion between query and target.
- *   0.5 is evenly.</DD>
- *
- *   <DT>queryRatio</DT> <DD>intersectionArea / queryArea; (see note)</DD>
- *   <DT>targetRatio</DT> <DD>intersectionArea / targetArea; (see note)</DD>
- *   <DT>queryFactor</DT> <DD>queryRatio * queryTargetProportion;</DD>
- *   <DT>targetFactor</DT> <DD>targetRatio * (1 - queryTargetProportion);</DD>
- *   <DT>score</DT> <DD>queryFactor + targetFactor;</DD>
- * </DL>
- * Additionally, note that an optional minimum side length {@code minSideLength} may be used whenever an
- * area is calculated (queryArea, targetArea, intersectionArea). This allows for points or horizontal/vertical lines
- * to be used as the query shape and in such case the descending order should have smallest boxes up front. Without
- * this, a point or line query shape typically scores everything with the same value since there is 0 area.
- * <p>
- * Note: The actual computation of queryRatio and targetRatio is more complicated so that it considers
- * points and lines. Lines have the ratio of overlap, and points are either 1.0 or 0.0 depending on whether
- * it intersects or not.
- * <p>
- * Originally based on Geoportal's
- * <a href="http://geoportal.svn.sourceforge.net/svnroot/geoportal/Geoportal/trunk/src/com/esri/gpt/catalog/lucene/SpatialRankingValueSource.java">
- *   SpatialRankingValueSource</a> but modified quite a bit. GeoPortal's algorithm will yield a score of 0
- * if either a line or point is compared, and it doesn't output a 0-1 normalized score (it multiplies the factors),
- * and it doesn't support minSideLength, and it had dateline bugs.
- *
- * @lucene.experimental
- */
-public class BBoxOverlapRatioValueSource extends BBoxSimilarityValueSource {
-
-  private final boolean isGeo;//-180/+180 degrees  (not part of identity; attached to parent strategy/field)
-
-  private final Rectangle queryExtent;
-  private final double queryArea;//not part of identity
-
-  private final double minSideLength;
-
-  private final double queryTargetProportion;
-
-  //TODO option to compute geodetic area
-
-  /**
-   *
-   * @param rectValueSource mandatory; source of rectangles
-   * @param isGeo True if ctx.isGeo() and thus dateline issues should be attended to
-   * @param queryExtent mandatory; the query rectangle
-   * @param queryTargetProportion see class javadocs. Between 0 and 1.
-   * @param minSideLength see class javadocs. 0.0 will effectively disable.
-   */
-  public BBoxOverlapRatioValueSource(ValueSource rectValueSource, boolean isGeo, Rectangle queryExtent,
-                                     double queryTargetProportion, double minSideLength) {
-    super(rectValueSource);
-    this.isGeo = isGeo;
-    this.minSideLength = minSideLength;
-    this.queryExtent = queryExtent;
-    this.queryArea = calcArea(queryExtent.getWidth(), queryExtent.getHeight());
-    assert queryArea >= 0;
-    this.queryTargetProportion = queryTargetProportion;
-    if (queryTargetProportion < 0 || queryTargetProportion > 1.0)
-      throw new IllegalArgumentException("queryTargetProportion must be >= 0 and <= 1");
-  }
-
-  /** Construct with 75% weighting towards target (roughly GeoPortal's default), geo degrees assumed, no
-   * minimum side length. */
-  public BBoxOverlapRatioValueSource(ValueSource rectValueSource, Rectangle queryExtent) {
-    this(rectValueSource, true, queryExtent, 0.25, 0.0);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!super.equals(o)) return false;
-
-    BBoxOverlapRatioValueSource that = (BBoxOverlapRatioValueSource) o;
-
-    if (Double.compare(that.minSideLength, minSideLength) != 0) return false;
-    if (Double.compare(that.queryTargetProportion, queryTargetProportion) != 0) return false;
-    if (!queryExtent.equals(that.queryExtent)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp;
-    result = 31 * result + queryExtent.hashCode();
-    temp = Double.doubleToLongBits(minSideLength);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(queryTargetProportion);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  protected String similarityDescription() {
-    return queryExtent.toString() + "," + queryTargetProportion;
-  }
-
-  @Override
-  protected double score(Rectangle target, AtomicReference<Explanation> exp) {
-    // calculate "height": the intersection height between two boxes.
-    double top = Math.min(queryExtent.getMaxY(), target.getMaxY());
-    double bottom = Math.max(queryExtent.getMinY(), target.getMinY());
-    double height = top - bottom;
-    if (height < 0) {
-      if (exp != null) {
-        exp.set(Explanation.noMatch("No intersection"));
-      }
-      return 0;//no intersection
-    }
-
-    // calculate "width": the intersection width between two boxes.
-    double width = 0;
-    {
-      Rectangle a = queryExtent;
-      Rectangle b = target;
-      if (a.getCrossesDateLine() == b.getCrossesDateLine()) {
-        //both either cross or don't
-        double left = Math.max(a.getMinX(), b.getMinX());
-        double right = Math.min(a.getMaxX(), b.getMaxX());
-        if (!a.getCrossesDateLine()) {//both don't
-          if (left <= right) {
-            width = right - left;
-          } else if (isGeo && (Math.abs(a.getMinX()) == 180 || Math.abs(a.getMaxX()) == 180)
-              && (Math.abs(b.getMinX()) == 180 || Math.abs(b.getMaxX()) == 180)) {
-            width = 0;//both adjacent to dateline
-          } else {
-            if (exp != null) {
-              exp.set(Explanation.noMatch("No intersection"));
-            }
-            return 0;//no intersection
-          }
-        } else {//both cross
-          width = right - left + 360;
-        }
-      } else {
-        if (!a.getCrossesDateLine()) {//then flip
-          a = target;
-          b = queryExtent;
-        }
-        //a crosses, b doesn't
-        double qryWestLeft = Math.max(a.getMinX(), b.getMinX());
-        double qryWestRight = b.getMaxX();
-        if (qryWestLeft < qryWestRight)
-          width += qryWestRight - qryWestLeft;
-
-        double qryEastLeft = b.getMinX();
-        double qryEastRight = Math.min(a.getMaxX(), b.getMaxX());
-        if (qryEastLeft < qryEastRight)
-          width += qryEastRight - qryEastLeft;
-
-        if (qryWestLeft > qryWestRight && qryEastLeft > qryEastRight) {
-          if (exp != null) {
-            exp.set(Explanation.noMatch("No intersection"));
-          }
-          return 0;//no intersection
-        }
-      }
-    }
-
-    // calculate queryRatio and targetRatio
-    double intersectionArea = calcArea(width, height);
-    double queryRatio;
-    if (queryArea > 0) {
-      queryRatio = intersectionArea / queryArea;
-    } else if (queryExtent.getHeight() > 0) {//vert line
-      queryRatio = height / queryExtent.getHeight();
-    } else if (queryExtent.getWidth() > 0) {//horiz line
-      queryRatio = width / queryExtent.getWidth();
-    } else {
-      queryRatio = queryExtent.relate(target).intersects() ? 1 : 0;//could be optimized
-    }
-
-    double targetArea = calcArea(target.getWidth(), target.getHeight());
-    assert targetArea >= 0;
-    double targetRatio;
-    if (targetArea > 0) {
-      targetRatio = intersectionArea / targetArea;
-    } else if (target.getHeight() > 0) {//vert line
-      targetRatio = height / target.getHeight();
-    } else if (target.getWidth() > 0) {//horiz line
-      targetRatio = width / target.getWidth();
-    } else {
-      targetRatio = target.relate(queryExtent).intersects() ? 1 : 0;//could be optimized
-    }
-    assert queryRatio >= 0 && queryRatio <= 1 : queryRatio;
-    assert targetRatio >= 0 && targetRatio <= 1 : targetRatio;
-
-    // combine ratios into a score
-
-    double queryFactor = queryRatio * queryTargetProportion;
-    double targetFactor = targetRatio * (1.0 - queryTargetProportion);
-    double score = queryFactor + targetFactor;
-
-    if (exp!=null) {
-      String minSideDesc = minSideLength > 0.0 ? " (minSide="+minSideLength+")" : "";
-      exp.set(Explanation.match((float) score,
-          this.getClass().getSimpleName()+": queryFactor + targetFactor",
-          Explanation.match((float)intersectionArea, "IntersectionArea" + minSideDesc,
-              Explanation.match((float)width, "width"),
-              Explanation.match((float)height, "height"),
-              Explanation.match((float)queryTargetProportion, "queryTargetProportion")),
-          Explanation.match((float)queryFactor, "queryFactor",
-              Explanation.match((float)targetRatio, "ratio"),
-              Explanation.match((float)queryArea,  "area of " + queryExtent + minSideDesc)),
-          Explanation.match((float)targetFactor, "targetFactor",
-              Explanation.match((float)targetRatio, "ratio"),
-              Explanation.match((float)targetArea,  "area of " + target + minSideDesc))));
-    }
-
-    return score;
-  }
-
-  /** Calculates the area while applying the minimum side length. */
-  private double calcArea(double width, double height) {
-    return Math.max(minSideLength, width) * Math.max(minSideLength, height);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/89db4950/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxSimilarityValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxSimilarityValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxSimilarityValueSource.java
deleted file mode 100644
index 15cd646..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/bbox/BBoxSimilarityValueSource.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.spatial.bbox;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
-import org.apache.lucene.search.Explanation;
-import org.apache.lucene.search.IndexSearcher;
-
-import com.spatial4j.core.shape.Rectangle;
-
-/**
- * A base class for calculating a spatial relevance rank per document from a provided
- * {@link ValueSource} in which {@link FunctionValues#objectVal(int)} returns a {@link
- * com.spatial4j.core.shape.Rectangle}.
- * <p>
- * Implementers: remember to implement equals and hashCode if you have
- * fields!
- *
- * @lucene.experimental
- */
-public abstract class BBoxSimilarityValueSource extends ValueSource {
-
-  private final ValueSource bboxValueSource;
-
-  public BBoxSimilarityValueSource(ValueSource bboxValueSource) {
-    this.bboxValueSource = bboxValueSource;
-  }
-
-  @Override
-  public void createWeight(Map context, IndexSearcher searcher) throws IOException {
-    bboxValueSource.createWeight(context, searcher);
-  }
-
-  @Override
-  public String description() {
-    return getClass().getSimpleName()+"(" + bboxValueSource.description() + "," + similarityDescription() + ")";
-  }
-
-  /** A comma-separated list of configurable items of the subclass to put into {@link #description()}. */
-  protected abstract String similarityDescription();
-
-  @Override
-  public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
-
-    final FunctionValues shapeValues = bboxValueSource.getValues(context, readerContext);
-
-    return new DoubleDocValues(this) {
-      @Override
-      public double doubleVal(int doc) {
-        //? limit to Rect or call getBoundingBox()? latter would encourage bad practice
-        final Rectangle rect = (Rectangle) shapeValues.objectVal(doc);
-        return rect==null ? 0 : score(rect, null);
-      }
-
-      @Override
-      public boolean exists(int doc) {
-        return shapeValues.exists(doc);
-      }
-
-      @Override
-      public Explanation explain(int doc) {
-        final Rectangle rect = (Rectangle) shapeValues.objectVal(doc);
-        if (rect == null)
-          return Explanation.noMatch("no rect");
-        AtomicReference<Explanation> explanation = new AtomicReference<>();
-        score(rect, explanation);
-        return explanation.get();
-      }
-    };
-  }
-
-  /**
-   * Return a relevancy score. If {@code exp} is provided then diagnostic information is added.
-   * @param rect The indexed rectangle; not null.
-   * @param exp Optional diagnostic holder.
-   * @return a score.
-   */
-  protected abstract double score(Rectangle rect, AtomicReference<Explanation> exp);
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;//same class
-
-    BBoxSimilarityValueSource that = (BBoxSimilarityValueSource) o;
-
-    if (!bboxValueSource.equals(that.bboxValueSource)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    return bboxValueSource.hashCode();
-  }
-}