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

[64/87] [abbrv] lucene-solr git commit: LUCENE-6997: refactors lucene-spatial module to a new lucene-spatial-extras module, and refactors sandbox GeoPointField and queries to lucene-spatial module

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java
new file mode 100644
index 0000000..45f8362
--- /dev/null
+++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoRelationUtils.java
@@ -0,0 +1,524 @@
+/*
+ * 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.util;
+
+import org.apache.lucene.util.SloppyMath;
+
+/**
+ * Reusable geo-relation utility methods
+ */
+public class GeoRelationUtils {
+
+  // No instance:
+  private GeoRelationUtils() {
+  }
+
+  /**
+   * Determine if a bbox (defined by minLon, minLat, maxLon, maxLat) contains the provided point (defined by lon, lat)
+   * NOTE: this is a basic method that does not handle dateline or pole crossing. Unwrapping must be done before
+   * calling this method.
+   */
+  public static boolean pointInRectPrecise(final double lon, final double lat, final double minLon,
+                                           final double minLat, final double maxLon, final double maxLat) {
+    return lon >= minLon && lon <= maxLon && lat >= minLat && lat <= maxLat;
+  }
+
+  /**
+   * simple even-odd point in polygon computation
+   *    1.  Determine if point is contained in the longitudinal range
+   *    2.  Determine whether point crosses the edge by computing the latitudinal delta
+   *        between the end-point of a parallel vector (originating at the point) and the
+   *        y-component of the edge sink
+   *
+   * NOTE: Requires polygon point (x,y) order either clockwise or counter-clockwise
+   */
+  public static boolean pointInPolygon(double[] x, double[] y, double lat, double lon) {
+    assert x.length == y.length;
+    boolean inPoly = false;
+    /**
+     * Note: This is using a euclidean coordinate system which could result in
+     * upwards of 110KM error at the equator.
+     * TODO convert coordinates to cylindrical projection (e.g. mercator)
+     */
+    for (int i = 1; i < x.length; i++) {
+      if (x[i] <= lon && x[i-1] >= lon || x[i-1] <= lon && x[i] >= lon) {
+        if (y[i] + (lon - x[i]) / (x[i-1] - x[i]) * (y[i-1] - y[i]) <= lat) {
+          inPoly = !inPoly;
+        }
+      }
+    }
+    return inPoly;
+  }
+
+  /////////////////////////
+  // Rectangle relations
+  /////////////////////////
+
+  /**
+   * Computes whether two rectangles are disjoint
+   */
+  public static boolean rectDisjoint(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
+                                     final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
+    return (aMaxX < bMinX || aMinX > bMaxX || aMaxY < bMinY || aMinY > bMaxY);
+  }
+
+  /**
+   * Computes whether the first (a) rectangle is wholly within another (b) rectangle (shared boundaries allowed)
+   */
+  public static boolean rectWithin(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
+                                   final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
+    return !(aMinX < bMinX || aMinY < bMinY || aMaxX > bMaxX || aMaxY > bMaxY);
+  }
+
+  /**
+   * Computes whether two rectangles cross
+   */
+  public static boolean rectCrosses(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
+                                    final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
+    return !(rectDisjoint(aMinX, aMinY, aMaxX, aMaxY, bMinX, bMinY, bMaxX, bMaxY) ||
+        rectWithin(aMinX, aMinY, aMaxX, aMaxY, bMinX, bMinY, bMaxX, bMaxY));
+  }
+
+  /**
+   * Computes whether rectangle a contains rectangle b (touching allowed)
+   */
+  public static boolean rectContains(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
+                                     final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
+    return !(bMinX < aMinX || bMinY < aMinY || bMaxX > aMaxX || bMaxY > aMaxY);
+  }
+
+  /**
+   * Computes whether a rectangle intersects another rectangle (crosses, within, touching, etc)
+   */
+  public static boolean rectIntersects(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
+                                       final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
+    return !((aMaxX < bMinX || aMinX > bMaxX || aMaxY < bMinY || aMinY > bMaxY) );
+  }
+
+  /////////////////////////
+  // Polygon relations
+  /////////////////////////
+
+  /**
+   * Convenience method for accurately computing whether a rectangle crosses a poly
+   */
+  public static boolean rectCrossesPolyPrecise(final double rMinX, final double rMinY, final double rMaxX,
+                                        final double rMaxY, final double[] shapeX, final double[] shapeY,
+                                        final double sMinX, final double sMinY, final double sMaxX,
+                                        final double sMaxY) {
+    // short-circuit: if the bounding boxes are disjoint then the shape does not cross
+    if (rectDisjoint(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY)) {
+      return false;
+    }
+    return rectCrossesPoly(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY);
+  }
+
+  /**
+   * Compute whether a rectangle crosses a shape. (touching not allowed) Includes a flag for approximating the
+   * relation.
+   */
+  public static boolean rectCrossesPolyApprox(final double rMinX, final double rMinY, final double rMaxX,
+                                              final double rMaxY, final double[] shapeX, final double[] shapeY,
+                                              final double sMinX, final double sMinY, final double sMaxX,
+                                              final double sMaxY) {
+    // short-circuit: if the bounding boxes are disjoint then the shape does not cross
+    if (rectDisjoint(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY)) {
+      return false;
+    }
+
+    final int polyLength = shapeX.length-1;
+    for (short p=0; p<polyLength; ++p) {
+      if (lineCrossesRect(shapeX[p], shapeY[p], shapeX[p+1], shapeY[p+1], rMinX, rMinY, rMaxX, rMaxY) == true) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Accurately compute (within restrictions of cartesian decimal degrees) whether a rectangle crosses a polygon
+   */
+  private static boolean rectCrossesPoly(final double rMinX, final double rMinY, final double rMaxX,
+                                         final double rMaxY, final double[] shapeX, final double[] shapeY) {
+    final double[][] bbox = new double[][] { {rMinX, rMinY}, {rMaxX, rMinY}, {rMaxX, rMaxY}, {rMinX, rMaxY}, {rMinX, rMinY} };
+    final int polyLength = shapeX.length-1;
+    double d, s, t, a1, b1, c1, a2, b2, c2;
+    double x00, y00, x01, y01, x10, y10, x11, y11;
+
+    // computes the intersection point between each bbox edge and the polygon edge
+    for (short b=0; b<4; ++b) {
+      a1 = bbox[b+1][1]-bbox[b][1];
+      b1 = bbox[b][0]-bbox[b+1][0];
+      c1 = a1*bbox[b+1][0] + b1*bbox[b+1][1];
+      for (int p=0; p<polyLength; ++p) {
+        a2 = shapeY[p+1]-shapeY[p];
+        b2 = shapeX[p]-shapeX[p+1];
+        // compute determinant
+        d = a1*b2 - a2*b1;
+        if (d != 0) {
+          // lines are not parallel, check intersecting points
+          c2 = a2*shapeX[p+1] + b2*shapeY[p+1];
+          s = (1/d)*(b2*c1 - b1*c2);
+          t = (1/d)*(a1*c2 - a2*c1);
+          x00 = StrictMath.min(bbox[b][0], bbox[b+1][0]) - GeoUtils.TOLERANCE;
+          x01 = StrictMath.max(bbox[b][0], bbox[b+1][0]) + GeoUtils.TOLERANCE;
+          y00 = StrictMath.min(bbox[b][1], bbox[b+1][1]) - GeoUtils.TOLERANCE;
+          y01 = StrictMath.max(bbox[b][1], bbox[b+1][1]) + GeoUtils.TOLERANCE;
+          x10 = StrictMath.min(shapeX[p], shapeX[p+1]) - GeoUtils.TOLERANCE;
+          x11 = StrictMath.max(shapeX[p], shapeX[p+1]) + GeoUtils.TOLERANCE;
+          y10 = StrictMath.min(shapeY[p], shapeY[p+1]) - GeoUtils.TOLERANCE;
+          y11 = StrictMath.max(shapeY[p], shapeY[p+1]) + GeoUtils.TOLERANCE;
+          // check whether the intersection point is touching one of the line segments
+          boolean touching = ((x00 == s && y00 == t) || (x01 == s && y01 == t))
+              || ((x10 == s && y10 == t) || (x11 == s && y11 == t));
+          // if line segments are not touching and the intersection point is within the range of either segment
+          if (!(touching || x00 > s || x01 < s || y00 > t || y01 < t || x10 > s || x11 < s || y10 > t || y11 < t)) {
+            return true;
+          }
+        }
+      } // for each poly edge
+    } // for each bbox edge
+    return false;
+  }
+
+  private static boolean lineCrossesRect(double aX1, double aY1, double aX2, double aY2,
+                                         final double rMinX, final double rMinY, final double rMaxX, final double rMaxY) {
+    // short-circuit: if one point inside rect, other outside
+    if (pointInRectPrecise(aX1, aY1, rMinX, rMinY, rMaxX, rMaxY) ?
+        !pointInRectPrecise(aX2, aY2, rMinX, rMinY, rMaxX, rMaxY) : pointInRectPrecise(aX2, aY2, rMinX, rMinY, rMaxX, rMaxY)) {
+      return true;
+    }
+
+    return lineCrossesLine(aX1, aY1, aX2, aY2, rMinX, rMinY, rMaxX, rMaxY)
+        || lineCrossesLine(aX1, aY1, aX2, aY2, rMaxX, rMinY, rMinX, rMaxY);
+  }
+
+  private static boolean lineCrossesLine(final double aX1, final double aY1, final double aX2, final double aY2,
+                                         final double bX1, final double bY1, final double bX2, final double bY2) {
+    // determine if three points are ccw (right-hand rule) by computing the determinate
+    final double aX2X1d = aX2 - aX1;
+    final double aY2Y1d = aY2 - aY1;
+    final double bX2X1d = bX2 - bX1;
+    final double bY2Y1d = bY2 - bY1;
+
+    final double t1B = aX2X1d * (bY2 - aY1) - aY2Y1d * (bX2 - aX1);
+    final double test1 = (aX2X1d * (bY1 - aY1) - aY2Y1d * (bX1 - aX1)) * t1B;
+    final double t2B = bX2X1d * (aY2 - bY1) - bY2Y1d * (aX2 - bX1);
+    final double test2 = (bX2X1d * (aY1 - bY1) - bY2Y1d * (aX1 - bX1)) * t2B;
+
+    if (test1 < 0 && test2 < 0) {
+      return true;
+    }
+
+    if (test1 == 0 || test2 == 0) {
+      // vertically collinear
+      if (aX1 == aX2 || bX1 == bX2) {
+        final double minAy = Math.min(aY1, aY2);
+        final double maxAy = Math.max(aY1, aY2);
+        final double minBy = Math.min(bY1, bY2);
+        final double maxBy = Math.max(bY1, bY2);
+
+        return !(minBy >= maxAy || maxBy <= minAy);
+      }
+      // horizontally collinear
+      final double minAx = Math.min(aX1, aX2);
+      final double maxAx = Math.max(aX1, aX2);
+      final double minBx = Math.min(bX1, bX2);
+      final double maxBx = Math.max(bX1, bX2);
+
+      return !(minBx >= maxAx || maxBx <= minAx);
+    }
+    return false;
+  }
+
+  /**
+   * Computes whether a rectangle is within a polygon (shared boundaries not allowed) with more rigor than the
+   * {@link GeoRelationUtils#rectWithinPolyApprox} counterpart
+   */
+  public static boolean rectWithinPolyPrecise(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                       final double[] shapeX, final double[] shapeY, final double sMinX,
+                                       final double sMinY, final double sMaxX, final double sMaxY) {
+    // check if rectangle crosses poly (to handle concave/pacman polys), then check that all 4 corners
+    // are contained
+    return !(rectCrossesPolyPrecise(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY, sMinX, sMinY, sMaxX, sMaxY) ||
+        !pointInPolygon(shapeX, shapeY, rMinY, rMinX) || !pointInPolygon(shapeX, shapeY, rMinY, rMaxX) ||
+        !pointInPolygon(shapeX, shapeY, rMaxY, rMaxX) || !pointInPolygon(shapeX, shapeY, rMaxY, rMinX));
+  }
+
+  /**
+   * Computes whether a rectangle is within a given polygon (shared boundaries allowed)
+   */
+  public static boolean rectWithinPolyApprox(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                       final double[] shapeX, final double[] shapeY, final double sMinX,
+                                       final double sMinY, final double sMaxX, final double sMaxY) {
+    // approximation: check if rectangle crosses poly (to handle concave/pacman polys), then check one of the corners
+    // are contained
+
+    // short-cut: if bounding boxes cross, rect is not within
+     if (rectCrosses(rMinX, rMinY, rMaxX, rMaxY, sMinX, sMinY, sMaxX, sMaxY) == true) {
+       return false;
+     }
+
+     return !(rectCrossesPolyApprox(rMinX, rMinY, rMaxX, rMaxY, shapeX, shapeY, sMinX, sMinY, sMaxX, sMaxY)
+         || !pointInPolygon(shapeX, shapeY, rMinY, rMinX));
+  }
+
+  /////////////////////////
+  // Circle relations
+  /////////////////////////
+
+  private static boolean rectAnyCornersInCircle(final double rMinX, final double rMinY, final double rMaxX,
+                                                final double rMaxY, final double centerLon, final double centerLat,
+                                                final double radiusMeters, final boolean approx) {
+    if (approx == true) {
+      return rectAnyCornersInCircleSloppy(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters);
+    }
+    double w = Math.abs(rMaxX - rMinX);
+    if (w <= 90.0) {
+      return GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMinX) <= radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMinX) <= radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMaxX) <= radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMaxX) <= radiusMeters;
+    }
+    // partition
+    w /= 4;
+    final double p1 = rMinX + w;
+    final double p2 = p1 + w;
+    final double p3 = p2 + w;
+
+    return GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMinX) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMinX) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, p1) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, p1) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, p2) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, p2) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, p3) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, p3) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMaxX) <= radiusMeters
+        || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMaxX) <= radiusMeters;
+  }
+
+  private static boolean rectAnyCornersInCircleSloppy(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                                      final double centerLon, final double centerLat, final double radiusMeters) {
+    return SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 <= radiusMeters;
+  }
+
+  /**
+   * Compute whether any of the 4 corners of the rectangle (defined by min/max X/Y) are outside the circle (defined
+   * by centerLon, centerLat, radiusMeters)
+   *
+   * Note: exotic rectangles at the poles (e.g., those whose lon/lat distance ratios greatly deviate from 1) can not
+   * be determined by using distance alone. For this reason the approx flag may be set to false, in which case the
+   * space will be further divided to more accurately compute whether the rectangle crosses the circle
+   */
+  private static boolean rectAnyCornersOutsideCircle(final double rMinX, final double rMinY, final double rMaxX,
+                                                     final double rMaxY, final double centerLon, final double centerLat,
+                                                     final double radiusMeters, final boolean approx) {
+    if (approx == true) {
+      return rectAnyCornersOutsideCircleSloppy(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters);
+    }
+    // if span is less than 70 degrees we can approximate using distance alone
+    if (Math.abs(rMaxX - rMinX) <= 70.0) {
+      return GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMinX) > radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMinX) > radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxY, rMaxX) > radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMinY, rMaxX) > radiusMeters;
+    }
+    return rectCrossesOblateCircle(centerLon, centerLat, radiusMeters, rMinX, rMinY, rMaxX, rMaxY);
+  }
+
+  /**
+   * Compute whether the rectangle (defined by min/max Lon/Lat) crosses a potentially oblate circle
+   *
+   * TODO benchmark for replacing existing rectCrossesCircle.
+   */
+  public static boolean rectCrossesOblateCircle(double centerLon, double centerLat, double radiusMeters, double rMinLon, double rMinLat, double  rMaxLon, double rMaxLat) {
+    double w = Math.abs(rMaxLon - rMinLon);
+    final int segs = (int)Math.ceil(w / 45.0);
+    w /= segs;
+    short i = 1;
+    double p1 = rMinLon;
+    double maxLon, midLon;
+    double[] pt = new double[2];
+
+    do {
+      maxLon = (i == segs) ? rMaxLon : p1 + w;
+
+      final double d1, d2;
+      // short-circuit if we find a corner outside the circle
+      if ( (d1 = GeoDistanceUtils.haversin(centerLat, centerLon, rMinLat, p1)) > radiusMeters
+          || (d2 = GeoDistanceUtils.haversin(centerLat, centerLon, rMinLat, maxLon)) > radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxLat, p1) > radiusMeters
+          || GeoDistanceUtils.haversin(centerLat, centerLon, rMaxLat, maxLon) > radiusMeters) {
+        return true;
+      }
+
+      // else we treat as an oblate circle by slicing the longitude space and checking the azimuthal range
+      // OPTIMIZATION: this is only executed for latitude values "closeTo" the poles (e.g., 88.0 > lat < -88.0)
+      if ( (rMaxLat > 88.0 || rMinLat < -88.0)
+          && (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(p1, rMinLat,
+          GeoProjectionUtils.bearingGreatCircle(p1, rMinLat, p1, rMaxLat), radiusMeters - d1, pt))[1] < rMinLat || pt[1] < rMaxLat
+          || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(maxLon, rMinLat,
+          GeoProjectionUtils.bearingGreatCircle(maxLon, rMinLat, maxLon, rMaxLat), radiusMeters - d2, pt))[1] < rMinLat || pt[1] < rMaxLat
+          || (pt = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(maxLon, rMinLat,
+          GeoProjectionUtils.bearingGreatCircle(maxLon, rMinLat, (midLon = p1 + 0.5*(maxLon - p1)), rMaxLat),
+          radiusMeters - GeoDistanceUtils.haversin(centerLat, centerLon, rMinLat, midLon), pt))[1] < rMinLat
+          || pt[1] < rMaxLat == false ) {
+        return true;
+      }
+      p1 += w;
+    } while (++i <= segs);
+    return false;
+  }
+
+  private static boolean rectAnyCornersOutsideCircleSloppy(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                                           final double centerLon, final double centerLat, final double radiusMeters) {
+    return SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 > radiusMeters;
+  }
+
+  /**
+   * Convenience method for computing whether a rectangle is within a circle using additional precision checks
+   */
+  public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                         final double centerLon, final double centerLat, final double radiusMeters) {
+    return rectWithinCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false);
+  }
+
+  /**
+   * Computes whether a rectangle is within a circle. Note: approx == true will be faster but less precise and may
+   * fail on large rectangles
+   */
+  public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                         final double centerLon, final double centerLat, final double radiusMeters,
+                                         final boolean approx) {
+    return rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx) == false;
+  }
+
+  /**
+   * Determine if a bbox (defined by minLon, minLat, maxLon, maxLat) contains the provided point (defined by lon, lat)
+   * NOTE: this is basic method that does not handle dateline or pole crossing. Unwrapping must be done before
+   * calling this method.
+   */
+  public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                          final double centerLon, final double centerLat, final double radiusMeters) {
+    return rectCrossesCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, false);
+  }
+
+  /**
+   * Computes whether a rectangle crosses a circle. Note: approx == true will be faster but less precise and may
+   * fail on large rectangles
+   */
+  public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                          final double centerLon, final double centerLat, final double radiusMeters,
+                                          final boolean approx) {
+    if (approx == true) {
+      return rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx)
+          || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx);
+    }
+
+    return (rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx) &&
+        rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx))
+        || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters, approx);
+  }
+
+  private static boolean isClosestPointOnRectWithinRange(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                                         final double centerLon, final double centerLat, final double radiusMeters,
+                                                         final boolean approx) {
+    double[] closestPt = {0, 0};
+    GeoDistanceUtils.closestPointOnBBox(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, closestPt);
+    boolean haverShortCut = GeoDistanceUtils.haversin(centerLat, centerLon, closestPt[1], closestPt[0]) <= radiusMeters;
+    if (approx == true || haverShortCut == true) {
+      return haverShortCut;
+    }
+    double lon1 = rMinX;
+    double lon2 = rMaxX;
+    double lat1 = rMinY;
+    double lat2 = rMaxY;
+    if (closestPt[0] == rMinX || closestPt[0] == rMaxX) {
+      lon1 = closestPt[0];
+      lon2 = lon1;
+    } else if (closestPt[1] == rMinY || closestPt[1] == rMaxY) {
+      lat1 = closestPt[1];
+      lat2 = lat1;
+    }
+
+    return lineCrossesSphere(lon1, lat1, 0, lon2, lat2, 0, centerLon, centerLat, 0, radiusMeters);
+  }
+
+  /**
+   * Computes whether or a 3dimensional line segment intersects or crosses a sphere
+   *
+   * @param lon1 longitudinal location of the line segment start point (in degrees)
+   * @param lat1 latitudinal location of the line segment start point (in degrees)
+   * @param alt1 altitude of the line segment start point (in degrees)
+   * @param lon2 longitudinal location of the line segment end point (in degrees)
+   * @param lat2 latitudinal location of the line segment end point (in degrees)
+   * @param alt2 altitude of the line segment end point (in degrees)
+   * @param centerLon longitudinal location of center search point (in degrees)
+   * @param centerLat latitudinal location of center search point (in degrees)
+   * @param centerAlt altitude of the center point (in meters)
+   * @param radiusMeters search sphere radius (in meters)
+   * @return whether the provided line segment is a secant of the
+   */
+  private static boolean lineCrossesSphere(double lon1, double lat1, double alt1, double lon2,
+                                           double lat2, double alt2, double centerLon, double centerLat,
+                                           double centerAlt, double radiusMeters) {
+    // convert to cartesian 3d (in meters)
+    double[] ecf1 = GeoProjectionUtils.llaToECF(lon1, lat1, alt1, null);
+    double[] ecf2 = GeoProjectionUtils.llaToECF(lon2, lat2, alt2, null);
+    double[] cntr = GeoProjectionUtils.llaToECF(centerLon, centerLat, centerAlt, null);
+
+    // convert radius from arc radius to cartesian radius
+    double[] oneEighty = GeoProjectionUtils.pointFromLonLatBearingGreatCircle(centerLon, centerLat, 180.0d, radiusMeters, new double[3]);
+    GeoProjectionUtils.llaToECF(oneEighty[0], oneEighty[1], 0, oneEighty);
+
+    radiusMeters = GeoDistanceUtils.linearDistance(oneEighty, cntr);//   Math.sqrt(oneEighty[0]*cntr[0] + oneEighty[1]*cntr[1] + oneEighty[2]*cntr[2]);
+
+    final double dX = ecf2[0] - ecf1[0];
+    final double dY = ecf2[1] - ecf1[1];
+    final double dZ = ecf2[2] - ecf1[2];
+    final double fX = ecf1[0] - cntr[0];
+    final double fY = ecf1[1] - cntr[1];
+    final double fZ = ecf1[2] - cntr[2];
+
+    final double a = dX*dX + dY*dY + dZ*dZ;
+    final double b = 2 * (fX*dX + fY*dY + fZ*dZ);
+    final double c = (fX*fX + fY*fY + fZ*fZ) - (radiusMeters*radiusMeters);
+
+    double discrim = (b*b)-(4*a*c);
+    if (discrim < 0) {
+      return false;
+    }
+
+    discrim = StrictMath.sqrt(discrim);
+    final double a2 = 2*a;
+    final double t1 = (-b - discrim)/a2;
+    final double t2 = (-b + discrim)/a2;
+
+    if ( (t1 < 0 || t1 > 1) ) {
+      return !(t2 < 0 || t2 > 1);
+    }
+
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java
new file mode 100644
index 0000000..a6512cd
--- /dev/null
+++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/GeoUtils.java
@@ -0,0 +1,247 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+
+import org.apache.lucene.util.BitUtil;
+
+import static java.lang.StrictMath.max;
+import static java.lang.StrictMath.min;
+import static java.lang.StrictMath.PI;
+
+import static org.apache.lucene.util.SloppyMath.asin;
+import static org.apache.lucene.util.SloppyMath.cos;
+import static org.apache.lucene.util.SloppyMath.sin;
+import static org.apache.lucene.util.SloppyMath.TO_DEGREES;
+import static org.apache.lucene.util.SloppyMath.TO_RADIANS;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LAT_RADIANS;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.MAX_LON_RADIANS;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LAT_RADIANS;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.MIN_LON_RADIANS;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.pointFromLonLatBearingGreatCircle;
+import static org.apache.lucene.spatial.util.GeoProjectionUtils.SEMIMAJOR_AXIS;
+
+/**
+ * Basic reusable geo-spatial utility methods
+ *
+ * @lucene.experimental
+ */
+public final class GeoUtils {
+  /** number of bits used for quantizing latitude and longitude values */
+  public static final short BITS = 31;
+  private static final double LON_SCALE = (0x1L<<BITS)/360.0D;
+  private static final double LAT_SCALE = (0x1L<<BITS)/180.0D;
+  /** rounding error for quantized latitude and longitude values */
+  public static final double TOLERANCE = 1E-6;
+
+  /** Minimum longitude value. */
+  public static final double MIN_LON_INCL = -180.0D;
+
+  /** Maximum longitude value. */
+  public static final double MAX_LON_INCL = 180.0D;
+
+  /** Minimum latitude value. */
+  public static final double MIN_LAT_INCL = -90.0D;
+
+  /** Maximum latitude value. */
+  public static final double MAX_LAT_INCL = 90.0D;
+
+  // No instance:
+  private GeoUtils() {
+  }
+
+  /**
+   * encode longitude, latitude geopoint values using morton encoding method
+   * https://en.wikipedia.org/wiki/Z-order_curve
+   */
+  public static final Long mortonHash(final double lon, final double lat) {
+    return BitUtil.interleave(scaleLon(lon), scaleLat(lat));
+  }
+
+  /** decode longitude value from morton encoded geo point */
+  public static final double mortonUnhashLon(final long hash) {
+    return unscaleLon(BitUtil.deinterleave(hash));
+  }
+
+  /** decode latitude value from morton encoded geo point */
+  public static final double mortonUnhashLat(final long hash) {
+    return unscaleLat(BitUtil.deinterleave(hash >>> 1));
+  }
+
+  private static final long scaleLon(final double val) {
+    return (long) ((val-MIN_LON_INCL) * LON_SCALE);
+  }
+
+  private static final long scaleLat(final double val) {
+    return (long) ((val-MIN_LAT_INCL) * LAT_SCALE);
+  }
+
+  private static final double unscaleLon(final long val) {
+    return (val / LON_SCALE) + MIN_LON_INCL;
+  }
+
+  private static final double unscaleLat(final long val) {
+    return (val / LAT_SCALE) + MIN_LAT_INCL;
+  }
+
+  /** Compare two position values within a {@link GeoUtils#TOLERANCE} factor */
+  public static double compare(final double v1, final double v2) {
+    final double delta = v1-v2;
+    return Math.abs(delta) <= TOLERANCE ? 0 : delta;
+  }
+
+  /** Puts longitude in range of -180 to +180. */
+  public static double normalizeLon(double lon_deg) {
+    if (lon_deg >= -180 && lon_deg <= 180) {
+      return lon_deg; //common case, and avoids slight double precision shifting
+    }
+    double off = (lon_deg + 180) % 360;
+    if (off < 0) {
+      return 180 + off;
+    } else if (off == 0 && lon_deg > 0) {
+      return 180;
+    } else {
+      return -180 + off;
+    }
+  }
+
+  /** Puts latitude in range of -90 to 90. */
+  public static double normalizeLat(double lat_deg) {
+    if (lat_deg >= -90 && lat_deg <= 90) {
+      return lat_deg; //common case, and avoids slight double precision shifting
+    }
+    double off = Math.abs((lat_deg + 90) % 360);
+    return (off <= 180 ? off : 360-off) - 90;
+  }
+
+  /** Converts long value to bit string (useful for debugging) */
+  public static String geoTermToString(long term) {
+    StringBuilder s = new StringBuilder(64);
+    final int numberOfLeadingZeros = Long.numberOfLeadingZeros(term);
+    for (int i = 0; i < numberOfLeadingZeros; i++) {
+      s.append('0');
+    }
+    if (term != 0) {
+      s.append(Long.toBinaryString(term));
+    }
+    return s.toString();
+  }
+
+  /**
+   * Converts a given circle (defined as a point/radius) to an approximated line-segment polygon
+   *
+   * @param lon longitudinal center of circle (in degrees)
+   * @param lat latitudinal center of circle (in degrees)
+   * @param radiusMeters distance radius of circle (in meters)
+   * @return a list of lon/lat points representing the circle
+   */
+  @SuppressWarnings({"unchecked","rawtypes"})
+  public static ArrayList<double[]> circleToPoly(final double lon, final double lat, final double radiusMeters) {
+    double angle;
+    // a little under-sampling (to limit the number of polygonal points): using archimedes estimation of pi
+    final int sides = 25;
+    ArrayList<double[]> geometry = new ArrayList();
+    double[] lons = new double[sides];
+    double[] lats = new double[sides];
+
+    double[] pt = new double[2];
+    final int sidesLen = sides-1;
+    for (int i=0; i<sidesLen; ++i) {
+      angle = (i*360/sides);
+      pt = pointFromLonLatBearingGreatCircle(lon, lat, angle, radiusMeters, pt);
+      lons[i] = pt[0];
+      lats[i] = pt[1];
+    }
+    // close the poly
+    lons[sidesLen] = lons[0];
+    lats[sidesLen] = lats[0];
+    geometry.add(lons);
+    geometry.add(lats);
+
+    return geometry;
+  }
+
+  /** Compute Bounding Box for a circle using WGS-84 parameters */
+  public static GeoBoundingBox circleToBBox(final double centerLon, final double centerLat, final double radiusMeters) {
+    final double radLat = TO_RADIANS * centerLat;
+    final double radLon = TO_RADIANS * centerLon;
+    double radDistance = radiusMeters / SEMIMAJOR_AXIS;
+    double minLat = radLat - radDistance;
+    double maxLat = radLat + radDistance;
+    double minLon;
+    double maxLon;
+
+    if (minLat > MIN_LAT_RADIANS && maxLat < MAX_LAT_RADIANS) {
+      double deltaLon = asin(sin(radDistance) / cos(radLat));
+      minLon = radLon - deltaLon;
+      if (minLon < MIN_LON_RADIANS) {
+        minLon += 2d * PI;
+      }
+      maxLon = radLon + deltaLon;
+      if (maxLon > MAX_LON_RADIANS) {
+        maxLon -= 2d * PI;
+      }
+    } else {
+      // a pole is within the distance
+      minLat = max(minLat, MIN_LAT_RADIANS);
+      maxLat = min(maxLat, MAX_LAT_RADIANS);
+      minLon = MIN_LON_RADIANS;
+      maxLon = MAX_LON_RADIANS;
+    }
+
+    return new GeoBoundingBox(TO_DEGREES * minLon, TO_DEGREES * maxLon, TO_DEGREES * minLat, TO_DEGREES * maxLat);
+  }
+
+  /** Compute Bounding Box for a polygon using WGS-84 parameters */
+  public static GeoBoundingBox polyToBBox(double[] polyLons, double[] polyLats) {
+    if (polyLons.length != polyLats.length) {
+      throw new IllegalArgumentException("polyLons and polyLats must be equal length");
+    }
+
+    double minLon = Double.POSITIVE_INFINITY;
+    double maxLon = Double.NEGATIVE_INFINITY;
+    double minLat = Double.POSITIVE_INFINITY;
+    double maxLat = Double.NEGATIVE_INFINITY;
+
+    for (int i=0;i<polyLats.length;i++) {
+      if (GeoUtils.isValidLon(polyLons[i]) == false) {
+        throw new IllegalArgumentException("invalid polyLons[" + i + "]=" + polyLons[i]);
+      }
+      if (GeoUtils.isValidLat(polyLats[i]) == false) {
+        throw new IllegalArgumentException("invalid polyLats[" + i + "]=" + polyLats[i]);
+      }
+      minLon = min(polyLons[i], minLon);
+      maxLon = max(polyLons[i], maxLon);
+      minLat = min(polyLats[i], minLat);
+      maxLat = max(polyLats[i], maxLat);
+    }
+    // expand bounding box by TOLERANCE factor to handle round-off error
+    return new GeoBoundingBox(max(minLon - TOLERANCE, MIN_LON_INCL), min(maxLon + TOLERANCE, MAX_LON_INCL),
+        max(minLat - TOLERANCE, MIN_LAT_INCL), min(maxLat + TOLERANCE, MAX_LAT_INCL));
+  }
+
+  /** validates latitude value is within standard +/-90 coordinate bounds */
+  public static boolean isValidLat(double lat) {
+    return Double.isNaN(lat) == false && lat >= MIN_LAT_INCL && lat <= MAX_LAT_INCL;
+  }
+
+  /** validates longitude value is within standard +/-180 coordinate bounds */
+  public static boolean isValidLon(double lon) {
+    return Double.isNaN(lon) == false && lon >= MIN_LON_INCL && lon <= MAX_LON_INCL;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
deleted file mode 100644
index dd391d1..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeAreaValueSource.java
+++ /dev/null
@@ -1,116 +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.util;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.shape.Shape;
-
-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;
-
-/**
- * The area of a Shape retrieved from a ValueSource via
- * {@link org.apache.lucene.queries.function.FunctionValues#objectVal(int)}.
- *
- * @see Shape#getArea(com.spatial4j.core.context.SpatialContext)
- *
- * @lucene.experimental
- */
-public class ShapeAreaValueSource extends ValueSource {
-  private final ValueSource shapeValueSource;
-  private final SpatialContext ctx;//not part of identity; should be associated with shapeValueSource indirectly
-  private final boolean geoArea;
-  private double multiplier;
-
-  public ShapeAreaValueSource(ValueSource shapeValueSource, SpatialContext ctx, boolean geoArea, double multiplier) {
-    this.shapeValueSource = shapeValueSource;
-    this.ctx = ctx;
-    this.geoArea = geoArea;
-    this.multiplier = multiplier;
-  }
-
-  @Override
-  public String description() {
-    return "area(" + shapeValueSource.description() + ",geo=" + geoArea + ")";
-  }
-
-  @Override
-  public void createWeight(Map context, IndexSearcher searcher) throws IOException {
-    shapeValueSource.createWeight(context, searcher);
-  }
-
-  @Override
-  public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
-    final FunctionValues shapeValues = shapeValueSource.getValues(context, readerContext);
-
-    return new DoubleDocValues(this) {
-      @Override
-      public double doubleVal(int doc) {
-        Shape shape = (Shape) shapeValues.objectVal(doc);
-        if (shape == null || shape.isEmpty())
-          return 0;//or NaN?
-        //This part of Spatial4j API is kinda weird. Passing null means 2D area, otherwise geo
-        //   assuming ctx.isGeo()
-        return shape.getArea( geoArea ? ctx : null ) * multiplier;
-      }
-
-      @Override
-      public boolean exists(int doc) {
-        return shapeValues.exists(doc);
-      }
-
-      @Override
-      public Explanation explain(int doc) {
-        Explanation exp = super.explain(doc);
-        List<Explanation> details = new ArrayList<>(Arrays.asList(exp.getDetails()));
-        details.add(shapeValues.explain(doc));
-        return Explanation.match(exp.getValue(), exp.getDescription(), details);
-      }
-    };
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    ShapeAreaValueSource that = (ShapeAreaValueSource) o;
-
-    if (geoArea != that.geoArea) return false;
-    if (!shapeValueSource.equals(that.shapeValueSource)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = shapeValueSource.hashCode();
-    result = 31 * result + (geoArea ? 1 : 0);
-    return result;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCache.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCache.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCache.java
deleted file mode 100644
index 480369b..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCache.java
+++ /dev/null
@@ -1,54 +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.util;
-
-import com.spatial4j.core.shape.Shape;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Bounded Cache of Shapes associated with docIds.  Note, multiple Shapes can be
- * associated with a given docId.
- * <p>
- * WARNING: This class holds the data in an extremely inefficient manner as all Points are in memory as objects and they
- * are stored in many ArrayLists (one per document).  So it works but doesn't scale.  It will be replaced in the future.
- *
- * @lucene.internal
- */
-public class ShapeFieldCache<T extends Shape> {
-  private final List<T>[] cache;
-  public final int defaultLength;
-
-  @SuppressWarnings({"unchecked", "rawtypes"})
-  public ShapeFieldCache( int length, int defaultLength ) {
-    cache = new List[length];
-    this.defaultLength= defaultLength;
-  }
-
-  public void add( int docid, T s ) {
-    List<T> list = cache[docid];
-    if( list == null ) {
-      list = cache[docid] = new ArrayList<>(defaultLength);
-    }
-    list.add( s );
-  }
-
-  public List<T> getShapes( int docid ) {
-    return cache[docid];
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheDistanceValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheDistanceValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheDistanceValueSource.java
deleted file mode 100644
index e4cb146..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheDistanceValueSource.java
+++ /dev/null
@@ -1,112 +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.util;
-
-import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.distance.DistanceCalculator;
-import com.spatial4j.core.shape.Point;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An implementation of the Lucene ValueSource that returns the spatial distance
- * between an input point and a document's points in
- * {@link ShapeFieldCacheProvider}. The shortest distance is returned if a
- * document has more than one point.
- *
- * @lucene.internal
- */
-public class ShapeFieldCacheDistanceValueSource extends ValueSource {
-
-  private final SpatialContext ctx;
-  private final Point from;
-  private final ShapeFieldCacheProvider<Point> provider;
-  private final double multiplier;
-
-  public ShapeFieldCacheDistanceValueSource(SpatialContext ctx,
-      ShapeFieldCacheProvider<Point> provider, Point from, double multiplier) {
-    this.ctx = ctx;
-    this.from = from;
-    this.provider = provider;
-    this.multiplier = multiplier;
-  }
-
-  @Override
-  public String description() {
-    return getClass().getSimpleName()+"("+provider+", "+from+")";
-  }
-
-  @Override
-  public FunctionValues getValues(Map context, final LeafReaderContext readerContext) throws IOException {
-    return new FunctionValues() {
-      private final ShapeFieldCache<Point> cache =
-          provider.getCache(readerContext.reader());
-      private final Point from = ShapeFieldCacheDistanceValueSource.this.from;
-      private final DistanceCalculator calculator = ctx.getDistCalc();
-      private final double nullValue = (ctx.isGeo() ? 180 * multiplier : Double.MAX_VALUE);
-
-      @Override
-      public float floatVal(int doc) {
-        return (float) doubleVal(doc);
-      }
-
-      @Override
-      public double doubleVal(int doc) {
-
-        List<Point> vals = cache.getShapes( doc );
-        if( vals != null ) {
-          double v = calculator.distance(from, vals.get(0));
-          for( int i=1; i<vals.size(); i++ ) {
-            v = Math.min(v, calculator.distance(from, vals.get(i)));
-          }
-          return v * multiplier;
-        }
-        return nullValue;
-      }
-
-      @Override
-      public String toString(int doc) {
-        return description() + "=" + floatVal(doc);
-      }
-    };
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    ShapeFieldCacheDistanceValueSource that = (ShapeFieldCacheDistanceValueSource) o;
-
-    if (!ctx.equals(that.ctx)) return false;
-    if (!from.equals(that.from)) return false;
-    if (!provider.equals(that.provider)) return false;
-    if (multiplier != that.multiplier) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    return from.hashCode();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheProvider.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheProvider.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheProvider.java
deleted file mode 100644
index 04c52f7..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapeFieldCacheProvider.java
+++ /dev/null
@@ -1,87 +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.util;
-
-import com.spatial4j.core.shape.Shape;
-import org.apache.lucene.index.*;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.util.BytesRef;
-
-import java.io.IOException;
-import java.util.WeakHashMap;
-import java.util.logging.Logger;
-
-/**
- * Provides access to a {@link ShapeFieldCache} for a given {@link org.apache.lucene.index.LeafReader}.
- *
- * If a Cache does not exist for the Reader, then it is built by iterating over
- * the all terms for a given field, reconstructing the Shape from them, and adding
- * them to the Cache.
- *
- * @lucene.internal
- */
-public abstract class ShapeFieldCacheProvider<T extends Shape> {
-  private Logger log = Logger.getLogger(getClass().getName());
-
-  // it may be a List<T> or T
-  WeakHashMap<IndexReader, ShapeFieldCache<T>> sidx = new WeakHashMap<>();
-
-  protected final int defaultSize;
-  protected final String shapeField;
-
-  public ShapeFieldCacheProvider(String shapeField, int defaultSize) {
-    this.shapeField = shapeField;
-    this.defaultSize = defaultSize;
-  }
-
-  protected abstract T readShape( BytesRef term );
-
-  public synchronized ShapeFieldCache<T> getCache(LeafReader reader) throws IOException {
-    ShapeFieldCache<T> idx = sidx.get(reader);
-    if (idx != null) {
-      return idx;
-    }
-    long startTime = System.currentTimeMillis();
-
-    log.fine("Building Cache [" + reader.maxDoc() + "]");
-    idx = new ShapeFieldCache<>(reader.maxDoc(),defaultSize);
-    int count = 0;
-    PostingsEnum docs = null;
-    Terms terms = reader.terms(shapeField);
-    if (terms != null) {
-      TermsEnum te = terms.iterator();
-      BytesRef term = te.next();
-      while (term != null) {
-        T shape = readShape(term);
-        if( shape != null ) {
-          docs = te.postings(docs, PostingsEnum.NONE);
-          Integer docid = docs.nextDoc();
-          while (docid != DocIdSetIterator.NO_MORE_DOCS) {
-            idx.add( docid, shape );
-            docid = docs.nextDoc();
-            count++;
-          }
-        }
-        term = te.next();
-      }
-    }
-    sidx.put(reader, idx);
-    long elapsed = System.currentTimeMillis() - startTime;
-    log.fine("Cached: [" + count + " in " + elapsed + "ms] " + idx);
-    return idx;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapePredicateValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapePredicateValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapePredicateValueSource.java
deleted file mode 100644
index b1dfaaa..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/ShapePredicateValueSource.java
+++ /dev/null
@@ -1,113 +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.util;
-
-import com.spatial4j.core.shape.Shape;
-
-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.BoolDocValues;
-import org.apache.lucene.search.Explanation;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.spatial.query.SpatialOperation;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A boolean ValueSource that compares a shape from a provided ValueSource with a given Shape and sees
- * if it matches a given {@link SpatialOperation} (the predicate).
- *
- * @lucene.experimental
- */
-public class ShapePredicateValueSource extends ValueSource {
-  private final ValueSource shapeValuesource;//the left hand side
-  private final SpatialOperation op;
-  private final Shape queryShape;//the right hand side (constant)
-
-  /**
-   *
-   * @param shapeValuesource Must yield {@link Shape} instances from its objectVal(doc). If null
-   *                         then the result is false. This is the left-hand (indexed) side.
-   * @param op the predicate
-   * @param queryShape The shape on the right-hand (query) side.
-   */
-  public ShapePredicateValueSource(ValueSource shapeValuesource, SpatialOperation op, Shape queryShape) {
-    this.shapeValuesource = shapeValuesource;
-    this.op = op;
-    this.queryShape = queryShape;
-  }
-
-  @Override
-  public String description() {
-    return shapeValuesource + " " + op + " " + queryShape;
-  }
-
-  @Override
-  public void createWeight(Map context, IndexSearcher searcher) throws IOException {
-    shapeValuesource.createWeight(context, searcher);
-  }
-
-  @Override
-  public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
-    final FunctionValues shapeValues = shapeValuesource.getValues(context, readerContext);
-
-    return new BoolDocValues(this) {
-      @Override
-      public boolean boolVal(int doc) {
-        Shape indexedShape = (Shape) shapeValues.objectVal(doc);
-        if (indexedShape == null)
-          return false;
-        return op.evaluate(indexedShape, queryShape);
-      }
-
-      @Override
-      public Explanation explain(int doc) {
-        Explanation exp = super.explain(doc);
-        List<Explanation> details = new ArrayList<>(Arrays.asList(exp.getDetails()));
-        details.add(shapeValues.explain(doc));
-        return Explanation.match(exp.getValue(), exp.getDescription(), details);
-      }
-    };
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    ShapePredicateValueSource that = (ShapePredicateValueSource) o;
-
-    if (!shapeValuesource.equals(that.shapeValuesource)) return false;
-    if (!op.equals(that.op)) return false;
-    if (!queryShape.equals(that.queryShape)) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = shapeValuesource.hashCode();
-    result = 31 * result + op.hashCode();
-    result = 31 * result + queryShape.hashCode();
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/util/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/util/package-info.java b/lucene/spatial/src/java/org/apache/lucene/spatial/util/package-info.java
index 39c3c40..5943573 100644
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/util/package-info.java
+++ b/lucene/spatial/src/java/org/apache/lucene/spatial/util/package-info.java
@@ -14,7 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-/** 
- * Various spatial utilities.
+
+/**
+ * Geospatial Utility Classes For Core Lucene
  */
-package org.apache.lucene.spatial.util;
+package org.apache.lucene.spatial.util;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/vector/DistanceValueSource.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/DistanceValueSource.java b/lucene/spatial/src/java/org/apache/lucene/spatial/vector/DistanceValueSource.java
deleted file mode 100644
index d31fd59..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/DistanceValueSource.java
+++ /dev/null
@@ -1,120 +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.vector;
-
-import com.spatial4j.core.distance.DistanceCalculator;
-import com.spatial4j.core.shape.Point;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.queries.function.FunctionValues;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.util.Bits;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * An implementation of the Lucene ValueSource model that returns the distance
- * for a {@link PointVectorStrategy}.
- *
- * @lucene.internal
- */
-public class DistanceValueSource extends ValueSource {
-
-  private PointVectorStrategy strategy;
-  private final Point from;
-  private final double multiplier;
-
-  /**
-   * Constructor.
-   */
-  public DistanceValueSource(PointVectorStrategy strategy, Point from, double multiplier) {
-    this.strategy = strategy;
-    this.from = from;
-    this.multiplier = multiplier;
-  }
-
-  /**
-   * Returns the ValueSource description.
-   */
-  @Override
-  public String description() {
-    return "DistanceValueSource("+strategy+", "+from+")";
-  }
-
-  /**
-   * Returns the FunctionValues used by the function query.
-   */
-  @Override
-  public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
-    LeafReader reader = readerContext.reader();
-
-    final NumericDocValues ptX = DocValues.getNumeric(reader, strategy.getFieldNameX());
-    final NumericDocValues ptY = DocValues.getNumeric(reader, strategy.getFieldNameY());
-    final Bits validX =  DocValues.getDocsWithField(reader, strategy.getFieldNameX());
-    final Bits validY =  DocValues.getDocsWithField(reader, strategy.getFieldNameY());
-
-    return new FunctionValues() {
-
-      private final Point from = DistanceValueSource.this.from;
-      private final DistanceCalculator calculator = strategy.getSpatialContext().getDistCalc();
-      private final double nullValue =
-          (strategy.getSpatialContext().isGeo() ? 180 * multiplier : Double.MAX_VALUE);
-
-      @Override
-      public float floatVal(int doc) {
-        return (float) doubleVal(doc);
-      }
-
-      @Override
-      public double doubleVal(int doc) {
-        // make sure it has minX and area
-        if (validX.get(doc)) {
-          assert validY.get(doc);
-          return calculator.distance(from, Double.longBitsToDouble(ptX.get(doc)), Double.longBitsToDouble(ptY.get(doc))) * multiplier;
-        }
-        return nullValue;
-      }
-
-      @Override
-      public String toString(int doc) {
-        return description() + "=" + floatVal(doc);
-      }
-    };
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-
-    DistanceValueSource that = (DistanceValueSource) o;
-
-    if (!from.equals(that.from)) return false;
-    if (!strategy.equals(that.strategy)) return false;
-    if (multiplier != that.multiplier) return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    return from.hashCode();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java b/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
deleted file mode 100644
index d046e24..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
+++ /dev/null
@@ -1,182 +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.vector;
-
-import com.spatial4j.core.context.SpatialContext;
-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 org.apache.lucene.document.LegacyDoubleField;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.FieldType;
-import org.apache.lucene.queries.function.FunctionRangeQuery;
-import org.apache.lucene.queries.function.ValueSource;
-import org.apache.lucene.search.BooleanClause;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.ConstantScoreQuery;
-import org.apache.lucene.search.LegacyNumericRangeQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.spatial.SpatialStrategy;
-import org.apache.lucene.spatial.query.SpatialArgs;
-import org.apache.lucene.spatial.query.SpatialOperation;
-import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
-
-/**
- * Simple {@link SpatialStrategy} which represents Points in two numeric {@link
- * org.apache.lucene.document.LegacyDoubleField}s.  The Strategy's best feature is decent distance sort.
- *
- * <p>
- * <b>Characteristics:</b>
- * <br>
- * <ul>
- * <li>Only indexes points; just one per field value.</li>
- * <li>Can query by a rectangle or circle.</li>
- * <li>{@link
- * org.apache.lucene.spatial.query.SpatialOperation#Intersects} and {@link
- * SpatialOperation#IsWithin} is supported.</li>
- * <li>Uses the FieldCache for
- * {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point)} and for
- * searching with a Circle.</li>
- * </ul>
- *
- * <p>
- * <b>Implementation:</b>
- * <p>
- * This is a simple Strategy.  Search works with {@link org.apache.lucene.search.LegacyNumericRangeQuery}s on
- * an x and y pair of fields.  A Circle query does the same bbox query but adds a
- * ValueSource filter on
- * {@link #makeDistanceValueSource(com.spatial4j.core.shape.Point)}.
- * <p>
- * One performance shortcoming with this strategy is that a scenario involving
- * both a search using a Circle and sort will result in calculations for the
- * spatial distance being done twice -- once for the filter and second for the
- * sort.
- *
- * @lucene.experimental
- */
-public class PointVectorStrategy extends SpatialStrategy {
-
-  public static final String SUFFIX_X = "__x";
-  public static final String SUFFIX_Y = "__y";
-
-  private final String fieldNameX;
-  private final String fieldNameY;
-
-  public int precisionStep = 8; // same as solr default
-
-  public PointVectorStrategy(SpatialContext ctx, String fieldNamePrefix) {
-    super(ctx, fieldNamePrefix);
-    this.fieldNameX = fieldNamePrefix+SUFFIX_X;
-    this.fieldNameY = fieldNamePrefix+SUFFIX_Y;
-  }
-
-  public void setPrecisionStep( int p ) {
-    precisionStep = p;
-    if (precisionStep<=0 || precisionStep>=64)
-      precisionStep=Integer.MAX_VALUE;
-  }
-
-  String getFieldNameX() {
-    return fieldNameX;
-  }
-
-  String getFieldNameY() {
-    return fieldNameY;
-  }
-
-  @Override
-  public Field[] createIndexableFields(Shape shape) {
-    if (shape instanceof Point)
-      return createIndexableFields((Point) shape);
-    throw new UnsupportedOperationException("Can only index Point, not " + shape);
-  }
-
-  /** @see #createIndexableFields(com.spatial4j.core.shape.Shape) */
-  public Field[] createIndexableFields(Point point) {
-    FieldType doubleFieldType = new FieldType(LegacyDoubleField.TYPE_NOT_STORED);
-    doubleFieldType.setNumericPrecisionStep(precisionStep);
-    Field[] f = new Field[2];
-    f[0] = new LegacyDoubleField(fieldNameX, point.getX(), doubleFieldType);
-    f[1] = new LegacyDoubleField(fieldNameY, point.getY(), doubleFieldType);
-    return f;
-  }
-
-  @Override
-  public ValueSource makeDistanceValueSource(Point queryPoint, double multiplier) {
-    return new DistanceValueSource(this, queryPoint, multiplier);
-  }
-
-  @Override
-  public ConstantScoreQuery makeQuery(SpatialArgs args) {
-    if(! SpatialOperation.is( args.getOperation(),
-        SpatialOperation.Intersects,
-        SpatialOperation.IsWithin ))
-      throw new UnsupportedSpatialOperation(args.getOperation());
-    Shape shape = args.getShape();
-    if (shape instanceof Rectangle) {
-      Rectangle bbox = (Rectangle) shape;
-      return new ConstantScoreQuery(makeWithin(bbox));
-    } else if (shape instanceof Circle) {
-      Circle circle = (Circle)shape;
-      Rectangle bbox = circle.getBoundingBox();
-      Query approxQuery = makeWithin(bbox);
-      BooleanQuery.Builder bqBuilder = new BooleanQuery.Builder();
-      FunctionRangeQuery vsRangeQuery =
-          new FunctionRangeQuery(makeDistanceValueSource(circle.getCenter()), 0.0, circle.getRadius(), true, true);
-      bqBuilder.add(approxQuery, BooleanClause.Occur.FILTER);//should have lowest "cost" value; will drive iteration
-      bqBuilder.add(vsRangeQuery, BooleanClause.Occur.FILTER);
-      return new ConstantScoreQuery(bqBuilder.build());
-    } else {
-      throw new UnsupportedOperationException("Only Rectangles and Circles are currently supported, " +
-          "found [" + shape.getClass() + "]");//TODO
-    }
-  }
-
-  /**
-   * Constructs a query to retrieve documents that fully contain the input envelope.
-   */
-  private Query makeWithin(Rectangle bbox) {
-    BooleanQuery.Builder bq = new BooleanQuery.Builder();
-    BooleanClause.Occur MUST = BooleanClause.Occur.MUST;
-    if (bbox.getCrossesDateLine()) {
-      //use null as performance trick since no data will be beyond the world bounds
-      bq.add(rangeQuery(fieldNameX, null/*-180*/, bbox.getMaxX()), BooleanClause.Occur.SHOULD );
-      bq.add(rangeQuery(fieldNameX, bbox.getMinX(), null/*+180*/), BooleanClause.Occur.SHOULD );
-      bq.setMinimumNumberShouldMatch(1);//must match at least one of the SHOULD
-    } else {
-      bq.add(rangeQuery(fieldNameX, bbox.getMinX(), bbox.getMaxX()), MUST);
-    }
-    bq.add(rangeQuery(fieldNameY, bbox.getMinY(), bbox.getMaxY()), MUST);
-    return bq.build();
-  }
-
-  private LegacyNumericRangeQuery<Double> rangeQuery(String fieldName, Double min, Double max) {
-    return LegacyNumericRangeQuery.newDoubleRange(
-        fieldName,
-        precisionStep,
-        min,
-        max,
-        true,
-        true);//inclusive
-  }
-
-}
-
-
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/org/apache/lucene/spatial/vector/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/package-info.java b/lucene/spatial/src/java/org/apache/lucene/spatial/vector/package-info.java
deleted file mode 100644
index 47c208c..0000000
--- a/lucene/spatial/src/java/org/apache/lucene/spatial/vector/package-info.java
+++ /dev/null
@@ -1,20 +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.
- */
-/** 
- * Spatial strategy that uses two fields.
- */
-package org.apache.lucene.spatial.vector;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/java/overview.html
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/java/overview.html b/lucene/spatial/src/java/overview.html
index fb6d4f6..3c1195f 100644
--- a/lucene/spatial/src/java/overview.html
+++ b/lucene/spatial/src/java/overview.html
@@ -15,53 +15,20 @@
  limitations under the License.
 -->
 <html>
-  <head>
-    <title>Apache Lucene Spatial Module</title>
-  </head>
-  <body>
+<head>
+  <title>Apache Lucene Spatial Module</title>
+</head>
+<body>
 
-  <h1>The Spatial Module for Apache Lucene</h1>
+<h1>The Spatial Module for Apache Lucene</h1>
 
-  <p>
-    The spatial module is new to Lucene 4, replacing the old "contrib" module
-    that came before it. The principle interface to the module is
-    a {@link org.apache.lucene.spatial.SpatialStrategy}
-    which encapsulates an approach to indexing and searching
-    based on shapes.  Different Strategies have different features and
-    performance profiles, which are documented at each Strategy implementation
-    class level.
-  </p>
-  <p>
-    For some sample code showing how to use the API, see
-      SpatialExample.java in the tests.
-  </p>
-  <p>
-    The spatial module uses
-    <a href="https://github.com/spatial4j/spatial4j">Spatial4j</a>
-    heavily.  Spatial4j is an ASL licensed library with these capabilities:
-    <ul>
-    <li>Provides shape implementations, namely point, rectangle,
-      and circle.  Both geospatial contexts and plain 2D Euclidean/Cartesian contexts
-      are supported.
-      With an additional dependency, it adds polygon and other geometry shape
-      support via integration with
-      <a href="http://sourceforge.net/projects/jts-topo-suite/">JTS Topology Suite</a>.
-      This includes dateline wrap support.</li>
-    <li>Shape parsing and serialization, including
-      <a href="http://en.wikipedia.org/wiki/Well-known_text">Well-Known Text (WKT)</a>
-      (via JTS).</li>
-    <li>Distance and other spatial related math calculations.</li>
-    </ul>
-  </p>
-  <p>
-    Historical note: The new spatial module was once known as
-    Lucene Spatial Playground (LSP) as an external project.  In ~March 2012, LSP
-    split into this new module as part of Lucene and Spatial4j externally. A
-    large chunk of the LSP implementation originated as SOLR-2155 which uses
-    trie/prefix-tree algorithms with a geohash encoding.  That approach is
-    implemented in {@link org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy}
-    today.
-  </p>
-
-  </body>
-</html>
\ No newline at end of file
+<p>
+  APIs for geospatial indexing and querying. Dependencies for the spatial module are
+  restricted to inner lucene modules only. That is, no third-party dependencies
+  are allowed. The intent is to keep this module free of any integration or
+  licensing issues that might arise as a result of depending on an external library.
+  For adding or leveraging spatial features that require third-party libraries see
+  the <a href="../spatial-extras/overview-summary.html">spatial-extras</a> package.
+</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/50a2f754/lucene/spatial/src/test-files/cities-Intersects-BBox.txt
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/test-files/cities-Intersects-BBox.txt b/lucene/spatial/src/test-files/cities-Intersects-BBox.txt
deleted file mode 100644
index e85748c..0000000
--- a/lucene/spatial/src/test-files/cities-Intersects-BBox.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-[San Francisco] G5391959 @ Intersects(ENVELOPE(-122.524918, -122.360123, 37.817108, 37.674973))
-[Wellington] G2179537 @ Intersects(ENVELOPE(174.711456, 174.854279, -41.213837, -41.360779))
-[Barcelona] G6544100 G3128760  @  Intersects(ENVELOPE(2.127228, 2.226105, 41.408844, 41.333313))
\ No newline at end of file